gsd-pi 2.26.0 → 2.27.0
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/README.md +43 -6
- package/dist/cli.js +4 -2
- package/dist/headless.d.ts +3 -0
- package/dist/headless.js +136 -8
- package/dist/help-text.js +3 -0
- package/dist/loader.js +33 -4
- package/dist/resources/extensions/bg-shell/index.ts +19 -2
- package/dist/resources/extensions/bg-shell/process-manager.ts +45 -0
- package/dist/resources/extensions/bg-shell/types.ts +21 -1
- package/dist/resources/extensions/gsd/auto/session.ts +224 -0
- package/dist/resources/extensions/gsd/auto-budget.ts +32 -0
- package/dist/resources/extensions/gsd/auto-dashboard.ts +63 -10
- package/dist/resources/extensions/gsd/auto-direct-dispatch.ts +229 -0
- package/dist/resources/extensions/gsd/auto-dispatch.ts +23 -10
- package/dist/resources/extensions/gsd/auto-model-selection.ts +179 -0
- package/dist/resources/extensions/gsd/auto-observability.ts +74 -0
- package/dist/resources/extensions/gsd/auto-prompts.ts +0 -1
- package/dist/resources/extensions/gsd/auto-timeout-recovery.ts +262 -0
- package/dist/resources/extensions/gsd/auto-tool-tracking.ts +54 -0
- package/dist/resources/extensions/gsd/auto-unit-closeout.ts +46 -0
- package/dist/resources/extensions/gsd/auto-worktree-sync.ts +207 -0
- package/dist/resources/extensions/gsd/auto.ts +977 -1551
- package/dist/resources/extensions/gsd/commands.ts +3 -3
- package/dist/resources/extensions/gsd/dashboard-overlay.ts +47 -72
- package/dist/resources/extensions/gsd/doctor-proactive.ts +9 -4
- package/dist/resources/extensions/gsd/export-html.ts +1001 -0
- package/dist/resources/extensions/gsd/export.ts +49 -1
- package/dist/resources/extensions/gsd/git-service.ts +6 -0
- package/dist/resources/extensions/gsd/gitignore.ts +4 -1
- package/dist/resources/extensions/gsd/guided-flow.ts +24 -5
- package/dist/resources/extensions/gsd/index.ts +54 -1
- package/dist/resources/extensions/gsd/native-git-bridge.ts +30 -2
- package/dist/resources/extensions/gsd/observability-validator.ts +21 -0
- package/dist/resources/extensions/gsd/parallel-orchestrator.ts +231 -20
- package/dist/resources/extensions/gsd/preferences.ts +62 -1
- package/dist/resources/extensions/gsd/prompts/execute-task.md +4 -3
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/reports.ts +510 -0
- package/dist/resources/extensions/gsd/roadmap-slices.ts +1 -1
- package/dist/resources/extensions/gsd/skills/gsd-headless/SKILL.md +178 -0
- package/dist/resources/extensions/gsd/skills/gsd-headless/references/answer-injection.md +54 -0
- package/dist/resources/extensions/gsd/skills/gsd-headless/references/commands.md +59 -0
- package/dist/resources/extensions/gsd/skills/gsd-headless/references/multi-session.md +185 -0
- package/dist/resources/extensions/gsd/state.ts +30 -0
- package/dist/resources/extensions/gsd/templates/task-summary.md +9 -0
- package/dist/resources/extensions/gsd/tests/auto-dashboard.test.ts +13 -0
- package/dist/resources/extensions/gsd/tests/continue-here.test.ts +81 -0
- package/dist/resources/extensions/gsd/tests/derive-state-db.test.ts +5 -0
- package/dist/resources/extensions/gsd/tests/derive-state-deps.test.ts +1 -0
- package/dist/resources/extensions/gsd/tests/derive-state-draft.test.ts +1 -0
- package/dist/resources/extensions/gsd/tests/derive-state.test.ts +10 -1
- package/dist/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +132 -0
- package/dist/resources/extensions/gsd/tests/doctor-proactive.test.ts +14 -0
- package/dist/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +1 -0
- package/dist/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/native-has-changes-cache.test.ts +61 -0
- package/dist/resources/extensions/gsd/tests/network-error-fallback.test.ts +51 -1
- package/dist/resources/extensions/gsd/tests/parallel-budget-atomicity.test.ts +331 -0
- package/dist/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +298 -0
- package/dist/resources/extensions/gsd/tests/parallel-merge.test.ts +465 -0
- package/dist/resources/extensions/gsd/tests/parallel-orchestration.test.ts +39 -10
- package/dist/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +71 -0
- package/dist/resources/extensions/gsd/tests/replan-slice.test.ts +42 -0
- package/dist/resources/extensions/gsd/tests/triage-dispatch.test.ts +9 -9
- package/dist/resources/extensions/gsd/tests/verification-evidence.test.ts +743 -0
- package/dist/resources/extensions/gsd/tests/verification-gate.test.ts +965 -0
- package/dist/resources/extensions/gsd/tests/visualizer-data.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/visualizer-overlay.test.ts +44 -10
- package/dist/resources/extensions/gsd/tests/worktree.test.ts +3 -1
- package/dist/resources/extensions/gsd/types.ts +38 -0
- package/dist/resources/extensions/gsd/verification-evidence.ts +183 -0
- package/dist/resources/extensions/gsd/verification-gate.ts +567 -0
- package/dist/resources/extensions/gsd/visualizer-data.ts +25 -3
- package/dist/resources/extensions/gsd/visualizer-overlay.ts +31 -21
- package/dist/resources/extensions/gsd/visualizer-views.ts +15 -66
- package/dist/resources/extensions/search-the-web/tool-search.ts +26 -0
- package/dist/resources/extensions/shared/format-utils.ts +85 -0
- package/dist/resources/extensions/shared/tests/format-utils.test.ts +153 -0
- package/dist/resources/extensions/subagent/index.ts +46 -1
- package/dist/resources/extensions/subagent/isolation.ts +9 -6
- package/package.json +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +7 -4
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/src/providers/openai-completions.ts +7 -4
- package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.js +7 -0
- package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/config.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/config.js +9 -2
- package/packages/pi-coding-agent/dist/core/lsp/config.js.map +1 -1
- package/packages/pi-coding-agent/src/core/lsp/client.ts +8 -0
- package/packages/pi-coding-agent/src/core/lsp/config.ts +9 -2
- package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/editor.js +1 -1
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/src/components/editor.ts +3 -1
- package/scripts/link-workspace-packages.cjs +22 -6
- package/src/resources/extensions/bg-shell/index.ts +19 -2
- package/src/resources/extensions/bg-shell/process-manager.ts +45 -0
- package/src/resources/extensions/bg-shell/types.ts +21 -1
- package/src/resources/extensions/gsd/auto/session.ts +224 -0
- package/src/resources/extensions/gsd/auto-budget.ts +32 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +63 -10
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +229 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +23 -10
- package/src/resources/extensions/gsd/auto-model-selection.ts +179 -0
- package/src/resources/extensions/gsd/auto-observability.ts +74 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +0 -1
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +262 -0
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +54 -0
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +46 -0
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +207 -0
- package/src/resources/extensions/gsd/auto.ts +977 -1551
- package/src/resources/extensions/gsd/commands.ts +3 -3
- package/src/resources/extensions/gsd/dashboard-overlay.ts +47 -72
- package/src/resources/extensions/gsd/doctor-proactive.ts +9 -4
- package/src/resources/extensions/gsd/export-html.ts +1001 -0
- package/src/resources/extensions/gsd/export.ts +49 -1
- package/src/resources/extensions/gsd/git-service.ts +6 -0
- package/src/resources/extensions/gsd/gitignore.ts +4 -1
- package/src/resources/extensions/gsd/guided-flow.ts +24 -5
- package/src/resources/extensions/gsd/index.ts +54 -1
- package/src/resources/extensions/gsd/native-git-bridge.ts +30 -2
- package/src/resources/extensions/gsd/observability-validator.ts +21 -0
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +231 -20
- package/src/resources/extensions/gsd/preferences.ts +62 -1
- package/src/resources/extensions/gsd/prompts/execute-task.md +4 -3
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/reports.ts +510 -0
- package/src/resources/extensions/gsd/roadmap-slices.ts +1 -1
- package/src/resources/extensions/gsd/skills/gsd-headless/SKILL.md +178 -0
- package/src/resources/extensions/gsd/skills/gsd-headless/references/answer-injection.md +54 -0
- package/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md +59 -0
- package/src/resources/extensions/gsd/skills/gsd-headless/references/multi-session.md +185 -0
- package/src/resources/extensions/gsd/state.ts +30 -0
- package/src/resources/extensions/gsd/templates/task-summary.md +9 -0
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +13 -0
- package/src/resources/extensions/gsd/tests/continue-here.test.ts +81 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +5 -0
- package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/derive-state-draft.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +10 -1
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +132 -0
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/native-has-changes-cache.test.ts +61 -0
- package/src/resources/extensions/gsd/tests/network-error-fallback.test.ts +51 -1
- package/src/resources/extensions/gsd/tests/parallel-budget-atomicity.test.ts +331 -0
- package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +298 -0
- package/src/resources/extensions/gsd/tests/parallel-merge.test.ts +465 -0
- package/src/resources/extensions/gsd/tests/parallel-orchestration.test.ts +39 -10
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +71 -0
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +9 -9
- package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +743 -0
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +965 -0
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +44 -10
- package/src/resources/extensions/gsd/tests/worktree.test.ts +3 -1
- package/src/resources/extensions/gsd/types.ts +38 -0
- package/src/resources/extensions/gsd/verification-evidence.ts +183 -0
- package/src/resources/extensions/gsd/verification-gate.ts +567 -0
- package/src/resources/extensions/gsd/visualizer-data.ts +25 -3
- package/src/resources/extensions/gsd/visualizer-overlay.ts +31 -21
- package/src/resources/extensions/gsd/visualizer-views.ts +15 -66
- package/src/resources/extensions/search-the-web/tool-search.ts +26 -0
- package/src/resources/extensions/shared/format-utils.ts +85 -0
- package/src/resources/extensions/shared/tests/format-utils.test.ts +153 -0
- package/src/resources/extensions/subagent/index.ts +46 -1
- package/src/resources/extensions/subagent/isolation.ts +9 -6
|
@@ -24,18 +24,28 @@ assertTrue(
|
|
|
24
24
|
);
|
|
25
25
|
|
|
26
26
|
assertTrue(
|
|
27
|
-
overlaySrc.includes('"
|
|
28
|
-
"has
|
|
27
|
+
overlaySrc.includes('"2 Timeline"'),
|
|
28
|
+
"has Timeline tab label",
|
|
29
29
|
);
|
|
30
30
|
|
|
31
31
|
assertTrue(
|
|
32
|
-
overlaySrc.includes('"
|
|
33
|
-
"has
|
|
32
|
+
overlaySrc.includes('"3 Deps"'),
|
|
33
|
+
"has Deps tab label",
|
|
34
34
|
);
|
|
35
35
|
|
|
36
36
|
assertTrue(
|
|
37
|
-
overlaySrc.includes('"
|
|
38
|
-
"has
|
|
37
|
+
overlaySrc.includes('"5 Health"'),
|
|
38
|
+
"has Health tab label",
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
assertTrue(
|
|
42
|
+
overlaySrc.includes('"6 Agent"'),
|
|
43
|
+
"has Agent tab label",
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
assertTrue(
|
|
47
|
+
overlaySrc.includes('"7 Changes"'),
|
|
48
|
+
"has Changes tab label",
|
|
39
49
|
);
|
|
40
50
|
|
|
41
51
|
assertTrue(
|
|
@@ -49,8 +59,8 @@ assertTrue(
|
|
|
49
59
|
);
|
|
50
60
|
|
|
51
61
|
assertTrue(
|
|
52
|
-
overlaySrc.includes('"0
|
|
53
|
-
"has
|
|
62
|
+
overlaySrc.includes('"0 Export"'),
|
|
63
|
+
"has Export tab label",
|
|
54
64
|
);
|
|
55
65
|
|
|
56
66
|
console.log("\n=== Overlay: Filter Mode ===");
|
|
@@ -162,8 +172,8 @@ assertTrue(
|
|
|
162
172
|
console.log("\n=== Overlay: Export Key Interception ===");
|
|
163
173
|
|
|
164
174
|
assertTrue(
|
|
165
|
-
overlaySrc.includes("activeTab ===
|
|
166
|
-
"export key handling checks for tab
|
|
175
|
+
overlaySrc.includes("activeTab === 9"),
|
|
176
|
+
"export key handling checks for tab 0 (index 9)",
|
|
167
177
|
);
|
|
168
178
|
|
|
169
179
|
assertTrue(
|
|
@@ -200,4 +210,28 @@ assertTrue(
|
|
|
200
210
|
"scroll offsets sized to TAB_COUNT",
|
|
201
211
|
);
|
|
202
212
|
|
|
213
|
+
console.log("\n=== Overlay: Terminal Resize Handling ===");
|
|
214
|
+
|
|
215
|
+
assertTrue(
|
|
216
|
+
overlaySrc.includes('resizeHandler'),
|
|
217
|
+
"has resizeHandler property",
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
assertTrue(
|
|
221
|
+
overlaySrc.includes('"resize"'),
|
|
222
|
+
"listens for resize events",
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
assertTrue(
|
|
226
|
+
overlaySrc.includes('removeListener("resize"'),
|
|
227
|
+
"removes resize listener on dispose",
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
console.log("\n=== Overlay: Shared Imports ===");
|
|
231
|
+
|
|
232
|
+
assertTrue(
|
|
233
|
+
overlaySrc.includes('from "../shared/format-utils.js"'),
|
|
234
|
+
"imports from shared format-utils",
|
|
235
|
+
);
|
|
236
|
+
|
|
203
237
|
report();
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
SLICE_BRANCH_RE,
|
|
16
16
|
} from "../worktree.ts";
|
|
17
17
|
import { readIntegrationBranch } from "../git-service.ts";
|
|
18
|
+
import { _resetHasChangesCache } from "../native-git-bridge.ts";
|
|
18
19
|
import { createTestContext } from './test-helpers.ts';
|
|
19
20
|
|
|
20
21
|
const { assertEq, assertTrue, report } = createTestContext();
|
|
@@ -40,7 +41,8 @@ async function main(): Promise<void> {
|
|
|
40
41
|
const cleanResult = autoCommitCurrentBranch(base, "execute-task", "M001/S01/T01");
|
|
41
42
|
assertEq(cleanResult, null, "returns null for clean repo");
|
|
42
43
|
|
|
43
|
-
// Make dirty
|
|
44
|
+
// Make dirty — reset the nativeHasChanges cache so the fresh dirt is detected
|
|
45
|
+
_resetHasChangesCache();
|
|
44
46
|
writeFileSync(join(base, "dirty.txt"), "uncommitted\n", "utf-8");
|
|
45
47
|
const dirtyResult = autoCommitCurrentBranch(base, "execute-task", "M001/S01/T01");
|
|
46
48
|
assertTrue(dirtyResult !== null, "returns commit message for dirty repo");
|
|
@@ -46,6 +46,44 @@ export interface TaskPlanEntry {
|
|
|
46
46
|
verify?: string; // e.g. "run tests" — extracted from "- Verify:" subline
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
// ─── Verification Gate ─────────────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
/** Result of a single verification command execution */
|
|
52
|
+
export interface VerificationCheck {
|
|
53
|
+
command: string; // e.g. "npm run lint"
|
|
54
|
+
exitCode: number; // 0 = pass
|
|
55
|
+
stdout: string;
|
|
56
|
+
stderr: string;
|
|
57
|
+
durationMs: number;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** A runtime error captured from bg-shell processes or browser console */
|
|
61
|
+
export interface RuntimeError {
|
|
62
|
+
source: "bg-shell" | "browser";
|
|
63
|
+
severity: "crash" | "error" | "warning";
|
|
64
|
+
message: string;
|
|
65
|
+
blocking: boolean;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** A dependency vulnerability warning from npm audit */
|
|
69
|
+
export interface AuditWarning {
|
|
70
|
+
name: string;
|
|
71
|
+
severity: "low" | "moderate" | "high" | "critical";
|
|
72
|
+
title: string;
|
|
73
|
+
url: string;
|
|
74
|
+
fixAvailable: boolean;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Aggregate result from the verification gate */
|
|
78
|
+
export interface VerificationResult {
|
|
79
|
+
passed: boolean; // true if all checks passed (or no checks discovered)
|
|
80
|
+
checks: VerificationCheck[]; // per-command results
|
|
81
|
+
discoverySource: "preference" | "task-plan" | "package-json" | "none";
|
|
82
|
+
timestamp: number; // Date.now() at gate start
|
|
83
|
+
runtimeErrors?: RuntimeError[]; // optional — populated by captureRuntimeErrors()
|
|
84
|
+
auditWarnings?: AuditWarning[]; // optional — populated by runDependencyAudit()
|
|
85
|
+
}
|
|
86
|
+
|
|
49
87
|
export interface SlicePlan {
|
|
50
88
|
id: string; // e.g. "S01"
|
|
51
89
|
title: string; // from the H1
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verification Evidence — JSON persistence and markdown table formatting.
|
|
3
|
+
*
|
|
4
|
+
* Two pure-ish functions:
|
|
5
|
+
* - writeVerificationJSON: persists a machine-readable T##-VERIFY.json artifact
|
|
6
|
+
* - formatEvidenceTable: returns a markdown evidence table string
|
|
7
|
+
*
|
|
8
|
+
* JSON schema uses schemaVersion: 1 for forward-compatibility.
|
|
9
|
+
* stdout/stderr are intentionally excluded from the JSON to avoid unbounded file sizes.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
import type { VerificationResult } from "./types.ts";
|
|
15
|
+
|
|
16
|
+
// ─── JSON Evidence Artifact ──────────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
export interface EvidenceCheckJSON {
|
|
19
|
+
command: string;
|
|
20
|
+
exitCode: number;
|
|
21
|
+
durationMs: number;
|
|
22
|
+
verdict: "pass" | "fail";
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface RuntimeErrorJSON {
|
|
26
|
+
source: string;
|
|
27
|
+
severity: string;
|
|
28
|
+
message: string;
|
|
29
|
+
blocking: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface AuditWarningJSON {
|
|
33
|
+
name: string;
|
|
34
|
+
severity: string;
|
|
35
|
+
title: string;
|
|
36
|
+
url: string;
|
|
37
|
+
fixAvailable: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface EvidenceJSON {
|
|
41
|
+
schemaVersion: 1;
|
|
42
|
+
taskId: string;
|
|
43
|
+
unitId: string;
|
|
44
|
+
timestamp: number;
|
|
45
|
+
passed: boolean;
|
|
46
|
+
discoverySource: string;
|
|
47
|
+
checks: EvidenceCheckJSON[];
|
|
48
|
+
retryAttempt?: number;
|
|
49
|
+
maxRetries?: number;
|
|
50
|
+
runtimeErrors?: RuntimeErrorJSON[];
|
|
51
|
+
auditWarnings?: AuditWarningJSON[];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Write a T##-VERIFY.json artifact to the tasks directory.
|
|
56
|
+
* Creates the directory with mkdirSync({ recursive: true }) if it doesn't exist.
|
|
57
|
+
*
|
|
58
|
+
* stdout/stderr are excluded from the JSON — the full output lives in VerificationResult
|
|
59
|
+
* in memory and is logged to stderr during the gate run.
|
|
60
|
+
*/
|
|
61
|
+
export function writeVerificationJSON(
|
|
62
|
+
result: VerificationResult,
|
|
63
|
+
tasksDir: string,
|
|
64
|
+
taskId: string,
|
|
65
|
+
unitId?: string,
|
|
66
|
+
retryAttempt?: number,
|
|
67
|
+
maxRetries?: number,
|
|
68
|
+
): void {
|
|
69
|
+
mkdirSync(tasksDir, { recursive: true });
|
|
70
|
+
|
|
71
|
+
const evidence: EvidenceJSON = {
|
|
72
|
+
schemaVersion: 1,
|
|
73
|
+
taskId,
|
|
74
|
+
unitId: unitId ?? taskId,
|
|
75
|
+
timestamp: result.timestamp,
|
|
76
|
+
passed: result.passed,
|
|
77
|
+
discoverySource: result.discoverySource,
|
|
78
|
+
checks: result.checks.map((check) => ({
|
|
79
|
+
command: check.command,
|
|
80
|
+
exitCode: check.exitCode,
|
|
81
|
+
durationMs: check.durationMs,
|
|
82
|
+
verdict: check.exitCode === 0 ? "pass" : "fail",
|
|
83
|
+
})),
|
|
84
|
+
...(retryAttempt !== undefined ? { retryAttempt } : {}),
|
|
85
|
+
...(maxRetries !== undefined ? { maxRetries } : {}),
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
if (result.runtimeErrors && result.runtimeErrors.length > 0) {
|
|
89
|
+
evidence.runtimeErrors = result.runtimeErrors.map(e => ({
|
|
90
|
+
source: e.source,
|
|
91
|
+
severity: e.severity,
|
|
92
|
+
message: e.message,
|
|
93
|
+
blocking: e.blocking,
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (result.auditWarnings && result.auditWarnings.length > 0) {
|
|
98
|
+
evidence.auditWarnings = result.auditWarnings.map(w => ({
|
|
99
|
+
name: w.name,
|
|
100
|
+
severity: w.severity,
|
|
101
|
+
title: w.title,
|
|
102
|
+
url: w.url,
|
|
103
|
+
fixAvailable: w.fixAvailable,
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const filePath = join(tasksDir, `${taskId}-VERIFY.json`);
|
|
108
|
+
writeFileSync(filePath, JSON.stringify(evidence, null, 2) + "\n", "utf-8");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ─── Markdown Evidence Table ─────────────────────────────────────────────────
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Format duration in milliseconds as seconds with 1 decimal place.
|
|
115
|
+
* e.g. 2340 → "2.3s", 150 → "0.2s", 0 → "0.0s"
|
|
116
|
+
*/
|
|
117
|
+
function formatDuration(ms: number): string {
|
|
118
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Generate a markdown evidence table from a VerificationResult.
|
|
123
|
+
*
|
|
124
|
+
* Returns a "no checks" note if result.checks is empty.
|
|
125
|
+
* Otherwise returns a 5-column markdown table: #, Command, Exit Code, Verdict, Duration.
|
|
126
|
+
*/
|
|
127
|
+
export function formatEvidenceTable(result: VerificationResult): string {
|
|
128
|
+
if (result.checks.length === 0) {
|
|
129
|
+
return "_No verification checks discovered._";
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const lines: string[] = [
|
|
133
|
+
"| # | Command | Exit Code | Verdict | Duration |",
|
|
134
|
+
"|---|---------|-----------|---------|----------|",
|
|
135
|
+
];
|
|
136
|
+
|
|
137
|
+
for (let i = 0; i < result.checks.length; i++) {
|
|
138
|
+
const check = result.checks[i];
|
|
139
|
+
const num = i + 1;
|
|
140
|
+
const verdict =
|
|
141
|
+
check.exitCode === 0 ? "✅ pass" : "❌ fail";
|
|
142
|
+
const duration = formatDuration(check.durationMs);
|
|
143
|
+
|
|
144
|
+
lines.push(
|
|
145
|
+
`| ${num} | ${check.command} | ${check.exitCode} | ${verdict} | ${duration} |`,
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (result.runtimeErrors && result.runtimeErrors.length > 0) {
|
|
150
|
+
lines.push("");
|
|
151
|
+
lines.push("**Runtime Errors**");
|
|
152
|
+
lines.push("");
|
|
153
|
+
lines.push("| # | Source | Severity | Blocking | Message |");
|
|
154
|
+
lines.push("|---|--------|----------|----------|---------|");
|
|
155
|
+
for (let i = 0; i < result.runtimeErrors.length; i++) {
|
|
156
|
+
const err = result.runtimeErrors[i];
|
|
157
|
+
const blockIcon = err.blocking ? "🚫 yes" : "ℹ️ no";
|
|
158
|
+
lines.push(`| ${i + 1} | ${err.source} | ${err.severity} | ${blockIcon} | ${err.message.slice(0, 100)} |`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (result.auditWarnings && result.auditWarnings.length > 0) {
|
|
163
|
+
const severityEmoji: Record<string, string> = {
|
|
164
|
+
critical: "🔴",
|
|
165
|
+
high: "🟠",
|
|
166
|
+
moderate: "🟡",
|
|
167
|
+
low: "⚪",
|
|
168
|
+
};
|
|
169
|
+
lines.push("");
|
|
170
|
+
lines.push("**Audit Warnings**");
|
|
171
|
+
lines.push("");
|
|
172
|
+
lines.push("| # | Package | Severity | Title | Fix Available |");
|
|
173
|
+
lines.push("|---|---------|----------|-------|---------------|");
|
|
174
|
+
for (let i = 0; i < result.auditWarnings.length; i++) {
|
|
175
|
+
const w = result.auditWarnings[i];
|
|
176
|
+
const emoji = severityEmoji[w.severity] ?? "⚪";
|
|
177
|
+
const fix = w.fixAvailable ? "✅ yes" : "❌ no";
|
|
178
|
+
lines.push(`| ${i + 1} | ${w.name} | ${emoji} ${w.severity} | ${w.title} | ${fix} |`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return lines.join("\n");
|
|
183
|
+
}
|