88 lines
3.6 KiB
TypeScript
88 lines
3.6 KiB
TypeScript
import { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
import { describe, expect, test } from "bun:test";
|
|
|
|
import {
|
|
collectMdtodoSafeTitleStdinCapability,
|
|
renderMdtodoSafeTitleCommand,
|
|
} from "../../src/components/microservices/code-queue/src/skill-availability";
|
|
|
|
function writeFixture(root: string, stdinReady: boolean): void {
|
|
const scripts = join(root, "mdtodo-edit", "scripts");
|
|
mkdirSync(scripts, { recursive: true });
|
|
const option = stdinReady ? " --stdin" : " title";
|
|
const script = `#!/usr/bin/env python3\nimport sys\nprint("usage: mdtodo " + sys.argv[1] + "\\n${option}")\n`;
|
|
const path = join(scripts, "mdtodo-edit-cli.py");
|
|
writeFileSync(path, script);
|
|
chmodSync(path, 0o755);
|
|
}
|
|
|
|
describe("MDTODO safe title stdin adoption", () => {
|
|
test("reports stale and ready source/target capability without blocking", () => {
|
|
const temporary = mkdtempSync("/tmp/unidesk-mdtodo-safe-input-");
|
|
try {
|
|
const source = join(temporary, "source");
|
|
const staleSource = join(temporary, "stale-source");
|
|
const staleTarget = join(temporary, "stale-target");
|
|
const readyTarget = join(temporary, "ready-target");
|
|
writeFixture(source, true);
|
|
writeFixture(staleSource, false);
|
|
writeFixture(staleTarget, false);
|
|
writeFixture(readyTarget, true);
|
|
|
|
expect(collectMdtodoSafeTitleStdinCapability(source, staleTarget)).toMatchObject({
|
|
nonBlocking: true,
|
|
ready: false,
|
|
freshness: "target-stale",
|
|
source: { ready: true },
|
|
target: { ready: false },
|
|
});
|
|
expect(collectMdtodoSafeTitleStdinCapability(source, readyTarget)).toMatchObject({
|
|
nonBlocking: true,
|
|
ready: true,
|
|
freshness: "ready",
|
|
warning: null,
|
|
});
|
|
expect(collectMdtodoSafeTitleStdinCapability(staleSource, readyTarget)).toMatchObject({
|
|
nonBlocking: true,
|
|
ready: true,
|
|
freshness: "source-stale",
|
|
source: { ready: false },
|
|
target: { ready: true },
|
|
warning: expect.stringContaining("approved source"),
|
|
});
|
|
} finally {
|
|
rmSync(temporary, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("keeps Markdown and shell syntax in quoted heredoc stdin", () => {
|
|
const temporary = mkdtempSync("/tmp/unidesk-mdtodo-command-");
|
|
try {
|
|
const home = join(temporary, "home");
|
|
const scripts = join(home, ".agents", "skills", "mdtodo-edit", "scripts");
|
|
const output = join(temporary, "title.txt");
|
|
const forbidden = join(temporary, "forbidden");
|
|
mkdirSync(scripts, { recursive: true });
|
|
writeFileSync(join(scripts, "mdtodo-edit-cli.py"), [
|
|
"import os, sys",
|
|
"open(os.environ['TITLE_OUTPUT'], 'w', encoding='utf-8').write(sys.stdin.read())",
|
|
].join("\n"));
|
|
const title = `修复 \`path\` 与 $(touch ${forbidden}) 的 'quoted' 标题`;
|
|
const command = renderMdtodoSafeTitleCommand("docs/MDTODO/demo file.md", "add").replace("<title>", title);
|
|
|
|
expect(command).toContain("'docs/MDTODO/demo file.md'");
|
|
expect(command).toContain("--stdin <<'EOF'");
|
|
expect(command.split("--stdin", 1)[0]).not.toContain(title);
|
|
const result = Bun.spawnSync(["bash", "-c", command], {
|
|
env: { ...process.env, HOME: home, TITLE_OUTPUT: output },
|
|
});
|
|
expect(result.exitCode).toBe(0);
|
|
expect(readFileSync(output, "utf8")).toBe(`${title}\n`);
|
|
expect(existsSync(forbidden)).toBe(false);
|
|
} finally {
|
|
rmSync(temporary, { recursive: true, force: true });
|
|
}
|
|
});
|
|
});
|