gsd-pi 2.48.0-dev.ced2eca → 2.49.0-dev.9e177e9
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/headless-ui.js +12 -2
- package/dist/headless.js +29 -13
- package/dist/resources/extensions/gsd/auto/infra-errors.js +1 -0
- package/dist/resources/extensions/gsd/auto/phases.js +11 -11
- package/dist/resources/extensions/gsd/auto/resolve.js +2 -2
- package/dist/resources/extensions/gsd/auto/run-unit.js +2 -2
- package/dist/resources/extensions/gsd/auto/session.js +4 -0
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +8 -10
- package/dist/resources/extensions/gsd/auto-dashboard.js +6 -3
- package/dist/resources/extensions/gsd/auto-dispatch.js +33 -21
- package/dist/resources/extensions/gsd/auto-post-unit.js +17 -24
- package/dist/resources/extensions/gsd/auto-prompts.js +102 -21
- package/dist/resources/extensions/gsd/auto-recovery.js +62 -184
- package/dist/resources/extensions/gsd/auto-start.js +4 -31
- package/dist/resources/extensions/gsd/auto-timers.js +2 -2
- package/dist/resources/extensions/gsd/auto-verification.js +4 -7
- package/dist/resources/extensions/gsd/auto-worktree.js +257 -113
- package/dist/resources/extensions/gsd/auto.js +7 -5
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +89 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +8 -1
- package/dist/resources/extensions/gsd/branch-patterns.js +13 -0
- package/dist/resources/extensions/gsd/doctor-checks.js +5 -1234
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +168 -0
- package/dist/resources/extensions/gsd/doctor-environment.js +28 -7
- package/dist/resources/extensions/gsd/doctor-git-checks.js +405 -0
- package/dist/resources/extensions/gsd/doctor-global-checks.js +74 -0
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +600 -0
- package/dist/resources/extensions/gsd/doctor.js +9 -1
- package/dist/resources/extensions/gsd/extension-manifest.json +1 -1
- package/dist/resources/extensions/gsd/git-service.js +9 -10
- package/dist/resources/extensions/gsd/gsd-db.js +124 -1
- package/dist/resources/extensions/gsd/guided-flow-queue.js +10 -11
- package/dist/resources/extensions/gsd/markdown-renderer.js +33 -5
- package/dist/resources/extensions/gsd/preferences-types.js +2 -1
- package/dist/resources/extensions/gsd/preferences-validation.js +39 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +27 -8
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +9 -8
- package/dist/resources/extensions/gsd/prompts/execute-task.md +16 -13
- package/dist/resources/extensions/gsd/prompts/forensics.md +12 -5
- package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +32 -0
- package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +8 -3
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +3 -0
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
- package/dist/resources/extensions/gsd/repo-identity.js +29 -0
- package/dist/resources/extensions/gsd/roadmap-slices.js +2 -2
- package/dist/resources/extensions/gsd/session-forensics.js +6 -11
- package/dist/resources/extensions/gsd/session-lock.js +67 -56
- package/dist/resources/extensions/gsd/state.js +34 -7
- package/dist/resources/extensions/gsd/templates/milestone-summary.md +8 -0
- package/dist/resources/extensions/gsd/templates/plan.md +16 -0
- package/dist/resources/extensions/gsd/templates/roadmap.md +13 -0
- package/dist/resources/extensions/gsd/templates/slice-summary.md +9 -0
- package/dist/resources/extensions/gsd/templates/task-plan.md +24 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +14 -1
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +3 -3
- package/dist/resources/extensions/gsd/verdict-parser.js +84 -0
- package/dist/resources/extensions/gsd/worktree-resolver.js +24 -0
- package/dist/resources/extensions/gsd/worktree.js +3 -2
- package/dist/resources/extensions/remote-questions/config.js +3 -5
- package/dist/resources/extensions/search-the-web/native-search.js +8 -3
- package/dist/resources/extensions/search-the-web/tool-search.js +19 -2
- package/dist/resources/skills/github-workflows/references/gh/SKILL.md +22 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +19 -19
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/required-server-files.json +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- 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 +19 -19
- package/dist/web/standalone/.next/server/chunks/229.js +2 -2
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/4024.7c75ac378de0f2b5.js +9 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-0a4cd455ec4197d2.js → webpack-2473ce2c3879fff4.js} +1 -1
- package/dist/web/standalone/server.js +1 -1
- package/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +4 -1
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.ts +4 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +39 -10
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/src/providers/openai-codex-responses.ts +39 -8
- package/packages/pi-coding-agent/dist/core/blob-store.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/blob-store.js +8 -3
- package/packages/pi-coding-agent/dist/core/blob-store.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/discovery-cache.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/discovery-cache.js +9 -2
- package/packages/pi-coding-agent/dist/core/discovery-cache.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -32
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/jsonl.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/jsonl.js +5 -0
- package/packages/pi-coding-agent/dist/modes/rpc/jsonl.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js +0 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/blob-store.ts +6 -3
- package/packages/pi-coding-agent/src/core/discovery-cache.ts +9 -2
- package/packages/pi-coding-agent/src/core/retry-handler.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +7 -32
- package/packages/pi-coding-agent/src/modes/rpc/jsonl.ts +6 -0
- package/packages/pi-coding-agent/src/modes/rpc/rpc-client.ts +0 -2
- package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/auto/infra-errors.ts +1 -0
- package/src/resources/extensions/gsd/auto/phases.ts +10 -11
- package/src/resources/extensions/gsd/auto/resolve.ts +3 -3
- package/src/resources/extensions/gsd/auto/run-unit.ts +2 -2
- package/src/resources/extensions/gsd/auto/session.ts +5 -0
- package/src/resources/extensions/gsd/auto/types.ts +13 -0
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +19 -21
- package/src/resources/extensions/gsd/auto-dashboard.ts +5 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +39 -21
- package/src/resources/extensions/gsd/auto-loop.ts +1 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +18 -28
- package/src/resources/extensions/gsd/auto-prompts.ts +113 -19
- package/src/resources/extensions/gsd/auto-recovery.ts +65 -199
- package/src/resources/extensions/gsd/auto-start.ts +7 -27
- package/src/resources/extensions/gsd/auto-timers.ts +2 -2
- package/src/resources/extensions/gsd/auto-verification.ts +4 -7
- package/src/resources/extensions/gsd/auto-worktree.ts +305 -108
- package/src/resources/extensions/gsd/auto.ts +11 -10
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +93 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +8 -0
- package/src/resources/extensions/gsd/branch-patterns.ts +16 -0
- package/src/resources/extensions/gsd/doctor-checks.ts +5 -1291
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +182 -0
- package/src/resources/extensions/gsd/doctor-environment.ts +30 -7
- package/src/resources/extensions/gsd/doctor-git-checks.ts +415 -0
- package/src/resources/extensions/gsd/doctor-global-checks.ts +84 -0
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +626 -0
- package/src/resources/extensions/gsd/doctor.ts +9 -1
- package/src/resources/extensions/gsd/extension-manifest.json +1 -1
- package/src/resources/extensions/gsd/git-service.ts +7 -15
- package/src/resources/extensions/gsd/gsd-db.ts +150 -2
- package/src/resources/extensions/gsd/guided-flow-queue.ts +11 -12
- package/src/resources/extensions/gsd/markdown-renderer.ts +37 -4
- package/src/resources/extensions/gsd/preferences-types.ts +5 -1
- package/src/resources/extensions/gsd/preferences-validation.ts +37 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +27 -8
- package/src/resources/extensions/gsd/prompts/complete-slice.md +9 -8
- package/src/resources/extensions/gsd/prompts/execute-task.md +16 -13
- package/src/resources/extensions/gsd/prompts/forensics.md +12 -5
- package/src/resources/extensions/gsd/prompts/gate-evaluate.md +32 -0
- package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +8 -3
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +3 -0
- package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
- package/src/resources/extensions/gsd/repo-identity.ts +28 -0
- package/src/resources/extensions/gsd/roadmap-slices.ts +2 -2
- package/src/resources/extensions/gsd/session-forensics.ts +6 -11
- package/src/resources/extensions/gsd/session-lock.ts +92 -64
- package/src/resources/extensions/gsd/state.ts +38 -5
- package/src/resources/extensions/gsd/templates/milestone-summary.md +8 -0
- package/src/resources/extensions/gsd/templates/plan.md +16 -0
- package/src/resources/extensions/gsd/templates/roadmap.md +13 -0
- package/src/resources/extensions/gsd/templates/slice-summary.md +9 -0
- package/src/resources/extensions/gsd/templates/task-plan.md +24 -0
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +1 -81
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +9 -12
- package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +115 -1
- package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +65 -1
- package/src/resources/extensions/gsd/tests/doctor-git.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +189 -0
- package/src/resources/extensions/gsd/tests/gate-storage.test.ts +156 -0
- package/src/resources/extensions/gsd/tests/git-service.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +12 -2
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/quality-gates.test.ts +347 -0
- package/src/resources/extensions/gsd/tests/queue-completed-milestone-perf.test.ts +155 -0
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +20 -16
- package/src/resources/extensions/gsd/tests/session-lock-transient-read.test.ts +223 -0
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +44 -4
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +0 -16
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +204 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +16 -0
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +3 -3
- package/src/resources/extensions/gsd/types.ts +30 -0
- package/src/resources/extensions/gsd/verdict-parser.ts +95 -0
- package/src/resources/extensions/gsd/verification-gate.ts +0 -2
- package/src/resources/extensions/gsd/worktree-resolver.ts +31 -0
- package/src/resources/extensions/gsd/worktree.ts +3 -2
- package/src/resources/extensions/remote-questions/config.ts +3 -5
- package/src/resources/extensions/search-the-web/native-search.ts +8 -3
- package/src/resources/extensions/search-the-web/tool-search.ts +22 -2
- package/src/resources/skills/github-workflows/references/gh/SKILL.md +22 -1
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +0 -191
- package/dist/resources/extensions/gsd/resource-version.js +0 -97
- package/dist/web/standalone/.next/static/chunks/4024.11ca5c01938e5948.js +0 -9
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +0 -234
- package/src/resources/extensions/gsd/resource-version.ts +0 -101
- /package/dist/web/standalone/.next/static/{PTL5V00OW8q4-092tUQKx → vNN0h0emdEi8l_npi8poE}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{PTL5V00OW8q4-092tUQKx → vNN0h0emdEi8l_npi8poE}/_ssgManifest.js +0 -0
|
@@ -48,11 +48,17 @@ export function attachJsonlLineReader(stream: Readable, onLine: (line: string) =
|
|
|
48
48
|
}
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
+
const onError = (_err: Error) => {
|
|
52
|
+
// Stream errors are non-fatal for JSONL reading
|
|
53
|
+
};
|
|
54
|
+
|
|
51
55
|
stream.on("data", onData);
|
|
52
56
|
stream.on("end", onEnd);
|
|
57
|
+
stream.on("error", onError);
|
|
53
58
|
|
|
54
59
|
return () => {
|
|
55
60
|
stream.off("data", onData);
|
|
56
61
|
stream.off("end", onEnd);
|
|
62
|
+
stream.off("error", onError);
|
|
57
63
|
};
|
|
58
64
|
}
|
|
@@ -488,8 +488,6 @@ export class RpcClient {
|
|
|
488
488
|
const fullCommand = { ...command, id } as RpcCommand;
|
|
489
489
|
|
|
490
490
|
return new Promise((resolve, reject) => {
|
|
491
|
-
this.pendingRequests.set(id, { resolve, reject });
|
|
492
|
-
|
|
493
491
|
const timeout = setTimeout(() => {
|
|
494
492
|
this.pendingRequests.delete(id);
|
|
495
493
|
reject(new Error(`Timeout waiting for response to ${command.type}. Stderr: ${this.stderr}`));
|
|
@@ -710,8 +710,8 @@ export async function runRpcMode(session: AgentSession): Promise<never> {
|
|
|
710
710
|
}
|
|
711
711
|
|
|
712
712
|
default: {
|
|
713
|
-
const unknownCommand = command as { type: string };
|
|
714
|
-
return error(
|
|
713
|
+
const unknownCommand = command as { type: string; id?: string };
|
|
714
|
+
return error(unknownCommand.id, unknownCommand.type, `Unknown command: ${unknownCommand.type}`);
|
|
715
715
|
}
|
|
716
716
|
}
|
|
717
717
|
};
|
package/pkg/package.json
CHANGED
|
@@ -18,6 +18,7 @@ export const INFRA_ERROR_CODES: ReadonlySet<string> = new Set([
|
|
|
18
18
|
"EDQUOT", // disk quota exceeded
|
|
19
19
|
"EMFILE", // too many open files (process)
|
|
20
20
|
"ENFILE", // too many open files (system)
|
|
21
|
+
"EAGAIN", // resource temporarily unavailable (resource exhaustion)
|
|
21
22
|
"ECONNREFUSED", // connection refused (offline / local server down)
|
|
22
23
|
"ENOTFOUND", // DNS lookup failed (offline / no network)
|
|
23
24
|
"ENETUNREACH", // network unreachable (offline / no route)
|
|
@@ -1039,17 +1039,16 @@ export async function runUnitPhase(
|
|
|
1039
1039
|
);
|
|
1040
1040
|
|
|
1041
1041
|
// Tag the most recent window entry with error info for stuck detection
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
if (
|
|
1042
|
+
const lastEntry = loopState.recentUnits[loopState.recentUnits.length - 1];
|
|
1043
|
+
if (lastEntry) {
|
|
1044
|
+
if (unitResult.errorContext) {
|
|
1045
|
+
lastEntry.error = `${unitResult.errorContext.category}:${unitResult.errorContext.message}`.slice(0, 200);
|
|
1046
|
+
} else if (unitResult.status === "error" || unitResult.status === "cancelled") {
|
|
1045
1047
|
lastEntry.error = `${unitResult.status}:${unitType}/${unitId}`;
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
if (/error|fail|exception/i.test(msgStr)) {
|
|
1051
|
-
const lastEntry = loopState.recentUnits[loopState.recentUnits.length - 1];
|
|
1052
|
-
if (lastEntry) {
|
|
1048
|
+
} else if (unitResult.event?.messages?.length) {
|
|
1049
|
+
const lastMsg = unitResult.event.messages[unitResult.event.messages.length - 1];
|
|
1050
|
+
const msgStr = typeof lastMsg === "string" ? lastMsg : JSON.stringify(lastMsg);
|
|
1051
|
+
if (/error|fail|exception/i.test(msgStr)) {
|
|
1053
1052
|
lastEntry.error = msgStr.slice(0, 200);
|
|
1054
1053
|
}
|
|
1055
1054
|
}
|
|
@@ -1122,7 +1121,7 @@ export async function runUnitPhase(
|
|
|
1122
1121
|
s.unitRecoveryCount.delete(`${unitType}/${unitId}`);
|
|
1123
1122
|
}
|
|
1124
1123
|
|
|
1125
|
-
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "unit-end", data: { unitType, unitId, status: unitResult.status, artifactVerified }, causedBy: { flowId: ic.flowId, seq: unitStartSeq } });
|
|
1124
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "unit-end", data: { unitType, unitId, status: unitResult.status, artifactVerified, ...(unitResult.errorContext ? { errorContext: unitResult.errorContext } : {}) }, causedBy: { flowId: ic.flowId, seq: unitStartSeq } });
|
|
1126
1125
|
|
|
1127
1126
|
return { action: "next", data: { unitStartedAt: s.currentUnit.startedAt } };
|
|
1128
1127
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Imports from: auto/types
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import type { UnitResult, AgentEndEvent } from "./types.js";
|
|
11
|
+
import type { UnitResult, AgentEndEvent, ErrorContext } from "./types.js";
|
|
12
12
|
import type { AutoSession } from "./session.js";
|
|
13
13
|
import { debugLog } from "../debug-logger.js";
|
|
14
14
|
|
|
@@ -77,12 +77,12 @@ export function isSessionSwitchInFlight(): boolean {
|
|
|
77
77
|
* blocks to ensure the autoLoop is never stuck awaiting a promise that
|
|
78
78
|
* will never resolve. Safe to call when no resolver is pending (no-op).
|
|
79
79
|
*/
|
|
80
|
-
export function resolveAgentEndCancelled(): void {
|
|
80
|
+
export function resolveAgentEndCancelled(errorContext?: ErrorContext): void {
|
|
81
81
|
if (_currentResolve) {
|
|
82
82
|
debugLog("resolveAgentEndCancelled", { status: "resolving-cancelled" });
|
|
83
83
|
const r = _currentResolve;
|
|
84
84
|
_currentResolve = null;
|
|
85
|
-
r({ status: "cancelled" });
|
|
85
|
+
r({ status: "cancelled", ...(errorContext ? { errorContext } : {}) });
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
|
|
@@ -58,13 +58,13 @@ export async function runUnit(
|
|
|
58
58
|
unitId,
|
|
59
59
|
error: msg,
|
|
60
60
|
});
|
|
61
|
-
return { status: "cancelled" };
|
|
61
|
+
return { status: "cancelled", errorContext: { message: `Session creation failed: ${msg}`, category: "session-failed", isTransient: true } };
|
|
62
62
|
}
|
|
63
63
|
if (sessionTimeoutHandle) clearTimeout(sessionTimeoutHandle);
|
|
64
64
|
|
|
65
65
|
if (sessionResult.cancelled) {
|
|
66
66
|
debugLog("runUnit-session-timeout", { unitType, unitId });
|
|
67
|
-
return { status: "cancelled" };
|
|
67
|
+
return { status: "cancelled", errorContext: { message: "Session creation timed out", category: "timeout", isTransient: true } };
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
if (!s.active) {
|
|
@@ -118,6 +118,10 @@ export class AutoSession {
|
|
|
118
118
|
// ── Sidecar queue ─────────────────────────────────────────────────────
|
|
119
119
|
sidecarQueue: SidecarItem[] = [];
|
|
120
120
|
|
|
121
|
+
// ── Isolation degradation ────────────────────────────────────────────
|
|
122
|
+
/** Set to true when worktree creation fails; prevents merge of nonexistent branch. */
|
|
123
|
+
isolationDegraded = false;
|
|
124
|
+
|
|
121
125
|
// ── Dispatch circuit breakers ──────────────────────────────────────
|
|
122
126
|
rewriteAttemptCount = 0;
|
|
123
127
|
|
|
@@ -200,6 +204,7 @@ export class AutoSession {
|
|
|
200
204
|
this.pendingQuickTasks = [];
|
|
201
205
|
this.sidecarQueue = [];
|
|
202
206
|
this.rewriteAttemptCount = 0;
|
|
207
|
+
this.isolationDegraded = false;
|
|
203
208
|
|
|
204
209
|
// Signal handler
|
|
205
210
|
this.sigtermHandler = null;
|
|
@@ -47,12 +47,25 @@ export interface AgentEndEvent {
|
|
|
47
47
|
messages: unknown[];
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Structured error context attached to a UnitResult when the unit ends
|
|
52
|
+
* due to an infrastructure or timeout error (not user-driven cancellation).
|
|
53
|
+
*/
|
|
54
|
+
export interface ErrorContext {
|
|
55
|
+
message: string;
|
|
56
|
+
category: "provider" | "timeout" | "idle" | "network" | "aborted" | "session-failed" | "unknown";
|
|
57
|
+
stopReason?: string;
|
|
58
|
+
isTransient?: boolean;
|
|
59
|
+
retryAfterMs?: number;
|
|
60
|
+
}
|
|
61
|
+
|
|
50
62
|
/**
|
|
51
63
|
* Result of a single unit execution (one iteration of the loop).
|
|
52
64
|
*/
|
|
53
65
|
export interface UnitResult {
|
|
54
66
|
status: "completed" | "cancelled" | "error";
|
|
55
67
|
event?: AgentEndEvent;
|
|
68
|
+
errorContext?: ErrorContext;
|
|
56
69
|
}
|
|
57
70
|
|
|
58
71
|
// ─── Phase pipeline types ────────────────────────────────────────────────────
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
buildSliceFileName,
|
|
14
14
|
buildTaskFileName,
|
|
15
15
|
} from "./paths.js";
|
|
16
|
+
import { parseUnitId } from "./unit-id.js";
|
|
16
17
|
import { join } from "node:path";
|
|
17
18
|
|
|
18
19
|
/**
|
|
@@ -23,9 +24,7 @@ export function resolveExpectedArtifactPath(
|
|
|
23
24
|
unitId: string,
|
|
24
25
|
base: string,
|
|
25
26
|
): string | null {
|
|
26
|
-
const
|
|
27
|
-
const mid = parts[0]!;
|
|
28
|
-
const sid = parts[1];
|
|
27
|
+
const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
|
|
29
28
|
switch (unitType) {
|
|
30
29
|
case "discuss-milestone": {
|
|
31
30
|
const dir = resolveMilestonePath(base, mid);
|
|
@@ -53,10 +52,9 @@ export function resolveExpectedArtifactPath(
|
|
|
53
52
|
}
|
|
54
53
|
case "run-uat": {
|
|
55
54
|
const dir = resolveSlicePath(base, mid, sid!);
|
|
56
|
-
return dir ? join(dir, buildSliceFileName(sid!, "UAT
|
|
55
|
+
return dir ? join(dir, buildSliceFileName(sid!, "UAT")) : null;
|
|
57
56
|
}
|
|
58
57
|
case "execute-task": {
|
|
59
|
-
const tid = parts[2];
|
|
60
58
|
const dir = resolveSlicePath(base, mid, sid!);
|
|
61
59
|
return dir && tid
|
|
62
60
|
? join(dir, "tasks", buildTaskFileName(tid, "SUMMARY"))
|
|
@@ -80,6 +78,9 @@ export function resolveExpectedArtifactPath(
|
|
|
80
78
|
}
|
|
81
79
|
case "rewrite-docs":
|
|
82
80
|
return null;
|
|
81
|
+
case "gate-evaluate":
|
|
82
|
+
// Gate evaluate writes to DB quality_gates table — verified via state derivation
|
|
83
|
+
return null;
|
|
83
84
|
case "reactive-execute":
|
|
84
85
|
// Reactive execute produces multiple task summaries — verified separately
|
|
85
86
|
return null;
|
|
@@ -93,38 +94,35 @@ export function diagnoseExpectedArtifact(
|
|
|
93
94
|
unitId: string,
|
|
94
95
|
base: string,
|
|
95
96
|
): string | null {
|
|
96
|
-
const
|
|
97
|
-
const mid = parts[0];
|
|
98
|
-
const sid = parts[1];
|
|
97
|
+
const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
|
|
99
98
|
switch (unitType) {
|
|
100
99
|
case "discuss-milestone":
|
|
101
|
-
return `${relMilestoneFile(base, mid
|
|
100
|
+
return `${relMilestoneFile(base, mid, "CONTEXT")} (milestone context from discussion)`;
|
|
102
101
|
case "research-milestone":
|
|
103
|
-
return `${relMilestoneFile(base, mid
|
|
102
|
+
return `${relMilestoneFile(base, mid, "RESEARCH")} (milestone research)`;
|
|
104
103
|
case "plan-milestone":
|
|
105
|
-
return `${relMilestoneFile(base, mid
|
|
104
|
+
return `${relMilestoneFile(base, mid, "ROADMAP")} (milestone roadmap)`;
|
|
106
105
|
case "research-slice":
|
|
107
|
-
return `${relSliceFile(base, mid
|
|
106
|
+
return `${relSliceFile(base, mid, sid!, "RESEARCH")} (slice research)`;
|
|
108
107
|
case "plan-slice":
|
|
109
|
-
return `${relSliceFile(base, mid
|
|
108
|
+
return `${relSliceFile(base, mid, sid!, "PLAN")} (slice plan)`;
|
|
110
109
|
case "execute-task": {
|
|
111
|
-
|
|
112
|
-
return `Task ${tid} marked [x] in ${relSliceFile(base, mid!, sid!, "PLAN")} + summary written`;
|
|
110
|
+
return `Task ${tid} marked [x] in ${relSliceFile(base, mid, sid!, "PLAN")} + summary written`;
|
|
113
111
|
}
|
|
114
112
|
case "complete-slice":
|
|
115
|
-
return `Slice ${sid} marked [x] in ${relMilestoneFile(base, mid
|
|
113
|
+
return `Slice ${sid} marked [x] in ${relMilestoneFile(base, mid, "ROADMAP")} + summary + UAT written`;
|
|
116
114
|
case "replan-slice":
|
|
117
|
-
return `${relSliceFile(base, mid
|
|
115
|
+
return `${relSliceFile(base, mid, sid!, "REPLAN")} + updated ${relSliceFile(base, mid, sid!, "PLAN")}`;
|
|
118
116
|
case "rewrite-docs":
|
|
119
117
|
return "Active overrides resolved in .gsd/OVERRIDES.md + plan documents updated";
|
|
120
118
|
case "reassess-roadmap":
|
|
121
|
-
return `${relSliceFile(base, mid
|
|
119
|
+
return `${relSliceFile(base, mid, sid!, "ASSESSMENT")} (roadmap reassessment)`;
|
|
122
120
|
case "run-uat":
|
|
123
|
-
return `${relSliceFile(base, mid
|
|
121
|
+
return `${relSliceFile(base, mid, sid!, "UAT")} (UAT result)`;
|
|
124
122
|
case "validate-milestone":
|
|
125
|
-
return `${relMilestoneFile(base, mid
|
|
123
|
+
return `${relMilestoneFile(base, mid, "VALIDATION")} (milestone validation report)`;
|
|
126
124
|
case "complete-milestone":
|
|
127
|
-
return `${relMilestoneFile(base, mid
|
|
125
|
+
return `${relMilestoneFile(base, mid, "SUMMARY")} (milestone summary)`;
|
|
128
126
|
default:
|
|
129
127
|
return null;
|
|
130
128
|
}
|
|
@@ -25,6 +25,7 @@ import { computeProgressScore } from "./progress-score.js";
|
|
|
25
25
|
import { getActiveWorktreeName } from "./worktree-command.js";
|
|
26
26
|
import { loadEffectiveGSDPreferences, getGlobalGSDPreferencesPath } from "./preferences.js";
|
|
27
27
|
import { resolveServiceTierIcon, getEffectiveServiceTier } from "./service-tier.js";
|
|
28
|
+
import { parseUnitId } from "./unit-id.js";
|
|
28
29
|
|
|
29
30
|
// ─── UAT Slice Extraction ─────────────────────────────────────────────────────
|
|
30
31
|
|
|
@@ -33,8 +34,8 @@ import { resolveServiceTierIcon, getEffectiveServiceTier } from "./service-tier.
|
|
|
33
34
|
* Returns null if the format doesn't match.
|
|
34
35
|
*/
|
|
35
36
|
export function extractUatSliceId(unitId: string): string | null {
|
|
36
|
-
const
|
|
37
|
-
if (
|
|
37
|
+
const { slice } = parseUnitId(unitId);
|
|
38
|
+
if (slice?.startsWith("S")) return slice;
|
|
38
39
|
return null;
|
|
39
40
|
}
|
|
40
41
|
|
|
@@ -151,6 +152,8 @@ export function describeNextUnit(state: GSDState): { label: string; description:
|
|
|
151
152
|
return { label: `Replan ${sid}: ${sTitle}`, description: "Blocker found — replan the slice." };
|
|
152
153
|
case "completing-milestone":
|
|
153
154
|
return { label: "Complete milestone", description: "Write milestone summary." };
|
|
155
|
+
case "evaluating-gates":
|
|
156
|
+
return { label: `Evaluate gates for ${sid}: ${sTitle}`, description: "Parallel quality gate assessment before execution." };
|
|
154
157
|
default:
|
|
155
158
|
return { label: "Continue", description: "Execute the next step." };
|
|
156
159
|
}
|
|
@@ -13,7 +13,8 @@ import type { GSDState } from "./types.js";
|
|
|
13
13
|
import type { GSDPreferences } from "./preferences.js";
|
|
14
14
|
import type { UatType } from "./files.js";
|
|
15
15
|
import { loadFile, extractUatType, loadActiveOverrides } from "./files.js";
|
|
16
|
-
import { isDbAvailable, getMilestoneSlices } from "./gsd-db.js";
|
|
16
|
+
import { isDbAvailable, getMilestoneSlices, getPendingGates, markAllGatesOmitted } from "./gsd-db.js";
|
|
17
|
+
import { extractVerdict, isAcceptableUatVerdict } from "./verdict-parser.js";
|
|
17
18
|
|
|
18
19
|
import {
|
|
19
20
|
resolveMilestoneFile,
|
|
@@ -43,6 +44,7 @@ import {
|
|
|
43
44
|
buildReassessRoadmapPrompt,
|
|
44
45
|
buildRewriteDocsPrompt,
|
|
45
46
|
buildReactiveExecutePrompt,
|
|
47
|
+
buildGateEvaluatePrompt,
|
|
46
48
|
checkNeedsReassessment,
|
|
47
49
|
checkNeedsRunUat,
|
|
48
50
|
} from "./auto-prompts.js";
|
|
@@ -184,30 +186,14 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
184
186
|
}
|
|
185
187
|
|
|
186
188
|
for (const sliceId of completedSliceIds) {
|
|
187
|
-
const resultFile = resolveSliceFile(basePath, mid, sliceId, "UAT
|
|
189
|
+
const resultFile = resolveSliceFile(basePath, mid, sliceId, "UAT");
|
|
188
190
|
if (!resultFile) continue;
|
|
189
191
|
const content = await loadFile(resultFile);
|
|
190
192
|
if (!content) continue;
|
|
191
|
-
const
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
// Determine acceptable verdicts based on UAT type.
|
|
195
|
-
// mixed / human-experience / live-runtime modes may legitimately
|
|
196
|
-
// produce PARTIAL when all automatable checks pass but human-only
|
|
197
|
-
// checks remain — this should not block progression.
|
|
198
|
-
const acceptableVerdicts: string[] = ["pass", "passed"];
|
|
199
|
-
const uatFile = resolveSliceFile(basePath, mid, sliceId, "UAT");
|
|
200
|
-
if (uatFile) {
|
|
201
|
-
const uatContent = await loadFile(uatFile);
|
|
202
|
-
if (uatContent) {
|
|
203
|
-
const uatType = extractUatType(uatContent);
|
|
204
|
-
if (uatType === "mixed" || uatType === "human-experience" || uatType === "live-runtime") {
|
|
205
|
-
acceptableVerdicts.push("partial");
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
193
|
+
const verdict = extractVerdict(content);
|
|
194
|
+
const uatType = extractUatType(content);
|
|
209
195
|
|
|
210
|
-
if (verdict && !
|
|
196
|
+
if (verdict && !isAcceptableUatVerdict(verdict, uatType)) {
|
|
211
197
|
return {
|
|
212
198
|
action: "stop" as const,
|
|
213
199
|
reason: `UAT verdict for ${sliceId} is "${verdict}" — blocking progression until resolved.\nReview the UAT result and update the verdict to PASS, or re-run /gsd auto after fixing.`,
|
|
@@ -348,6 +334,38 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
348
334
|
};
|
|
349
335
|
},
|
|
350
336
|
},
|
|
337
|
+
{
|
|
338
|
+
name: "evaluating-gates → gate-evaluate",
|
|
339
|
+
match: async ({ state, mid, midTitle, basePath, prefs }) => {
|
|
340
|
+
if (state.phase !== "evaluating-gates") return null;
|
|
341
|
+
if (!state.activeSlice) return missingSliceStop(mid, state.phase);
|
|
342
|
+
const sid = state.activeSlice.id;
|
|
343
|
+
const sTitle = state.activeSlice.title;
|
|
344
|
+
|
|
345
|
+
// Gate evaluation is opt-in via preferences
|
|
346
|
+
const gateConfig = prefs?.gate_evaluation;
|
|
347
|
+
if (!gateConfig?.enabled) {
|
|
348
|
+
markAllGatesOmitted(mid, sid);
|
|
349
|
+
return { action: "skip" };
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const pending = getPendingGates(mid, sid, "slice");
|
|
353
|
+
if (pending.length === 0) return { action: "skip" };
|
|
354
|
+
|
|
355
|
+
return {
|
|
356
|
+
action: "dispatch",
|
|
357
|
+
unitType: "gate-evaluate",
|
|
358
|
+
unitId: `${mid}/${sid}/gates+${pending.map(g => g.gate_id).join(",")}`,
|
|
359
|
+
prompt: await buildGateEvaluatePrompt(
|
|
360
|
+
mid,
|
|
361
|
+
midTitle,
|
|
362
|
+
sid,
|
|
363
|
+
sTitle,
|
|
364
|
+
basePath,
|
|
365
|
+
),
|
|
366
|
+
};
|
|
367
|
+
},
|
|
368
|
+
},
|
|
351
369
|
{
|
|
352
370
|
name: "replanning-slice → replan-slice",
|
|
353
371
|
match: async ({ state, mid, midTitle, basePath }) => {
|
|
@@ -13,4 +13,4 @@ export { resolveAgentEnd, resolveAgentEndCancelled, isSessionSwitchInFlight, _re
|
|
|
13
13
|
export { detectStuck } from "./auto/detect-stuck.js";
|
|
14
14
|
export { runUnit } from "./auto/run-unit.js";
|
|
15
15
|
export type { LoopDeps } from "./auto/loop-deps.js";
|
|
16
|
-
export type { AgentEndEvent, UnitResult } from "./auto/types.js";
|
|
16
|
+
export type { AgentEndEvent, ErrorContext, UnitResult } from "./auto/types.js";
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
buildTaskFileName,
|
|
24
24
|
} from "./paths.js";
|
|
25
25
|
import { invalidateAllCaches } from "./cache.js";
|
|
26
|
+
import { parseUnitId } from "./unit-id.js";
|
|
26
27
|
import { closeoutUnit, type CloseoutOptions } from "./auto-unit-closeout.js";
|
|
27
28
|
import {
|
|
28
29
|
autoCommitCurrentBranch,
|
|
@@ -33,7 +34,7 @@ import {
|
|
|
33
34
|
resolveExpectedArtifactPath,
|
|
34
35
|
} from "./auto-recovery.js";
|
|
35
36
|
import { regenerateIfMissing } from "./workflow-projections.js";
|
|
36
|
-
import { syncStateToProjectRoot } from "./auto-worktree
|
|
37
|
+
import { syncStateToProjectRoot } from "./auto-worktree.js";
|
|
37
38
|
import { isDbAvailable, getTask, getSlice, getMilestone, updateTaskStatus, _getAdapter } from "./gsd-db.js";
|
|
38
39
|
import { renderPlanCheckboxes } from "./markdown-renderer.js";
|
|
39
40
|
import { consumeSignal } from "./session-status-io.js";
|
|
@@ -84,6 +85,15 @@ export interface RogueFileWrite {
|
|
|
84
85
|
* in postUnitPostVerification() eventually ingests rogue files, but explicit
|
|
85
86
|
* detection provides immediate diagnostics so operators know the prompt failed.
|
|
86
87
|
*/
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
89
|
+
function hasNonEmptyFields(row: Record<string, any> | null, fields: string[]): boolean {
|
|
90
|
+
if (!row) return false;
|
|
91
|
+
return fields.some(f => String(row[f] || "").trim().length > 0);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const MILESTONE_PLANNING_FIELDS = ["title", "vision", "requirement_coverage", "boundary_map_markdown"];
|
|
95
|
+
const SLICE_PLANNING_FIELDS = ["title", "demo", "risk", "depends"];
|
|
96
|
+
|
|
87
97
|
export function detectRogueFileWrites(
|
|
88
98
|
unitType: string,
|
|
89
99
|
unitId: string,
|
|
@@ -91,11 +101,10 @@ export function detectRogueFileWrites(
|
|
|
91
101
|
): RogueFileWrite[] {
|
|
92
102
|
if (!isDbAvailable()) return [];
|
|
93
103
|
|
|
94
|
-
const
|
|
104
|
+
const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
|
|
95
105
|
const rogues: RogueFileWrite[] = [];
|
|
96
106
|
|
|
97
107
|
if (unitType === "execute-task") {
|
|
98
|
-
const [mid, sid, tid] = parts;
|
|
99
108
|
if (!mid || !sid || !tid) return [];
|
|
100
109
|
|
|
101
110
|
const summaryPath = resolveTaskFile(basePath, mid, sid, tid, "SUMMARY");
|
|
@@ -106,7 +115,6 @@ export function detectRogueFileWrites(
|
|
|
106
115
|
rogues.push({ path: summaryPath, unitType, unitId });
|
|
107
116
|
}
|
|
108
117
|
} else if (unitType === "complete-slice") {
|
|
109
|
-
const [mid, sid] = parts;
|
|
110
118
|
if (!mid || !sid) return [];
|
|
111
119
|
|
|
112
120
|
const summaryPath = resolveSliceFile(basePath, mid, sid, "SUMMARY");
|
|
@@ -117,37 +125,25 @@ export function detectRogueFileWrites(
|
|
|
117
125
|
rogues.push({ path: summaryPath, unitType, unitId });
|
|
118
126
|
}
|
|
119
127
|
} else if (unitType === "plan-milestone") {
|
|
120
|
-
const [mid] = parts;
|
|
121
128
|
if (!mid) return [];
|
|
122
129
|
|
|
123
130
|
const roadmapPath = resolveMilestoneFile(basePath, mid, "ROADMAP");
|
|
124
131
|
if (!roadmapPath || !existsSync(roadmapPath)) return [];
|
|
125
132
|
|
|
126
133
|
const dbRow = getMilestone(mid);
|
|
127
|
-
const hasPlanningState =
|
|
128
|
-
String(dbRow.title || "").trim().length > 0 ||
|
|
129
|
-
String(dbRow.vision || "").trim().length > 0 ||
|
|
130
|
-
String(dbRow.requirement_coverage || "").trim().length > 0 ||
|
|
131
|
-
String(dbRow.boundary_map_markdown || "").trim().length > 0
|
|
132
|
-
);
|
|
134
|
+
const hasPlanningState = hasNonEmptyFields(dbRow, MILESTONE_PLANNING_FIELDS);
|
|
133
135
|
|
|
134
136
|
if (!hasPlanningState) {
|
|
135
137
|
rogues.push({ path: roadmapPath, unitType, unitId });
|
|
136
138
|
}
|
|
137
139
|
} else if (unitType === "plan-slice" || unitType === "replan-slice") {
|
|
138
|
-
const [mid, sid] = parts;
|
|
139
140
|
if (!mid || !sid) return [];
|
|
140
141
|
|
|
141
142
|
const planPath = resolveSliceFile(basePath, mid, sid, "PLAN");
|
|
142
143
|
if (!planPath || !existsSync(planPath)) return [];
|
|
143
144
|
|
|
144
145
|
const dbRow = getSlice(mid, sid);
|
|
145
|
-
const hasPlanningState =
|
|
146
|
-
String(dbRow.title || "").trim().length > 0 ||
|
|
147
|
-
String(dbRow.demo || "").trim().length > 0 ||
|
|
148
|
-
String(dbRow.risk || "").trim().length > 0 ||
|
|
149
|
-
String(dbRow.depends || "").trim().length > 0
|
|
150
|
-
);
|
|
146
|
+
const hasPlanningState = hasNonEmptyFields(dbRow, SLICE_PLANNING_FIELDS);
|
|
151
147
|
|
|
152
148
|
if (!hasPlanningState) {
|
|
153
149
|
rogues.push({ path: planPath, unitType, unitId });
|
|
@@ -159,7 +155,6 @@ export function detectRogueFileWrites(
|
|
|
159
155
|
rogues.push({ path: replanPath, unitType, unitId });
|
|
160
156
|
}
|
|
161
157
|
} else if (unitType === "reassess-roadmap") {
|
|
162
|
-
const [mid, sid] = parts;
|
|
163
158
|
if (!mid || !sid) return [];
|
|
164
159
|
|
|
165
160
|
const assessPath = resolveSliceFile(basePath, mid, sid, "ASSESSMENT");
|
|
@@ -176,7 +171,6 @@ export function detectRogueFileWrites(
|
|
|
176
171
|
}
|
|
177
172
|
}
|
|
178
173
|
} else if (unitType === "plan-task") {
|
|
179
|
-
const [mid, sid, tid] = parts;
|
|
180
174
|
if (!mid || !sid || !tid) return [];
|
|
181
175
|
|
|
182
176
|
const taskPlanPath = resolveTaskFile(basePath, mid, sid, tid, "PLAN");
|
|
@@ -249,8 +243,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
|
|
|
249
243
|
let taskContext: TaskCommitContext | undefined;
|
|
250
244
|
|
|
251
245
|
if (s.currentUnit.type === "execute-task") {
|
|
252
|
-
const
|
|
253
|
-
const [mid, sid, tid] = parts;
|
|
246
|
+
const { milestone: mid, slice: sid, task: tid } = parseUnitId(s.currentUnit.id);
|
|
254
247
|
if (mid && sid && tid) {
|
|
255
248
|
const summaryPath = resolveTaskFile(s.basePath, mid, sid, tid, "SUMMARY");
|
|
256
249
|
if (summaryPath) {
|
|
@@ -354,8 +347,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
|
|
|
354
347
|
// Reactive state cleanup on slice completion
|
|
355
348
|
if (s.currentUnit.type === "complete-slice") {
|
|
356
349
|
try {
|
|
357
|
-
const
|
|
358
|
-
const [mid, sid] = parts;
|
|
350
|
+
const { milestone: mid, slice: sid } = parseUnitId(s.currentUnit.id);
|
|
359
351
|
if (mid && sid) {
|
|
360
352
|
const { clearReactiveState } = await import("./reactive-graph.js");
|
|
361
353
|
clearReactiveState(s.basePath, mid, sid);
|
|
@@ -440,8 +432,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
|
|
|
440
432
|
// from DB data before giving up (e.g. research-slice produces PLAN from engine).
|
|
441
433
|
if (!triggerArtifactVerified) {
|
|
442
434
|
try {
|
|
443
|
-
const
|
|
444
|
-
const [mid, sid] = parts;
|
|
435
|
+
const { milestone: mid, slice: sid } = parseUnitId(s.currentUnit.id);
|
|
445
436
|
if (mid && sid) {
|
|
446
437
|
const regenerated = regenerateIfMissing(s.basePath, mid, sid, "PLAN");
|
|
447
438
|
if (regenerated) {
|
|
@@ -541,8 +532,7 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
|
|
|
541
532
|
|
|
542
533
|
// ── State reset: undo the completion so deriveState re-derives the unit ──
|
|
543
534
|
try {
|
|
544
|
-
const
|
|
545
|
-
const [mid, sid, tid] = parts;
|
|
535
|
+
const { milestone: mid, slice: sid, task: tid } = parseUnitId(trigger.unitId);
|
|
546
536
|
|
|
547
537
|
// 1. Reset task status in DB and re-render plan checkboxes
|
|
548
538
|
if (mid && sid && tid) {
|