import assert from "node:assert/strict"; import { existsSync, readFileSync, unlinkSync, writeFileSync } from "node:fs"; import { clearOutputMetrics, getOutputMetricsSummary, trackOutputSavings } from "./output-metrics.ts"; import { mock, runTest } from "./test-helpers.test.ts"; import { matchesCommandPatterns, normalizeCommandForDetection } from "./techniques/command-detection.ts"; import { compactPath } from "./techniques/path-utils.ts"; import { filterAggressive } from "./techniques/source.ts"; import { aggregateTestOutput } from "./techniques/test-output.ts"; import { applyWindowsBashCompatibilityFixes } from "./windows-command-helpers.ts"; import { applyRewrittenCommandShellSafetyFixups } from "./rewrite-pipeline-safety.ts"; import { applyRtkCommandEnvironment } from "./rtk-command-environment.ts"; import { sanitizeStreamingBashExecutionResult } from "./tool-execution-sanitizer.ts"; mock.module("@earendil-works/pi-coding-agent", { namedExports: { getAgentDir: () => "/tmp/.pi/agent", }, }); const { ensureConfigExists, getRtkIntegrationConfigPath, loadRtkIntegrationConfig, normalizeRtkIntegrationConfig, saveRtkIntegrationConfig, } = await import("./config-store.ts"); function makeTempConfigPath(): string { return `${getRtkIntegrationConfigPath()}.test-${Date.now()}-${Math.random().toString(16).slice(2)}.json`; } function cleanupFile(path: string): void { for (const candidate of [path, `${path}.tmp`]) { try { if (existsSync(candidate)) { unlinkSync(candidate); } } catch { // Ignore cleanup failures in tests. } } } runTest("config-store normalizes invalid values and clamps numeric ranges", () => { const normalized = normalizeRtkIntegrationConfig({ enabled: "yes", mode: "invalid", rewriteGitGithub: false, outputCompaction: { stripAnsi: false, sourceCodeFilteringEnabled: "sometimes", sourceCodeFiltering: "extreme", truncate: { enabled: true, maxChars: 12, }, smartTruncate: { enabled: true, maxLines: 999_999, }, trackSavings: false, }, }); assert.equal(normalized.enabled, true); assert.equal(normalized.mode, "rewrite"); assert.equal(Object.hasOwn(normalized, "rewriteGitGithub"), false); assert.equal(normalized.outputCompaction.stripAnsi, false); assert.equal(normalized.outputCompaction.readCompaction.enabled, true); assert.equal(normalized.outputCompaction.sourceCodeFilteringEnabled, true); assert.equal(normalized.outputCompaction.sourceCodeFiltering, "minimal"); assert.equal(normalized.outputCompaction.truncate.maxChars, 1_000); assert.equal(normalized.outputCompaction.smartTruncate.maxLines, 4_000); assert.equal(normalized.outputCompaction.trackSavings, false); }); runTest("config-store uses safer read defaults when readCompaction is explicit", () => { const normalized = normalizeRtkIntegrationConfig({ outputCompaction: { readCompaction: { enabled: false }, }, }); assert.equal(normalized.outputCompaction.readCompaction.enabled, false); assert.equal(normalized.outputCompaction.sourceCodeFilteringEnabled, false); assert.equal(normalized.outputCompaction.sourceCodeFiltering, "none"); assert.equal(normalized.outputCompaction.smartTruncate.enabled, false); }); runTest("config-store can ensure, save, and reload isolated config files", () => { const tempPath = makeTempConfigPath(); cleanupFile(tempPath); try { const ensured = ensureConfigExists(tempPath); assert.equal(ensured.error, undefined); assert.equal(existsSync(tempPath), true); const defaultLoad = loadRtkIntegrationConfig(tempPath); assert.equal(defaultLoad.warning, undefined); assert.equal(defaultLoad.config.mode, "rewrite"); assert.equal(defaultLoad.config.outputCompaction.readCompaction.enabled, false); const saved = saveRtkIntegrationConfig( { ...defaultLoad.config, mode: "suggest", outputCompaction: { ...defaultLoad.config.outputCompaction, truncate: { ...defaultLoad.config.outputCompaction.truncate, maxChars: 250_000, }, }, }, tempPath, ); assert.equal(saved.success, true); const reloaded = loadRtkIntegrationConfig(tempPath); assert.equal(reloaded.config.mode, "suggest"); assert.equal(reloaded.config.outputCompaction.truncate.maxChars, 200_000); assert.ok(readFileSync(tempPath, "utf-8").endsWith("\n")); } finally { cleanupFile(tempPath); } }); runTest("config-store falls back to defaults when JSON is invalid", () => { const tempPath = makeTempConfigPath(); cleanupFile(tempPath); try { writeFileSync(tempPath, "{not valid json", "utf-8"); const loaded = loadRtkIntegrationConfig(tempPath); assert.equal(loaded.config.mode, "rewrite"); assert.ok((loaded.warning ?? "").includes(tempPath)); assert.ok((loaded.warning ?? "").includes("Failed to parse")); } finally { cleanupFile(tempPath); } }); runTest("config-store malformed-file defaults are isolated from caller mutation", () => { const tempPath = makeTempConfigPath(); cleanupFile(tempPath); try { writeFileSync(tempPath, "{not valid json", "utf-8"); const firstLoad = loadRtkIntegrationConfig(tempPath); firstLoad.config.outputCompaction.truncate.maxChars = 42_424; firstLoad.config.outputCompaction.readCompaction.enabled = true; const secondLoad = loadRtkIntegrationConfig(tempPath); assert.equal(secondLoad.config.outputCompaction.truncate.maxChars, 12_000); assert.equal(secondLoad.config.outputCompaction.readCompaction.enabled, false); } finally { cleanupFile(tempPath); } }); runTest("output metrics summarize tracked savings and clear state", () => { clearOutputMetrics(); assert.equal(getOutputMetricsSummary(), "RTK output compaction metrics: no data yet."); const first = trackOutputSavings("1234567890", "12345", "bash", ["ansi", "truncate"]); assert.equal(first.tool, "bash"); assert.equal(first.techniques, "ansi,truncate"); assert.equal(first.savingsPercent, 50); trackOutputSavings("123456", "1234", "read", []); const summary = getOutputMetricsSummary(); assert.ok(summary.includes("calls=2, saved=7 chars (43.8%)")); assert.ok(summary.includes("- bash: 1 calls, saved 5 chars (50.0%)")); assert.ok(summary.includes("- read: 1 calls, saved 2 chars (33.3%)")); clearOutputMetrics(); assert.equal(getOutputMetricsSummary(), "RTK output compaction metrics: no data yet."); }); runTest("aggressive source filtering ignores string and inline comment braces while tracking implementation blocks", () => { const withLiteralBrace = [ "function first() {", ' const value = "{";', " return value;", "}", "function second() {", " return true;", "}", ].join("\n"); const withoutLiteralBrace = [ "function first() {", ' const value = "plain";', " return value;", "}", "function second() {", " return true;", "}", ].join("\n"); const withInlineCommentBrace = [ "function first() {", " const value = 1; // {", " return value;", "}", "function second() {", " return true;", "}", ].join("\n"); const withoutInlineCommentBrace = [ "function first() {", " const value = 1; // no brace", " return value;", "}", "function second() {", " return true;", "}", ].join("\n"); assert.equal(filterAggressive(withLiteralBrace, "typescript"), filterAggressive(withoutLiteralBrace, "typescript")); assert.equal(filterAggressive(withInlineCommentBrace, "typescript"), filterAggressive(withoutInlineCommentBrace, "typescript")); }); runTest("test output fallback counts unicode pass and fail symbols", () => { const result = aggregateTestOutput("āœ“ creates user\nāœ” updates user\nāœ• deletes user\nāœ— archives user\n", "bun test"); assert.ok(result?.includes("PASS: 2 passed")); assert.ok(result?.includes("FAIL: 2 failed")); }); runTest("command detection ignores env prefixes, blank lines, and chained suffixes", () => { assert.equal(normalizeCommandForDetection("NODE_ENV=test FOO=bar npm test && echo done"), "npm test"); assert.equal(normalizeCommandForDetection("\n\n PYTHONPATH=src git status\n echo later"), "git status"); assert.equal(normalizeCommandForDetection(" "), null); assert.equal(matchesCommandPatterns("CI=1 bun test | head -5", [/^bun test/]), true); assert.equal(matchesCommandPatterns("echo hello", [/^bun test/]), false); }); runTest("RTK command environment preserves explicit leading RTK_DB_PATH overrides", () => { const command = 'RTK_DB_PATH="/custom/history.db" rtk git diff'; assert.equal(applyRtkCommandEnvironment(command), command); const singleQuotedCommand = "RTK_DB_PATH='/custom/it'\\''s/history.db' rtk git diff"; assert.equal(applyRtkCommandEnvironment(singleQuotedCommand), singleQuotedCommand); const exportedCommand = 'export RTK_DB_PATH="/custom/history.db"; rtk git diff'; assert.equal(applyRtkCommandEnvironment(exportedCommand), exportedCommand); }); runTest("RTK command environment respects inherited RTK_DB_PATH values", () => { const previousRtkDbPath = process.env.RTK_DB_PATH; const command = "rtk git status"; try { process.env.RTK_DB_PATH = "/persistent/shared/history.db"; assert.equal(applyRtkCommandEnvironment(command), command); } finally { if (previousRtkDbPath === undefined) { delete process.env.RTK_DB_PATH; } else { process.env.RTK_DB_PATH = previousRtkDbPath; } } }); runTest("RTK command environment ignores blank inherited RTK_DB_PATH values", () => { const previousRtkDbPath = process.env.RTK_DB_PATH; try { process.env.RTK_DB_PATH = " "; assert.match(applyRtkCommandEnvironment("rtk git status"), /^export RTK_DB_PATH=/); } finally { if (previousRtkDbPath === undefined) { delete process.env.RTK_DB_PATH; } else { process.env.RTK_DB_PATH = previousRtkDbPath; } } }); runTest("RTK command environment single-quotes hostile temp paths", () => { const previousTmpDir = process.env.TMPDIR; const previousTmp = process.env.TMP; const previousTemp = process.env.TEMP; const hostilePath = process.platform === "win32" ? "C:\\Temp\\$(touch owned)`bad`'dir" : "/tmp/$(touch owned)`bad`'dir"; try { process.env.TMPDIR = hostilePath; process.env.TMP = hostilePath; process.env.TEMP = hostilePath; const rewritten = applyRtkCommandEnvironment("rtk git status"); assert.ok(rewritten.startsWith("export RTK_DB_PATH='")); assert.ok(rewritten.includes("$(touch owned)`bad`'\\''dir")); assert.ok(rewritten.endsWith("; rtk git status")); assert.equal(/^export RTK_DB_PATH=\"/.test(rewritten), false); } finally { process.env.TMPDIR = previousTmpDir; process.env.TMP = previousTmp; process.env.TEMP = previousTemp; } }); runTest("path compaction preserves the tail and handles Windows separators", () => { const unixPath = "/Users/example/projects/pi-rtk-optimizer/src/techniques/path-utils.ts"; const compactUnixPath = compactPath(unixPath, 28); assert.ok(compactUnixPath.length <= 28); assert.ok(compactUnixPath.endsWith("path-utils.ts")); assert.ok(compactUnixPath.includes("/")); const windowsPath = "C:\\Users\\Administrator\\Documents\\pi-rtk-optimizer\\src\\windows-command-helpers.ts"; const compactWindowsPath = compactPath(windowsPath, 30); assert.ok(compactWindowsPath.length <= 30); assert.equal(compactWindowsPath.includes("\\"), true); assert.ok(compactWindowsPath.endsWith("windows-command-helpers.ts")); assert.equal(compactPath("src/file.ts", 40), "src/file.ts"); }); runTest("windows bash compatibility rewrites only when the runtime is Windows", () => { const command = "cd /d C:\\Users\\Administrator\\project && python script.py"; const fixed = applyWindowsBashCompatibilityFixes(command, "win32"); assert.deepEqual(fixed.applied, ["cd-/d", "python-utf8"]); assert.equal( fixed.command, 'PYTHONIOENCODING=utf-8 cd "C:/Users/Administrator/project" && python script.py', ); const unchanged = applyWindowsBashCompatibilityFixes(command, "linux"); assert.deepEqual(unchanged.applied, []); assert.equal(unchanged.command, command); const alreadyUtf8 = applyWindowsBashCompatibilityFixes("PYTHONIOENCODING=utf-8 python script.py", "win32"); assert.deepEqual(alreadyUtf8.applied, []); assert.equal(alreadyUtf8.command, "PYTHONIOENCODING=utf-8 python script.py"); }); runTest("windows bash compatibility rewrites compound cd slash-d operators", () => { assert.equal( applyWindowsBashCompatibilityFixes("cd /d C:\\work || echo failed", "win32").command, 'cd "C:/work" || echo failed', ); assert.equal( applyWindowsBashCompatibilityFixes("cd /d C:\\work ; echo done", "win32").command, 'cd "C:/work" ; echo done', ); assert.equal( applyWindowsBashCompatibilityFixes("cd /d C:\\work | cat", "win32").command, 'cd "C:/work" | cat', ); assert.equal( applyWindowsBashCompatibilityFixes('cd /d "C:\\work space" || echo failed', "win32").command, 'cd "C:/work space" || echo failed', ); }); runTest("rewrite pipeline safety buffers rewritten Windows producer commands", () => { const rewritten = applyRewrittenCommandShellSafetyFixups("rtk git diff | grep TODO", "win32"); assert.ok(rewritten.includes('mktemp')); assert.ok(rewritten.includes('trap')); assert.ok(rewritten.includes('rtk git diff > "$__pi_rtk_pipe_tmp"')); assert.ok(rewritten.includes('(grep TODO) < "$__pi_rtk_pipe_tmp"')); assert.equal( applyRewrittenCommandShellSafetyFixups("rtk git diff | grep TODO", "linux"), "rtk git diff | grep TODO", ); assert.equal(applyRewrittenCommandShellSafetyFixups("git diff | grep TODO", "win32"), "git diff | grep TODO"); }); runTest("rewrite pipeline safety buffers leading pipelines before compound suffixes", () => { const andCommand = applyRewrittenCommandShellSafetyFixups("rtk git diff | grep TODO && echo done", "win32"); assert.ok(andCommand.includes('(grep TODO) < "$__pi_rtk_pipe_tmp"')); assert.ok(andCommand.endsWith("&& echo done")); const orCommand = applyRewrittenCommandShellSafetyFixups("rtk git diff | grep TODO || echo none", "win32"); assert.ok(orCommand.includes('(grep TODO) < "$__pi_rtk_pipe_tmp"')); assert.ok(orCommand.endsWith("|| echo none")); const semicolonCommand = applyRewrittenCommandShellSafetyFixups("rtk git diff | grep TODO; echo done", "win32"); assert.ok(semicolonCommand.includes('(grep TODO) < "$__pi_rtk_pipe_tmp"')); assert.ok(semicolonCommand.endsWith("; echo done")); }); runTest("rewrite pipeline safety keeps exported RTK_DB_PATH on rewritten producer commands", () => { const envScopedCommand = applyRtkCommandEnvironment("rtk git diff agent/extensions/pi-multi-auth/account-manager.ts | head -200"); const rewritten = applyRewrittenCommandShellSafetyFixups(envScopedCommand, "win32"); assert.ok(rewritten.startsWith("export RTK_DB_PATH=")); assert.equal(rewritten.startsWith("RTK_DB_PATH="), false); assert.ok(rewritten.includes("; {")); assert.ok( rewritten.includes('rtk git diff agent/extensions/pi-multi-auth/account-manager.ts > "$__pi_rtk_pipe_tmp"'), ); assert.ok(rewritten.includes('(head -200) < "$__pi_rtk_pipe_tmp"')); assert.equal(applyRewrittenCommandShellSafetyFixups(envScopedCommand, "linux"), envScopedCommand); }); runTest("rewrite pipeline safety buffers explicit RTK_DB_PATH export preludes", () => { const command = 'export RTK_DB_PATH="/custom/history.db"; rtk git diff | head -200'; const rewritten = applyRewrittenCommandShellSafetyFixups(command, "win32"); assert.ok(rewritten.startsWith('export RTK_DB_PATH="/custom/history.db"; {')); assert.ok(rewritten.includes('rtk git diff > "$__pi_rtk_pipe_tmp"')); assert.ok(rewritten.includes('(head -200) < "$__pi_rtk_pipe_tmp"')); assert.equal(applyRewrittenCommandShellSafetyFixups(command, "linux"), command); }); runTest("RTK command environment uses export prelude for shell compound commands", () => { const rewritten = applyRtkCommandEnvironment('for d in a b; do echo "$d"; done'); assert.ok(/^export RTK_DB_PATH=/.test(rewritten)); assert.ok(/; for d in a b; do echo "\$d"; done$/.test(rewritten)); }); runTest("streaming sanitizer strips ANSI codes and preserves non-text blocks", () => { const ansiResult = { content: [ { type: "text", text: "\x1B[32mworking tree clean\x1B[0m\n" }, { type: "image", url: "ignored" }, ], }; const ansiSanitization = sanitizeStreamingBashExecutionResult(ansiResult, "rtk git status"); assert.equal(ansiSanitization.changed, true); assert.equal( ((ansiSanitization.result as typeof ansiResult).content[0] as { text: string }).text, "working tree clean\n", ); assert.equal((ansiResult.content[0] as { text: string }).text, "\x1B[32mworking tree clean\x1B[0m\n"); assert.deepEqual((ansiSanitization.result as typeof ansiResult).content[1], { type: "image", url: "ignored" }); const plainResult = { content: [ { type: "text", text: "[rtk] warning: builtin filters: parse failure\n\nworking tree clean\n", }, ], }; const plainSanitization = sanitizeStreamingBashExecutionResult(plainResult, "rtk git status"); assert.equal(plainSanitization.changed, false); assert.equal(plainSanitization.result, plainResult); assert.equal( (plainResult.content[0] as { text: string }).text, "[rtk] warning: builtin filters: parse failure\n\nworking tree clean\n", ); }); console.log("All additional coverage tests passed.");