@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
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
/** browser-tools —
|
|
1
|
+
/** browser-tools — Pi Browser Automation Contract adapter. */
|
|
2
2
|
import { importExtensionModule, type ExtensionAPI } from "@gsd/pi-coding-agent";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
import { closeManagedGsdBrowser, registerManagedGsdBrowserTools } from "./engine/managed-gsd-browser.js";
|
|
5
|
+
import { resolveBrowserEngineMode, type BrowserEngineMode } from "./engine/selection.js";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
let legacyRegistrationPromise: Promise<void> | null = null;
|
|
8
|
+
let managedRegistrationPromise: Promise<void> | null = null;
|
|
9
|
+
let registeredEngine: Exclude<BrowserEngineMode, "off"> | null = null;
|
|
10
|
+
|
|
11
|
+
async function registerLegacyBrowserTools(pi: ExtensionAPI): Promise<void> {
|
|
12
|
+
if (!legacyRegistrationPromise) {
|
|
13
|
+
legacyRegistrationPromise = (async () => {
|
|
9
14
|
const [
|
|
10
15
|
lifecycle,
|
|
11
16
|
capture,
|
|
@@ -136,12 +141,55 @@ async function registerBrowserTools(pi: ExtensionAPI): Promise<void> {
|
|
|
136
141
|
injectionDetection.registerInjectionDetectionTools(pi, deps);
|
|
137
142
|
verify.registerVerifyTools(pi, deps);
|
|
138
143
|
})().catch((error) => {
|
|
139
|
-
|
|
144
|
+
legacyRegistrationPromise = null;
|
|
140
145
|
throw error;
|
|
141
146
|
});
|
|
142
147
|
}
|
|
143
148
|
|
|
144
|
-
return
|
|
149
|
+
return legacyRegistrationPromise;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async function registerBrowserTools(pi: ExtensionAPI): Promise<void> {
|
|
153
|
+
const engine = resolveBrowserEngineMode();
|
|
154
|
+
if (engine === "off") return;
|
|
155
|
+
if (registeredEngine && registeredEngine !== engine) {
|
|
156
|
+
throw new Error(
|
|
157
|
+
`Browser tools already registered with GSD_BROWSER_ENGINE=${registeredEngine}. Restart GSD before switching to ${engine}.`,
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
let registration: Promise<void>;
|
|
162
|
+
if (engine === "legacy") {
|
|
163
|
+
registration = registerLegacyBrowserTools(pi);
|
|
164
|
+
} else if (!managedRegistrationPromise) {
|
|
165
|
+
managedRegistrationPromise = Promise.resolve()
|
|
166
|
+
.then(() => {
|
|
167
|
+
registerManagedGsdBrowserTools(pi);
|
|
168
|
+
})
|
|
169
|
+
.catch((error) => {
|
|
170
|
+
managedRegistrationPromise = null;
|
|
171
|
+
throw error;
|
|
172
|
+
});
|
|
173
|
+
registration = managedRegistrationPromise;
|
|
174
|
+
} else {
|
|
175
|
+
registration = managedRegistrationPromise;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
registeredEngine = engine;
|
|
179
|
+
try {
|
|
180
|
+
await registration;
|
|
181
|
+
} catch (error) {
|
|
182
|
+
if (registeredEngine === engine) registeredEngine = null;
|
|
183
|
+
throw error;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async function closeActiveBrowserEngines(): Promise<void> {
|
|
188
|
+
await closeManagedGsdBrowser();
|
|
189
|
+
if (legacyRegistrationPromise) {
|
|
190
|
+
const { closeBrowser } = await importExtensionModule<typeof import("./lifecycle.js")>(import.meta.url, "./lifecycle.js");
|
|
191
|
+
await closeBrowser();
|
|
192
|
+
}
|
|
145
193
|
}
|
|
146
194
|
|
|
147
195
|
export default function (pi: ExtensionAPI) {
|
|
@@ -157,7 +205,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
157
205
|
});
|
|
158
206
|
|
|
159
207
|
pi.on("session_shutdown", async () => {
|
|
160
|
-
|
|
161
|
-
|
|
208
|
+
await closeActiveBrowserEngines();
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
pi.on("session_switch", async () => {
|
|
212
|
+
await closeActiveBrowserEngines();
|
|
162
213
|
});
|
|
163
214
|
}
|
|
@@ -4,16 +4,20 @@
|
|
|
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": ["./index.ts"]
|
|
11
11
|
},
|
|
12
12
|
"peerDependencies": {
|
|
13
|
+
"@opengsd/gsd-browser": ">=0.1.27",
|
|
13
14
|
"playwright": ">=1.40.0",
|
|
14
15
|
"sharp": ">=0.33.0"
|
|
15
16
|
},
|
|
16
17
|
"peerDependenciesMeta": {
|
|
18
|
+
"@opengsd/gsd-browser": {
|
|
19
|
+
"optional": true
|
|
20
|
+
},
|
|
17
21
|
"playwright": {
|
|
18
22
|
"optional": true
|
|
19
23
|
},
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { dirname } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const require = createRequire(import.meta.url);
|
|
9
|
+
const jiti = require("jiti")(__dirname, { interopDefault: true, debug: false });
|
|
10
|
+
|
|
11
|
+
const { resolveBrowserEngineMode } = jiti("../engine/selection.ts");
|
|
12
|
+
|
|
13
|
+
describe("resolveBrowserEngineMode", () => {
|
|
14
|
+
it("defaults to gsd-browser", () => {
|
|
15
|
+
assert.equal(resolveBrowserEngineMode({}), "gsd-browser");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("accepts the explicit engine modes", () => {
|
|
19
|
+
assert.equal(resolveBrowserEngineMode({ GSD_BROWSER_ENGINE: "gsd-browser" }), "gsd-browser");
|
|
20
|
+
assert.equal(resolveBrowserEngineMode({ GSD_BROWSER_ENGINE: "legacy" }), "legacy");
|
|
21
|
+
assert.equal(resolveBrowserEngineMode({ GSD_BROWSER_ENGINE: "off" }), "off");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("accepts compatibility aliases", () => {
|
|
25
|
+
assert.equal(resolveBrowserEngineMode({ GSD_BROWSER_ENGINE: "playwright" }), "legacy");
|
|
26
|
+
assert.equal(resolveBrowserEngineMode({ GSD_BROWSER_ENGINE: "false" }), "off");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("rejects unknown engine modes", () => {
|
|
30
|
+
assert.throws(
|
|
31
|
+
() => resolveBrowserEngineMode({ GSD_BROWSER_ENGINE: "surprise" }),
|
|
32
|
+
/Expected "gsd-browser", "legacy", or "off"/,
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
MANAGED_GSD_BROWSER_TOOL_NAMES,
|
|
6
|
+
registerManagedGsdBrowserTools,
|
|
7
|
+
} = await import("../engine/managed-gsd-browser.ts");
|
|
8
|
+
|
|
9
|
+
describe("registerManagedGsdBrowserTools", () => {
|
|
10
|
+
it("registers the curated Pi browser contract", () => {
|
|
11
|
+
const tools = [];
|
|
12
|
+
registerManagedGsdBrowserTools({
|
|
13
|
+
registerTool(tool) {
|
|
14
|
+
tools.push(tool);
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
assert.deepEqual(tools.map((tool) => tool.name), [...MANAGED_GSD_BROWSER_TOOL_NAMES]);
|
|
19
|
+
assert.equal(new Set(tools.map((tool) => tool.name)).size, tools.length);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("keeps screenshots marked as image-producing evidence", () => {
|
|
23
|
+
const tools = [];
|
|
24
|
+
registerManagedGsdBrowserTools({
|
|
25
|
+
registerTool(tool) {
|
|
26
|
+
tools.push(tool);
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const screenshot = tools.find((tool) => tool.name === "browser_screenshot");
|
|
31
|
+
assert.equal(screenshot?.compatibility?.producesImages, true);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -277,7 +277,6 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
277
277
|
this.status.activeUnit = { unitType: decision.unitType, unitId: decision.unitId };
|
|
278
278
|
this.status.phase = "running";
|
|
279
279
|
this.lastAdvanceKey = nextKey;
|
|
280
|
-
this.lastFinalizedUnitKey = null;
|
|
281
280
|
this.bumpTransition();
|
|
282
281
|
|
|
283
282
|
await this.deps.runtime.journalTransition({
|
|
@@ -13,10 +13,11 @@ import type {
|
|
|
13
13
|
ExtensionCommandContext,
|
|
14
14
|
ReadonlyFooterDataProvider,
|
|
15
15
|
Theme,
|
|
16
|
+
ThemeColor,
|
|
16
17
|
} from "@gsd/pi-coding-agent";
|
|
17
18
|
import type { GSDState } from "./types.js";
|
|
18
19
|
import { getActiveHook } from "./post-unit-hooks.js";
|
|
19
|
-
import { getLedger } from "./metrics.js";
|
|
20
|
+
import { getLedger, getProjectTotals } from "./metrics.js";
|
|
20
21
|
import { getErrorMessage } from "./error-utils.js";
|
|
21
22
|
import { nativeIsRepo } from "./native-git-bridge.js";
|
|
22
23
|
import {
|
|
@@ -304,6 +305,40 @@ export function shouldRenderRoadmapProgress(
|
|
|
304
305
|
return !!progress && progress.total > 0;
|
|
305
306
|
}
|
|
306
307
|
|
|
308
|
+
function widgetGridLabel(theme: Theme, text: string, color: ThemeColor = "borderAccent"): string {
|
|
309
|
+
return theme.fg(color, theme.bold(text.toUpperCase()));
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function widgetGridColumn(content: string, width: number): string {
|
|
313
|
+
return padRightVisible(truncateToWidth(content, width, "…"), width);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function widgetGridColumns(theme: Theme, width: number, parts: string[]): string {
|
|
317
|
+
if (parts.length === 0) return "";
|
|
318
|
+
const gap = theme.fg("dim", " │ ");
|
|
319
|
+
const gapWidth = visibleWidth(gap) * (parts.length - 1);
|
|
320
|
+
const available = Math.max(parts.length * 8, width - gapWidth);
|
|
321
|
+
const base = Math.floor(available / parts.length);
|
|
322
|
+
let remaining = available - base * parts.length;
|
|
323
|
+
const columns = parts.map((part) => {
|
|
324
|
+
const columnWidth = base + (remaining > 0 ? 1 : 0);
|
|
325
|
+
remaining--;
|
|
326
|
+
return widgetGridColumn(part, columnWidth);
|
|
327
|
+
});
|
|
328
|
+
return truncateToWidth(columns.join(gap), width, "…");
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function formatSmallWidgetSpend(): string {
|
|
332
|
+
const ledger = getLedger();
|
|
333
|
+
if (!ledger || ledger.units.length === 0) return "--";
|
|
334
|
+
|
|
335
|
+
const totals = getProjectTotals(ledger.units);
|
|
336
|
+
const parts: string[] = [];
|
|
337
|
+
if (totals.tokens.total > 0) parts.push(formatWidgetTokens(totals.tokens.total));
|
|
338
|
+
if (totals.cost > 0) parts.push(`$${totals.cost.toFixed(2)}`);
|
|
339
|
+
return parts.length > 0 ? parts.join(" · ") : "--";
|
|
340
|
+
}
|
|
341
|
+
|
|
307
342
|
// ─── ETA Estimation ──────────────────────────────────────────────────────────
|
|
308
343
|
|
|
309
344
|
/**
|
|
@@ -836,29 +871,62 @@ export function updateProgressWidget(
|
|
|
836
871
|
return lines;
|
|
837
872
|
}
|
|
838
873
|
|
|
839
|
-
// ── Mode: small —
|
|
874
|
+
// ── Mode: small — dense horizontal grid ───────────────────────
|
|
840
875
|
if (widgetMode === "small") {
|
|
841
|
-
lines.
|
|
842
|
-
|
|
843
|
-
// Action line
|
|
844
|
-
const target = task ? `${task.id}: ${task.title}` : unitId;
|
|
845
|
-
const actionLeft = `${pad}${theme.fg("accent", "▸")} ${theme.fg("accent", verb)} ${theme.fg("text", target)}`;
|
|
846
|
-
lines.push(rightAlign(actionLeft, theme.fg("dim", phaseLabel), width));
|
|
876
|
+
lines.length = 0;
|
|
877
|
+
lines.push(...ui.bar());
|
|
847
878
|
|
|
848
|
-
// Progress bar
|
|
849
879
|
const roadmapSlices = mid ? getRoadmapSlicesSync() : null;
|
|
880
|
+
const unitLabel = unitId || [mid?.id, slice?.id, task?.id].filter(Boolean).join("/");
|
|
881
|
+
const statusParts = [
|
|
882
|
+
spinner,
|
|
883
|
+
theme.fg("success", modeTag),
|
|
884
|
+
theme.fg(stateColor, activeState),
|
|
885
|
+
];
|
|
886
|
+
if (runtimeSignal?.summary) {
|
|
887
|
+
statusParts.push(theme.fg(healthColor, healthSummary));
|
|
888
|
+
} else if (healthLevel !== "green") {
|
|
889
|
+
statusParts.push(`${theme.fg(healthColor, healthIcon)} ${theme.fg(healthColor, healthSummary)}`);
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
const timeValue = [elapsed, etaShort].filter(Boolean).join(" · ") || "--";
|
|
893
|
+
const rowOne = widgetGridColumns(theme, width, [
|
|
894
|
+
`${widgetGridLabel(theme, "status", "border")} ${statusParts.join(" ")}`,
|
|
895
|
+
`${widgetGridLabel(theme, "unit")} ${theme.fg("text", unitLabel || "--")}`,
|
|
896
|
+
`${widgetGridLabel(theme, "spend", "border")} ${theme.fg("dim", formatSmallWidgetSpend())}`,
|
|
897
|
+
`${widgetGridLabel(theme, "time")} ${theme.fg("dim", timeValue)}`,
|
|
898
|
+
]);
|
|
899
|
+
|
|
900
|
+
const target = task
|
|
901
|
+
? `${task.id}: ${task.title}`
|
|
902
|
+
: slice
|
|
903
|
+
? `${slice.id}: ${slice.title}`
|
|
904
|
+
: unitId;
|
|
905
|
+
|
|
906
|
+
let taskValue = task?.id ?? "--";
|
|
907
|
+
let sliceValue = slice?.id ?? "--";
|
|
850
908
|
if (shouldRenderRoadmapProgress(roadmapSlices)) {
|
|
851
909
|
const { done, total, activeSliceTasks } = roadmapSlices;
|
|
852
|
-
const barWidth = Math.max(
|
|
910
|
+
const barWidth = Math.max(4, Math.min(14, Math.floor(width * 0.12)));
|
|
853
911
|
const bar = renderProgressBar(theme, done, total, barWidth);
|
|
854
|
-
|
|
912
|
+
sliceValue = `${bar} ${theme.fg("text", `${done}/${total}`)}`;
|
|
855
913
|
if (activeSliceTasks && activeSliceTasks.total > 0) {
|
|
856
|
-
const
|
|
857
|
-
|
|
914
|
+
const taskNum = isHook
|
|
915
|
+
? Math.max(activeSliceTasks.done, 1)
|
|
916
|
+
: Math.min(activeSliceTasks.done + 1, activeSliceTasks.total);
|
|
917
|
+
taskValue = `${theme.fg("accent", `${taskNum}`)}${theme.fg("dim", `/${activeSliceTasks.total}`)}`;
|
|
858
918
|
}
|
|
859
|
-
lines.push(`${pad}${bar} ${meta}`);
|
|
860
919
|
}
|
|
861
920
|
|
|
921
|
+
const rowTwo = widgetGridColumns(theme, width, [
|
|
922
|
+
`${widgetGridLabel(theme, "phase", "border")} ${theme.fg("dim", unitType)}`,
|
|
923
|
+
`${widgetGridLabel(theme, "work")} ${theme.fg("text", target || "--")}`,
|
|
924
|
+
`${widgetGridLabel(theme, "task", "border")} ${taskValue}`,
|
|
925
|
+
`${widgetGridLabel(theme, "slice")} ${sliceValue}`,
|
|
926
|
+
]);
|
|
927
|
+
|
|
928
|
+
lines.push(rowOne);
|
|
929
|
+
lines.push(rowTwo);
|
|
862
930
|
lines.push(...ui.bar());
|
|
863
931
|
cachedLines = lines;
|
|
864
932
|
cachedWidth = width;
|
|
@@ -622,6 +622,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
622
622
|
structuredQuestionsAvailable,
|
|
623
623
|
{ headless: !!process.env.GSD_HEADLESS },
|
|
624
624
|
),
|
|
625
|
+
pauseAfterDispatch: !process.env.GSD_HEADLESS,
|
|
625
626
|
};
|
|
626
627
|
},
|
|
627
628
|
},
|
|
@@ -772,6 +773,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
772
773
|
structuredQuestionsAvailable,
|
|
773
774
|
{ headless: !!process.env.GSD_HEADLESS },
|
|
774
775
|
),
|
|
776
|
+
pauseAfterDispatch: !process.env.GSD_HEADLESS,
|
|
775
777
|
};
|
|
776
778
|
},
|
|
777
779
|
},
|
|
@@ -805,6 +807,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
805
807
|
unitType: "discuss-project",
|
|
806
808
|
unitId: "PROJECT",
|
|
807
809
|
prompt: await buildDiscussProjectPrompt(basePath, structuredQuestionsAvailable),
|
|
810
|
+
pauseAfterDispatch: !process.env.GSD_HEADLESS,
|
|
808
811
|
};
|
|
809
812
|
},
|
|
810
813
|
},
|
|
@@ -826,6 +829,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
826
829
|
unitType: "discuss-requirements",
|
|
827
830
|
unitId: "REQUIREMENTS",
|
|
828
831
|
prompt: await buildDiscussRequirementsPrompt(basePath, structuredQuestionsAvailable),
|
|
832
|
+
pauseAfterDispatch: !process.env.GSD_HEADLESS,
|
|
829
833
|
};
|
|
830
834
|
},
|
|
831
835
|
},
|
|
@@ -940,6 +944,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
940
944
|
structuredQuestionsAvailable,
|
|
941
945
|
{ headless: !!process.env.GSD_HEADLESS },
|
|
942
946
|
),
|
|
947
|
+
pauseAfterDispatch: !process.env.GSD_HEADLESS,
|
|
943
948
|
};
|
|
944
949
|
},
|
|
945
950
|
},
|
|
@@ -55,8 +55,10 @@ import { parseRoadmap as parseLegacyRoadmap } from "./parsers-legacy.js";
|
|
|
55
55
|
import { consumeSignal } from "./session-status-io.js";
|
|
56
56
|
import {
|
|
57
57
|
checkPostUnitHooks,
|
|
58
|
+
consumeHookFailure,
|
|
58
59
|
isRetryPending,
|
|
59
60
|
consumeRetryTrigger,
|
|
61
|
+
consumeGateBlock,
|
|
60
62
|
persistHookState,
|
|
61
63
|
resolveHookArtifactPath,
|
|
62
64
|
} from "./post-unit-hooks.js";
|
|
@@ -2227,11 +2229,11 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
|
|
|
2227
2229
|
// ── Post-unit hooks ──
|
|
2228
2230
|
if (s.currentUnit && !s.stepMode) {
|
|
2229
2231
|
const hookUnit = checkPostUnitHooks(s.currentUnit.type, s.currentUnit.id, s.basePath);
|
|
2232
|
+
persistHookState(s.basePath);
|
|
2230
2233
|
if (hookUnit) {
|
|
2231
2234
|
if (s.currentUnit) {
|
|
2232
2235
|
await closeoutUnit(ctx, s.basePath, s.currentUnit.type, s.currentUnit.id, s.currentUnit.startedAt, buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id));
|
|
2233
2236
|
}
|
|
2234
|
-
persistHookState(s.basePath);
|
|
2235
2237
|
|
|
2236
2238
|
return enqueueSidecar(
|
|
2237
2239
|
s, ctx,
|
|
@@ -2240,12 +2242,23 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
|
|
|
2240
2242
|
);
|
|
2241
2243
|
}
|
|
2242
2244
|
|
|
2245
|
+
const hookFailure = consumeHookFailure();
|
|
2246
|
+
if (hookFailure) {
|
|
2247
|
+
ctx.ui.notify(
|
|
2248
|
+
`Post-unit hook ${hookFailure.hookName} failed for ${hookFailure.unitId}: ${hookFailure.reason}. Pausing auto-mode.`,
|
|
2249
|
+
"warning",
|
|
2250
|
+
);
|
|
2251
|
+
await pauseAuto(ctx, pi);
|
|
2252
|
+
return "stopped";
|
|
2253
|
+
}
|
|
2254
|
+
|
|
2243
2255
|
// Check if a hook requested a retry of the trigger unit
|
|
2244
2256
|
if (isRetryPending()) {
|
|
2245
2257
|
const trigger = consumeRetryTrigger();
|
|
2246
2258
|
if (trigger) {
|
|
2259
|
+
persistHookState(s.basePath);
|
|
2247
2260
|
ctx.ui.notify(
|
|
2248
|
-
`Hook requested retry of ${trigger.unitType} ${trigger.unitId} — resetting
|
|
2261
|
+
`Hook requested retry of ${trigger.unitType} ${trigger.unitId} — resetting trigger unit state.`,
|
|
2249
2262
|
"info",
|
|
2250
2263
|
);
|
|
2251
2264
|
|
|
@@ -2299,6 +2312,19 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
|
|
|
2299
2312
|
// Fall through to normal dispatch — deriveState will re-derive the unit
|
|
2300
2313
|
}
|
|
2301
2314
|
}
|
|
2315
|
+
|
|
2316
|
+
const gateBlock = consumeGateBlock();
|
|
2317
|
+
if (gateBlock) {
|
|
2318
|
+
persistHookState(s.basePath);
|
|
2319
|
+
const verdict = gateBlock.verdict ? ` verdict=${gateBlock.verdict};` : "";
|
|
2320
|
+
const artifact = gateBlock.artifact ? ` artifact=${gateBlock.artifact};` : "";
|
|
2321
|
+
const message =
|
|
2322
|
+
`Post-unit gate "${gateBlock.hookName}" blocked ${gateBlock.triggerUnitType} ${gateBlock.triggerUnitId}:` +
|
|
2323
|
+
`${verdict}${artifact} ${gateBlock.reason}. Run /gsd status to inspect, then /gsd auto after recovery.`;
|
|
2324
|
+
ctx.ui.notify(message, "warning");
|
|
2325
|
+
await pauseAuto(ctx, pi);
|
|
2326
|
+
return "stopped";
|
|
2327
|
+
}
|
|
2302
2328
|
}
|
|
2303
2329
|
|
|
2304
2330
|
// ── Fast-path stop detection (#3487) ──
|
|
@@ -45,6 +45,7 @@ import { classifyProject, type ProjectClassification } from "./detection.js";
|
|
|
45
45
|
import { hasBrowserRequiredText } from "./browser-evidence.js";
|
|
46
46
|
import { debugLog } from "./debug-logger.js";
|
|
47
47
|
import { buildSkillActivationBlock, buildSkillDiscoveryVars } from "./skill-activation.js";
|
|
48
|
+
import { findMilestoneIds } from "./milestone-ids.js";
|
|
48
49
|
|
|
49
50
|
export { buildSkillActivationBlock, buildSkillDiscoveryVars };
|
|
50
51
|
|
|
@@ -1428,7 +1429,7 @@ export async function checkNeedsRunUat(
|
|
|
1428
1429
|
// If the UAT file already contains a verdict, UAT has been run — skip
|
|
1429
1430
|
if (hasVerdict(uatContent)) continue;
|
|
1430
1431
|
// Also check the ASSESSMENT file — the run-uat prompt writes the verdict
|
|
1431
|
-
// there (via
|
|
1432
|
+
// there (via gsd_uat_result_save), not into the
|
|
1432
1433
|
// UAT spec file. Without this check the unit re-dispatches indefinitely.
|
|
1433
1434
|
const assessmentFile = resolveSliceFile(base, mid, sid, "ASSESSMENT");
|
|
1434
1435
|
if (assessmentFile) {
|
|
@@ -1482,21 +1483,84 @@ export async function checkNeedsRunUat(
|
|
|
1482
1483
|
* as a seed when present. The discussion agent interviews the user, writes
|
|
1483
1484
|
* a full CONTEXT.md, and the phase transitions to pre-planning automatically.
|
|
1484
1485
|
*/
|
|
1486
|
+
export interface DiscussMilestonePromptOptions {
|
|
1487
|
+
headless?: boolean;
|
|
1488
|
+
commitInstruction?: string;
|
|
1489
|
+
fastPathInstruction?: string;
|
|
1490
|
+
includeDraftSeed?: boolean;
|
|
1491
|
+
includeContextMode?: boolean;
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
export async function buildDiscussMilestoneInlinedContext(mid: string, base: string): Promise<string> {
|
|
1495
|
+
const inlined: string[] = [];
|
|
1496
|
+
|
|
1497
|
+
const roadmapInline = await inlineFileOptional(
|
|
1498
|
+
resolveMilestoneFile(base, mid, "ROADMAP"),
|
|
1499
|
+
relMilestoneFile(base, mid, "ROADMAP"),
|
|
1500
|
+
"Milestone Roadmap",
|
|
1501
|
+
);
|
|
1502
|
+
if (roadmapInline) inlined.push(roadmapInline);
|
|
1503
|
+
|
|
1504
|
+
const contextInline = await inlineFileOptional(
|
|
1505
|
+
resolveMilestoneFile(base, mid, "CONTEXT"),
|
|
1506
|
+
relMilestoneFile(base, mid, "CONTEXT"),
|
|
1507
|
+
"Milestone Context",
|
|
1508
|
+
);
|
|
1509
|
+
if (contextInline) inlined.push(contextInline);
|
|
1510
|
+
|
|
1511
|
+
const researchInline = await inlineFileOptional(
|
|
1512
|
+
resolveMilestoneFile(base, mid, "RESEARCH"),
|
|
1513
|
+
relMilestoneFile(base, mid, "RESEARCH"),
|
|
1514
|
+
"Milestone Research",
|
|
1515
|
+
);
|
|
1516
|
+
if (researchInline) inlined.push(researchInline);
|
|
1517
|
+
|
|
1518
|
+
const decisionsPath = resolveGsdRootFile(base, "DECISIONS");
|
|
1519
|
+
if (existsSync(decisionsPath)) {
|
|
1520
|
+
const decisionsContent = await loadFile(decisionsPath);
|
|
1521
|
+
if (decisionsContent) {
|
|
1522
|
+
inlined.push(`### Decisions Register\nSource: \`${relGsdRootFile("DECISIONS")}\`\n\n${decisionsContent.trim()}`);
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
const milestoneIds = findMilestoneIds(base);
|
|
1527
|
+
const currentIndex = milestoneIds.indexOf(mid);
|
|
1528
|
+
const priorMilestoneIds = currentIndex >= 0 ? milestoneIds.slice(0, currentIndex) : milestoneIds;
|
|
1529
|
+
for (const priorMid of priorMilestoneIds) {
|
|
1530
|
+
const summaryInline = await inlineFileOptional(
|
|
1531
|
+
resolveMilestoneFile(base, priorMid, "SUMMARY"),
|
|
1532
|
+
relMilestoneFile(base, priorMid, "SUMMARY"),
|
|
1533
|
+
`${priorMid} Prior Milestone Summary`,
|
|
1534
|
+
);
|
|
1535
|
+
if (summaryInline) inlined.push(summaryInline);
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
return inlined.length > 0
|
|
1539
|
+
? `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`
|
|
1540
|
+
: "## Inlined Context\n\n_(no milestone context files found yet — go in blind and ask broad questions)_";
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1485
1543
|
export async function buildDiscussMilestonePrompt(
|
|
1486
1544
|
mid: string,
|
|
1487
1545
|
midTitle: string,
|
|
1488
1546
|
base: string,
|
|
1489
1547
|
structuredQuestionsAvailable = "false",
|
|
1490
|
-
{
|
|
1548
|
+
{
|
|
1549
|
+
headless = false,
|
|
1550
|
+
commitInstruction = "Do not commit planning artifacts — .gsd/ is managed externally.",
|
|
1551
|
+
fastPathInstruction = "",
|
|
1552
|
+
includeDraftSeed = true,
|
|
1553
|
+
includeContextMode = true,
|
|
1554
|
+
}: DiscussMilestonePromptOptions = {},
|
|
1491
1555
|
): Promise<string> {
|
|
1492
|
-
const
|
|
1556
|
+
const contextTemplate = inlineTemplate("context", "Context");
|
|
1493
1557
|
|
|
1494
1558
|
if (headless) {
|
|
1495
1559
|
const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
|
|
1496
1560
|
const roadmapContent = roadmapPath ? await loadFile(roadmapPath) : null;
|
|
1497
1561
|
return loadPrompt("discuss-headless", {
|
|
1498
1562
|
seedContext: roadmapContent ?? "",
|
|
1499
|
-
inlinedTemplates:
|
|
1563
|
+
inlinedTemplates: contextTemplate,
|
|
1500
1564
|
workingDirectory: base,
|
|
1501
1565
|
milestoneId: mid,
|
|
1502
1566
|
contextPath: relMilestoneFile(base, mid, "CONTEXT"),
|
|
@@ -1505,7 +1569,9 @@ export async function buildDiscussMilestonePrompt(
|
|
|
1505
1569
|
});
|
|
1506
1570
|
}
|
|
1507
1571
|
|
|
1508
|
-
const
|
|
1572
|
+
const rawInlinedContext = await buildDiscussMilestoneInlinedContext(mid, base);
|
|
1573
|
+
const cappedInlinedContext = capPreamble(rawInlinedContext);
|
|
1574
|
+
const discussTemplates = [cappedInlinedContext, contextTemplate].join("\n\n---\n\n");
|
|
1509
1575
|
|
|
1510
1576
|
const basePrompt = loadPrompt("guided-discuss-milestone", {
|
|
1511
1577
|
workingDirectory: base,
|
|
@@ -1513,20 +1579,22 @@ export async function buildDiscussMilestonePrompt(
|
|
|
1513
1579
|
milestoneTitle: midTitle,
|
|
1514
1580
|
inlinedTemplates: discussTemplates,
|
|
1515
1581
|
structuredQuestionsAvailable,
|
|
1516
|
-
commitInstruction
|
|
1517
|
-
fastPathInstruction
|
|
1582
|
+
commitInstruction,
|
|
1583
|
+
fastPathInstruction,
|
|
1518
1584
|
});
|
|
1519
|
-
const promptWithContextMode =
|
|
1585
|
+
const promptWithContextMode = includeContextMode
|
|
1586
|
+
? prependContextModeToBlock("discuss-milestone", base, basePrompt)
|
|
1587
|
+
: basePrompt;
|
|
1520
1588
|
|
|
1521
1589
|
// If a CONTEXT-DRAFT.md exists, append it as seed material
|
|
1522
1590
|
const draftPath = resolveMilestoneFile(base, mid, "CONTEXT-DRAFT");
|
|
1523
1591
|
const draftContent = draftPath ? await loadFile(draftPath) : null;
|
|
1524
1592
|
|
|
1525
|
-
if (draftContent) {
|
|
1593
|
+
if (includeDraftSeed && draftContent) {
|
|
1526
1594
|
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}`;
|
|
1527
1595
|
}
|
|
1528
1596
|
|
|
1529
|
-
return
|
|
1597
|
+
return promptWithContextMode;
|
|
1530
1598
|
}
|
|
1531
1599
|
|
|
1532
1600
|
/**
|
|
@@ -2918,13 +2986,23 @@ export async function buildValidateMilestonePrompt(
|
|
|
2918
2986
|
if (isDbAvailable()) {
|
|
2919
2987
|
const milestone = getMilestone(mid);
|
|
2920
2988
|
if (milestone) {
|
|
2989
|
+
const escapeCell = (value: string) =>
|
|
2990
|
+
value.replace(/[\\|]/g, (char) => `\\${char}`).replace(/\r?\n/g, " ");
|
|
2921
2991
|
const classes: string[] = [];
|
|
2922
|
-
if (milestone.verification_contract) classes.push(
|
|
2923
|
-
if (milestone.verification_integration) classes.push(
|
|
2924
|
-
if (milestone.verification_operational) classes.push(
|
|
2925
|
-
if (milestone.verification_uat) classes.push(
|
|
2992
|
+
if (milestone.verification_contract) classes.push(`| Contract | ${escapeCell(milestone.verification_contract)} |`);
|
|
2993
|
+
if (milestone.verification_integration) classes.push(`| Integration | ${escapeCell(milestone.verification_integration)} |`);
|
|
2994
|
+
if (milestone.verification_operational) classes.push(`| Operational | ${escapeCell(milestone.verification_operational)} |`);
|
|
2995
|
+
if (milestone.verification_uat) classes.push(`| UAT | ${escapeCell(milestone.verification_uat)} |`);
|
|
2926
2996
|
if (classes.length > 0) {
|
|
2927
|
-
const verificationClasses =
|
|
2997
|
+
const verificationClasses = [
|
|
2998
|
+
"### Verification Classes (from planning)",
|
|
2999
|
+
"",
|
|
3000
|
+
"These verification tiers were defined during milestone planning. Every row in this table must appear in `verificationClasses` with the same canonical class name.",
|
|
3001
|
+
"",
|
|
3002
|
+
"| Class | Planned Check |",
|
|
3003
|
+
"| --- | --- |",
|
|
3004
|
+
...classes,
|
|
3005
|
+
].join("\n");
|
|
2928
3006
|
inlined.push(verificationClasses);
|
|
2929
3007
|
trackPromptContext(contextTelemetry, "verification-classes", "inline", verificationClasses);
|
|
2930
3008
|
}
|
|
@@ -42,6 +42,10 @@ export function isAutoPaused(): boolean {
|
|
|
42
42
|
return autoSession.paused;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
export function isAutoCompletionStopInProgress(): boolean {
|
|
46
|
+
return autoSession.completionStopInProgress;
|
|
47
|
+
}
|
|
48
|
+
|
|
45
49
|
export function markToolStart(toolCallId: string, toolName?: string): void {
|
|
46
50
|
markTrackedToolStart(toolCallId, autoSession.active, toolName);
|
|
47
51
|
}
|
|
@@ -94,7 +94,7 @@ export function clearInFlightTools(): void {
|
|
|
94
94
|
* from the tool handler. When these errors occur, retrying the same unit will
|
|
95
95
|
* produce the same failure, so the retry loop must be broken.
|
|
96
96
|
*/
|
|
97
|
-
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;
|
|
97
|
+
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;
|
|
98
98
|
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;
|
|
99
99
|
|
|
100
100
|
/**
|
|
@@ -2311,10 +2311,20 @@ export function createWiredAutoOrchestrationModule(
|
|
|
2311
2311
|
async reconcileBeforeDispatch() {
|
|
2312
2312
|
const activeBasePath = getLiveDispatchBasePath();
|
|
2313
2313
|
const result = await reconcileBeforeDispatch(activeBasePath);
|
|
2314
|
-
|
|
2314
|
+
// Failure-path summaries written by gsd_summary_save create
|
|
2315
|
+
// artifact-db-status-divergence blockers for tasks that are still
|
|
2316
|
+
// pending (gsd_task_complete never ran). These tasks can still be
|
|
2317
|
+
// dispatched and the drift self-heals once they complete successfully.
|
|
2318
|
+
const hardBlockers = result.blockers.filter(
|
|
2319
|
+
(b) =>
|
|
2320
|
+
!b.includes("has SUMMARY artifact while DB status is") &&
|
|
2321
|
+
!b.includes("has SUMMARY on disk while DB status is") &&
|
|
2322
|
+
!b.includes("has task SUMMARY artifacts but no DB tasks"),
|
|
2323
|
+
);
|
|
2324
|
+
if (hardBlockers.length > 0) {
|
|
2315
2325
|
return {
|
|
2316
2326
|
ok: false,
|
|
2317
|
-
reason:
|
|
2327
|
+
reason: hardBlockers[0],
|
|
2318
2328
|
stateSnapshot: result.stateSnapshot,
|
|
2319
2329
|
};
|
|
2320
2330
|
}
|