@danypops/papyrus 0.29.6 → 0.29.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/extension/src/domain-tools.ts +24 -1
- package/package.json +1 -1
- package/src/ops.ts +28 -44
|
@@ -238,7 +238,7 @@ const checklistCriterionSchema = Type.Object({
|
|
|
238
238
|
proof: Type.Array(proofReferenceSchema, { minItems: 1 }),
|
|
239
239
|
});
|
|
240
240
|
|
|
241
|
-
export function
|
|
241
|
+
export function registerTasksTool(pi: ExtensionAPI): void {
|
|
242
242
|
pi.registerTool({
|
|
243
243
|
name: "tasks",
|
|
244
244
|
label: "Tasks",
|
|
@@ -445,7 +445,9 @@ export function registerDomainTools(pi: ExtensionAPI): void {
|
|
|
445
445
|
}
|
|
446
446
|
},
|
|
447
447
|
});
|
|
448
|
+
}
|
|
448
449
|
|
|
450
|
+
export function registerNotesTool(pi: ExtensionAPI): void {
|
|
449
451
|
pi.registerTool({
|
|
450
452
|
name: "notes",
|
|
451
453
|
label: "Notes",
|
|
@@ -496,7 +498,9 @@ export function registerDomainTools(pi: ExtensionAPI): void {
|
|
|
496
498
|
}
|
|
497
499
|
},
|
|
498
500
|
});
|
|
501
|
+
}
|
|
499
502
|
|
|
503
|
+
export function registerDocsTool(pi: ExtensionAPI): void {
|
|
500
504
|
pi.registerTool({
|
|
501
505
|
name: "docs",
|
|
502
506
|
label: "Documents",
|
|
@@ -556,7 +560,9 @@ export function registerDomainTools(pi: ExtensionAPI): void {
|
|
|
556
560
|
}
|
|
557
561
|
},
|
|
558
562
|
});
|
|
563
|
+
}
|
|
559
564
|
|
|
565
|
+
export function registerRulesTool(pi: ExtensionAPI): void {
|
|
560
566
|
pi.registerTool({
|
|
561
567
|
name: "rules",
|
|
562
568
|
label: "Rules",
|
|
@@ -604,7 +610,9 @@ export function registerDomainTools(pi: ExtensionAPI): void {
|
|
|
604
610
|
}
|
|
605
611
|
},
|
|
606
612
|
});
|
|
613
|
+
}
|
|
607
614
|
|
|
615
|
+
export function registerPlaybooksTool(pi: ExtensionAPI): void {
|
|
608
616
|
pi.registerTool({
|
|
609
617
|
name: "playbooks",
|
|
610
618
|
label: "Playbooks",
|
|
@@ -652,7 +660,9 @@ export function registerDomainTools(pi: ExtensionAPI): void {
|
|
|
652
660
|
}
|
|
653
661
|
},
|
|
654
662
|
});
|
|
663
|
+
}
|
|
655
664
|
|
|
665
|
+
export function registerSkillsTool(pi: ExtensionAPI): void {
|
|
656
666
|
pi.registerTool({
|
|
657
667
|
name: "skills",
|
|
658
668
|
label: "Skills",
|
|
@@ -729,7 +739,9 @@ export function registerDomainTools(pi: ExtensionAPI): void {
|
|
|
729
739
|
}
|
|
730
740
|
},
|
|
731
741
|
});
|
|
742
|
+
}
|
|
732
743
|
|
|
744
|
+
export function registerDiscussTool(pi: ExtensionAPI): void {
|
|
733
745
|
pi.registerTool({
|
|
734
746
|
name: "discuss",
|
|
735
747
|
label: "Discuss",
|
|
@@ -827,3 +839,14 @@ export function registerDomainTools(pi: ExtensionAPI): void {
|
|
|
827
839
|
},
|
|
828
840
|
});
|
|
829
841
|
}
|
|
842
|
+
|
|
843
|
+
/** Thin orchestrator: each domain's tool is independently navigable/testable via its own registerXTool function. */
|
|
844
|
+
export function registerDomainTools(pi: ExtensionAPI): void {
|
|
845
|
+
registerTasksTool(pi);
|
|
846
|
+
registerNotesTool(pi);
|
|
847
|
+
registerDocsTool(pi);
|
|
848
|
+
registerRulesTool(pi);
|
|
849
|
+
registerPlaybooksTool(pi);
|
|
850
|
+
registerSkillsTool(pi);
|
|
851
|
+
registerDiscussTool(pi);
|
|
852
|
+
}
|
package/package.json
CHANGED
package/src/ops.ts
CHANGED
|
@@ -507,53 +507,38 @@ function readBoundedGateFile(path: string): string {
|
|
|
507
507
|
return readFileSync(path, "utf-8") as string;
|
|
508
508
|
}
|
|
509
509
|
|
|
510
|
+
/** Shared by the sync and async process-gate runners so "test" is never a second, independently
|
|
511
|
+
* maintained copy of "command"'s own command-template/timeout selection. */
|
|
512
|
+
function processGateCommand(gate: Gate): { command: string; timeout: number } {
|
|
513
|
+
if (gate.type === "test") return { command: `npx vitest run ${gate.target} --reporter=dot`, timeout: GATE_TEST_TIMEOUT_MS };
|
|
514
|
+
return { command: gate.target, timeout: GATE_COMMAND_TIMEOUT_MS };
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* spawnSync + manual stdout/stderr concatenation, not execSync: execSync's return value is stdout
|
|
519
|
+
* only. Many real commands (bun test's own per-test lines and its pass/fail summary among them, and
|
|
520
|
+
* vitest's own "test" gate output) write their actual output to stderr, so an execSync-based match
|
|
521
|
+
* against gate.expect saw only the first line of a banner and never the result -- every such gate
|
|
522
|
+
* failed regardless of whether the command actually passed. This one function now serves both
|
|
523
|
+
* "command" and "test" gates; previously "test" was a second, separately-maintained execSync path
|
|
524
|
+
* that never checked gate.expect at all.
|
|
525
|
+
*/
|
|
526
|
+
function runProcessGateSync(gate: Gate, cwd?: string): GateResult {
|
|
527
|
+
const { spawnSync } = require_("node:child_process");
|
|
528
|
+
const { command, timeout } = processGateCommand(gate);
|
|
529
|
+
const result = spawnSync(command, { shell: true, encoding: "utf-8", timeout, ...(cwd ? { cwd } : {}) });
|
|
530
|
+
if (result.error) return { gate, passed: false, output: result.error.message.slice(0, GATE_OUTPUT_LIMIT) };
|
|
531
|
+
const combined = `${result.stdout ?? ""}${result.stderr ?? ""}`.trim();
|
|
532
|
+
const passed = result.status === 0 && (gate.expect ? combined.includes(gate.expect) : true);
|
|
533
|
+
return { gate, passed, output: combined.slice(0, GATE_OUTPUT_LIMIT) || (result.status === 0 ? "ok" : `command exited with code ${result.status}`) };
|
|
534
|
+
}
|
|
535
|
+
|
|
510
536
|
export function runGates(db: Db, artifactId: string, options: GateRunOptions = {}): GateResult[] {
|
|
511
537
|
const art = getArtifact(db, artifactId);
|
|
512
538
|
if (!art) throw new Error("artifact not found");
|
|
513
539
|
const gates = (art.extra["gates"] as Gate[]) ?? [];
|
|
514
540
|
const cwd = options.cwd;
|
|
515
|
-
return gates.map((gate) =>
|
|
516
|
-
switch (gate.type) {
|
|
517
|
-
case "file-exists": {
|
|
518
|
-
const { existsSync } = require_("node:fs");
|
|
519
|
-
const exists = existsSync(gate.target);
|
|
520
|
-
return { gate, passed: exists, output: exists ? "exists" : "not found" };
|
|
521
|
-
}
|
|
522
|
-
case "contains": {
|
|
523
|
-
try {
|
|
524
|
-
const content = readBoundedGateFile(gate.target);
|
|
525
|
-
const found = gate.expect ? content.includes(gate.expect) : content.length > 0;
|
|
526
|
-
return { gate, passed: found, output: found ? "found" : `"${gate.expect ?? ""}" not found` };
|
|
527
|
-
} catch {
|
|
528
|
-
return { gate, passed: false, output: "file not readable" };
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
case "command": {
|
|
532
|
-
// spawnSync + manual stdout/stderr concatenation, not execSync: execSync's return value is
|
|
533
|
-
// stdout only. Many real commands (bun test's own per-test lines and its pass/fail summary
|
|
534
|
-
// among them) write their actual output to stderr, so an execSync-based match against
|
|
535
|
-
// gate.expect saw only the first line of a banner and never the result -- every such gate
|
|
536
|
-
// failed regardless of whether the command actually passed.
|
|
537
|
-
const { spawnSync } = require_("node:child_process");
|
|
538
|
-
const result = spawnSync(gate.target, { shell: true, encoding: "utf-8", timeout: GATE_COMMAND_TIMEOUT_MS, ...(cwd ? { cwd } : {}) });
|
|
539
|
-
if (result.error) return { gate, passed: false, output: result.error.message.slice(0, GATE_OUTPUT_LIMIT) };
|
|
540
|
-
const combined = `${result.stdout ?? ""}${result.stderr ?? ""}`.trim();
|
|
541
|
-
const passed = result.status === 0 && (gate.expect ? combined.includes(gate.expect) : true);
|
|
542
|
-
return { gate, passed, output: combined.slice(0, GATE_OUTPUT_LIMIT) || (result.status === 0 ? "ok" : `command exited with code ${result.status}`) };
|
|
543
|
-
}
|
|
544
|
-
case "test": {
|
|
545
|
-
const { execSync } = require_("node:child_process");
|
|
546
|
-
try {
|
|
547
|
-
execSync(`npx vitest run ${gate.target} --reporter=dot`, { encoding: "utf-8", timeout: GATE_TEST_TIMEOUT_MS, stdio: ["pipe", "pipe", "pipe"], ...(cwd ? { cwd } : {}) });
|
|
548
|
-
return { gate, passed: true, output: "tests passed" };
|
|
549
|
-
} catch (e) {
|
|
550
|
-
return { gate, passed: false, output: e instanceof Error ? e.message.slice(0, GATE_OUTPUT_LIMIT) : "tests failed" };
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
default:
|
|
554
|
-
return { gate, passed: false, output: `unknown gate type: ${String(gate.type)}` };
|
|
555
|
-
}
|
|
556
|
-
});
|
|
541
|
+
return gates.map((gate) => (gate.type === "command" || gate.type === "test") ? runProcessGateSync(gate, cwd) : runNonProcessGate(gate));
|
|
557
542
|
}
|
|
558
543
|
|
|
559
544
|
/**
|
|
@@ -652,8 +637,7 @@ export async function runGatesAsync(db: Db, artifactId: string, options: GateRun
|
|
|
652
637
|
continue;
|
|
653
638
|
}
|
|
654
639
|
if (gate.type === "command" || gate.type === "test") {
|
|
655
|
-
const command
|
|
656
|
-
const configuredTimeout = gate.type === "test" ? GATE_TEST_TIMEOUT_MS : GATE_COMMAND_TIMEOUT_MS;
|
|
640
|
+
const { command, timeout: configuredTimeout } = processGateCommand(gate);
|
|
657
641
|
const timeout = remainingMs === undefined ? configuredTimeout : Math.max(1, Math.min(configuredTimeout, remainingMs));
|
|
658
642
|
const executed = await executeGateCommand(command, timeout, options.cwd);
|
|
659
643
|
results.push({
|