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
package/dist/headless-ui.js
CHANGED
|
@@ -13,9 +13,19 @@ export function handleExtensionUIRequest(event, writeToStdin) {
|
|
|
13
13
|
const { id, method } = event;
|
|
14
14
|
let response;
|
|
15
15
|
switch (method) {
|
|
16
|
-
case 'select':
|
|
17
|
-
|
|
16
|
+
case 'select': {
|
|
17
|
+
// Lock-guard prompts list "View status" first, but headless needs "Force start"
|
|
18
|
+
// to proceed. Detect by title and pick the force option.
|
|
19
|
+
const title = String(event.title ?? '');
|
|
20
|
+
let selected = event.options?.[0] ?? '';
|
|
21
|
+
if (title.includes('Auto-mode is running') && event.options) {
|
|
22
|
+
const forceOption = event.options.find(o => o.toLowerCase().includes('force start'));
|
|
23
|
+
if (forceOption)
|
|
24
|
+
selected = forceOption;
|
|
25
|
+
}
|
|
26
|
+
response = { type: 'extension_ui_response', id, value: selected };
|
|
18
27
|
break;
|
|
28
|
+
}
|
|
19
29
|
case 'confirm':
|
|
20
30
|
response = { type: 'extension_ui_response', id, confirmed: true };
|
|
21
31
|
break;
|
package/dist/headless.js
CHANGED
|
@@ -37,8 +37,8 @@ export function parseHeadlessArgs(argv) {
|
|
|
37
37
|
if (!positionalStarted && arg.startsWith('--')) {
|
|
38
38
|
if (arg === '--timeout' && i + 1 < args.length) {
|
|
39
39
|
options.timeout = parseInt(args[++i], 10);
|
|
40
|
-
if (Number.isNaN(options.timeout) || options.timeout
|
|
41
|
-
process.stderr.write('[headless] Error: --timeout must be a
|
|
40
|
+
if (Number.isNaN(options.timeout) || options.timeout < 0) {
|
|
41
|
+
process.stderr.write('[headless] Error: --timeout must be a non-negative integer (milliseconds, 0 to disable)\n');
|
|
42
42
|
process.exit(1);
|
|
43
43
|
}
|
|
44
44
|
}
|
|
@@ -132,6 +132,13 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
132
132
|
if (isNewMilestone && options.timeout === 300_000) {
|
|
133
133
|
options.timeout = 600_000; // 10 minutes
|
|
134
134
|
}
|
|
135
|
+
// auto-mode sessions are long-running (minutes to hours) with their own internal
|
|
136
|
+
// per-unit timeout via auto-supervisor. Disable the overall timeout unless the
|
|
137
|
+
// user explicitly set --timeout.
|
|
138
|
+
const isAutoMode = options.command === 'auto';
|
|
139
|
+
if (isAutoMode && options.timeout === 300_000) {
|
|
140
|
+
options.timeout = 0;
|
|
141
|
+
}
|
|
135
142
|
// Supervised mode cannot share stdin with --context -
|
|
136
143
|
if (options.supervised && options.context === '-') {
|
|
137
144
|
process.stderr.write('[headless] Error: --supervised cannot be used with --context - (both require stdin)\n');
|
|
@@ -267,12 +274,14 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
267
274
|
}
|
|
268
275
|
// Precompute supervised response timeout
|
|
269
276
|
const responseTimeout = options.responseTimeout ?? 30_000;
|
|
270
|
-
// Overall timeout
|
|
271
|
-
const timeoutTimer =
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
277
|
+
// Overall timeout (disabled when options.timeout === 0, e.g. auto-mode)
|
|
278
|
+
const timeoutTimer = options.timeout > 0
|
|
279
|
+
? setTimeout(() => {
|
|
280
|
+
process.stderr.write(`[headless] Timeout after ${options.timeout / 1000}s\n`);
|
|
281
|
+
exitCode = 1;
|
|
282
|
+
resolveCompletion();
|
|
283
|
+
}, options.timeout)
|
|
284
|
+
: null;
|
|
276
285
|
// Event handler
|
|
277
286
|
client.onEvent((event) => {
|
|
278
287
|
const eventObj = event;
|
|
@@ -354,7 +363,8 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
354
363
|
interrupted = true;
|
|
355
364
|
exitCode = 1;
|
|
356
365
|
client.stop().finally(() => {
|
|
357
|
-
|
|
366
|
+
if (timeoutTimer)
|
|
367
|
+
clearTimeout(timeoutTimer);
|
|
358
368
|
if (idleTimer)
|
|
359
369
|
clearTimeout(idleTimer);
|
|
360
370
|
process.exit(exitCode);
|
|
@@ -368,7 +378,8 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
368
378
|
}
|
|
369
379
|
catch (err) {
|
|
370
380
|
process.stderr.write(`[headless] Error: Failed to start RPC session: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
371
|
-
|
|
381
|
+
if (timeoutTimer)
|
|
382
|
+
clearTimeout(timeoutTimer);
|
|
372
383
|
process.exit(1);
|
|
373
384
|
}
|
|
374
385
|
// Access stdin writer from the internal process
|
|
@@ -376,7 +387,8 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
376
387
|
if (!internalProcess?.stdin) {
|
|
377
388
|
process.stderr.write('[headless] Error: Cannot access child process stdin\n');
|
|
378
389
|
await client.stop();
|
|
379
|
-
|
|
390
|
+
if (timeoutTimer)
|
|
391
|
+
clearTimeout(timeoutTimer);
|
|
380
392
|
process.exit(1);
|
|
381
393
|
}
|
|
382
394
|
stdinWriter = (data) => {
|
|
@@ -424,7 +436,10 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
424
436
|
if (!options.json) {
|
|
425
437
|
process.stderr.write('[headless] Milestone ready — chaining into auto-mode...\n');
|
|
426
438
|
}
|
|
427
|
-
// Reset completion state for the auto-mode phase
|
|
439
|
+
// Reset completion state for the auto-mode phase.
|
|
440
|
+
// Disable the overall timeout — auto-mode has its own internal supervisor.
|
|
441
|
+
if (timeoutTimer)
|
|
442
|
+
clearTimeout(timeoutTimer);
|
|
428
443
|
completed = false;
|
|
429
444
|
milestoneReady = false;
|
|
430
445
|
blocked = false;
|
|
@@ -443,7 +458,8 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
443
458
|
}
|
|
444
459
|
}
|
|
445
460
|
// Cleanup
|
|
446
|
-
|
|
461
|
+
if (timeoutTimer)
|
|
462
|
+
clearTimeout(timeoutTimer);
|
|
447
463
|
if (idleTimer)
|
|
448
464
|
clearTimeout(idleTimer);
|
|
449
465
|
pendingResponseTimers.forEach((timer) => clearTimeout(timer));
|
|
@@ -17,6 +17,7 @@ export const INFRA_ERROR_CODES = new Set([
|
|
|
17
17
|
"EDQUOT", // disk quota exceeded
|
|
18
18
|
"EMFILE", // too many open files (process)
|
|
19
19
|
"ENFILE", // too many open files (system)
|
|
20
|
+
"EAGAIN", // resource temporarily unavailable (resource exhaustion)
|
|
20
21
|
"ECONNREFUSED", // connection refused (offline / local server down)
|
|
21
22
|
"ENOTFOUND", // DNS lookup failed (offline / no network)
|
|
22
23
|
"ENETUNREACH", // network unreachable (offline / no route)
|
|
@@ -721,18 +721,18 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
721
721
|
deps.updateSessionLock(deps.lockBase(), unitType, unitId, sessionFile);
|
|
722
722
|
deps.writeLock(deps.lockBase(), unitType, unitId, sessionFile);
|
|
723
723
|
// Tag the most recent window entry with error info for stuck detection
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
if (
|
|
724
|
+
const lastEntry = loopState.recentUnits[loopState.recentUnits.length - 1];
|
|
725
|
+
if (lastEntry) {
|
|
726
|
+
if (unitResult.errorContext) {
|
|
727
|
+
lastEntry.error = `${unitResult.errorContext.category}:${unitResult.errorContext.message}`.slice(0, 200);
|
|
728
|
+
}
|
|
729
|
+
else if (unitResult.status === "error" || unitResult.status === "cancelled") {
|
|
727
730
|
lastEntry.error = `${unitResult.status}:${unitType}/${unitId}`;
|
|
728
731
|
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
if (/error|fail|exception/i.test(msgStr)) {
|
|
734
|
-
const lastEntry = loopState.recentUnits[loopState.recentUnits.length - 1];
|
|
735
|
-
if (lastEntry) {
|
|
732
|
+
else if (unitResult.event?.messages?.length) {
|
|
733
|
+
const lastMsg = unitResult.event.messages[unitResult.event.messages.length - 1];
|
|
734
|
+
const msgStr = typeof lastMsg === "string" ? lastMsg : JSON.stringify(lastMsg);
|
|
735
|
+
if (/error|fail|exception/i.test(msgStr)) {
|
|
736
736
|
lastEntry.error = msgStr.slice(0, 200);
|
|
737
737
|
}
|
|
738
738
|
}
|
|
@@ -779,7 +779,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
779
779
|
s.unitDispatchCount.delete(`${unitType}/${unitId}`);
|
|
780
780
|
s.unitRecoveryCount.delete(`${unitType}/${unitId}`);
|
|
781
781
|
}
|
|
782
|
-
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 } });
|
|
782
|
+
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 } });
|
|
783
783
|
return { action: "next", data: { unitStartedAt: s.currentUnit.startedAt } };
|
|
784
784
|
}
|
|
785
785
|
// ─── runFinalize ──────────────────────────────────────────────────────────────
|
|
@@ -64,12 +64,12 @@ export function isSessionSwitchInFlight() {
|
|
|
64
64
|
* blocks to ensure the autoLoop is never stuck awaiting a promise that
|
|
65
65
|
* will never resolve. Safe to call when no resolver is pending (no-op).
|
|
66
66
|
*/
|
|
67
|
-
export function resolveAgentEndCancelled() {
|
|
67
|
+
export function resolveAgentEndCancelled(errorContext) {
|
|
68
68
|
if (_currentResolve) {
|
|
69
69
|
debugLog("resolveAgentEndCancelled", { status: "resolving-cancelled" });
|
|
70
70
|
const r = _currentResolve;
|
|
71
71
|
_currentResolve = null;
|
|
72
|
-
r({ status: "cancelled" });
|
|
72
|
+
r({ status: "cancelled", ...(errorContext ? { errorContext } : {}) });
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
// ─── resetPendingResolve (test helper) ───────────────────────────────────────
|
|
@@ -41,13 +41,13 @@ export async function runUnit(ctx, pi, s, unitType, unitId, prompt) {
|
|
|
41
41
|
unitId,
|
|
42
42
|
error: msg,
|
|
43
43
|
});
|
|
44
|
-
return { status: "cancelled" };
|
|
44
|
+
return { status: "cancelled", errorContext: { message: `Session creation failed: ${msg}`, category: "session-failed", isTransient: true } };
|
|
45
45
|
}
|
|
46
46
|
if (sessionTimeoutHandle)
|
|
47
47
|
clearTimeout(sessionTimeoutHandle);
|
|
48
48
|
if (sessionResult.cancelled) {
|
|
49
49
|
debugLog("runUnit-session-timeout", { unitType, unitId });
|
|
50
|
-
return { status: "cancelled" };
|
|
50
|
+
return { status: "cancelled", errorContext: { message: "Session creation timed out", category: "timeout", isTransient: true } };
|
|
51
51
|
}
|
|
52
52
|
if (!s.active) {
|
|
53
53
|
return { status: "cancelled" };
|
|
@@ -61,6 +61,9 @@ export class AutoSession {
|
|
|
61
61
|
lastStateRebuildAt = 0;
|
|
62
62
|
// ── Sidecar queue ─────────────────────────────────────────────────────
|
|
63
63
|
sidecarQueue = [];
|
|
64
|
+
// ── Isolation degradation ────────────────────────────────────────────
|
|
65
|
+
/** Set to true when worktree creation fails; prevents merge of nonexistent branch. */
|
|
66
|
+
isolationDegraded = false;
|
|
64
67
|
// ── Dispatch circuit breakers ──────────────────────────────────────
|
|
65
68
|
rewriteAttemptCount = 0;
|
|
66
69
|
// ── Metrics ──────────────────────────────────────────────────────────────
|
|
@@ -140,6 +143,7 @@ export class AutoSession {
|
|
|
140
143
|
this.pendingQuickTasks = [];
|
|
141
144
|
this.sidecarQueue = [];
|
|
142
145
|
this.rewriteAttemptCount = 0;
|
|
146
|
+
this.isolationDegraded = false;
|
|
143
147
|
// Signal handler
|
|
144
148
|
this.sigtermHandler = null;
|
|
145
149
|
// Loop promise state lives in auto-loop.ts module scope
|
|
@@ -4,14 +4,13 @@
|
|
|
4
4
|
// auto-recovery.ts (Phase 5 dead-code cleanup). The artifact verification
|
|
5
5
|
// function was removed entirely — callers now query WorkflowEngine directly.
|
|
6
6
|
import { resolveMilestonePath, resolveSlicePath, relMilestoneFile, relSliceFile, buildMilestoneFileName, buildSliceFileName, buildTaskFileName, } from "./paths.js";
|
|
7
|
+
import { parseUnitId } from "./unit-id.js";
|
|
7
8
|
import { join } from "node:path";
|
|
8
9
|
/**
|
|
9
10
|
* Resolve the expected artifact for a unit to an absolute path.
|
|
10
11
|
*/
|
|
11
12
|
export function resolveExpectedArtifactPath(unitType, unitId, base) {
|
|
12
|
-
const
|
|
13
|
-
const mid = parts[0];
|
|
14
|
-
const sid = parts[1];
|
|
13
|
+
const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
|
|
15
14
|
switch (unitType) {
|
|
16
15
|
case "discuss-milestone": {
|
|
17
16
|
const dir = resolveMilestonePath(base, mid);
|
|
@@ -39,10 +38,9 @@ export function resolveExpectedArtifactPath(unitType, unitId, base) {
|
|
|
39
38
|
}
|
|
40
39
|
case "run-uat": {
|
|
41
40
|
const dir = resolveSlicePath(base, mid, sid);
|
|
42
|
-
return dir ? join(dir, buildSliceFileName(sid, "UAT
|
|
41
|
+
return dir ? join(dir, buildSliceFileName(sid, "UAT")) : null;
|
|
43
42
|
}
|
|
44
43
|
case "execute-task": {
|
|
45
|
-
const tid = parts[2];
|
|
46
44
|
const dir = resolveSlicePath(base, mid, sid);
|
|
47
45
|
return dir && tid
|
|
48
46
|
? join(dir, "tasks", buildTaskFileName(tid, "SUMMARY"))
|
|
@@ -66,6 +64,9 @@ export function resolveExpectedArtifactPath(unitType, unitId, base) {
|
|
|
66
64
|
}
|
|
67
65
|
case "rewrite-docs":
|
|
68
66
|
return null;
|
|
67
|
+
case "gate-evaluate":
|
|
68
|
+
// Gate evaluate writes to DB quality_gates table — verified via state derivation
|
|
69
|
+
return null;
|
|
69
70
|
case "reactive-execute":
|
|
70
71
|
// Reactive execute produces multiple task summaries — verified separately
|
|
71
72
|
return null;
|
|
@@ -74,9 +75,7 @@ export function resolveExpectedArtifactPath(unitType, unitId, base) {
|
|
|
74
75
|
}
|
|
75
76
|
}
|
|
76
77
|
export function diagnoseExpectedArtifact(unitType, unitId, base) {
|
|
77
|
-
const
|
|
78
|
-
const mid = parts[0];
|
|
79
|
-
const sid = parts[1];
|
|
78
|
+
const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
|
|
80
79
|
switch (unitType) {
|
|
81
80
|
case "discuss-milestone":
|
|
82
81
|
return `${relMilestoneFile(base, mid, "CONTEXT")} (milestone context from discussion)`;
|
|
@@ -89,7 +88,6 @@ export function diagnoseExpectedArtifact(unitType, unitId, base) {
|
|
|
89
88
|
case "plan-slice":
|
|
90
89
|
return `${relSliceFile(base, mid, sid, "PLAN")} (slice plan)`;
|
|
91
90
|
case "execute-task": {
|
|
92
|
-
const tid = parts[2];
|
|
93
91
|
return `Task ${tid} marked [x] in ${relSliceFile(base, mid, sid, "PLAN")} + summary written`;
|
|
94
92
|
}
|
|
95
93
|
case "complete-slice":
|
|
@@ -101,7 +99,7 @@ export function diagnoseExpectedArtifact(unitType, unitId, base) {
|
|
|
101
99
|
case "reassess-roadmap":
|
|
102
100
|
return `${relSliceFile(base, mid, sid, "ASSESSMENT")} (roadmap reassessment)`;
|
|
103
101
|
case "run-uat":
|
|
104
|
-
return `${relSliceFile(base, mid, sid, "UAT
|
|
102
|
+
return `${relSliceFile(base, mid, sid, "UAT")} (UAT result)`;
|
|
105
103
|
case "validate-milestone":
|
|
106
104
|
return `${relMilestoneFile(base, mid, "VALIDATION")} (milestone validation report)`;
|
|
107
105
|
case "complete-milestone":
|
|
@@ -18,15 +18,16 @@ import { computeProgressScore } from "./progress-score.js";
|
|
|
18
18
|
import { getActiveWorktreeName } from "./worktree-command.js";
|
|
19
19
|
import { loadEffectiveGSDPreferences, getGlobalGSDPreferencesPath } from "./preferences.js";
|
|
20
20
|
import { resolveServiceTierIcon, getEffectiveServiceTier } from "./service-tier.js";
|
|
21
|
+
import { parseUnitId } from "./unit-id.js";
|
|
21
22
|
// ─── UAT Slice Extraction ─────────────────────────────────────────────────────
|
|
22
23
|
/**
|
|
23
24
|
* Extract the target slice ID from a run-uat unit ID (e.g. "M001/S01" → "S01").
|
|
24
25
|
* Returns null if the format doesn't match.
|
|
25
26
|
*/
|
|
26
27
|
export function extractUatSliceId(unitId) {
|
|
27
|
-
const
|
|
28
|
-
if (
|
|
29
|
-
return
|
|
28
|
+
const { slice } = parseUnitId(unitId);
|
|
29
|
+
if (slice?.startsWith("S"))
|
|
30
|
+
return slice;
|
|
30
31
|
return null;
|
|
31
32
|
}
|
|
32
33
|
// ─── Unit Description Helpers ─────────────────────────────────────────────────
|
|
@@ -115,6 +116,8 @@ export function describeNextUnit(state) {
|
|
|
115
116
|
return { label: `Replan ${sid}: ${sTitle}`, description: "Blocker found — replan the slice." };
|
|
116
117
|
case "completing-milestone":
|
|
117
118
|
return { label: "Complete milestone", description: "Write milestone summary." };
|
|
119
|
+
case "evaluating-gates":
|
|
120
|
+
return { label: `Evaluate gates for ${sid}: ${sTitle}`, description: "Parallel quality gate assessment before execution." };
|
|
118
121
|
default:
|
|
119
122
|
return { label: "Continue", description: "Execute the next step." };
|
|
120
123
|
}
|
|
@@ -9,12 +9,13 @@
|
|
|
9
9
|
* without modifying orchestration code.
|
|
10
10
|
*/
|
|
11
11
|
import { loadFile, extractUatType, loadActiveOverrides } from "./files.js";
|
|
12
|
-
import { isDbAvailable, getMilestoneSlices } from "./gsd-db.js";
|
|
12
|
+
import { isDbAvailable, getMilestoneSlices, getPendingGates, markAllGatesOmitted } from "./gsd-db.js";
|
|
13
|
+
import { extractVerdict, isAcceptableUatVerdict } from "./verdict-parser.js";
|
|
13
14
|
import { resolveMilestoneFile, resolveMilestonePath, resolveSliceFile, resolveTaskFile, relSliceFile, buildMilestoneFileName, } from "./paths.js";
|
|
14
15
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
15
16
|
import { join } from "node:path";
|
|
16
17
|
import { hasImplementationArtifacts } from "./auto-recovery.js";
|
|
17
|
-
import { buildDiscussMilestonePrompt, buildResearchMilestonePrompt, buildPlanMilestonePrompt, buildResearchSlicePrompt, buildPlanSlicePrompt, buildExecuteTaskPrompt, buildCompleteSlicePrompt, buildCompleteMilestonePrompt, buildValidateMilestonePrompt, buildReplanSlicePrompt, buildRunUatPrompt, buildReassessRoadmapPrompt, buildRewriteDocsPrompt, buildReactiveExecutePrompt, checkNeedsReassessment, checkNeedsRunUat, } from "./auto-prompts.js";
|
|
18
|
+
import { buildDiscussMilestonePrompt, buildResearchMilestonePrompt, buildPlanMilestonePrompt, buildResearchSlicePrompt, buildPlanSlicePrompt, buildExecuteTaskPrompt, buildCompleteSlicePrompt, buildCompleteMilestonePrompt, buildValidateMilestonePrompt, buildReplanSlicePrompt, buildRunUatPrompt, buildReassessRoadmapPrompt, buildRewriteDocsPrompt, buildReactiveExecutePrompt, buildGateEvaluatePrompt, checkNeedsReassessment, checkNeedsRunUat, } from "./auto-prompts.js";
|
|
18
19
|
function missingSliceStop(mid, phase) {
|
|
19
20
|
return {
|
|
20
21
|
action: "stop",
|
|
@@ -104,30 +105,15 @@ export const DISPATCH_RULES = [
|
|
|
104
105
|
return null;
|
|
105
106
|
}
|
|
106
107
|
for (const sliceId of completedSliceIds) {
|
|
107
|
-
const resultFile = resolveSliceFile(basePath, mid, sliceId, "UAT
|
|
108
|
+
const resultFile = resolveSliceFile(basePath, mid, sliceId, "UAT");
|
|
108
109
|
if (!resultFile)
|
|
109
110
|
continue;
|
|
110
111
|
const content = await loadFile(resultFile);
|
|
111
112
|
if (!content)
|
|
112
113
|
continue;
|
|
113
|
-
const
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
// mixed / human-experience / live-runtime modes may legitimately
|
|
117
|
-
// produce PARTIAL when all automatable checks pass but human-only
|
|
118
|
-
// checks remain — this should not block progression.
|
|
119
|
-
const acceptableVerdicts = ["pass", "passed"];
|
|
120
|
-
const uatFile = resolveSliceFile(basePath, mid, sliceId, "UAT");
|
|
121
|
-
if (uatFile) {
|
|
122
|
-
const uatContent = await loadFile(uatFile);
|
|
123
|
-
if (uatContent) {
|
|
124
|
-
const uatType = extractUatType(uatContent);
|
|
125
|
-
if (uatType === "mixed" || uatType === "human-experience" || uatType === "live-runtime") {
|
|
126
|
-
acceptableVerdicts.push("partial");
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
if (verdict && !acceptableVerdicts.includes(verdict)) {
|
|
114
|
+
const verdict = extractVerdict(content);
|
|
115
|
+
const uatType = extractUatType(content);
|
|
116
|
+
if (verdict && !isAcceptableUatVerdict(verdict, uatType)) {
|
|
131
117
|
return {
|
|
132
118
|
action: "stop",
|
|
133
119
|
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.`,
|
|
@@ -261,6 +247,32 @@ export const DISPATCH_RULES = [
|
|
|
261
247
|
};
|
|
262
248
|
},
|
|
263
249
|
},
|
|
250
|
+
{
|
|
251
|
+
name: "evaluating-gates → gate-evaluate",
|
|
252
|
+
match: async ({ state, mid, midTitle, basePath, prefs }) => {
|
|
253
|
+
if (state.phase !== "evaluating-gates")
|
|
254
|
+
return null;
|
|
255
|
+
if (!state.activeSlice)
|
|
256
|
+
return missingSliceStop(mid, state.phase);
|
|
257
|
+
const sid = state.activeSlice.id;
|
|
258
|
+
const sTitle = state.activeSlice.title;
|
|
259
|
+
// Gate evaluation is opt-in via preferences
|
|
260
|
+
const gateConfig = prefs?.gate_evaluation;
|
|
261
|
+
if (!gateConfig?.enabled) {
|
|
262
|
+
markAllGatesOmitted(mid, sid);
|
|
263
|
+
return { action: "skip" };
|
|
264
|
+
}
|
|
265
|
+
const pending = getPendingGates(mid, sid, "slice");
|
|
266
|
+
if (pending.length === 0)
|
|
267
|
+
return { action: "skip" };
|
|
268
|
+
return {
|
|
269
|
+
action: "dispatch",
|
|
270
|
+
unitType: "gate-evaluate",
|
|
271
|
+
unitId: `${mid}/${sid}/gates+${pending.map(g => g.gate_id).join(",")}`,
|
|
272
|
+
prompt: await buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, basePath),
|
|
273
|
+
};
|
|
274
|
+
},
|
|
275
|
+
},
|
|
264
276
|
{
|
|
265
277
|
name: "replanning-slice → replan-slice",
|
|
266
278
|
match: async ({ state, mid, midTitle, basePath }) => {
|
|
@@ -15,11 +15,12 @@ import { loadFile, parseSummary, resolveAllOverrides } from "./files.js";
|
|
|
15
15
|
import { loadPrompt } from "./prompt-loader.js";
|
|
16
16
|
import { resolveSliceFile, resolveTaskFile, resolveMilestoneFile, resolveTasksDir, buildTaskFileName, } from "./paths.js";
|
|
17
17
|
import { invalidateAllCaches } from "./cache.js";
|
|
18
|
+
import { parseUnitId } from "./unit-id.js";
|
|
18
19
|
import { closeoutUnit } from "./auto-unit-closeout.js";
|
|
19
20
|
import { autoCommitCurrentBranch, } from "./worktree.js";
|
|
20
21
|
import { verifyExpectedArtifact, resolveExpectedArtifactPath, } from "./auto-recovery.js";
|
|
21
22
|
import { regenerateIfMissing } from "./workflow-projections.js";
|
|
22
|
-
import { syncStateToProjectRoot } from "./auto-worktree
|
|
23
|
+
import { syncStateToProjectRoot } from "./auto-worktree.js";
|
|
23
24
|
import { isDbAvailable, getTask, getSlice, getMilestone, updateTaskStatus, _getAdapter } from "./gsd-db.js";
|
|
24
25
|
import { renderPlanCheckboxes } from "./markdown-renderer.js";
|
|
25
26
|
import { consumeSignal } from "./session-status-io.js";
|
|
@@ -47,13 +48,20 @@ import { _resetHasChangesCache } from "./native-git-bridge.js";
|
|
|
47
48
|
* in postUnitPostVerification() eventually ingests rogue files, but explicit
|
|
48
49
|
* detection provides immediate diagnostics so operators know the prompt failed.
|
|
49
50
|
*/
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
52
|
+
function hasNonEmptyFields(row, fields) {
|
|
53
|
+
if (!row)
|
|
54
|
+
return false;
|
|
55
|
+
return fields.some(f => String(row[f] || "").trim().length > 0);
|
|
56
|
+
}
|
|
57
|
+
const MILESTONE_PLANNING_FIELDS = ["title", "vision", "requirement_coverage", "boundary_map_markdown"];
|
|
58
|
+
const SLICE_PLANNING_FIELDS = ["title", "demo", "risk", "depends"];
|
|
50
59
|
export function detectRogueFileWrites(unitType, unitId, basePath) {
|
|
51
60
|
if (!isDbAvailable())
|
|
52
61
|
return [];
|
|
53
|
-
const
|
|
62
|
+
const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
|
|
54
63
|
const rogues = [];
|
|
55
64
|
if (unitType === "execute-task") {
|
|
56
|
-
const [mid, sid, tid] = parts;
|
|
57
65
|
if (!mid || !sid || !tid)
|
|
58
66
|
return [];
|
|
59
67
|
const summaryPath = resolveTaskFile(basePath, mid, sid, tid, "SUMMARY");
|
|
@@ -65,7 +73,6 @@ export function detectRogueFileWrites(unitType, unitId, basePath) {
|
|
|
65
73
|
}
|
|
66
74
|
}
|
|
67
75
|
else if (unitType === "complete-slice") {
|
|
68
|
-
const [mid, sid] = parts;
|
|
69
76
|
if (!mid || !sid)
|
|
70
77
|
return [];
|
|
71
78
|
const summaryPath = resolveSliceFile(basePath, mid, sid, "SUMMARY");
|
|
@@ -77,33 +84,25 @@ export function detectRogueFileWrites(unitType, unitId, basePath) {
|
|
|
77
84
|
}
|
|
78
85
|
}
|
|
79
86
|
else if (unitType === "plan-milestone") {
|
|
80
|
-
const [mid] = parts;
|
|
81
87
|
if (!mid)
|
|
82
88
|
return [];
|
|
83
89
|
const roadmapPath = resolveMilestoneFile(basePath, mid, "ROADMAP");
|
|
84
90
|
if (!roadmapPath || !existsSync(roadmapPath))
|
|
85
91
|
return [];
|
|
86
92
|
const dbRow = getMilestone(mid);
|
|
87
|
-
const hasPlanningState =
|
|
88
|
-
String(dbRow.vision || "").trim().length > 0 ||
|
|
89
|
-
String(dbRow.requirement_coverage || "").trim().length > 0 ||
|
|
90
|
-
String(dbRow.boundary_map_markdown || "").trim().length > 0);
|
|
93
|
+
const hasPlanningState = hasNonEmptyFields(dbRow, MILESTONE_PLANNING_FIELDS);
|
|
91
94
|
if (!hasPlanningState) {
|
|
92
95
|
rogues.push({ path: roadmapPath, unitType, unitId });
|
|
93
96
|
}
|
|
94
97
|
}
|
|
95
98
|
else if (unitType === "plan-slice" || unitType === "replan-slice") {
|
|
96
|
-
const [mid, sid] = parts;
|
|
97
99
|
if (!mid || !sid)
|
|
98
100
|
return [];
|
|
99
101
|
const planPath = resolveSliceFile(basePath, mid, sid, "PLAN");
|
|
100
102
|
if (!planPath || !existsSync(planPath))
|
|
101
103
|
return [];
|
|
102
104
|
const dbRow = getSlice(mid, sid);
|
|
103
|
-
const hasPlanningState =
|
|
104
|
-
String(dbRow.demo || "").trim().length > 0 ||
|
|
105
|
-
String(dbRow.risk || "").trim().length > 0 ||
|
|
106
|
-
String(dbRow.depends || "").trim().length > 0);
|
|
105
|
+
const hasPlanningState = hasNonEmptyFields(dbRow, SLICE_PLANNING_FIELDS);
|
|
107
106
|
if (!hasPlanningState) {
|
|
108
107
|
rogues.push({ path: planPath, unitType, unitId });
|
|
109
108
|
}
|
|
@@ -114,7 +113,6 @@ export function detectRogueFileWrites(unitType, unitId, basePath) {
|
|
|
114
113
|
}
|
|
115
114
|
}
|
|
116
115
|
else if (unitType === "reassess-roadmap") {
|
|
117
|
-
const [mid, sid] = parts;
|
|
118
116
|
if (!mid || !sid)
|
|
119
117
|
return [];
|
|
120
118
|
const assessPath = resolveSliceFile(basePath, mid, sid, "ASSESSMENT");
|
|
@@ -130,7 +128,6 @@ export function detectRogueFileWrites(unitType, unitId, basePath) {
|
|
|
130
128
|
}
|
|
131
129
|
}
|
|
132
130
|
else if (unitType === "plan-task") {
|
|
133
|
-
const [mid, sid, tid] = parts;
|
|
134
131
|
if (!mid || !sid || !tid)
|
|
135
132
|
return [];
|
|
136
133
|
const taskPlanPath = resolveTaskFile(basePath, mid, sid, tid, "PLAN");
|
|
@@ -180,8 +177,7 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
180
177
|
try {
|
|
181
178
|
let taskContext;
|
|
182
179
|
if (s.currentUnit.type === "execute-task") {
|
|
183
|
-
const
|
|
184
|
-
const [mid, sid, tid] = parts;
|
|
180
|
+
const { milestone: mid, slice: sid, task: tid } = parseUnitId(s.currentUnit.id);
|
|
185
181
|
if (mid && sid && tid) {
|
|
186
182
|
const summaryPath = resolveTaskFile(s.basePath, mid, sid, tid, "SUMMARY");
|
|
187
183
|
if (summaryPath) {
|
|
@@ -284,8 +280,7 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
284
280
|
// Reactive state cleanup on slice completion
|
|
285
281
|
if (s.currentUnit.type === "complete-slice") {
|
|
286
282
|
try {
|
|
287
|
-
const
|
|
288
|
-
const [mid, sid] = parts;
|
|
283
|
+
const { milestone: mid, slice: sid } = parseUnitId(s.currentUnit.id);
|
|
289
284
|
if (mid && sid) {
|
|
290
285
|
const { clearReactiveState } = await import("./reactive-graph.js");
|
|
291
286
|
clearReactiveState(s.basePath, mid, sid);
|
|
@@ -356,8 +351,7 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
356
351
|
// from DB data before giving up (e.g. research-slice produces PLAN from engine).
|
|
357
352
|
if (!triggerArtifactVerified) {
|
|
358
353
|
try {
|
|
359
|
-
const
|
|
360
|
-
const [mid, sid] = parts;
|
|
354
|
+
const { milestone: mid, slice: sid } = parseUnitId(s.currentUnit.id);
|
|
361
355
|
if (mid && sid) {
|
|
362
356
|
const regenerated = regenerateIfMissing(s.basePath, mid, sid, "PLAN");
|
|
363
357
|
if (regenerated) {
|
|
@@ -444,8 +438,7 @@ export async function postUnitPostVerification(pctx) {
|
|
|
444
438
|
ctx.ui.notify(`Hook requested retry of ${trigger.unitType} ${trigger.unitId} — resetting task state.`, "info");
|
|
445
439
|
// ── State reset: undo the completion so deriveState re-derives the unit ──
|
|
446
440
|
try {
|
|
447
|
-
const
|
|
448
|
-
const [mid, sid, tid] = parts;
|
|
441
|
+
const { milestone: mid, slice: sid, task: tid } = parseUnitId(trigger.unitId);
|
|
449
442
|
// 1. Reset task status in DB and re-render plan checkboxes
|
|
450
443
|
if (mid && sid && tid) {
|
|
451
444
|
try {
|