@opengsd/gsd-pi 1.1.1-dev.74e8dd1 → 1.1.1-dev.9bb7453
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/cli.js +3 -2
- package/dist/help-text.js +10 -6
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +495 -0
- package/dist/resources/extensions/browser-tools/engine/selection.js +16 -0
- package/dist/resources/extensions/browser-tools/extension-manifest.json +2 -2
- package/dist/resources/extensions/browser-tools/index.js +57 -9
- package/dist/resources/extensions/browser-tools/package.json +5 -1
- package/dist/resources/extensions/gsd/auto/orchestrator.js +0 -1
- package/dist/resources/extensions/gsd/auto-dashboard.js +77 -13
- package/dist/resources/extensions/gsd/auto-dispatch.js +5 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +21 -3
- package/dist/resources/extensions/gsd/auto-prompts.js +59 -22
- package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +1 -1
- package/dist/resources/extensions/gsd/auto.js +9 -2
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +4 -4
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +9 -5
- package/dist/resources/extensions/gsd/browser-evidence.js +29 -2
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -2
- package/dist/resources/extensions/gsd/commands-handlers.js +76 -11
- package/dist/resources/extensions/gsd/commands-mcp-status.js +2 -1
- package/dist/resources/extensions/gsd/dashboard-overlay.js +21 -7
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -0
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +2 -2
- package/dist/resources/extensions/gsd/escalation.js +4 -4
- package/dist/resources/extensions/gsd/forensics.js +74 -2
- package/dist/resources/extensions/gsd/gsd-db.js +5 -2
- package/dist/resources/extensions/gsd/guided-flow.js +29 -68
- package/dist/resources/extensions/gsd/mcp-project-config.js +9 -76
- package/dist/resources/extensions/gsd/memory-store.js +4 -1
- package/dist/resources/extensions/gsd/post-unit-hooks.js +9 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +39 -0
- package/dist/resources/extensions/gsd/prompt-loader.js +7 -0
- package/dist/resources/extensions/gsd/prompts/forensics.md +61 -1
- package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +40 -22
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
- package/dist/resources/extensions/gsd/rule-registry.js +428 -52
- package/dist/resources/extensions/gsd/state.js +2 -2
- package/dist/resources/extensions/gsd/templates/plan.md +3 -1
- package/dist/resources/extensions/gsd/tools/complete-slice.js +15 -1
- package/dist/resources/extensions/gsd/tools/complete-task.js +11 -1
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +46 -16
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +51 -14
- package/dist/resources/extensions/gsd/verdict-parser.js +59 -15
- package/dist/resources/extensions/gsd/verification-gate.js +72 -1
- package/dist/resources/extensions/shared/gsd-browser-cli.js +145 -0
- package/dist/rtk.d.ts +7 -1
- package/dist/rtk.js +27 -11
- package/dist/update-check.d.ts +15 -1
- package/dist/update-check.js +87 -12
- package/dist/update-cmd.d.ts +1 -0
- package/dist/update-cmd.js +53 -2
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
- 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/api/update/route.js +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 +7 -7
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- 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 +4 -2
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/agent-session.d.ts +9 -0
- package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/agent-session.js +32 -0
- package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
- package/packages/gsd-agent-core/dist/index.d.ts +1 -0
- package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/index.js +1 -0
- package/packages/gsd-agent-core/dist/index.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts +2 -0
- package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-compaction.js +8 -2
- package/packages/gsd-agent-core/dist/session/agent-session-compaction.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +7 -0
- package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +69 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
- package/packages/gsd-agent-core/dist/turn-latency.d.ts +47 -0
- package/packages/gsd-agent-core/dist/turn-latency.d.ts.map +1 -0
- package/packages/gsd-agent-core/dist/turn-latency.js +123 -0
- package/packages/gsd-agent-core/dist/turn-latency.js.map +1 -0
- package/packages/gsd-agent-core/package.json +6 -6
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts +21 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js +213 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +20 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +7 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js +6 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -1
- package/packages/mcp-server/dist/remote-questions.js +23 -9
- package/packages/mcp-server/dist/remote-questions.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +2 -2
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +38 -0
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/agent.d.ts +5 -1
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +2 -0
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/dist/types.d.ts +3 -0
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/api-registry.d.ts +2 -0
- package/packages/pi-ai/dist/api-registry.d.ts.map +1 -1
- package/packages/pi-ai/dist/api-registry.js +23 -0
- package/packages/pi-ai/dist/api-registry.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +68 -0
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +72 -4
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/stream.js +6 -6
- package/packages/pi-ai/dist/stream.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +579 -0
- package/src/resources/extensions/browser-tools/engine/selection.ts +19 -0
- package/src/resources/extensions/browser-tools/extension-manifest.json +2 -2
- package/src/resources/extensions/browser-tools/index.ts +60 -9
- package/src/resources/extensions/browser-tools/package.json +5 -1
- package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +35 -0
- package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +33 -0
- package/src/resources/extensions/gsd/auto/orchestrator.ts +0 -1
- package/src/resources/extensions/gsd/auto-dashboard.ts +82 -14
- package/src/resources/extensions/gsd/auto-dispatch.ts +5 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +28 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +93 -15
- package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -0
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +1 -1
- package/src/resources/extensions/gsd/auto.ts +12 -2
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +4 -4
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +9 -5
- package/src/resources/extensions/gsd/browser-evidence.ts +26 -2
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +2 -2
- package/src/resources/extensions/gsd/commands-handlers.ts +76 -11
- package/src/resources/extensions/gsd/commands-mcp-status.ts +2 -1
- package/src/resources/extensions/gsd/dashboard-overlay.ts +28 -7
- package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -0
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +2 -2
- package/src/resources/extensions/gsd/escalation.ts +4 -4
- package/src/resources/extensions/gsd/forensics.ts +99 -5
- package/src/resources/extensions/gsd/gsd-db.ts +5 -2
- package/src/resources/extensions/gsd/guided-flow.ts +90 -82
- package/src/resources/extensions/gsd/mcp-project-config.ts +13 -78
- package/src/resources/extensions/gsd/memory-store.ts +4 -1
- package/src/resources/extensions/gsd/post-unit-hooks.ts +14 -1
- package/src/resources/extensions/gsd/preferences-validation.ts +36 -0
- package/src/resources/extensions/gsd/prompt-loader.ts +8 -0
- package/src/resources/extensions/gsd/prompts/forensics.md +61 -1
- package/src/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +40 -22
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
- package/src/resources/extensions/gsd/rule-registry.ts +558 -58
- package/src/resources/extensions/gsd/rule-types.ts +2 -0
- package/src/resources/extensions/gsd/state.ts +2 -2
- package/src/resources/extensions/gsd/templates/plan.md +3 -1
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +105 -4
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/browser-evidence.test.ts +142 -0
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/deep-planning-mode-dispatch.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/discuss-milestone-structured-questions.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/doctor-runtime-checks.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/escalation.test.ts +16 -27
- package/src/resources/extensions/gsd/tests/forensics-issue-routing.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/forensics-prompt-rendering.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/forensics-tool-scope.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +40 -1
- package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +86 -0
- package/src/resources/extensions/gsd/tests/guided-flow.test.ts +12 -9
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +66 -10
- package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/memory-maintenance.test.ts +39 -8
- package/src/resources/extensions/gsd/tests/new-milestone-discuss-routing.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +179 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +43 -1
- package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +7 -8
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +139 -0
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +133 -0
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +130 -0
- package/src/resources/extensions/gsd/tools/complete-slice.ts +14 -1
- package/src/resources/extensions/gsd/tools/complete-task.ts +20 -2
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +46 -15
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +63 -15
- package/src/resources/extensions/gsd/types.ts +69 -5
- package/src/resources/extensions/gsd/verdict-parser.ts +54 -13
- package/src/resources/extensions/gsd/verification-gate.ts +87 -1
- package/src/resources/extensions/shared/gsd-browser-cli.ts +172 -0
- /package/dist/web/standalone/.next/static/{eRWf-RI9bzbrwEurm_3uI → jBtwT9v1u2lUA3UEOy_ZH}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{eRWf-RI9bzbrwEurm_3uI → jBtwT9v1u2lUA3UEOy_ZH}/_ssgManifest.js +0 -0
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"version": "1.0.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "node --test tests/*.test.mjs"
|
|
7
|
+
"test": "node --import ../gsd/tests/resolve-ts.mjs --experimental-strip-types --test tests/*.test.mjs"
|
|
8
8
|
},
|
|
9
9
|
"pi": {
|
|
10
10
|
"extensions": [
|
|
@@ -12,10 +12,14 @@
|
|
|
12
12
|
]
|
|
13
13
|
},
|
|
14
14
|
"peerDependencies": {
|
|
15
|
+
"@opengsd/gsd-browser": ">=0.1.27",
|
|
15
16
|
"playwright": ">=1.40.0",
|
|
16
17
|
"sharp": ">=0.33.0"
|
|
17
18
|
},
|
|
18
19
|
"peerDependenciesMeta": {
|
|
20
|
+
"@opengsd/gsd-browser": {
|
|
21
|
+
"optional": true
|
|
22
|
+
},
|
|
19
23
|
"playwright": {
|
|
20
24
|
"optional": true
|
|
21
25
|
},
|
|
@@ -256,7 +256,6 @@ export class AutoOrchestrator {
|
|
|
256
256
|
this.status.activeUnit = { unitType: decision.unitType, unitId: decision.unitId };
|
|
257
257
|
this.status.phase = "running";
|
|
258
258
|
this.lastAdvanceKey = nextKey;
|
|
259
|
-
this.lastFinalizedUnitKey = null;
|
|
260
259
|
this.bumpTransition();
|
|
261
260
|
await this.deps.runtime.journalTransition({
|
|
262
261
|
name: "advance",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// gsd-pi + src/resources/extensions/gsd/auto-dashboard.ts - Auto-mode progress widget rendering and dashboard helpers.
|
|
2
2
|
import { getActiveHook } from "./post-unit-hooks.js";
|
|
3
|
-
import { getLedger } from "./metrics.js";
|
|
3
|
+
import { getLedger, getProjectTotals } from "./metrics.js";
|
|
4
4
|
import { getErrorMessage } from "./error-utils.js";
|
|
5
5
|
import { nativeIsRepo } from "./native-git-bridge.js";
|
|
6
6
|
import { isDbAvailable, getMilestoneSlices, getSliceTasks } from "./gsd-db.js";
|
|
@@ -196,6 +196,39 @@ export function formatRuntimeHealthSignal(record, now = Date.now()) {
|
|
|
196
196
|
export function shouldRenderRoadmapProgress(progress) {
|
|
197
197
|
return !!progress && progress.total > 0;
|
|
198
198
|
}
|
|
199
|
+
function widgetGridLabel(theme, text, color = "borderAccent") {
|
|
200
|
+
return theme.fg(color, theme.bold(text.toUpperCase()));
|
|
201
|
+
}
|
|
202
|
+
function widgetGridColumn(content, width) {
|
|
203
|
+
return padRightVisible(truncateToWidth(content, width, "…"), width);
|
|
204
|
+
}
|
|
205
|
+
function widgetGridColumns(theme, width, parts) {
|
|
206
|
+
if (parts.length === 0)
|
|
207
|
+
return "";
|
|
208
|
+
const gap = theme.fg("dim", " │ ");
|
|
209
|
+
const gapWidth = visibleWidth(gap) * (parts.length - 1);
|
|
210
|
+
const available = Math.max(parts.length * 8, width - gapWidth);
|
|
211
|
+
const base = Math.floor(available / parts.length);
|
|
212
|
+
let remaining = available - base * parts.length;
|
|
213
|
+
const columns = parts.map((part) => {
|
|
214
|
+
const columnWidth = base + (remaining > 0 ? 1 : 0);
|
|
215
|
+
remaining--;
|
|
216
|
+
return widgetGridColumn(part, columnWidth);
|
|
217
|
+
});
|
|
218
|
+
return truncateToWidth(columns.join(gap), width, "…");
|
|
219
|
+
}
|
|
220
|
+
function formatSmallWidgetSpend() {
|
|
221
|
+
const ledger = getLedger();
|
|
222
|
+
if (!ledger || ledger.units.length === 0)
|
|
223
|
+
return "--";
|
|
224
|
+
const totals = getProjectTotals(ledger.units);
|
|
225
|
+
const parts = [];
|
|
226
|
+
if (totals.tokens.total > 0)
|
|
227
|
+
parts.push(formatWidgetTokens(totals.tokens.total));
|
|
228
|
+
if (totals.cost > 0)
|
|
229
|
+
parts.push(`$${totals.cost.toFixed(2)}`);
|
|
230
|
+
return parts.length > 0 ? parts.join(" · ") : "--";
|
|
231
|
+
}
|
|
199
232
|
// ─── ETA Estimation ──────────────────────────────────────────────────────────
|
|
200
233
|
/**
|
|
201
234
|
* Estimate remaining time based on average unit duration from the metrics ledger.
|
|
@@ -642,26 +675,57 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
642
675
|
cachedWidth = width;
|
|
643
676
|
return lines;
|
|
644
677
|
}
|
|
645
|
-
// ── Mode: small —
|
|
678
|
+
// ── Mode: small — dense horizontal grid ───────────────────────
|
|
646
679
|
if (widgetMode === "small") {
|
|
647
|
-
lines.
|
|
648
|
-
|
|
649
|
-
const target = task ? `${task.id}: ${task.title}` : unitId;
|
|
650
|
-
const actionLeft = `${pad}${theme.fg("accent", "▸")} ${theme.fg("accent", verb)} ${theme.fg("text", target)}`;
|
|
651
|
-
lines.push(rightAlign(actionLeft, theme.fg("dim", phaseLabel), width));
|
|
652
|
-
// Progress bar
|
|
680
|
+
lines.length = 0;
|
|
681
|
+
lines.push(...ui.bar());
|
|
653
682
|
const roadmapSlices = mid ? getRoadmapSlicesSync() : null;
|
|
683
|
+
const unitLabel = unitId || [mid?.id, slice?.id, task?.id].filter(Boolean).join("/");
|
|
684
|
+
const statusParts = [
|
|
685
|
+
spinner,
|
|
686
|
+
theme.fg("success", modeTag),
|
|
687
|
+
theme.fg(stateColor, activeState),
|
|
688
|
+
];
|
|
689
|
+
if (runtimeSignal?.summary) {
|
|
690
|
+
statusParts.push(theme.fg(healthColor, healthSummary));
|
|
691
|
+
}
|
|
692
|
+
else if (healthLevel !== "green") {
|
|
693
|
+
statusParts.push(`${theme.fg(healthColor, healthIcon)} ${theme.fg(healthColor, healthSummary)}`);
|
|
694
|
+
}
|
|
695
|
+
const timeValue = [elapsed, etaShort].filter(Boolean).join(" · ") || "--";
|
|
696
|
+
const rowOne = widgetGridColumns(theme, width, [
|
|
697
|
+
`${widgetGridLabel(theme, "status", "border")} ${statusParts.join(" ")}`,
|
|
698
|
+
`${widgetGridLabel(theme, "unit")} ${theme.fg("text", unitLabel || "--")}`,
|
|
699
|
+
`${widgetGridLabel(theme, "spend", "border")} ${theme.fg("dim", formatSmallWidgetSpend())}`,
|
|
700
|
+
`${widgetGridLabel(theme, "time")} ${theme.fg("dim", timeValue)}`,
|
|
701
|
+
]);
|
|
702
|
+
const target = task
|
|
703
|
+
? `${task.id}: ${task.title}`
|
|
704
|
+
: slice
|
|
705
|
+
? `${slice.id}: ${slice.title}`
|
|
706
|
+
: unitId;
|
|
707
|
+
let taskValue = task?.id ?? "--";
|
|
708
|
+
let sliceValue = slice?.id ?? "--";
|
|
654
709
|
if (shouldRenderRoadmapProgress(roadmapSlices)) {
|
|
655
710
|
const { done, total, activeSliceTasks } = roadmapSlices;
|
|
656
|
-
const barWidth = Math.max(
|
|
711
|
+
const barWidth = Math.max(4, Math.min(14, Math.floor(width * 0.12)));
|
|
657
712
|
const bar = renderProgressBar(theme, done, total, barWidth);
|
|
658
|
-
|
|
713
|
+
sliceValue = `${bar} ${theme.fg("text", `${done}/${total}`)}`;
|
|
659
714
|
if (activeSliceTasks && activeSliceTasks.total > 0) {
|
|
660
|
-
const
|
|
661
|
-
|
|
715
|
+
const taskNum = isHook
|
|
716
|
+
? Math.max(activeSliceTasks.done, 1)
|
|
717
|
+
: Math.min(activeSliceTasks.done + 1, activeSliceTasks.total);
|
|
718
|
+
taskValue = `${theme.fg("accent", `${taskNum}`)}${theme.fg("dim", `/${activeSliceTasks.total}`)}`;
|
|
662
719
|
}
|
|
663
|
-
lines.push(`${pad}${bar} ${meta}`);
|
|
664
720
|
}
|
|
721
|
+
const rowTwo = widgetGridColumns(theme, width, [
|
|
722
|
+
`${widgetGridLabel(theme, "phase", "border")} ${theme.fg("dim", unitType)}`,
|
|
723
|
+
`${widgetGridLabel(theme, "work")} ${theme.fg("text", target || "--")}`,
|
|
724
|
+
`${widgetGridLabel(theme, "task", "border")} ${taskValue}`,
|
|
725
|
+
`${widgetGridLabel(theme, "slice")} ${sliceValue}`,
|
|
726
|
+
]);
|
|
727
|
+
lines.push(rowOne);
|
|
728
|
+
lines.push(rowTwo);
|
|
665
729
|
lines.push(...ui.bar());
|
|
666
730
|
cachedLines = lines;
|
|
667
731
|
cachedWidth = width;
|
|
@@ -443,6 +443,7 @@ export const DISPATCH_RULES = [
|
|
|
443
443
|
unitType: "discuss-milestone",
|
|
444
444
|
unitId: mid,
|
|
445
445
|
prompt: await buildDiscussMilestonePrompt(mid, midTitle, basePath, structuredQuestionsAvailable, { headless: !!process.env.GSD_HEADLESS }),
|
|
446
|
+
pauseAfterDispatch: !process.env.GSD_HEADLESS,
|
|
446
447
|
};
|
|
447
448
|
},
|
|
448
449
|
},
|
|
@@ -578,6 +579,7 @@ export const DISPATCH_RULES = [
|
|
|
578
579
|
unitType: "discuss-milestone",
|
|
579
580
|
unitId: mid,
|
|
580
581
|
prompt: await buildDiscussMilestonePrompt(mid, midTitle, basePath, structuredQuestionsAvailable, { headless: !!process.env.GSD_HEADLESS }),
|
|
582
|
+
pauseAfterDispatch: !process.env.GSD_HEADLESS,
|
|
581
583
|
};
|
|
582
584
|
},
|
|
583
585
|
},
|
|
@@ -617,6 +619,7 @@ export const DISPATCH_RULES = [
|
|
|
617
619
|
unitType: "discuss-project",
|
|
618
620
|
unitId: "PROJECT",
|
|
619
621
|
prompt: await buildDiscussProjectPrompt(basePath, structuredQuestionsAvailable),
|
|
622
|
+
pauseAfterDispatch: !process.env.GSD_HEADLESS,
|
|
620
623
|
};
|
|
621
624
|
},
|
|
622
625
|
},
|
|
@@ -642,6 +645,7 @@ export const DISPATCH_RULES = [
|
|
|
642
645
|
unitType: "discuss-requirements",
|
|
643
646
|
unitId: "REQUIREMENTS",
|
|
644
647
|
prompt: await buildDiscussRequirementsPrompt(basePath, structuredQuestionsAvailable),
|
|
648
|
+
pauseAfterDispatch: !process.env.GSD_HEADLESS,
|
|
645
649
|
};
|
|
646
650
|
},
|
|
647
651
|
},
|
|
@@ -757,6 +761,7 @@ export const DISPATCH_RULES = [
|
|
|
757
761
|
unitType: "discuss-milestone",
|
|
758
762
|
unitId: mid,
|
|
759
763
|
prompt: await buildDiscussMilestonePrompt(mid, midTitle, basePath, structuredQuestionsAvailable, { headless: !!process.env.GSD_HEADLESS }),
|
|
764
|
+
pauseAfterDispatch: !process.env.GSD_HEADLESS,
|
|
760
765
|
};
|
|
761
766
|
},
|
|
762
767
|
},
|
|
@@ -32,7 +32,7 @@ import { isDbAvailable, getDbPath, refreshOpenDatabaseFromDisk, getTask, getSlic
|
|
|
32
32
|
import { renderPlanCheckboxes, renderRoadmapFromDb } from "./markdown-renderer.js";
|
|
33
33
|
import { parseRoadmap as parseLegacyRoadmap } from "./parsers-legacy.js";
|
|
34
34
|
import { consumeSignal } from "./session-status-io.js";
|
|
35
|
-
import { checkPostUnitHooks, isRetryPending, consumeRetryTrigger, persistHookState, resolveHookArtifactPath, } from "./post-unit-hooks.js";
|
|
35
|
+
import { checkPostUnitHooks, consumeHookFailure, isRetryPending, consumeRetryTrigger, consumeGateBlock, persistHookState, resolveHookArtifactPath, } from "./post-unit-hooks.js";
|
|
36
36
|
import { hasPendingCaptures, loadPendingCaptures, revertExecutorResolvedCaptures } from "./captures.js";
|
|
37
37
|
import { debugLog } from "./debug-logger.js";
|
|
38
38
|
import { runSafely } from "./auto-utils.js";
|
|
@@ -1860,18 +1860,25 @@ export async function postUnitPostVerification(pctx) {
|
|
|
1860
1860
|
// ── Post-unit hooks ──
|
|
1861
1861
|
if (s.currentUnit && !s.stepMode) {
|
|
1862
1862
|
const hookUnit = checkPostUnitHooks(s.currentUnit.type, s.currentUnit.id, s.basePath);
|
|
1863
|
+
persistHookState(s.basePath);
|
|
1863
1864
|
if (hookUnit) {
|
|
1864
1865
|
if (s.currentUnit) {
|
|
1865
1866
|
await closeoutUnit(ctx, s.basePath, s.currentUnit.type, s.currentUnit.id, s.currentUnit.startedAt, buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id));
|
|
1866
1867
|
}
|
|
1867
|
-
persistHookState(s.basePath);
|
|
1868
1868
|
return enqueueSidecar(s, ctx, { kind: "hook", unitType: hookUnit.unitType, unitId: hookUnit.unitId, prompt: hookUnit.prompt, model: hookUnit.model }, { hookName: hookUnit.hookName });
|
|
1869
1869
|
}
|
|
1870
|
+
const hookFailure = consumeHookFailure();
|
|
1871
|
+
if (hookFailure) {
|
|
1872
|
+
ctx.ui.notify(`Post-unit hook ${hookFailure.hookName} failed for ${hookFailure.unitId}: ${hookFailure.reason}. Pausing auto-mode.`, "warning");
|
|
1873
|
+
await pauseAuto(ctx, pi);
|
|
1874
|
+
return "stopped";
|
|
1875
|
+
}
|
|
1870
1876
|
// Check if a hook requested a retry of the trigger unit
|
|
1871
1877
|
if (isRetryPending()) {
|
|
1872
1878
|
const trigger = consumeRetryTrigger();
|
|
1873
1879
|
if (trigger) {
|
|
1874
|
-
|
|
1880
|
+
persistHookState(s.basePath);
|
|
1881
|
+
ctx.ui.notify(`Hook requested retry of ${trigger.unitType} ${trigger.unitId} — resetting trigger unit state.`, "info");
|
|
1875
1882
|
await s.orchestration?.retryActiveUnit({
|
|
1876
1883
|
unitType: trigger.unitType,
|
|
1877
1884
|
unitId: trigger.unitId,
|
|
@@ -1918,6 +1925,17 @@ export async function postUnitPostVerification(pctx) {
|
|
|
1918
1925
|
// Fall through to normal dispatch — deriveState will re-derive the unit
|
|
1919
1926
|
}
|
|
1920
1927
|
}
|
|
1928
|
+
const gateBlock = consumeGateBlock();
|
|
1929
|
+
if (gateBlock) {
|
|
1930
|
+
persistHookState(s.basePath);
|
|
1931
|
+
const verdict = gateBlock.verdict ? ` verdict=${gateBlock.verdict};` : "";
|
|
1932
|
+
const artifact = gateBlock.artifact ? ` artifact=${gateBlock.artifact};` : "";
|
|
1933
|
+
const message = `Post-unit gate "${gateBlock.hookName}" blocked ${gateBlock.triggerUnitType} ${gateBlock.triggerUnitId}:` +
|
|
1934
|
+
`${verdict}${artifact} ${gateBlock.reason}. Run /gsd status to inspect, then /gsd auto after recovery.`;
|
|
1935
|
+
ctx.ui.notify(message, "warning");
|
|
1936
|
+
await pauseAuto(ctx, pi);
|
|
1937
|
+
return "stopped";
|
|
1938
|
+
}
|
|
1921
1939
|
}
|
|
1922
1940
|
// ── Fast-path stop detection (#3487) ──
|
|
1923
1941
|
// Before waiting for triage, check if any PENDING captures contain explicit
|
|
@@ -30,6 +30,7 @@ import { classifyProject } from "./detection.js";
|
|
|
30
30
|
import { hasBrowserRequiredText } from "./browser-evidence.js";
|
|
31
31
|
import { debugLog } from "./debug-logger.js";
|
|
32
32
|
import { buildSkillActivationBlock, buildSkillDiscoveryVars } from "./skill-activation.js";
|
|
33
|
+
import { findMilestoneIds } from "./milestone-ids.js";
|
|
33
34
|
export { buildSkillActivationBlock, buildSkillDiscoveryVars };
|
|
34
35
|
// ─── Preamble Cap ─────────────────────────────────────────────────────────────
|
|
35
36
|
/**
|
|
@@ -1270,7 +1271,7 @@ export async function checkNeedsRunUat(base, mid, state, prefs) {
|
|
|
1270
1271
|
if (hasVerdict(uatContent))
|
|
1271
1272
|
continue;
|
|
1272
1273
|
// Also check the ASSESSMENT file — the run-uat prompt writes the verdict
|
|
1273
|
-
// there (via
|
|
1274
|
+
// there (via gsd_uat_result_save), not into the
|
|
1274
1275
|
// UAT spec file. Without this check the unit re-dispatches indefinitely.
|
|
1275
1276
|
const assessmentFile = resolveSliceFile(base, mid, sid, "ASSESSMENT");
|
|
1276
1277
|
if (assessmentFile) {
|
|
@@ -1325,21 +1326,44 @@ export async function checkNeedsRunUat(base, mid, state, prefs) {
|
|
|
1325
1326
|
}
|
|
1326
1327
|
return null;
|
|
1327
1328
|
}
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
const
|
|
1329
|
+
export async function buildDiscussMilestoneInlinedContext(mid, base) {
|
|
1330
|
+
const inlined = [];
|
|
1331
|
+
const roadmapInline = await inlineFileOptional(resolveMilestoneFile(base, mid, "ROADMAP"), relMilestoneFile(base, mid, "ROADMAP"), "Milestone Roadmap");
|
|
1332
|
+
if (roadmapInline)
|
|
1333
|
+
inlined.push(roadmapInline);
|
|
1334
|
+
const contextInline = await inlineFileOptional(resolveMilestoneFile(base, mid, "CONTEXT"), relMilestoneFile(base, mid, "CONTEXT"), "Milestone Context");
|
|
1335
|
+
if (contextInline)
|
|
1336
|
+
inlined.push(contextInline);
|
|
1337
|
+
const researchInline = await inlineFileOptional(resolveMilestoneFile(base, mid, "RESEARCH"), relMilestoneFile(base, mid, "RESEARCH"), "Milestone Research");
|
|
1338
|
+
if (researchInline)
|
|
1339
|
+
inlined.push(researchInline);
|
|
1340
|
+
const decisionsPath = resolveGsdRootFile(base, "DECISIONS");
|
|
1341
|
+
if (existsSync(decisionsPath)) {
|
|
1342
|
+
const decisionsContent = await loadFile(decisionsPath);
|
|
1343
|
+
if (decisionsContent) {
|
|
1344
|
+
inlined.push(`### Decisions Register\nSource: \`${relGsdRootFile("DECISIONS")}\`\n\n${decisionsContent.trim()}`);
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
const milestoneIds = findMilestoneIds(base);
|
|
1348
|
+
const currentIndex = milestoneIds.indexOf(mid);
|
|
1349
|
+
const priorMilestoneIds = currentIndex >= 0 ? milestoneIds.slice(0, currentIndex) : milestoneIds;
|
|
1350
|
+
for (const priorMid of priorMilestoneIds) {
|
|
1351
|
+
const summaryInline = await inlineFileOptional(resolveMilestoneFile(base, priorMid, "SUMMARY"), relMilestoneFile(base, priorMid, "SUMMARY"), `${priorMid} Prior Milestone Summary`);
|
|
1352
|
+
if (summaryInline)
|
|
1353
|
+
inlined.push(summaryInline);
|
|
1354
|
+
}
|
|
1355
|
+
return inlined.length > 0
|
|
1356
|
+
? `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`
|
|
1357
|
+
: "## Inlined Context\n\n_(no milestone context files found yet — go in blind and ask broad questions)_";
|
|
1358
|
+
}
|
|
1359
|
+
export async function buildDiscussMilestonePrompt(mid, midTitle, base, structuredQuestionsAvailable = "false", { headless = false, commitInstruction = "Do not commit planning artifacts — .gsd/ is managed externally.", fastPathInstruction = "", includeDraftSeed = true, includeContextMode = true, } = {}) {
|
|
1360
|
+
const contextTemplate = inlineTemplate("context", "Context");
|
|
1337
1361
|
if (headless) {
|
|
1338
1362
|
const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
|
|
1339
1363
|
const roadmapContent = roadmapPath ? await loadFile(roadmapPath) : null;
|
|
1340
1364
|
return loadPrompt("discuss-headless", {
|
|
1341
1365
|
seedContext: roadmapContent ?? "",
|
|
1342
|
-
inlinedTemplates:
|
|
1366
|
+
inlinedTemplates: contextTemplate,
|
|
1343
1367
|
workingDirectory: base,
|
|
1344
1368
|
milestoneId: mid,
|
|
1345
1369
|
contextPath: relMilestoneFile(base, mid, "CONTEXT"),
|
|
@@ -1347,24 +1371,28 @@ export async function buildDiscussMilestonePrompt(mid, midTitle, base, structure
|
|
|
1347
1371
|
multiMilestoneCommitInstruction: "Do not commit planning artifacts — .gsd/ is managed externally.",
|
|
1348
1372
|
});
|
|
1349
1373
|
}
|
|
1350
|
-
const
|
|
1374
|
+
const rawInlinedContext = await buildDiscussMilestoneInlinedContext(mid, base);
|
|
1375
|
+
const cappedInlinedContext = capPreamble(rawInlinedContext);
|
|
1376
|
+
const discussTemplates = [cappedInlinedContext, contextTemplate].join("\n\n---\n\n");
|
|
1351
1377
|
const basePrompt = loadPrompt("guided-discuss-milestone", {
|
|
1352
1378
|
workingDirectory: base,
|
|
1353
1379
|
milestoneId: mid,
|
|
1354
1380
|
milestoneTitle: midTitle,
|
|
1355
1381
|
inlinedTemplates: discussTemplates,
|
|
1356
1382
|
structuredQuestionsAvailable,
|
|
1357
|
-
commitInstruction
|
|
1358
|
-
fastPathInstruction
|
|
1383
|
+
commitInstruction,
|
|
1384
|
+
fastPathInstruction,
|
|
1359
1385
|
});
|
|
1360
|
-
const promptWithContextMode =
|
|
1386
|
+
const promptWithContextMode = includeContextMode
|
|
1387
|
+
? prependContextModeToBlock("discuss-milestone", base, basePrompt)
|
|
1388
|
+
: basePrompt;
|
|
1361
1389
|
// If a CONTEXT-DRAFT.md exists, append it as seed material
|
|
1362
1390
|
const draftPath = resolveMilestoneFile(base, mid, "CONTEXT-DRAFT");
|
|
1363
1391
|
const draftContent = draftPath ? await loadFile(draftPath) : null;
|
|
1364
|
-
if (draftContent) {
|
|
1392
|
+
if (includeDraftSeed && draftContent) {
|
|
1365
1393
|
return `${promptWithContextMode}\n\n## Prior Discussion (Draft Seed)\n\nThe following draft was captured from a prior multi-milestone discussion. Use it as seed material — the user has already provided this context. Start with a brief reflection on what the draft covers, then probe for any gaps or open questions before writing the full CONTEXT.md.\n\n${draftContent}`;
|
|
1366
1394
|
}
|
|
1367
|
-
return
|
|
1395
|
+
return promptWithContextMode;
|
|
1368
1396
|
}
|
|
1369
1397
|
/**
|
|
1370
1398
|
* Build a prompt for the workflow-preferences unit type (deep mode).
|
|
@@ -2540,17 +2568,26 @@ export async function buildValidateMilestonePrompt(mid, midTitle, base, level) {
|
|
|
2540
2568
|
if (isDbAvailable()) {
|
|
2541
2569
|
const milestone = getMilestone(mid);
|
|
2542
2570
|
if (milestone) {
|
|
2571
|
+
const escapeCell = (value) => value.replace(/[\\|]/g, (char) => `\\${char}`).replace(/\r?\n/g, " ");
|
|
2543
2572
|
const classes = [];
|
|
2544
2573
|
if (milestone.verification_contract)
|
|
2545
|
-
classes.push(
|
|
2574
|
+
classes.push(`| Contract | ${escapeCell(milestone.verification_contract)} |`);
|
|
2546
2575
|
if (milestone.verification_integration)
|
|
2547
|
-
classes.push(
|
|
2576
|
+
classes.push(`| Integration | ${escapeCell(milestone.verification_integration)} |`);
|
|
2548
2577
|
if (milestone.verification_operational)
|
|
2549
|
-
classes.push(
|
|
2578
|
+
classes.push(`| Operational | ${escapeCell(milestone.verification_operational)} |`);
|
|
2550
2579
|
if (milestone.verification_uat)
|
|
2551
|
-
classes.push(
|
|
2580
|
+
classes.push(`| UAT | ${escapeCell(milestone.verification_uat)} |`);
|
|
2552
2581
|
if (classes.length > 0) {
|
|
2553
|
-
const verificationClasses =
|
|
2582
|
+
const verificationClasses = [
|
|
2583
|
+
"### Verification Classes (from planning)",
|
|
2584
|
+
"",
|
|
2585
|
+
"These verification tiers were defined during milestone planning. Every row in this table must appear in `verificationClasses` with the same canonical class name.",
|
|
2586
|
+
"",
|
|
2587
|
+
"| Class | Planned Check |",
|
|
2588
|
+
"| --- | --- |",
|
|
2589
|
+
...classes,
|
|
2590
|
+
].join("\n");
|
|
2554
2591
|
inlined.push(verificationClasses);
|
|
2555
2592
|
trackPromptContext(contextTelemetry, "verification-classes", "inline", verificationClasses);
|
|
2556
2593
|
}
|
|
@@ -20,6 +20,9 @@ export function isAutoActive() {
|
|
|
20
20
|
export function isAutoPaused() {
|
|
21
21
|
return autoSession.paused;
|
|
22
22
|
}
|
|
23
|
+
export function isAutoCompletionStopInProgress() {
|
|
24
|
+
return autoSession.completionStopInProgress;
|
|
25
|
+
}
|
|
23
26
|
export function markToolStart(toolCallId, toolName) {
|
|
24
27
|
markTrackedToolStart(toolCallId, autoSession.active, toolName);
|
|
25
28
|
}
|
|
@@ -83,7 +83,7 @@ export function clearInFlightTools() {
|
|
|
83
83
|
* from the tool handler. When these errors occur, retrying the same unit will
|
|
84
84
|
* produce the same failure, so the retry loop must be broken.
|
|
85
85
|
*/
|
|
86
|
-
const TOOL_INVOCATION_ERROR_RE = /Validation failed for tool|Expected ',' or '\}'(?: after property value)?(?: in JSON)?|Unexpected end of JSON|Unexpected token.*in JSON|does not provide an export named|Named export .* not found|Cannot find module|ERR_MODULE_NOT_FOUND|ERR_MODULE_NOT_EXPORTED|ERR_PACKAGE_PATH_NOT_EXPORTED/i;
|
|
86
|
+
const TOOL_INVOCATION_ERROR_RE = /Validation failed for tool|Input validation error|Invalid arguments for tool|MCP error -32602|No such tool available|Expected ',' or '\}'(?: after property value)?(?: in JSON)?|Unexpected end of JSON|Unexpected token.*in JSON|does not provide an export named|Named export .* not found|Cannot find module|ERR_MODULE_NOT_FOUND|ERR_MODULE_NOT_EXPORTED|ERR_PACKAGE_PATH_NOT_EXPORTED/i;
|
|
87
87
|
const DETERMINISTIC_POLICY_ERROR_RE = /(?:^|\b)(?:HARD BLOCK:|Blocked: \/gsd queue is a planning tool|Direct writes to \.gsd\/STATE\.md and \.gsd\/gsd\.db are blocked|This is a mechanical gate)/i;
|
|
88
88
|
/**
|
|
89
89
|
* Returns true if the error message indicates a deterministic invocation or
|
|
@@ -1774,10 +1774,17 @@ export function createWiredAutoOrchestrationModule(ctx, pi, dispatchBasePath, ru
|
|
|
1774
1774
|
async reconcileBeforeDispatch() {
|
|
1775
1775
|
const activeBasePath = getLiveDispatchBasePath();
|
|
1776
1776
|
const result = await reconcileBeforeDispatch(activeBasePath);
|
|
1777
|
-
|
|
1777
|
+
// Failure-path summaries written by gsd_summary_save create
|
|
1778
|
+
// artifact-db-status-divergence blockers for tasks that are still
|
|
1779
|
+
// pending (gsd_task_complete never ran). These tasks can still be
|
|
1780
|
+
// dispatched and the drift self-heals once they complete successfully.
|
|
1781
|
+
const hardBlockers = result.blockers.filter((b) => !b.includes("has SUMMARY artifact while DB status is") &&
|
|
1782
|
+
!b.includes("has SUMMARY on disk while DB status is") &&
|
|
1783
|
+
!b.includes("has task SUMMARY artifacts but no DB tasks"));
|
|
1784
|
+
if (hardBlockers.length > 0) {
|
|
1778
1785
|
return {
|
|
1779
1786
|
ok: false,
|
|
1780
|
-
reason:
|
|
1787
|
+
reason: hardBlockers[0],
|
|
1781
1788
|
stateSnapshot: result.stateSnapshot,
|
|
1782
1789
|
};
|
|
1783
1790
|
}
|
|
@@ -788,7 +788,7 @@ export function registerDbTools(pi) {
|
|
|
788
788
|
recommendation: Type.String({ description: "Option id the executor recommends." }),
|
|
789
789
|
recommendationRationale: Type.String({ description: "Why the recommendation — 1–2 sentences." }),
|
|
790
790
|
continueWithDefault: Type.Boolean({
|
|
791
|
-
description: "When true,
|
|
791
|
+
description: "When true, the recommendation is recorded as the default, but auto-mode still pauses until the user resolves via /gsd escalate resolve.",
|
|
792
792
|
}),
|
|
793
793
|
}, { description: "ADR-011 Phase 2: optional escalation payload. Only honored when phases.mid_execution_escalation is true." })),
|
|
794
794
|
verificationEvidence: Type.Optional(Type.Array(Type.Object({
|
|
@@ -829,7 +829,7 @@ export function registerDbTools(pi) {
|
|
|
829
829
|
sliceTitle: Type.String({ description: "Title of the slice" }),
|
|
830
830
|
oneLiner: Type.String({ description: "One-line summary of what the slice accomplished" }),
|
|
831
831
|
narrative: Type.String({ description: "Detailed narrative of what happened across all tasks" }),
|
|
832
|
-
verification: Type.String({ description: "What was verified across all tasks" }),
|
|
832
|
+
verification: Type.Optional(Type.String({ description: "What was verified across all tasks — if omitted, summary records verification as passed without detail." })),
|
|
833
833
|
uatContent: Type.String({ description: "UAT test content (markdown body)" }),
|
|
834
834
|
// ── Enrichment metadata (optional — defaults to empty) ────────────
|
|
835
835
|
deviations: Type.Optional(Type.String({ description: "Deviations from the slice plan, or 'None.'" })),
|
|
@@ -1010,7 +1010,7 @@ export function registerDbTools(pi) {
|
|
|
1010
1010
|
promptGuidelines: [
|
|
1011
1011
|
"Use gsd_validate_milestone when all slices are done and the milestone needs validation before completion.",
|
|
1012
1012
|
"Parameters: milestoneId, verdict, remediationRound, successCriteriaChecklist, sliceDeliveryAudit, crossSliceIntegration, requirementCoverage, verificationClasses (optional), verdictRationale, remediationPlan (optional).",
|
|
1013
|
-
"If verification classes were planned, verificationClasses must
|
|
1013
|
+
"If verification classes were planned, verificationClasses must be a complete canonical table with one row for every applicable planned class using the exact class names Contract, Integration, Operational, and UAT. Do not submit a partial table.",
|
|
1014
1014
|
"Planned verification text marked as none/not required/not applicable/N/A (including suffixed variants such as 'not required - backend-only') is treated as not applicable and does not require a class row.",
|
|
1015
1015
|
"If verdict is 'needs-remediation', also provide remediationPlan and use gsd_reassess_roadmap to add remediation slices to the roadmap.",
|
|
1016
1016
|
"On success, returns validationPath where VALIDATION.md was written.",
|
|
@@ -1023,7 +1023,7 @@ export function registerDbTools(pi) {
|
|
|
1023
1023
|
sliceDeliveryAudit: Type.String({ description: "Markdown table auditing each slice's claimed vs delivered output" }),
|
|
1024
1024
|
crossSliceIntegration: Type.String({ description: "Markdown describing any cross-slice boundary mismatches" }),
|
|
1025
1025
|
requirementCoverage: Type.String({ description: "Markdown describing any unaddressed requirements" }),
|
|
1026
|
-
verificationClasses: Type.Optional(Type.String({ description: "
|
|
1026
|
+
verificationClasses: Type.Optional(Type.String({ description: "Complete markdown table describing verification class compliance and gaps; include one canonical row for every applicable planned class (Contract, Integration, Operational, UAT)" })),
|
|
1027
1027
|
verdictRationale: Type.String({ description: "Why this verdict was chosen" }),
|
|
1028
1028
|
remediationPlan: Type.Optional(Type.String({ description: "Remediation plan (required if verdict is needs-remediation)" })),
|
|
1029
1029
|
}),
|
|
@@ -11,7 +11,7 @@ import { canonicalToolName, clearDiscussionFlowState, isDepthConfirmationAnswer,
|
|
|
11
11
|
import { resolveManifest } from "../unit-context-manifest.js";
|
|
12
12
|
import { isBlockedStateFile, isBashWriteToStateFile, BLOCKED_WRITE_ERROR } from "../write-intercept.js";
|
|
13
13
|
import { loadFile, saveFile, formatContinue } from "../files.js";
|
|
14
|
-
import { clearToolInvocationError, getAutoRuntimeSnapshot, isAutoActive, isAutoPaused, markToolEnd, markToolStart, recordToolInvocationError } from "../auto-runtime-state.js";
|
|
14
|
+
import { clearToolInvocationError, getAutoRuntimeSnapshot, isAutoActive, isAutoCompletionStopInProgress, isAutoPaused, markToolEnd, markToolStart, recordToolInvocationError } from "../auto-runtime-state.js";
|
|
15
15
|
import { checkToolCallLoop, resetToolCallLoopGuard } from "./tool-call-loop-guard.js";
|
|
16
16
|
import { maybePauseAutoForApprovalGate, resetPendingGatePauseGuard } from "./pending-gate-pause.js";
|
|
17
17
|
import { saveActivityLog } from "../activity-log.js";
|
|
@@ -424,8 +424,9 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
424
424
|
registerPlanMilestoneSchemaRecovery(pi);
|
|
425
425
|
pi.on("session_start", async (_event, ctx) => {
|
|
426
426
|
const basePath = contextBasePath(ctx);
|
|
427
|
+
const preserveCloseoutSurface = isAutoCompletionStopInProgress();
|
|
427
428
|
initSessionNotifications(ctx);
|
|
428
|
-
if (!isAutoActive()) {
|
|
429
|
+
if (!isAutoActive() && !preserveCloseoutSurface) {
|
|
429
430
|
const { initHealthWidget } = await import("../health-widget.js");
|
|
430
431
|
initHealthWidget(ctx);
|
|
431
432
|
}
|
|
@@ -445,14 +446,17 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
445
446
|
process.env.GSD_SHOW_TOKEN_COST = prefs?.preferences.show_token_cost ? "1" : "";
|
|
446
447
|
}
|
|
447
448
|
catch { /* non-fatal */ }
|
|
448
|
-
|
|
449
|
+
if (!preserveCloseoutSurface) {
|
|
450
|
+
await installWelcomeHeader(ctx);
|
|
451
|
+
}
|
|
449
452
|
await loadToolApiKeysForSession();
|
|
450
|
-
if (isAutoActive()) {
|
|
453
|
+
if (isAutoActive() || preserveCloseoutSurface) {
|
|
451
454
|
ctx.ui.setWidget("gsd-health", undefined);
|
|
452
455
|
}
|
|
453
456
|
});
|
|
454
457
|
pi.on("session_switch", async (_event, ctx) => {
|
|
455
458
|
const basePath = contextBasePath(ctx);
|
|
459
|
+
const preserveCloseoutSurface = isAutoCompletionStopInProgress();
|
|
456
460
|
initSessionNotifications(ctx);
|
|
457
461
|
resetWriteGateState(basePath);
|
|
458
462
|
resetToolCallLoopGuard();
|
|
@@ -464,7 +468,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
464
468
|
await applyCompactionThresholdOverride(ctx);
|
|
465
469
|
await prepareWorkflowMcpForHookContext(ctx, basePath);
|
|
466
470
|
await loadToolApiKeysForSession();
|
|
467
|
-
if (!isAutoActive()) {
|
|
471
|
+
if (!isAutoActive() && !preserveCloseoutSurface) {
|
|
468
472
|
ctx.ui.setWidget("gsd-progress", undefined);
|
|
469
473
|
ctx.ui.setWidget("gsd-outcome", undefined);
|
|
470
474
|
const { initHealthWidget } = await import("../health-widget.js");
|
|
@@ -1,17 +1,44 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: Shared browser-observable UAT requirement and evidence detection.
|
|
3
|
-
export const BROWSER_REQUIREMENT_RE = /\b(?:
|
|
3
|
+
export const BROWSER_REQUIREMENT_RE = /\b(?:file:\/\/|localhost|playwright|chrome|screenshot|snapshot|browser_(?:assert|batch|find|verify|snapshot_refs))\b|\b(?:open|launch|navigate|load|visit|serve|start)\b.{0,80}\b(?:browser|page|localhost|file:\/\/)\b|\bbrowser\s+(?:check|session|test|uat|tool|automation|interaction|flow)\b/i;
|
|
4
4
|
export const NO_BROWSER_EVIDENCE_RE = /\b(?:no|without|not|wasn'?t|isn'?t)\s+(?:automated\s+)?(?:live\s+)?browser(?:\s+(?:session|test|uat))?|\bno\s+automated\s+browser\b|\bnot\s+conducted\b/i;
|
|
5
5
|
export const BROWSER_RUNTIME_RE = /\b(?:browser|playwright|chrome|camoufox|browser_(?:assert|batch|find|verify|snapshot_refs)|screenshot|snapshot|file:\/\/|localhost)\b/i;
|
|
6
6
|
export const BROWSER_ACTION_RE = /\b(?:open(?:ed)?|navigate(?:d)?|click(?:ed)?|type(?:d)?|reload(?:ed)?|capture(?:d)?|screenshot|snapshot)\b/i;
|
|
7
7
|
export const BROWSER_ASSERTION_RE = /\b(?:assert(?:ed|ion)?|observed|confirmed|verified|expected|visible|text|count|label|strikethrough|localstorage|screenshot|snapshot|passed)\b/i;
|
|
8
|
+
const NON_REQUIREMENT_BROWSER_HEADING_RE = /^(?:not\s+proven|not\s+covered|out\s+of\s+scope|deferred|follow-?ups?|known\s+limitations|notes\s+for\s+tester)\b/i;
|
|
9
|
+
const NON_REQUIREMENT_BROWSER_LINE_RE = /\b(?:deferred|not\s+proven|not\s+covered|out\s+of\s+scope|future\s+slice|follow-?up|no\s+(?:live\s+)?browser|without\s+(?:a\s+)?browser|not\s+(?:a\s+)?browser)\b/i;
|
|
8
10
|
export function compactTextParts(parts) {
|
|
9
11
|
return parts.flatMap((part) => Array.isArray(part) ? part : [part])
|
|
10
12
|
.filter((part) => typeof part === "string" && part.trim().length > 0)
|
|
11
13
|
.join("\n");
|
|
12
14
|
}
|
|
13
15
|
export function hasBrowserRequiredText(text) {
|
|
14
|
-
|
|
16
|
+
let inNonRequirementSection = false;
|
|
17
|
+
let nonRequirementDepth = 0;
|
|
18
|
+
for (const line of text.split(/\r?\n/)) {
|
|
19
|
+
const headingMatch = line.match(/^(#{1,6})\s+(.+?)\s*$/);
|
|
20
|
+
if (headingMatch) {
|
|
21
|
+
const depth = headingMatch[1].length;
|
|
22
|
+
const title = headingMatch[2] ?? "";
|
|
23
|
+
// Only update section context when at the same or higher level than the
|
|
24
|
+
// heading that opened the non-requirement zone. A sub-heading deeper than
|
|
25
|
+
// the opening heading must not escape or re-enter the zone on its own.
|
|
26
|
+
if (!inNonRequirementSection || depth <= nonRequirementDepth) {
|
|
27
|
+
inNonRequirementSection = NON_REQUIREMENT_BROWSER_HEADING_RE.test(title);
|
|
28
|
+
nonRequirementDepth = inNonRequirementSection ? depth : 0;
|
|
29
|
+
}
|
|
30
|
+
// Check the heading title itself — section state is already updated, so
|
|
31
|
+
// we correctly skip headings that opened a non-requirement zone.
|
|
32
|
+
if (!inNonRequirementSection && BROWSER_REQUIREMENT_RE.test(title))
|
|
33
|
+
return true;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (inNonRequirementSection || NON_REQUIREMENT_BROWSER_LINE_RE.test(line))
|
|
37
|
+
continue;
|
|
38
|
+
if (BROWSER_REQUIREMENT_RE.test(line))
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
return false;
|
|
15
42
|
}
|
|
16
43
|
export function hasBrowserEvidenceText(text) {
|
|
17
44
|
if (!text.trim())
|
|
@@ -266,8 +266,8 @@ Examples:
|
|
|
266
266
|
await handleInspect(ctx);
|
|
267
267
|
return true;
|
|
268
268
|
}
|
|
269
|
-
if (trimmed === "update" || trimmed === "upgrade") {
|
|
270
|
-
await handleUpdate(ctx);
|
|
269
|
+
if (trimmed === "update" || trimmed.startsWith("update ") || trimmed === "upgrade" || trimmed.startsWith("upgrade ")) {
|
|
270
|
+
await handleUpdate(ctx, trimmed.replace(/^(?:update|upgrade)\s*/, "").trim());
|
|
271
271
|
return true;
|
|
272
272
|
}
|
|
273
273
|
if (trimmed === "fast" || trimmed.startsWith("fast ")) {
|