Merge pull request #1920 from pikasTech/fix/mdtodo-safe-input-adoption
fix: 让 MDTODO 安全 stdin skill 漂移可见
This commit is contained in:
@@ -6091,6 +6091,9 @@ function compactSkillsStatus(value: unknown): Record<string, unknown> | null {
|
||||
readonly: record.readonly ?? false,
|
||||
skillCount: record.skillCount ?? 0,
|
||||
version: record.version ?? null,
|
||||
capabilities: record.capabilities ?? null,
|
||||
warnings: Array.isArray(record.warnings) ? record.warnings.map(String) : [],
|
||||
next: record.next ?? null,
|
||||
sourceSkillCount: record.sourceSkillCount ?? null,
|
||||
targetSkillCount: record.targetSkillCount ?? null,
|
||||
sourceMissingSkills: Array.isArray(record.sourceMissingSkills) ? record.sourceMissingSkills.map(String) : [],
|
||||
@@ -6151,6 +6154,8 @@ function compactSkillsSyncStatus(value: unknown, full = false): Record<string, u
|
||||
expected: record.expected ?? null,
|
||||
counts: record.counts ?? null,
|
||||
version: record.version ?? null,
|
||||
capabilities: record.capabilities ?? null,
|
||||
warnings: Array.isArray(record.warnings) ? record.warnings.map(String) : [],
|
||||
missing: record.missing ?? null,
|
||||
permissionFailures: Array.isArray(record.permissionFailures) ? record.permissionFailures.slice(0, full ? undefined : 4) : [],
|
||||
permissionFailureCount: Array.isArray(record.permissionFailures) ? record.permissionFailures.length : 0,
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
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 });
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user