gsd-pi 2.76.0-dev.97807402 → 2.76.0-dev.97f5583d9
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/dist/resources/extensions/gsd/auto/phases.js +28 -1
- package/dist/resources/extensions/gsd/auto/session.js +12 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +16 -3
- package/dist/resources/extensions/gsd/auto-post-unit.js +24 -1
- package/dist/resources/extensions/gsd/auto-prompts.js +14 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +21 -5
- package/dist/resources/extensions/gsd/auto.js +42 -10
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +11 -1
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +22 -1
- package/dist/resources/extensions/gsd/clean-root-preflight.js +93 -0
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +96 -0
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +3 -1
- package/dist/resources/extensions/gsd/safety/safety-harness.js +1 -1
- package/dist/resources/extensions/gsd/uok/plan-v2.js +20 -3
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +1 -1
- package/packages/mcp-server/dist/server.d.ts +7 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +23 -3
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/src/mcp-server.test.ts +30 -0
- package/packages/mcp-server/src/server.ts +43 -9
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js +1 -1
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +25 -4
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +8 -3
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +80 -0
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -0
- package/packages/pi-ai/src/providers/anthropic-auth.test.ts +1 -1
- package/packages/pi-ai/src/providers/anthropic-shared.ts +23 -4
- package/packages/pi-ai/src/providers/anthropic.ts +9 -3
- package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +98 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/src/resources/extensions/gsd/auto/loop-deps.ts +13 -0
- package/src/resources/extensions/gsd/auto/phases.ts +52 -1
- package/src/resources/extensions/gsd/auto/session.ts +22 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +16 -3
- package/src/resources/extensions/gsd/auto-post-unit.ts +28 -1
- package/src/resources/extensions/gsd/auto-prompts.ts +28 -1
- package/src/resources/extensions/gsd/auto-worktree.ts +28 -11
- package/src/resources/extensions/gsd/auto.ts +46 -10
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +11 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +22 -1
- package/src/resources/extensions/gsd/clean-root-preflight.ts +111 -0
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +119 -0
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +3 -1
- package/src/resources/extensions/gsd/safety/safety-harness.ts +3 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +272 -0
- package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +205 -0
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +23 -0
- package/src/resources/extensions/gsd/uok/plan-v2.ts +26 -3
- package/src/resources/extensions/gsd/workflow-logger.ts +2 -1
- /package/dist/web/standalone/.next/static/{pI48IF3dgfs0CBrYi2bh_ → lLdDRDspgYzfz0bJAmUSz}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{pI48IF3dgfs0CBrYi2bh_ → lLdDRDspgYzfz0bJAmUSz}/_ssgManifest.js +0 -0
|
@@ -3,9 +3,17 @@
|
|
|
3
3
|
* Tracks every bash command, file write, and file edit during a unit execution.
|
|
4
4
|
* Evidence is compared against LLM completion claims in evidence-cross-ref.ts.
|
|
5
5
|
*
|
|
6
|
+
* Evidence is persisted to .gsd/safety/evidence-<mid>-<sid>-<tid>.json so it
|
|
7
|
+
* survives session restarts (pause/resume, crash recovery). On unit start,
|
|
8
|
+
* call resetEvidence() then loadEvidenceFromDisk(). On every new tool call,
|
|
9
|
+
* saveEvidenceToDisk() is called automatically by recordToolCall/recordToolResult.
|
|
10
|
+
*
|
|
6
11
|
* Follows the same module-level Map pattern as auto-tool-tracking.ts.
|
|
7
12
|
* Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
|
|
8
13
|
*/
|
|
14
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync, unlinkSync, } from "node:fs";
|
|
15
|
+
import { join, dirname } from "node:path";
|
|
16
|
+
import { randomBytes } from "node:crypto";
|
|
9
17
|
// ─── Module State ───────────────────────────────────────────────────────────
|
|
10
18
|
let unitEvidence = [];
|
|
11
19
|
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
@@ -27,6 +35,94 @@ export function getFilePaths() {
|
|
|
27
35
|
.filter((e) => e.kind === "write" || e.kind === "edit")
|
|
28
36
|
.map(e => e.path);
|
|
29
37
|
}
|
|
38
|
+
// ─── Persistence (Bug #4385 — evidence must survive session restarts) ────────
|
|
39
|
+
/**
|
|
40
|
+
* Build the path for the evidence JSON file for a given unit.
|
|
41
|
+
* Lives under .gsd/safety/ which is gitignored and session-scoped.
|
|
42
|
+
*/
|
|
43
|
+
function evidencePath(basePath, milestoneId, sliceId, taskId) {
|
|
44
|
+
return join(basePath, ".gsd", "safety", `evidence-${milestoneId}-${sliceId}-${taskId}.json`);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Validate that a parsed value is an array of EvidenceEntry objects.
|
|
48
|
+
* Rejects corrupt / schema-mismatch data rather than letting it poison state.
|
|
49
|
+
*/
|
|
50
|
+
function isEvidenceArray(data) {
|
|
51
|
+
if (!Array.isArray(data))
|
|
52
|
+
return false;
|
|
53
|
+
return data.every((e) => {
|
|
54
|
+
if (e === null || typeof e !== "object")
|
|
55
|
+
return false;
|
|
56
|
+
const rec = e;
|
|
57
|
+
if (typeof rec.toolCallId !== "string")
|
|
58
|
+
return false;
|
|
59
|
+
if (typeof rec.timestamp !== "number")
|
|
60
|
+
return false;
|
|
61
|
+
if (rec.kind === "bash") {
|
|
62
|
+
return (typeof rec.command === "string" &&
|
|
63
|
+
typeof rec.exitCode === "number" &&
|
|
64
|
+
typeof rec.outputSnippet === "string");
|
|
65
|
+
}
|
|
66
|
+
if (rec.kind === "write" || rec.kind === "edit") {
|
|
67
|
+
return typeof rec.path === "string";
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Persist the current in-memory evidence to disk so it survives a session
|
|
74
|
+
* restart. Called from saveEvidenceToDisk after recordToolCall/recordToolResult.
|
|
75
|
+
* Non-fatal — persistence failures must never break unit execution.
|
|
76
|
+
*/
|
|
77
|
+
export function saveEvidenceToDisk(basePath, milestoneId, sliceId, taskId) {
|
|
78
|
+
try {
|
|
79
|
+
const path = evidencePath(basePath, milestoneId, sliceId, taskId);
|
|
80
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
81
|
+
const tmp = `${path}.tmp.${randomBytes(4).toString("hex")}`;
|
|
82
|
+
writeFileSync(tmp, JSON.stringify(unitEvidence, null, 2) + "\n", "utf-8");
|
|
83
|
+
renameSync(tmp, path);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// Non-fatal — don't let persistence failures break unit execution
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Load persisted evidence from disk into the in-memory array.
|
|
91
|
+
* Call after resetEvidence() on session resume to restore context for a
|
|
92
|
+
* partially-executed unit. If the file does not exist (fresh unit), this
|
|
93
|
+
* is a no-op — getEvidence() will return [] which is correct.
|
|
94
|
+
*/
|
|
95
|
+
export function loadEvidenceFromDisk(basePath, milestoneId, sliceId, taskId) {
|
|
96
|
+
try {
|
|
97
|
+
const path = evidencePath(basePath, milestoneId, sliceId, taskId);
|
|
98
|
+
if (!existsSync(path))
|
|
99
|
+
return;
|
|
100
|
+
const raw = readFileSync(path, "utf-8");
|
|
101
|
+
const parsed = JSON.parse(raw);
|
|
102
|
+
if (isEvidenceArray(parsed)) {
|
|
103
|
+
unitEvidence = parsed;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// Non-fatal — corrupt / missing file is treated as empty evidence
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Delete the persisted evidence file for a unit after it has been fully
|
|
112
|
+
* processed. Prevents stale evidence from affecting future retries of
|
|
113
|
+
* the same unit ID.
|
|
114
|
+
*/
|
|
115
|
+
export function clearEvidenceFromDisk(basePath, milestoneId, sliceId, taskId) {
|
|
116
|
+
try {
|
|
117
|
+
const path = evidencePath(basePath, milestoneId, sliceId, taskId);
|
|
118
|
+
if (existsSync(path)) {
|
|
119
|
+
unlinkSync(path);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// Non-fatal
|
|
124
|
+
}
|
|
125
|
+
}
|
|
30
126
|
// ─── Recording (called from register-hooks.ts) ─────────────────────────────
|
|
31
127
|
/**
|
|
32
128
|
* Record a tool call at dispatch time (before execution).
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Uses tasks.expected_output (DB column, populated from per-task ## Expected Output)
|
|
6
6
|
* and tasks.files (from slice PLAN.md - Files: subline) as the expected set.
|
|
7
|
-
* Compares against git diff
|
|
7
|
+
* Compares against `git diff-tree --root --no-commit-id -r --name-only HEAD` after auto-commit.
|
|
8
|
+
* Using diff-tree --root handles initial commits, shallow clones, and merge commits correctly
|
|
9
|
+
* (Bug #4385 — git diff HEAD~1 failed on initial commits).
|
|
8
10
|
*
|
|
9
11
|
* Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
|
|
10
12
|
*/
|
|
@@ -60,7 +60,7 @@ export function isHarnessEnabled(raw) {
|
|
|
60
60
|
return DEFAULTS.enabled;
|
|
61
61
|
}
|
|
62
62
|
// ─── Re-exports ─────────────────────────────────────────────────────────────
|
|
63
|
-
export { resetEvidence, getEvidence, getBashEvidence, getFilePaths, recordToolCall, recordToolResult, } from "./evidence-collector.js";
|
|
63
|
+
export { resetEvidence, getEvidence, getBashEvidence, getFilePaths, recordToolCall, recordToolResult, saveEvidenceToDisk, loadEvidenceFromDisk, clearEvidenceFromDisk, } from "./evidence-collector.js";
|
|
64
64
|
export { classifyCommand } from "./destructive-guard.js";
|
|
65
65
|
export { validateFileChanges } from "./file-change-validator.js";
|
|
66
66
|
export { crossReferenceEvidence } from "./evidence-cross-ref.js";
|
|
@@ -22,6 +22,23 @@ function hasFileContent(path) {
|
|
|
22
22
|
return false;
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
+
function getArtifactLookupBases(basePath) {
|
|
26
|
+
const bases = [basePath];
|
|
27
|
+
const projectRoot = process.env.GSD_PROJECT_ROOT;
|
|
28
|
+
if (projectRoot && projectRoot.trim().length > 0 && projectRoot !== basePath) {
|
|
29
|
+
bases.push(projectRoot);
|
|
30
|
+
}
|
|
31
|
+
return bases;
|
|
32
|
+
}
|
|
33
|
+
function hasMilestoneFileContent(basePath, milestoneId, suffix) {
|
|
34
|
+
const bases = getArtifactLookupBases(basePath);
|
|
35
|
+
for (const candidateBase of bases) {
|
|
36
|
+
if (hasFileContent(resolveMilestoneFile(candidateBase, milestoneId, suffix))) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
25
42
|
function countSliceResearchArtifacts(basePath, milestoneId, slices) {
|
|
26
43
|
let count = 0;
|
|
27
44
|
for (const slice of slices) {
|
|
@@ -43,9 +60,9 @@ export function compileUnitGraphFromState(basePath, state) {
|
|
|
43
60
|
const slices = getMilestoneSlices(mid).sort((a, b) => Number(a.sequence ?? 0) - Number(b.sequence ?? 0));
|
|
44
61
|
const nodes = [];
|
|
45
62
|
const clarifyRoundLimit = PLAN_V2_CLARIFY_ROUND_LIMIT;
|
|
46
|
-
const draftContextIncluded =
|
|
47
|
-
const finalizedContextIncluded =
|
|
48
|
-
const researchSynthesized =
|
|
63
|
+
const draftContextIncluded = hasMilestoneFileContent(basePath, mid, "CONTEXT-DRAFT");
|
|
64
|
+
const finalizedContextIncluded = hasMilestoneFileContent(basePath, mid, "CONTEXT");
|
|
65
|
+
const researchSynthesized = hasMilestoneFileContent(basePath, mid, "RESEARCH")
|
|
49
66
|
|| countSliceResearchArtifacts(basePath, mid, slices) > 0;
|
|
50
67
|
if (isExecutionEntryPhase(state.phase) && !finalizedContextIncluded) {
|
|
51
68
|
const reason = draftContextIncluded
|