@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
|
@@ -227,21 +227,22 @@ async function dispatchDiscussForNextMilestoneWithBacklog(
|
|
|
227
227
|
nextId: string,
|
|
228
228
|
): Promise<void> {
|
|
229
229
|
const backlogContext = buildRequirementsBacklogDiscussContext(nextId);
|
|
230
|
-
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
231
230
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
232
|
-
const basePrompt =
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
inlinedTemplates: discussMilestoneTemplates,
|
|
231
|
+
const basePrompt = await buildDiscussMilestonePrompt(
|
|
232
|
+
nextId,
|
|
233
|
+
`New milestone ${nextId}`,
|
|
234
|
+
basePath,
|
|
237
235
|
structuredQuestionsAvailable,
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
236
|
+
{
|
|
237
|
+
commitInstruction: buildDocsCommitInstruction(`docs(${nextId}): milestone context from discuss`),
|
|
238
|
+
includeContextMode: false,
|
|
239
|
+
fastPathInstruction: [
|
|
240
|
+
"> **Requirements backlog active.**",
|
|
241
|
+
"> Map unmapped active requirements to this milestone before finalizing context.",
|
|
242
|
+
"> Confirm ownership with the user when scope is ambiguous.",
|
|
243
|
+
].join("\n"),
|
|
244
|
+
},
|
|
245
|
+
);
|
|
245
246
|
const prompt = backlogContext ? `${basePrompt}\n\n${backlogContext}` : basePrompt;
|
|
246
247
|
await dispatchWorkflow(pi, prompt, "gsd-discuss", ctx, "discuss-milestone", { basePath });
|
|
247
248
|
}
|
|
@@ -1371,6 +1372,7 @@ async function buildDiscussPreparationContext(
|
|
|
1371
1372
|
ctx: ExtensionCommandContext,
|
|
1372
1373
|
basePath: string,
|
|
1373
1374
|
mode: "greenfield" | "milestone" = "greenfield",
|
|
1375
|
+
skipPriorContext = false,
|
|
1374
1376
|
): Promise<string> {
|
|
1375
1377
|
const prefs = loadEffectiveGSDPreferences()?.preferences ?? {};
|
|
1376
1378
|
if (prefs.discuss_preparation === false) return "";
|
|
@@ -1388,7 +1390,7 @@ async function buildDiscussPreparationContext(
|
|
|
1388
1390
|
const priorContextBrief = prepResult.priorContextBrief || formatPriorContextBrief(prepResult.priorContext);
|
|
1389
1391
|
const parts: string[] = [];
|
|
1390
1392
|
if (codebaseBrief) parts.push(`### Codebase Brief\n\n${codebaseBrief}`);
|
|
1391
|
-
if (priorContextBrief) parts.push(`### Prior Context Brief\n\n${priorContextBrief}`);
|
|
1393
|
+
if (priorContextBrief && !skipPriorContext) parts.push(`### Prior Context Brief\n\n${priorContextBrief}`);
|
|
1392
1394
|
if (parts.length === 0) return "";
|
|
1393
1395
|
|
|
1394
1396
|
const guidance = mode === "milestone"
|
|
@@ -1441,18 +1443,18 @@ async function dispatchNewMilestoneDiscuss(
|
|
|
1441
1443
|
return;
|
|
1442
1444
|
}
|
|
1443
1445
|
|
|
1444
|
-
const preparationContext = await buildDiscussPreparationContext(ctx, basePath, "milestone");
|
|
1445
|
-
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
1446
|
+
const preparationContext = await buildDiscussPreparationContext(ctx, basePath, "milestone", true);
|
|
1446
1447
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
1447
|
-
let prompt =
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
inlinedTemplates: discussMilestoneTemplates,
|
|
1448
|
+
let prompt = await buildDiscussMilestonePrompt(
|
|
1449
|
+
nextId,
|
|
1450
|
+
`New milestone ${nextId}`,
|
|
1451
|
+
basePath,
|
|
1452
1452
|
structuredQuestionsAvailable,
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1453
|
+
{
|
|
1454
|
+
commitInstruction: buildDocsCommitInstruction(`docs(${nextId}): milestone context from discuss`),
|
|
1455
|
+
includeContextMode: false,
|
|
1456
|
+
},
|
|
1457
|
+
);
|
|
1456
1458
|
if (preparationContext) prompt += preparationContext;
|
|
1457
1459
|
await dispatchWorkflow(pi, prompt, "gsd-discuss", ctx, "discuss-milestone", { basePath });
|
|
1458
1460
|
}
|
|
@@ -1759,9 +1761,6 @@ export async function showDiscuss(
|
|
|
1759
1761
|
// Special case: milestone is in needs-discussion phase (has CONTEXT-DRAFT.md but no roadmap yet).
|
|
1760
1762
|
// Route to the draft discussion flow instead of erroring — the discussion IS how the roadmap gets created.
|
|
1761
1763
|
if (state.phase === "needs-discussion") {
|
|
1762
|
-
const draftFile = resolveMilestoneFile(basePath, mid, "CONTEXT-DRAFT");
|
|
1763
|
-
const draftContent = draftFile ? await loadFile(draftFile) : null;
|
|
1764
|
-
|
|
1765
1764
|
const choice = await showNextAction(ctx, {
|
|
1766
1765
|
title: `GSD — ${mid}: ${milestoneTitle}`,
|
|
1767
1766
|
summary: ["This milestone has a draft context from a prior discussion.", "It needs a dedicated discussion before auto-planning can begin."],
|
|
@@ -1787,29 +1786,34 @@ export async function showDiscuss(
|
|
|
1787
1786
|
});
|
|
1788
1787
|
|
|
1789
1788
|
if (choice === "discuss_draft") {
|
|
1790
|
-
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
1791
1789
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
1792
|
-
const
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1790
|
+
const seed = await buildDiscussMilestonePrompt(
|
|
1791
|
+
mid,
|
|
1792
|
+
milestoneTitle,
|
|
1793
|
+
basePath,
|
|
1794
|
+
structuredQuestionsAvailable,
|
|
1795
|
+
{
|
|
1796
|
+
commitInstruction: buildDocsCommitInstruction(`docs(${mid}): milestone context from discuss`),
|
|
1797
|
+
includeContextMode: false,
|
|
1798
|
+
},
|
|
1799
|
+
);
|
|
1801
1800
|
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: mid, step: true });
|
|
1802
1801
|
await dispatchWorkflow(pi, seed, "gsd-discuss", ctx, "discuss-milestone", { basePath });
|
|
1803
1802
|
} else if (choice === "discuss_fresh") {
|
|
1804
|
-
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
1805
1803
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
1804
|
+
const prompt = await buildDiscussMilestonePrompt(
|
|
1805
|
+
mid,
|
|
1806
|
+
milestoneTitle,
|
|
1807
|
+
basePath,
|
|
1808
|
+
structuredQuestionsAvailable,
|
|
1809
|
+
{
|
|
1810
|
+
commitInstruction: buildDocsCommitInstruction(`docs(${mid}): milestone context from discuss`),
|
|
1811
|
+
includeContextMode: false,
|
|
1812
|
+
includeDraftSeed: false,
|
|
1813
|
+
},
|
|
1814
|
+
);
|
|
1806
1815
|
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: mid, step: true });
|
|
1807
|
-
await dispatchWorkflow(pi,
|
|
1808
|
-
workingDirectory: basePath,
|
|
1809
|
-
milestoneId: mid, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
|
|
1810
|
-
commitInstruction: buildDocsCommitInstruction(`docs(${mid}): milestone context from discuss`),
|
|
1811
|
-
fastPathInstruction: "",
|
|
1812
|
-
}), "gsd-discuss", ctx, "discuss-milestone", { basePath });
|
|
1816
|
+
await dispatchWorkflow(pi, prompt, "gsd-discuss", ctx, "discuss-milestone", { basePath });
|
|
1813
1817
|
} else if (choice === "skip_milestone") {
|
|
1814
1818
|
const { ensureDbOpen } = await import("./bootstrap/dynamic-tools.js");
|
|
1815
1819
|
await ensureDbOpen(basePath);
|
|
@@ -2068,20 +2072,18 @@ async function dispatchDiscussForMilestone(
|
|
|
2068
2072
|
"> Ask only questions where the answer would materially change scope.",
|
|
2069
2073
|
].join("\n")
|
|
2070
2074
|
: "";
|
|
2071
|
-
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
2072
2075
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
2073
|
-
const
|
|
2074
|
-
|
|
2075
|
-
milestoneId: mid,
|
|
2076
|
+
const prompt = await buildDiscussMilestonePrompt(
|
|
2077
|
+
mid,
|
|
2076
2078
|
milestoneTitle,
|
|
2077
|
-
|
|
2079
|
+
basePath,
|
|
2078
2080
|
structuredQuestionsAvailable,
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2081
|
+
{
|
|
2082
|
+
commitInstruction: buildDocsCommitInstruction(`docs(${mid}): milestone context from discuss`),
|
|
2083
|
+
includeContextMode: false,
|
|
2084
|
+
fastPathInstruction,
|
|
2085
|
+
},
|
|
2086
|
+
);
|
|
2085
2087
|
await dispatchWorkflow(pi, prompt, "gsd-discuss", ctx, "discuss-milestone", { basePath });
|
|
2086
2088
|
}
|
|
2087
2089
|
|
|
@@ -2612,9 +2614,6 @@ export async function showSmartEntry(
|
|
|
2612
2614
|
|
|
2613
2615
|
// ── Draft milestone — needs discussion before planning ────────────────
|
|
2614
2616
|
if (state.phase === "needs-discussion") {
|
|
2615
|
-
const draftFile = resolveMilestoneFile(basePath, milestoneId, "CONTEXT-DRAFT");
|
|
2616
|
-
const draftContent = draftFile ? await loadFile(draftFile) : null;
|
|
2617
|
-
|
|
2618
2617
|
const choice = await showNextAction(ctx, {
|
|
2619
2618
|
title: `GSD — ${milestoneId}: ${milestoneTitle}`,
|
|
2620
2619
|
summary: ["This milestone has a draft context from a prior discussion.", "It needs a dedicated discussion before auto-planning can begin."],
|
|
@@ -2640,29 +2639,34 @@ export async function showSmartEntry(
|
|
|
2640
2639
|
});
|
|
2641
2640
|
|
|
2642
2641
|
if (choice === "discuss_draft") {
|
|
2643
|
-
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
2644
2642
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
2645
|
-
const
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2643
|
+
const seed = await buildDiscussMilestonePrompt(
|
|
2644
|
+
milestoneId,
|
|
2645
|
+
milestoneTitle,
|
|
2646
|
+
basePath,
|
|
2647
|
+
structuredQuestionsAvailable,
|
|
2648
|
+
{
|
|
2649
|
+
commitInstruction: buildDocsCommitInstruction(`docs(${milestoneId}): milestone context from discuss`),
|
|
2650
|
+
includeContextMode: false,
|
|
2651
|
+
},
|
|
2652
|
+
);
|
|
2654
2653
|
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId, step: stepMode });
|
|
2655
2654
|
await dispatchWorkflow(pi, seed, "gsd-discuss", ctx, "discuss-milestone", { basePath });
|
|
2656
2655
|
} else if (choice === "discuss_fresh") {
|
|
2657
|
-
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
2658
2656
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
2657
|
+
const prompt = await buildDiscussMilestonePrompt(
|
|
2658
|
+
milestoneId,
|
|
2659
|
+
milestoneTitle,
|
|
2660
|
+
basePath,
|
|
2661
|
+
structuredQuestionsAvailable,
|
|
2662
|
+
{
|
|
2663
|
+
commitInstruction: buildDocsCommitInstruction(`docs(${milestoneId}): milestone context from discuss`),
|
|
2664
|
+
includeContextMode: false,
|
|
2665
|
+
includeDraftSeed: false,
|
|
2666
|
+
},
|
|
2667
|
+
);
|
|
2659
2668
|
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId, step: stepMode });
|
|
2660
|
-
await dispatchWorkflow(pi,
|
|
2661
|
-
workingDirectory: basePath,
|
|
2662
|
-
milestoneId, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
|
|
2663
|
-
commitInstruction: buildDocsCommitInstruction(`docs(${milestoneId}): milestone context from discuss`),
|
|
2664
|
-
fastPathInstruction: "",
|
|
2665
|
-
}), "gsd-discuss", ctx, "discuss-milestone", { basePath });
|
|
2669
|
+
await dispatchWorkflow(pi, prompt, "gsd-discuss", ctx, "discuss-milestone", { basePath });
|
|
2666
2670
|
} else if (choice === "skip_milestone") {
|
|
2667
2671
|
const milestoneIds = findMilestoneIds(basePath);
|
|
2668
2672
|
const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
|
|
@@ -2783,14 +2787,18 @@ export async function showSmartEntry(
|
|
|
2783
2787
|
{ basePath },
|
|
2784
2788
|
);
|
|
2785
2789
|
} else if (choice === "discuss") {
|
|
2786
|
-
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
2787
2790
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
2788
|
-
await
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2791
|
+
const prompt = await buildDiscussMilestonePrompt(
|
|
2792
|
+
milestoneId,
|
|
2793
|
+
milestoneTitle,
|
|
2794
|
+
basePath,
|
|
2795
|
+
structuredQuestionsAvailable,
|
|
2796
|
+
{
|
|
2797
|
+
commitInstruction: buildDocsCommitInstruction(`docs(${milestoneId}): milestone context from discuss`),
|
|
2798
|
+
includeContextMode: false,
|
|
2799
|
+
},
|
|
2800
|
+
);
|
|
2801
|
+
await dispatchWorkflow(pi, prompt, "gsd-run", ctx, "discuss-milestone", { basePath });
|
|
2794
2802
|
} else if (choice === "skip_milestone") {
|
|
2795
2803
|
const milestoneIds = findMilestoneIds(basePath);
|
|
2796
2804
|
const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
-
import {
|
|
4
|
-
import { basename, resolve } from "node:path";
|
|
2
|
+
import { resolve } from "node:path";
|
|
5
3
|
import { fileURLToPath } from "node:url";
|
|
6
4
|
|
|
5
|
+
import {
|
|
6
|
+
GSD_BROWSER_MCP_SERVER_NAME,
|
|
7
|
+
resolveBundledGsdBrowserCliPath,
|
|
8
|
+
resolveGsdBrowserMcpLaunchConfig,
|
|
9
|
+
} from "../shared/gsd-browser-cli.js";
|
|
7
10
|
import { assertSafeDirectory } from "./validate-directory.js";
|
|
8
11
|
import { detectWorkflowMcpLaunchConfig } from "./workflow-mcp.js";
|
|
9
12
|
|
|
10
13
|
export const GSD_WORKFLOW_MCP_SERVER_NAME = "gsd-workflow";
|
|
11
|
-
export
|
|
14
|
+
export { GSD_BROWSER_MCP_SERVER_NAME, resolveBundledGsdBrowserCliPath };
|
|
12
15
|
|
|
13
16
|
export interface ProjectMcpServerConfig {
|
|
14
17
|
command?: string;
|
|
@@ -59,31 +62,6 @@ export function resolveBundledGsdCliPath(env: NodeJS.ProcessEnv = process.env):
|
|
|
59
62
|
return null;
|
|
60
63
|
}
|
|
61
64
|
|
|
62
|
-
export function resolveBundledGsdBrowserCliPath(env: NodeJS.ProcessEnv = process.env): string | null {
|
|
63
|
-
const explicit = env.GSD_BROWSER_CLI_PATH?.trim() || env.GSD_BROWSER_BIN_PATH?.trim();
|
|
64
|
-
if (explicit) return explicit;
|
|
65
|
-
|
|
66
|
-
try {
|
|
67
|
-
const requireFromHere = createRequire(import.meta.url);
|
|
68
|
-
const packageJsonPath = requireFromHere.resolve("@opengsd/gsd-browser/package.json");
|
|
69
|
-
const candidate = resolve(packageJsonPath, "..", "bin", "gsd-browser");
|
|
70
|
-
if (existsSync(candidate)) return candidate;
|
|
71
|
-
} catch {
|
|
72
|
-
// Fall through to path candidates for source/dist layouts.
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const candidates = [
|
|
76
|
-
resolve(fileURLToPath(new URL("../../../../node_modules/@opengsd/gsd-browser/bin/gsd-browser", import.meta.url))),
|
|
77
|
-
resolve(fileURLToPath(new URL("../../../../node_modules/.bin/gsd-browser", import.meta.url))),
|
|
78
|
-
];
|
|
79
|
-
|
|
80
|
-
for (const candidate of candidates) {
|
|
81
|
-
if (existsSync(candidate)) return candidate;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
65
|
export function buildProjectWorkflowMcpServerConfig(
|
|
88
66
|
projectRoot: string,
|
|
89
67
|
env: NodeJS.ProcessEnv = process.env,
|
|
@@ -119,31 +97,12 @@ function buildProjectWorkflowMcpServerSpec(
|
|
|
119
97
|
};
|
|
120
98
|
}
|
|
121
99
|
|
|
122
|
-
function parseJsonEnv<T>(env: NodeJS.ProcessEnv, name: string): T | undefined {
|
|
123
|
-
const raw = env[name];
|
|
124
|
-
if (!raw) return undefined;
|
|
125
|
-
try {
|
|
126
|
-
return JSON.parse(raw) as T;
|
|
127
|
-
} catch {
|
|
128
|
-
throw new Error(`Invalid JSON in ${name}`);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
100
|
function isEnvDisabled(value: string | undefined): boolean {
|
|
133
101
|
if (!value) return false;
|
|
134
102
|
const normalized = value.trim().toLowerCase();
|
|
135
103
|
return normalized === "0" || normalized === "false" || normalized === "off";
|
|
136
104
|
}
|
|
137
105
|
|
|
138
|
-
function buildBrowserSessionName(projectRoot: string): string {
|
|
139
|
-
const resolvedProjectRoot = resolve(projectRoot);
|
|
140
|
-
const base = basename(resolvedProjectRoot)
|
|
141
|
-
.replace(/[^a-zA-Z0-9._-]+/g, "-")
|
|
142
|
-
.replace(/^-+|-+$/g, "") || "project";
|
|
143
|
-
const hash = createHash("sha1").update(resolvedProjectRoot).digest("hex").slice(0, 8);
|
|
144
|
-
return `gsd-${base}-${hash}`;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
106
|
export function buildProjectBrowserMcpServerConfig(
|
|
148
107
|
projectRoot: string,
|
|
149
108
|
env: NodeJS.ProcessEnv = process.env,
|
|
@@ -157,39 +116,15 @@ function buildProjectBrowserMcpServerSpec(
|
|
|
157
116
|
): ProjectMcpServerSpec | null {
|
|
158
117
|
if (isEnvDisabled(env.GSD_BROWSER_MCP_ENABLED)) return null;
|
|
159
118
|
|
|
160
|
-
const
|
|
161
|
-
const serverName = env.GSD_BROWSER_MCP_NAME?.trim() || GSD_BROWSER_MCP_SERVER_NAME;
|
|
162
|
-
const explicitArgs = parseJsonEnv<unknown>(env, "GSD_BROWSER_MCP_ARGS");
|
|
163
|
-
const explicitEnv = parseJsonEnv<Record<string, string>>(env, "GSD_BROWSER_MCP_ENV");
|
|
164
|
-
const explicitCommand = env.GSD_BROWSER_MCP_COMMAND?.trim();
|
|
165
|
-
const explicitCliPath = env.GSD_BROWSER_CLI_PATH?.trim() || env.GSD_BROWSER_BIN_PATH?.trim();
|
|
166
|
-
const bundledCliPath = !explicitCommand && !explicitCliPath ? resolveBundledGsdBrowserCliPath(env) : null;
|
|
167
|
-
const command =
|
|
168
|
-
explicitCommand
|
|
169
|
-
|| explicitCliPath
|
|
170
|
-
|| (bundledCliPath ? process.execPath : undefined)
|
|
171
|
-
|| "gsd-browser";
|
|
172
|
-
const args = Array.isArray(explicitArgs) && explicitArgs.length > 0
|
|
173
|
-
? explicitArgs.map(String)
|
|
174
|
-
: [
|
|
175
|
-
...(bundledCliPath ? [bundledCliPath] : []),
|
|
176
|
-
"mcp",
|
|
177
|
-
"--session",
|
|
178
|
-
buildBrowserSessionName(resolvedProjectRoot),
|
|
179
|
-
"--identity-scope",
|
|
180
|
-
"project",
|
|
181
|
-
"--identity-project",
|
|
182
|
-
resolvedProjectRoot,
|
|
183
|
-
];
|
|
184
|
-
const cwd = env.GSD_BROWSER_MCP_CWD?.trim() || resolvedProjectRoot;
|
|
119
|
+
const launch = resolveGsdBrowserMcpLaunchConfig(projectRoot, env);
|
|
185
120
|
|
|
186
121
|
return {
|
|
187
|
-
serverName,
|
|
122
|
+
serverName: launch.serverName,
|
|
188
123
|
server: {
|
|
189
|
-
command,
|
|
190
|
-
args,
|
|
191
|
-
cwd,
|
|
192
|
-
...(
|
|
124
|
+
command: launch.command,
|
|
125
|
+
args: launch.args,
|
|
126
|
+
cwd: launch.cwd,
|
|
127
|
+
...(launch.env ? { env: launch.env } : {}),
|
|
193
128
|
},
|
|
194
129
|
};
|
|
195
130
|
}
|
|
@@ -777,7 +777,10 @@ export function decayStaleMemories(thresholdUnits = 20): string[] {
|
|
|
777
777
|
const cutoff = row['processed_at'] as string;
|
|
778
778
|
const affected = adapter.prepare(
|
|
779
779
|
`SELECT id FROM memories
|
|
780
|
-
WHERE superseded_by IS NULL
|
|
780
|
+
WHERE superseded_by IS NULL
|
|
781
|
+
AND updated_at < :cutoff
|
|
782
|
+
AND confidence > 0.1
|
|
783
|
+
AND (structured_fields IS NULL OR structured_fields NOT LIKE '%"sourceDecisionId"%')`,
|
|
781
784
|
).all({ ':cutoff': cutoff }).map((r) => r['id'] as string);
|
|
782
785
|
|
|
783
786
|
decayMemoriesBefore(cutoff, new Date().toISOString());
|
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
HookDispatchResult,
|
|
10
10
|
PreDispatchResult,
|
|
11
11
|
HookStatusEntry,
|
|
12
|
+
PostUnitGateBlock,
|
|
12
13
|
} from "./types.js";
|
|
13
14
|
import { getOrCreateRegistry, resolveHookArtifactPath } from "./rule-registry.js";
|
|
14
15
|
|
|
@@ -33,10 +34,22 @@ export function isRetryPending(): boolean {
|
|
|
33
34
|
return getOrCreateRegistry().isRetryPending();
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
export function consumeRetryTrigger(): { unitType: string; unitId: string; retryArtifact
|
|
37
|
+
export function consumeRetryTrigger(): { unitType: string; unitId: string; retryArtifact?: string } | null {
|
|
37
38
|
return getOrCreateRegistry().consumeRetryTrigger();
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
export function consumeHookFailure(): { hookName: string; unitType: string; unitId: string; reason: string } | null {
|
|
42
|
+
return getOrCreateRegistry().consumeHookFailure();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function isGateBlockPending(): boolean {
|
|
46
|
+
return getOrCreateRegistry().isGateBlockPending();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function consumeGateBlock(): PostUnitGateBlock | null {
|
|
50
|
+
return getOrCreateRegistry().consumeGateBlock();
|
|
51
|
+
}
|
|
52
|
+
|
|
40
53
|
export function resetHookState(): void {
|
|
41
54
|
getOrCreateRegistry().resetState();
|
|
42
55
|
}
|
|
@@ -29,6 +29,14 @@ const VALID_UOK_TURN_ACTIONS = new Set<"commit" | "snapshot" | "status-only">([
|
|
|
29
29
|
"snapshot",
|
|
30
30
|
"status-only",
|
|
31
31
|
]);
|
|
32
|
+
const VALID_POST_UNIT_HOOK_CRITICALITIES = new Set(["advisory", "blocking"]);
|
|
33
|
+
const VALID_POST_UNIT_HOOK_ON_BLOCK_ACTIONS = new Set([
|
|
34
|
+
"retry-unit",
|
|
35
|
+
"retry-task",
|
|
36
|
+
"queue-task",
|
|
37
|
+
"queue-slice",
|
|
38
|
+
"pause",
|
|
39
|
+
]);
|
|
32
40
|
|
|
33
41
|
export function validatePreferences(preferences: GSDPreferences): {
|
|
34
42
|
preferences: GSDPreferences;
|
|
@@ -486,9 +494,37 @@ export function validatePreferences(preferences: GSDPreferences): {
|
|
|
486
494
|
if (typeof hook.artifact === "string" && hook.artifact.trim()) {
|
|
487
495
|
validHook.artifact = hook.artifact.trim();
|
|
488
496
|
}
|
|
497
|
+
if (hook.criticality !== undefined) {
|
|
498
|
+
const criticality = typeof hook.criticality === "string" ? hook.criticality.trim() : "";
|
|
499
|
+
if (VALID_POST_UNIT_HOOK_CRITICALITIES.has(criticality)) {
|
|
500
|
+
validHook.criticality = criticality as PostUnitHookConfig["criticality"];
|
|
501
|
+
} else {
|
|
502
|
+
errors.push(`post_unit_hooks "${name}" invalid criticality: ${String(hook.criticality)}`);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
489
505
|
if (typeof hook.retry_on === "string" && hook.retry_on.trim()) {
|
|
490
506
|
validHook.retry_on = hook.retry_on.trim();
|
|
491
507
|
}
|
|
508
|
+
if (hook.on_block !== undefined) {
|
|
509
|
+
if (!hook.on_block || typeof hook.on_block !== "object") {
|
|
510
|
+
errors.push(`post_unit_hooks "${name}" on_block must be an object`);
|
|
511
|
+
} else {
|
|
512
|
+
const onBlock = hook.on_block as unknown as Record<string, unknown>;
|
|
513
|
+
const action = typeof onBlock.action === "string" ? onBlock.action.trim() : "";
|
|
514
|
+
if (!VALID_POST_UNIT_HOOK_ON_BLOCK_ACTIONS.has(action)) {
|
|
515
|
+
errors.push(`post_unit_hooks "${name}" invalid on_block action: ${String(onBlock.action)}`);
|
|
516
|
+
} else {
|
|
517
|
+
validHook.on_block = { action: action as NonNullable<PostUnitHookConfig["on_block"]>["action"] };
|
|
518
|
+
if (typeof onBlock.artifact === "string" && onBlock.artifact.trim()) {
|
|
519
|
+
validHook.on_block.artifact = onBlock.artifact.trim();
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
if (validHook.criticality === "blocking" && !validHook.artifact) {
|
|
525
|
+
errors.push(`post_unit_hooks "${name}" criticality blocking requires artifact`);
|
|
526
|
+
continue;
|
|
527
|
+
}
|
|
492
528
|
if (typeof hook.agent === "string" && hook.agent.trim()) {
|
|
493
529
|
validHook.agent = hook.agent.trim();
|
|
494
530
|
}
|
|
@@ -33,6 +33,10 @@ function hasRequiredExtensionAssets(rootDir: string, exists: ExistsFn = existsSy
|
|
|
33
33
|
);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
function isSourceExtensionDir(moduleDir: string): boolean {
|
|
37
|
+
return moduleDir.replaceAll("\\", "/").endsWith("/src/resources/extensions/gsd");
|
|
38
|
+
}
|
|
39
|
+
|
|
36
40
|
export function resolveExtensionDirFromCandidates(
|
|
37
41
|
moduleDir: string,
|
|
38
42
|
agentGsdDir: string,
|
|
@@ -41,6 +45,10 @@ export function resolveExtensionDirFromCandidates(
|
|
|
41
45
|
const moduleUsable = hasRequiredExtensionAssets(moduleDir, exists);
|
|
42
46
|
const agentUsable = hasRequiredExtensionAssets(agentGsdDir, exists);
|
|
43
47
|
|
|
48
|
+
// Source checkouts must use their own prompt tree. Otherwise local tests and
|
|
49
|
+
// dev runs can silently render stale prompts from ~/.gsd/agent/extensions/gsd.
|
|
50
|
+
if (moduleUsable && isSourceExtensionDir(moduleDir)) return moduleDir;
|
|
51
|
+
|
|
44
52
|
// Prefer the user-local extension tree when both are valid. This avoids
|
|
45
53
|
// leaking npm/global-install paths into prompts on Windows.
|
|
46
54
|
if (agentUsable) return agentGsdDir;
|
|
@@ -12,6 +12,8 @@ Debug GSD itself. Trace the symptom to root cause in current source and produce
|
|
|
12
12
|
|
|
13
13
|
GSD extension source: `{{gsdSourceDir}}`
|
|
14
14
|
|
|
15
|
+
{{toolingSection}}
|
|
16
|
+
|
|
15
17
|
### Source Map by Domain
|
|
16
18
|
|
|
17
19
|
| Domain | Files |
|
|
@@ -101,7 +103,7 @@ Then **offer GitHub issue creation**: "Would you like me to create a GitHub issu
|
|
|
101
103
|
|
|
102
104
|
**CRITICAL:** The `github_issues` tool targets only the current user's repository and has no `repo` parameter. Use `gh issue create --repo open-gsd/gsd-pi` via `bash`. Do NOT use the `github_issues` tool.
|
|
103
105
|
|
|
104
|
-
If yes, create using the `bash` tool:
|
|
106
|
+
If yes and `bash` is available, create using the `bash` tool:
|
|
105
107
|
|
|
106
108
|
```bash
|
|
107
109
|
ISSUE_BODY_FILE="${TMPDIR:-${TEMP:-${TMP:-.}}}/gsd-forensic-issue.md"
|
|
@@ -142,6 +144,64 @@ TYPE_ID=$(gh api graphql -f query='{ repository(owner:"open-gsd",name:"gsd-pi")
|
|
|
142
144
|
gh api graphql -f query='mutation { updateIssue(input:{id:"'"$ISSUE_ID"'",issueTypeId:"'"$TYPE_ID"'"}) { issue { number } } }'
|
|
143
145
|
```
|
|
144
146
|
|
|
147
|
+
If `bash` is unavailable, do not attempt `bash`, `write`, or `github_issues` tool calls. Instead, provide exactly one paste-once shell script for the user to run locally and say that the live duplicate check / issue creation must be run by the user:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
KEYWORDS="..."
|
|
151
|
+
echo "Searching closed issues for possible duplicates..."
|
|
152
|
+
gh issue list --repo open-gsd/gsd-pi --state closed --search "$KEYWORDS" --limit 20
|
|
153
|
+
|
|
154
|
+
echo "Searching open PRs for possible fixes..."
|
|
155
|
+
gh pr list --repo open-gsd/gsd-pi --state open --search "$KEYWORDS" --limit 10
|
|
156
|
+
|
|
157
|
+
echo "Searching merged PRs for possible fixes..."
|
|
158
|
+
gh pr list --repo open-gsd/gsd-pi --state merged --search "$KEYWORDS" --limit 10
|
|
159
|
+
|
|
160
|
+
read -r -p "Review the duplicate search above. Continue filing a new issue? [y/N] " SHOULD_FILE
|
|
161
|
+
case "$SHOULD_FILE" in
|
|
162
|
+
y|Y|yes|YES) ;;
|
|
163
|
+
*) echo "Issue filing aborted."; exit 0 ;;
|
|
164
|
+
esac
|
|
165
|
+
|
|
166
|
+
ISSUE_BODY_FILE="${TMPDIR:-${TEMP:-${TMP:-.}}}/gsd-forensic-issue.md"
|
|
167
|
+
cat > "$ISSUE_BODY_FILE" << 'GSD_ISSUE_BODY'
|
|
168
|
+
## Problem
|
|
169
|
+
[1-2 sentence summary]
|
|
170
|
+
|
|
171
|
+
## Root Cause
|
|
172
|
+
[Specific file:line in GSD source, with code snippet showing the bug]
|
|
173
|
+
|
|
174
|
+
## Expected Behavior
|
|
175
|
+
[What the code should do instead — concrete fix suggestion]
|
|
176
|
+
|
|
177
|
+
## Environment
|
|
178
|
+
- GSD version: [from report]
|
|
179
|
+
- Model: [from report]
|
|
180
|
+
- Unit: [type/id that failed]
|
|
181
|
+
|
|
182
|
+
## Reproduction Context
|
|
183
|
+
[Phase, milestone, slice, what was happening when it failed]
|
|
184
|
+
|
|
185
|
+
## Forensic Evidence
|
|
186
|
+
[Key anomalies, error traces, relevant tool call sequences from the report]
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
*Auto-generated by `/gsd forensics`*
|
|
190
|
+
GSD_ISSUE_BODY
|
|
191
|
+
|
|
192
|
+
ISSUE_URL=$(gh issue create --repo open-gsd/gsd-pi \
|
|
193
|
+
--title "..." \
|
|
194
|
+
--label "auto-generated" \
|
|
195
|
+
--body-file "$ISSUE_BODY_FILE")
|
|
196
|
+
rm -f "$ISSUE_BODY_FILE"
|
|
197
|
+
|
|
198
|
+
ISSUE_NUM=$(echo "$ISSUE_URL" | grep -oE '[0-9]+$')
|
|
199
|
+
ISSUE_ID=$(gh api graphql -f query='{ repository(owner:"open-gsd",name:"gsd-pi") { issue(number:'"$ISSUE_NUM"') { id } } }' --jq '.data.repository.issue.id')
|
|
200
|
+
TYPE_ID=$(gh api graphql -f query='{ repository(owner:"open-gsd",name:"gsd-pi") { issueTypes(first:20) { nodes { id name } } } }' --jq '.data.repository.issueTypes.nodes[] | select(.name=="Bug") | .id')
|
|
201
|
+
gh api graphql -f query='mutation { updateIssue(input:{id:"'"$ISSUE_ID"'",issueTypeId:"'"$TYPE_ID"'"}) { issue { number } } }'
|
|
202
|
+
echo "$ISSUE_URL"
|
|
203
|
+
```
|
|
204
|
+
|
|
145
205
|
### Redaction Rules (CRITICAL)
|
|
146
206
|
|
|
147
207
|
Before creating the issue, you MUST:
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
You are evaluating **quality gates in parallel** for this slice. Each gate is an independent question that must be answered before task execution begins. Use the `subagent` tool to dispatch all gate evaluations simultaneously.
|
|
10
10
|
|
|
11
|
+
**Tool call format:** Call `subagent` with `tasks: [...]` as a **native JSON array** — one object per gate. Do NOT JSON.stringify the array into a string; the tool validates that `tasks` is an array, and a serialized string will be rejected with "must be array".
|
|
12
|
+
|
|
11
13
|
## Slice Plan Context
|
|
12
14
|
|
|
13
15
|
{{slicePlanContent}}
|
|
@@ -20,7 +22,7 @@ You are evaluating **quality gates in parallel** for this slice. Each gate is an
|
|
|
20
22
|
|
|
21
23
|
## Execution Protocol
|
|
22
24
|
|
|
23
|
-
1. **Dispatch all gates** using `subagent` in parallel mode. Each subagent prompt is provided below.
|
|
25
|
+
1. **Dispatch all gates** using `subagent` in parallel mode. Call `subagent` with `tasks: [{ agent: "tester", task: "<prompt>" }, ...]` — one object per gate. Each subagent prompt is provided below.
|
|
24
26
|
Pass `tasks` as a **JSON array**, not a string. Example shape:
|
|
25
27
|
|
|
26
28
|
```json
|
|
@@ -12,9 +12,11 @@ You are dispatching parallel research agents for **{{sliceCount}} slices** in mi
|
|
|
12
12
|
|
|
13
13
|
Dispatch ALL slices simultaneously using the `subagent` tool in **parallel mode**. Each subagent will independently research its slice and write a RESEARCH file.
|
|
14
14
|
|
|
15
|
+
**Tool call format:** Call `subagent` with `tasks: [...]` as a **native JSON array** — one object per slice. Do NOT JSON.stringify the array into a string; the tool validates that `tasks` is an array, and a serialized string will be rejected with "must be array".
|
|
16
|
+
|
|
15
17
|
## Execution Protocol
|
|
16
18
|
|
|
17
|
-
1. Call `subagent` with `tasks: [...]` containing one entry per slice below
|
|
19
|
+
1. Call `subagent` with `tasks: [{ agent: "scout", task: "<prompt>" }, ...]` containing one entry per slice below
|
|
18
20
|
2. Wait for ALL subagents to complete
|
|
19
21
|
3. Verify each slice's RESEARCH file was written (check `.gsd/milestones/{{mid}}/slices/<slice-id>/`)
|
|
20
22
|
4. If a subagent failed to write its RESEARCH file, retry it **once** individually
|
|
@@ -43,7 +43,7 @@ If slice research is inlined, trust its architectural findings, but verify every
|
|
|
43
43
|
5. Define slice verification before tasks. Non-trivial slices need real tests or executable assertions; boundary contracts need contract-exercising checks. Tests must not read .gitignore/gitignored paths such as `.gsd/`, `.planning/`, or `.audits/`.
|
|
44
44
|
6. Include Threat Surface (Q3), Requirement Impact (Q4), proof level, observability, integration closure, Failure Modes (Q5), Load Profile (Q6), and Negative Tests (Q7) only where applicable.
|
|
45
45
|
7. Right-size tasks. Simple slices can be one task; split only when context, ownership, or verification boundaries justify it.
|
|
46
|
-
8. Task `verify` commands must be safe, simple commands. Do not use shell pipes, redirects, semicolons, backticks, command substitution, output trimming, or grep regex alternation with `|`. If multiple checks are needed, create a small test file and run it with `node --test` or a package test script, or use separate simple commands joined only with `&&`.
|
|
46
|
+
8. Task `verify` commands must be safe, simple commands. Do not use shell pipes, redirects, semicolons, backticks, command substitution, output trimming, or grep regex alternation with `|`. If multiple checks are needed, create a small test file and run it with `node --test` or a package test script, or use separate simple commands joined only with `&&`. For absence checks, verify a pattern does not exist with `! grep -q 'pattern' file` or `! rg -q 'pattern' file`; do not use `grep -c` or `rg -c` to assert zero matches because count commands exit 1 when they find zero matches, and the verification gate treats that as failure.
|
|
47
47
|
9. Each task needs the exact `gsd_plan_slice.tasks[]` shape: `taskId`, `title`, `description`, `estimate`, `files`, `verify`, `inputs`, `expectedOutput`, and optional `observabilityImpact`. `description` should contain the Why / Do / Done-when narrative. `files`, `inputs`, and `expectedOutput` must be JSON arrays of strings, even when there is only one path (for example, `"inputs": ["src/index.ts"]`, never `"inputs": "src/index.ts"`). Use paths relative to `{{workingDirectory}}`; do not put absolute paths to the original checkout or any directory outside `{{workingDirectory}}` in `files`, `inputs`, `expectedOutput`, or verification commands. **`expectedOutput` must only list files the task actually creates or overwrites on disk.** Do NOT include files the task merely reads, verifies, or tests — those belong only in `inputs`. If a task is a pure verification or test task that produces no new files, `expectedOutput` may be `[]` or limited to test-result artifacts (e.g. a log or assertion output). A file that does not yet exist on disk and is needed as an `input` must be produced by an earlier task's `expectedOutput` — if no prior task creates it, add a task before this one that does.
|
|
48
48
|
10. Persist with `gsd_plan_slice` using `milestoneId`, `sliceId`, `goal`, optional `successCriteria`/`proofLevel`/`integrationClosure`/`observabilityImpact`, and `tasks`. `gsd_plan_slice` handles task persistence transactionally and renders `{{outputPath}}` plus task plans; do not call `gsd_plan_task`. The DB-backed tool is the canonical write path. Do **not** rely on direct `PLAN.md` writes as the source of truth.
|
|
49
49
|
11. Self-audit before finishing: goal/demo closure, requirement coverage, deliverable coverage audit (cross-check every file listed in CONTEXT.md `## Scope` / `### In Scope` against task `files` or `expectedOutput`), locked decisions, concrete paths, dependency order, wiring, scope size, proof truthfulness, feature completeness, and quality gates. Quality gates: non-trivial slices/tasks include specific Q3-Q7 coverage where applicable.
|