gsd-pi 2.82.0-dev.2841a1e44 → 2.82.0-dev.98ea09b1e
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/README.md +2 -2
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +7 -0
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
- package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
- package/dist/resources/extensions/gsd/auto/loop.js +5 -5
- package/dist/resources/extensions/gsd/auto/orchestrator.js +11 -0
- package/dist/resources/extensions/gsd/auto/phases.js +8 -1
- package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +13 -6
- package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +70 -9
- package/dist/resources/extensions/gsd/auto-recovery.js +31 -1
- package/dist/resources/extensions/gsd/auto-start.js +85 -12
- package/dist/resources/extensions/gsd/auto-worktree.js +111 -1
- package/dist/resources/extensions/gsd/auto.js +30 -3
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +4 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +9 -8
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +5 -2
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +13 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +17 -1
- package/dist/resources/extensions/gsd/crash-recovery.js +31 -5
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
- package/dist/resources/extensions/gsd/doctor.js +2 -28
- package/dist/resources/extensions/gsd/export-html.js +27 -425
- package/dist/resources/extensions/gsd/git-service.js +39 -1
- package/dist/resources/extensions/gsd/gsd-db.js +1 -0
- package/dist/resources/extensions/gsd/guided-flow.js +13 -6
- package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
- package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
- package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
- package/dist/resources/extensions/gsd/native-git-bridge.js +48 -12
- package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
- package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
- package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
- package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
- package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
- package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
- package/dist/resources/extensions/gsd/status-guards.js +4 -0
- package/dist/resources/extensions/gsd/templates/plan.md +8 -5
- package/dist/resources/extensions/gsd/templates/task-plan.md +4 -2
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
- package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
- package/dist/resources/extensions/gsd/tools/plan-slice.js +89 -14
- package/dist/resources/extensions/gsd/unit-context-manifest.js +7 -8
- package/dist/resources/extensions/gsd/validation.js +23 -1
- package/dist/resources/extensions/gsd/verification-gate.js +68 -7
- package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +33 -8
- package/dist/resources/extensions/shared/html-shell.js +388 -0
- package/dist/resources/extensions/visual-brief/page-contract.js +2 -0
- package/dist/resources/extensions/visual-brief/prompts.js +29 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- 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/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
- 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 +4 -5
- 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 +2 -5
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -7
- 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 +4 -7
- 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 +4 -5
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
- package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +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/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-6a95bc41e0f7ec89.js → webpack-9a4db269f9ed63ad.js} +1 -1
- package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
- package/package.json +2 -2
- package/packages/mcp-server/src/workflow-tools.test.ts +1 -1
- package/packages/native/tsconfig.json +2 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +82 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +52 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.d.ts +2 -4
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +5 -6
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/simple-options.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.test.js +50 -0
- package/packages/pi-ai/dist/providers/simple-options.test.js.map +1 -0
- package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
- package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
- package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
- package/packages/pi-ai/src/providers/simple-options.ts +5 -6
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/src/resources/GSD-WORKFLOW.md +7 -0
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
- package/src/resources/extensions/gsd/auto/contracts.ts +14 -6
- package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
- package/src/resources/extensions/gsd/auto/loop.ts +8 -5
- package/src/resources/extensions/gsd/auto/orchestrator.ts +11 -0
- package/src/resources/extensions/gsd/auto/phases.ts +7 -1
- package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +14 -6
- package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +77 -7
- package/src/resources/extensions/gsd/auto-recovery.ts +29 -0
- package/src/resources/extensions/gsd/auto-start.ts +92 -9
- package/src/resources/extensions/gsd/auto-worktree.ts +119 -1
- package/src/resources/extensions/gsd/auto.ts +32 -3
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +6 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +9 -8
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +3 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +16 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +17 -1
- package/src/resources/extensions/gsd/crash-recovery.ts +30 -4
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
- package/src/resources/extensions/gsd/doctor.ts +2 -27
- package/src/resources/extensions/gsd/export-html.ts +27 -427
- package/src/resources/extensions/gsd/git-service.ts +45 -1
- package/src/resources/extensions/gsd/gsd-db.ts +3 -0
- package/src/resources/extensions/gsd/guided-flow.ts +14 -7
- package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
- package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
- package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
- package/src/resources/extensions/gsd/native-git-bridge.ts +54 -12
- package/src/resources/extensions/gsd/post-execution-checks.ts +87 -2
- package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -1
- package/src/resources/extensions/gsd/prompt-loader.ts +1 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
- package/src/resources/extensions/gsd/prompts/discuss.md +9 -9
- package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -4
- package/src/resources/extensions/gsd/prompts/queue.md +4 -4
- package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
- package/src/resources/extensions/gsd/status-guards.ts +5 -0
- package/src/resources/extensions/gsd/templates/plan.md +8 -5
- package/src/resources/extensions/gsd/templates/task-plan.md +4 -2
- package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +80 -1
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +15 -1
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +43 -2
- package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +59 -2
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +103 -1
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +225 -1
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
- package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
- package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +46 -2
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +31 -1
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
- package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
- package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +65 -7
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +38 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
- package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
- package/src/resources/extensions/gsd/tools/plan-slice.ts +98 -12
- package/src/resources/extensions/gsd/types.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +12 -9
- package/src/resources/extensions/gsd/validation.ts +23 -1
- package/src/resources/extensions/gsd/verification-gate.ts +78 -6
- package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +41 -8
- package/src/resources/extensions/shared/html-shell.ts +412 -0
- package/src/resources/extensions/visual-brief/page-contract.ts +2 -0
- package/src/resources/extensions/visual-brief/prompts.ts +37 -1
- package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +40 -0
- package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
- package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
- package/dist/web/standalone/.next/static/css/0262768ec1b89d34.css +0 -1
- package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
- package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- /package/dist/web/standalone/.next/static/{Qgr2B_MRhPxC0z8fwv4vT → euQ0CLP_v8V4e76Tu3odJ}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Qgr2B_MRhPxC0z8fwv4vT → euQ0CLP_v8V4e76Tu3odJ}/_ssgManifest.js +0 -0
|
@@ -270,6 +270,30 @@ function isExcludedScopedPath(path: string, exclusions: readonly string[]): bool
|
|
|
270
270
|
return false;
|
|
271
271
|
}
|
|
272
272
|
|
|
273
|
+
function submodulePathsFromLsFiles(output: string): Set<string> {
|
|
274
|
+
const submodulePaths = new Set<string>();
|
|
275
|
+
if (!output) return submodulePaths;
|
|
276
|
+
|
|
277
|
+
for (const line of output.split("\n")) {
|
|
278
|
+
const match = line.match(/^160000\s+\S+\s+\d+\t(.+)$/);
|
|
279
|
+
if (!match) continue;
|
|
280
|
+
submodulePaths.add(match[1].replace(/\\/g, "/").replace(/\/+$/, ""));
|
|
281
|
+
}
|
|
282
|
+
return submodulePaths;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function isInsideSubmodule(path: string, submodulePaths: ReadonlySet<string>): boolean {
|
|
286
|
+
const normalizedPath = path.replace(/\\/g, "/");
|
|
287
|
+
if (submodulePaths.has(normalizedPath)) return true;
|
|
288
|
+
|
|
289
|
+
let slashIndex = normalizedPath.lastIndexOf("/");
|
|
290
|
+
while (slashIndex > 0) {
|
|
291
|
+
if (submodulePaths.has(normalizedPath.slice(0, slashIndex))) return true;
|
|
292
|
+
slashIndex = normalizedPath.lastIndexOf("/", slashIndex - 1);
|
|
293
|
+
}
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
|
|
273
297
|
/**
|
|
274
298
|
* Thrown when a slice merge hits code conflicts in non-.gsd files.
|
|
275
299
|
* The working tree is left in a conflicted state (no reset) so the
|
|
@@ -764,6 +788,26 @@ export class GitServiceImpl {
|
|
|
764
788
|
.filter(file => !nativeIsIgnored(this.basePath, file))
|
|
765
789
|
.filter(file => !isExcludedScopedPath(file, allExclusions));
|
|
766
790
|
|
|
791
|
+
const scopedPaths: string[] = [];
|
|
792
|
+
const submodulePaths: string[] = [];
|
|
793
|
+
const repoSubmodules = submodulePathsFromLsFiles(
|
|
794
|
+
runGit(this.basePath, ["ls-files", "--stage"], { allowFailure: true }),
|
|
795
|
+
);
|
|
796
|
+
for (const path of normalized) {
|
|
797
|
+
if (isInsideSubmodule(path, repoSubmodules)) {
|
|
798
|
+
submodulePaths.push(path);
|
|
799
|
+
} else {
|
|
800
|
+
scopedPaths.push(path);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
if (submodulePaths.length > 0) {
|
|
804
|
+
logWarning(
|
|
805
|
+
"engine",
|
|
806
|
+
`scoped stage: dropping ${submodulePaths.length} keyFile(s) inside git submodule(s): ${submodulePaths.join(", ")}`,
|
|
807
|
+
{ file: "git-service.ts" },
|
|
808
|
+
);
|
|
809
|
+
}
|
|
810
|
+
|
|
767
811
|
// Drop entries that don't exist on disk. The LLM occasionally lists files
|
|
768
812
|
// it intended to write but didn't (or names them with wrong casing/path).
|
|
769
813
|
// Pre-`b304f738b` `git add -A` swallowed these silently; the scoped
|
|
@@ -771,7 +815,7 @@ export class GitServiceImpl {
|
|
|
771
815
|
// the whole commit fail (see #5500). Filter so valid paths still commit.
|
|
772
816
|
const missing: string[] = [];
|
|
773
817
|
const existing: string[] = [];
|
|
774
|
-
for (const path of
|
|
818
|
+
for (const path of scopedPaths) {
|
|
775
819
|
if (existsSync(join(this.basePath, path))) {
|
|
776
820
|
existing.push(path);
|
|
777
821
|
} else {
|
|
@@ -2081,6 +2081,9 @@ export function deleteTask(milestoneId: string, sliceId: string, taskId: string)
|
|
|
2081
2081
|
currentDb!.prepare(
|
|
2082
2082
|
`DELETE FROM verification_evidence WHERE milestone_id = :mid AND slice_id = :sid AND task_id = :tid`,
|
|
2083
2083
|
).run({ ":mid": milestoneId, ":sid": sliceId, ":tid": taskId });
|
|
2084
|
+
currentDb!.prepare(
|
|
2085
|
+
`DELETE FROM quality_gates WHERE milestone_id = :mid AND slice_id = :sid AND task_id = :tid`,
|
|
2086
|
+
).run({ ":mid": milestoneId, ":sid": sliceId, ":tid": taskId });
|
|
2084
2087
|
currentDb!.prepare(
|
|
2085
2088
|
`DELETE FROM tasks WHERE milestone_id = :mid AND slice_id = :sid AND id = :tid`,
|
|
2086
2089
|
).run({ ":mid": milestoneId, ":sid": sliceId, ":tid": taskId });
|
|
@@ -1539,6 +1539,7 @@ export async function showDiscuss(
|
|
|
1539
1539
|
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
1540
1540
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
1541
1541
|
const basePrompt = loadPrompt("guided-discuss-milestone", {
|
|
1542
|
+
workingDirectory: basePath,
|
|
1542
1543
|
milestoneId: mid, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
|
|
1543
1544
|
commitInstruction: buildDocsCommitInstruction(`docs(${mid}): milestone context from discuss`),
|
|
1544
1545
|
fastPathInstruction: "",
|
|
@@ -1553,6 +1554,7 @@ export async function showDiscuss(
|
|
|
1553
1554
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
1554
1555
|
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: mid, step: false });
|
|
1555
1556
|
await dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
|
|
1557
|
+
workingDirectory: basePath,
|
|
1556
1558
|
milestoneId: mid, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
|
|
1557
1559
|
commitInstruction: buildDocsCommitInstruction(`docs(${mid}): milestone context from discuss`),
|
|
1558
1560
|
fastPathInstruction: "",
|
|
@@ -1822,6 +1824,7 @@ async function dispatchDiscussForMilestone(
|
|
|
1822
1824
|
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
1823
1825
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
1824
1826
|
const basePrompt = loadPrompt("guided-discuss-milestone", {
|
|
1827
|
+
workingDirectory: basePath,
|
|
1825
1828
|
milestoneId: mid,
|
|
1826
1829
|
milestoneTitle,
|
|
1827
1830
|
inlinedTemplates: discussMilestoneTemplates,
|
|
@@ -2121,18 +2124,19 @@ export async function showSmartEntry(
|
|
|
2121
2124
|
|
|
2122
2125
|
if (interrupted.classification !== "recoverable") {
|
|
2123
2126
|
try {
|
|
2124
|
-
const {
|
|
2125
|
-
const result = await
|
|
2126
|
-
if (result.action === "
|
|
2127
|
+
const { checkMarkdownHierarchyAgainstDb } = await import("./migration-auto-check.js");
|
|
2128
|
+
const result = await checkMarkdownHierarchyAgainstDb(basePath);
|
|
2129
|
+
if (result.action === "recovery-required") {
|
|
2127
2130
|
ctx.ui.notify(
|
|
2128
|
-
|
|
2129
|
-
|
|
2131
|
+
result.message ??
|
|
2132
|
+
`Markdown planning artifacts do not match the authoritative DB. Run \`${result.recoveryCommand ?? "gsd recover"}\` to import markdown explicitly.`,
|
|
2133
|
+
"warning",
|
|
2130
2134
|
);
|
|
2131
2135
|
}
|
|
2132
2136
|
} catch (err) {
|
|
2133
2137
|
const message = err instanceof Error ? err.message : String(err);
|
|
2134
|
-
ctx.ui.notify(`GSD could not
|
|
2135
|
-
logWarning("guided", `planning state
|
|
2138
|
+
ctx.ui.notify(`GSD could not compare markdown planning artifacts with gsd.db: ${message}`, "warning");
|
|
2139
|
+
logWarning("guided", `planning state DB/markdown comparison failed: ${message}`, { file: "guided-flow.ts" });
|
|
2136
2140
|
}
|
|
2137
2141
|
}
|
|
2138
2142
|
|
|
@@ -2356,6 +2360,7 @@ export async function showSmartEntry(
|
|
|
2356
2360
|
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
2357
2361
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
2358
2362
|
const basePrompt = loadPrompt("guided-discuss-milestone", {
|
|
2363
|
+
workingDirectory: basePath,
|
|
2359
2364
|
milestoneId, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
|
|
2360
2365
|
commitInstruction: buildDocsCommitInstruction(`docs(${milestoneId}): milestone context from discuss`),
|
|
2361
2366
|
fastPathInstruction: "",
|
|
@@ -2370,6 +2375,7 @@ export async function showSmartEntry(
|
|
|
2370
2375
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
2371
2376
|
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId, step: stepMode });
|
|
2372
2377
|
await dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
|
|
2378
|
+
workingDirectory: basePath,
|
|
2373
2379
|
milestoneId, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
|
|
2374
2380
|
commitInstruction: buildDocsCommitInstruction(`docs(${milestoneId}): milestone context from discuss`),
|
|
2375
2381
|
fastPathInstruction: "",
|
|
@@ -2462,6 +2468,7 @@ export async function showSmartEntry(
|
|
|
2462
2468
|
const discussMilestoneTemplates = inlineTemplate("context", "Context");
|
|
2463
2469
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
2464
2470
|
await dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
|
|
2471
|
+
workingDirectory: basePath,
|
|
2465
2472
|
milestoneId, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
|
|
2466
2473
|
commitInstruction: buildDocsCommitInstruction(`docs(${milestoneId}): milestone context from discuss`),
|
|
2467
2474
|
fastPathInstruction: "",
|
|
@@ -95,6 +95,17 @@ function parsePhaseEntry(line: string): PlanningRoadmapEntry | null {
|
|
|
95
95
|
};
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
// Format 3: - ✅ v1.0 MVP — Phases 1-6
|
|
99
|
+
const fmtVersionPhases = stripped.match(/^-\s+([✅🚧])\s+v\d+(?:\.\d+)*\s+(.+?)\s*[—–]\s*Phases?\s+(\d+(?:\.\d+)?)(?:\s*-\s*\d+(?:\.\d+)?)?(?:\s+\(.*\))?\s*$/iu);
|
|
100
|
+
if (fmtVersionPhases) {
|
|
101
|
+
return {
|
|
102
|
+
number: parseFloat(fmtVersionPhases[3]),
|
|
103
|
+
title: fmtVersionPhases[2].trim(),
|
|
104
|
+
done: fmtVersionPhases[1] === '✅',
|
|
105
|
+
raw: line,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
98
109
|
return null;
|
|
99
110
|
}
|
|
100
111
|
|
|
@@ -2,21 +2,17 @@ import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
|
2
2
|
|
|
3
3
|
import { ensureDbOpen } from "./bootstrap/dynamic-tools.js";
|
|
4
4
|
import {
|
|
5
|
-
clearEngineHierarchy,
|
|
6
5
|
getAllMilestones,
|
|
7
6
|
getMilestoneSlices,
|
|
8
7
|
getSliceTasks,
|
|
9
8
|
isDbAvailable,
|
|
10
|
-
transaction,
|
|
11
9
|
} from "./gsd-db.js";
|
|
12
|
-
import { migrateHierarchyToDb } from "./md-importer.js";
|
|
13
10
|
import { parsePlan, parseRoadmap } from "./parsers-legacy.js";
|
|
14
11
|
import {
|
|
15
12
|
milestonesDir,
|
|
16
13
|
resolveMilestoneFile,
|
|
17
14
|
resolveSliceFile,
|
|
18
15
|
} from "./paths.js";
|
|
19
|
-
import { invalidateStateCache } from "./state.js";
|
|
20
16
|
|
|
21
17
|
export interface HierarchyCounts {
|
|
22
18
|
milestones: number;
|
|
@@ -25,11 +21,13 @@ export interface HierarchyCounts {
|
|
|
25
21
|
}
|
|
26
22
|
|
|
27
23
|
export interface MigrationAutoCheckResult {
|
|
28
|
-
action: "none" | "
|
|
24
|
+
action: "none" | "recovery-required";
|
|
29
25
|
reason: "no-markdown" | "in-sync" | "db-empty" | "count-mismatch";
|
|
30
26
|
markdown: HierarchyCounts;
|
|
31
27
|
beforeDb: HierarchyCounts;
|
|
32
28
|
afterDb: HierarchyCounts;
|
|
29
|
+
recoveryCommand?: string;
|
|
30
|
+
message?: string;
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
function zeroCounts(): HierarchyCounts {
|
|
@@ -83,7 +81,7 @@ export function countDbHierarchy(): HierarchyCounts {
|
|
|
83
81
|
return counts;
|
|
84
82
|
}
|
|
85
83
|
|
|
86
|
-
export async function
|
|
84
|
+
export async function checkMarkdownHierarchyAgainstDb(
|
|
87
85
|
basePath: string,
|
|
88
86
|
): Promise<MigrationAutoCheckResult> {
|
|
89
87
|
const markdown = countMarkdownHierarchy(basePath);
|
|
@@ -108,22 +106,16 @@ export async function autoImportMarkdownHierarchyIfDbMismatch(
|
|
|
108
106
|
}
|
|
109
107
|
|
|
110
108
|
const reason = sameCounts(beforeDb, zeroCounts()) ? "db-empty" : "count-mismatch";
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
109
|
+
return {
|
|
110
|
+
action: "recovery-required",
|
|
111
|
+
reason,
|
|
112
|
+
markdown,
|
|
113
|
+
beforeDb,
|
|
114
|
+
afterDb: beforeDb,
|
|
115
|
+
recoveryCommand: "gsd recover",
|
|
116
|
+
message:
|
|
117
|
+
`Markdown planning artifacts (${markdown.milestones}M/${markdown.slices}S/${markdown.tasks}T) ` +
|
|
118
|
+
`do not match the authoritative DB (${beforeDb.milestones}M/${beforeDb.slices}S/${beforeDb.tasks}T). ` +
|
|
119
|
+
"Runtime startup will not import markdown automatically; run explicit GSD recovery if markdown should repopulate the database.",
|
|
121
120
|
};
|
|
122
|
-
if (!sameCounts(markdown, afterDb)) {
|
|
123
|
-
throw new Error(
|
|
124
|
-
`migration auto-import verification failed: markdown ${markdown.milestones}M/${markdown.slices}S/${markdown.tasks}T, db ${afterDb.milestones}M/${afterDb.slices}S/${afterDb.tasks}T`,
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return { action: "imported", reason, markdown, beforeDb, afterDb };
|
|
129
121
|
}
|
|
@@ -24,6 +24,7 @@ import { deleteMilestone, getMilestone, isDbAvailable, updateMilestoneStatus } f
|
|
|
24
24
|
import { removeWorktree } from "./worktree-manager.js";
|
|
25
25
|
import { logWarning } from "./workflow-logger.js";
|
|
26
26
|
import { isAutoActive } from "./auto.js";
|
|
27
|
+
import { isClosedStatus } from "./status-guards.js";
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* Writer-side assert for mutations that race with auto-mode's squash merge (#4704).
|
|
@@ -44,7 +45,7 @@ function assertNotAutoActive(action: string): void {
|
|
|
44
45
|
/**
|
|
45
46
|
* Park a milestone — creates a PARKED.md marker file with reason and timestamp.
|
|
46
47
|
* Parked milestones are skipped during active-milestone discovery but stay on disk.
|
|
47
|
-
* Returns true if successfully parked, false if milestone not found
|
|
48
|
+
* Returns true if successfully parked, false if milestone not found, already parked, or complete.
|
|
48
49
|
*/
|
|
49
50
|
export function parkMilestone(basePath: string, milestoneId: string, reason: string): boolean {
|
|
50
51
|
assertNotAutoActive("park milestone");
|
|
@@ -52,8 +53,13 @@ export function parkMilestone(basePath: string, milestoneId: string, reason: str
|
|
|
52
53
|
if (!mDir || !existsSync(mDir)) return false;
|
|
53
54
|
|
|
54
55
|
// Guard: do not park a completed milestone — it would corrupt depends_on satisfaction
|
|
55
|
-
const
|
|
56
|
-
|
|
56
|
+
const dbAvailable = isDbAvailable();
|
|
57
|
+
const milestone = dbAvailable ? getMilestone(milestoneId) : null;
|
|
58
|
+
if (milestone && isClosedStatus(milestone.status)) return false;
|
|
59
|
+
if (!dbAvailable) {
|
|
60
|
+
const summaryFile = resolveMilestoneFile(basePath, milestoneId, "SUMMARY");
|
|
61
|
+
if (summaryFile) return false;
|
|
62
|
+
}
|
|
57
63
|
|
|
58
64
|
const parkedPath = join(mDir, buildMilestoneFileName(milestoneId, "PARKED"));
|
|
59
65
|
if (existsSync(parkedPath)) return false; // already parked
|
|
@@ -72,7 +78,7 @@ export function parkMilestone(basePath: string, milestoneId: string, reason: str
|
|
|
72
78
|
|
|
73
79
|
writeFileSync(parkedPath, content, "utf-8");
|
|
74
80
|
// Sync DB status so deriveStateFromDb also skips this milestone (#2694)
|
|
75
|
-
if (
|
|
81
|
+
if (dbAvailable) {
|
|
76
82
|
try {
|
|
77
83
|
updateMilestoneStatus(milestoneId, "parked");
|
|
78
84
|
} catch (err) {
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// execSync calls because git2 credential handling is too complex.
|
|
7
7
|
|
|
8
8
|
import { execSync, execFileSync } from "node:child_process";
|
|
9
|
+
import type { ExecFileSyncOptionsWithStringEncoding } from "node:child_process";
|
|
9
10
|
import { existsSync, readFileSync, unlinkSync, rmSync, writeFileSync } from "node:fs";
|
|
10
11
|
import { join } from "node:path";
|
|
11
12
|
import { GSDError, GSD_GIT_ERROR } from "./errors.js";
|
|
@@ -16,6 +17,8 @@ import { isInfrastructureError } from "./auto/infra-errors.js";
|
|
|
16
17
|
// Issue #453: keep auto-mode bookkeeping on the stable git CLI path unless a
|
|
17
18
|
// caller explicitly opts into the native helper.
|
|
18
19
|
const NATIVE_GSD_GIT_ENABLED = process.env.GSD_ENABLE_NATIVE_GSD_GIT === "1";
|
|
20
|
+
const TRANSIENT_GIT_RETRY_CODES = new Set(["ENOBUFS", "EAGAIN"]);
|
|
21
|
+
const GIT_RETRY_DELAY_MS = 200;
|
|
19
22
|
|
|
20
23
|
// ─── Native Module Types ──────────────────────────────────────────────────
|
|
21
24
|
|
|
@@ -144,9 +147,46 @@ function gitExec(basePath: string, args: string[], allowFailure = false): string
|
|
|
144
147
|
encoding: "utf-8",
|
|
145
148
|
env: GIT_NO_PROMPT_ENV,
|
|
146
149
|
}).trim();
|
|
147
|
-
} catch {
|
|
150
|
+
} catch (err) {
|
|
148
151
|
if (allowFailure) return "";
|
|
149
|
-
throw new GSDError(GSD_GIT_ERROR, `git ${args.join(" ")} failed in ${basePath}`);
|
|
152
|
+
throw new GSDError(GSD_GIT_ERROR, `git ${args.join(" ")} failed in ${basePath}: ${getErrorMessage(err)}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** sleepSync uses Atomics.wait for a blocking pause without busy-waiting; it blocks the current thread and requires Atomics.wait support. */
|
|
157
|
+
function sleepSync(ms: number): void {
|
|
158
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function isRetryableGitError(err: unknown): boolean {
|
|
162
|
+
const code = isInfrastructureError(err)
|
|
163
|
+
?? isInfrastructureError((err as { stderr?: string })?.stderr ?? "");
|
|
164
|
+
return code !== null && TRANSIENT_GIT_RETRY_CODES.has(code);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function execGitFileSyncWithRetry(
|
|
168
|
+
basePath: string,
|
|
169
|
+
args: string[],
|
|
170
|
+
options: Partial<ExecFileSyncOptionsWithStringEncoding>,
|
|
171
|
+
): string {
|
|
172
|
+
try {
|
|
173
|
+
return execFileSync("git", args, {
|
|
174
|
+
cwd: basePath,
|
|
175
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
176
|
+
encoding: "utf-8",
|
|
177
|
+
env: GIT_NO_PROMPT_ENV,
|
|
178
|
+
...options,
|
|
179
|
+
}).trim();
|
|
180
|
+
} catch (err) {
|
|
181
|
+
if (!isRetryableGitError(err)) throw err;
|
|
182
|
+
sleepSync(GIT_RETRY_DELAY_MS);
|
|
183
|
+
return execFileSync("git", args, {
|
|
184
|
+
cwd: basePath,
|
|
185
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
186
|
+
encoding: "utf-8",
|
|
187
|
+
env: GIT_NO_PROMPT_ENV,
|
|
188
|
+
...options,
|
|
189
|
+
}).trim();
|
|
150
190
|
}
|
|
151
191
|
}
|
|
152
192
|
|
|
@@ -159,9 +199,9 @@ function gitFileExec(basePath: string, args: string[], allowFailure = false): st
|
|
|
159
199
|
encoding: "utf-8",
|
|
160
200
|
env: GIT_NO_PROMPT_ENV,
|
|
161
201
|
}).trim();
|
|
162
|
-
} catch {
|
|
202
|
+
} catch (err) {
|
|
163
203
|
if (allowFailure) return "";
|
|
164
|
-
throw new GSDError(GSD_GIT_ERROR, `git ${args.join(" ")} failed in ${basePath}`);
|
|
204
|
+
throw new GSDError(GSD_GIT_ERROR, `git ${args.join(" ")} failed in ${basePath}: ${getErrorMessage(err)}`);
|
|
165
205
|
}
|
|
166
206
|
}
|
|
167
207
|
|
|
@@ -428,16 +468,21 @@ export function nativeDiffNameStatus(
|
|
|
428
468
|
|
|
429
469
|
/**
|
|
430
470
|
* Get numstat diff between two refs.
|
|
471
|
+
* useMergeBase: if true, uses three-dot semantics.
|
|
431
472
|
* Native: libgit2 patch line stats.
|
|
432
473
|
* Fallback: `git diff --numstat`.
|
|
433
474
|
*/
|
|
434
|
-
export function nativeDiffNumstat(basePath: string, fromRef: string, toRef: string): GitNumstat[] {
|
|
475
|
+
export function nativeDiffNumstat(basePath: string, fromRef: string, toRef: string, useMergeBase?: boolean): GitNumstat[] {
|
|
435
476
|
const native = loadNative();
|
|
436
|
-
if (native) {
|
|
477
|
+
if (native && !useMergeBase) {
|
|
437
478
|
return native.gitDiffNumstat(basePath, fromRef, toRef);
|
|
438
479
|
}
|
|
439
480
|
|
|
440
|
-
const
|
|
481
|
+
const refspec = useMergeBase ? `${fromRef}...${toRef}` : undefined;
|
|
482
|
+
const args = refspec
|
|
483
|
+
? ["diff", "--numstat", refspec]
|
|
484
|
+
: ["diff", "--numstat", fromRef, toRef];
|
|
485
|
+
const result = gitExec(basePath, args, true);
|
|
441
486
|
if (!result) return [];
|
|
442
487
|
|
|
443
488
|
return result.split("\n").filter(Boolean).map(line => {
|
|
@@ -935,13 +980,10 @@ export function nativeCommit(
|
|
|
935
980
|
try {
|
|
936
981
|
const args = ["commit", "-F", "-"];
|
|
937
982
|
if (options?.allowEmpty) args.push("--allow-empty");
|
|
938
|
-
const result =
|
|
939
|
-
cwd: basePath,
|
|
983
|
+
const result = execGitFileSyncWithRetry(basePath, args, {
|
|
940
984
|
stdio: ["pipe", "pipe", "pipe"],
|
|
941
|
-
encoding: "utf-8",
|
|
942
|
-
env: GIT_NO_PROMPT_ENV,
|
|
943
985
|
input: message,
|
|
944
|
-
})
|
|
986
|
+
});
|
|
945
987
|
return result;
|
|
946
988
|
} catch (err: unknown) {
|
|
947
989
|
const errObj = err as { stdout?: string; stderr?: string; message?: string };
|
|
@@ -46,6 +46,46 @@ export interface PostExecutionResult {
|
|
|
46
46
|
|
|
47
47
|
// ─── Import Resolution Check ─────────────────────────────────────────────────
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Replace the contents of single- and double-quoted string literals on a single
|
|
51
|
+
* source line with spaces so import patterns do not match text inside strings.
|
|
52
|
+
* Template-literal spans are handled separately via the inTemplateLiteral flag.
|
|
53
|
+
*/
|
|
54
|
+
function stripStringLiterals(line: string): string {
|
|
55
|
+
let result = "";
|
|
56
|
+
let i = 0;
|
|
57
|
+
|
|
58
|
+
while (i < line.length) {
|
|
59
|
+
const ch = line[i];
|
|
60
|
+
|
|
61
|
+
if (ch === '"' || ch === "'") {
|
|
62
|
+
result += ch;
|
|
63
|
+
i++;
|
|
64
|
+
|
|
65
|
+
while (i < line.length) {
|
|
66
|
+
const c = line[i];
|
|
67
|
+
|
|
68
|
+
if (c === "\\" && i + 1 < line.length) {
|
|
69
|
+
result += " ";
|
|
70
|
+
i += 2;
|
|
71
|
+
} else if (c === ch) {
|
|
72
|
+
result += ch;
|
|
73
|
+
i++;
|
|
74
|
+
break;
|
|
75
|
+
} else {
|
|
76
|
+
result += " ";
|
|
77
|
+
i++;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
result += ch;
|
|
82
|
+
i++;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
|
|
49
89
|
/**
|
|
50
90
|
* Extract relative import paths from TypeScript/JavaScript source code.
|
|
51
91
|
* Returns array of { importPath, lineNum } for relative imports.
|
|
@@ -62,14 +102,23 @@ export function extractRelativeImports(
|
|
|
62
102
|
// import './path'
|
|
63
103
|
// require('./path')
|
|
64
104
|
// require("../path")
|
|
65
|
-
const importPattern = /(
|
|
105
|
+
const importPattern = /(?:^|[;{}]\s*)import\s+(?:.*?\s+from\s+)?(['"])(\.\.?\/[^'"]+)\1/g;
|
|
106
|
+
const requirePattern = /require\s*\(\s*(['"])(\.\.?\/[^'"]+)\1/g;
|
|
66
107
|
|
|
67
108
|
// Track if we're inside a block comment
|
|
68
109
|
let inBlockComment = false;
|
|
110
|
+
let inTemplateLiteral = false;
|
|
69
111
|
|
|
70
112
|
for (let i = 0; i < lines.length; i++) {
|
|
71
113
|
const line = lines[i];
|
|
72
114
|
|
|
115
|
+
if (inTemplateLiteral) {
|
|
116
|
+
if ((line.match(/(?<!\\)`/g) ?? []).length % 2 === 1) {
|
|
117
|
+
inTemplateLiteral = false;
|
|
118
|
+
}
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
|
|
73
122
|
// Handle block comment boundaries
|
|
74
123
|
if (inBlockComment) {
|
|
75
124
|
if (line.includes("*/")) {
|
|
@@ -101,10 +150,22 @@ export function extractRelativeImports(
|
|
|
101
150
|
|
|
102
151
|
// Reset lastIndex for each line
|
|
103
152
|
importPattern.lastIndex = 0;
|
|
153
|
+
requirePattern.lastIndex = 0;
|
|
154
|
+
|
|
155
|
+
const strippedLine = stripStringLiterals(line);
|
|
104
156
|
|
|
105
157
|
while ((match = importPattern.exec(line)) !== null) {
|
|
158
|
+
const importOffset = match[0].indexOf("import");
|
|
159
|
+
const importStart = match.index + importOffset;
|
|
160
|
+
if (
|
|
161
|
+
strippedLine.slice(importStart, importStart + "import".length) !==
|
|
162
|
+
"import"
|
|
163
|
+
) {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
|
|
106
167
|
// Check if this match is after a // comment marker on the same line
|
|
107
|
-
const beforeMatch =
|
|
168
|
+
const beforeMatch = strippedLine.substring(0, match.index);
|
|
108
169
|
if (beforeMatch.includes("//")) {
|
|
109
170
|
continue;
|
|
110
171
|
}
|
|
@@ -114,6 +175,30 @@ export function extractRelativeImports(
|
|
|
114
175
|
lineNum: i + 1,
|
|
115
176
|
});
|
|
116
177
|
}
|
|
178
|
+
|
|
179
|
+
while ((match = requirePattern.exec(line)) !== null) {
|
|
180
|
+
if (
|
|
181
|
+
strippedLine.slice(match.index, match.index + "require".length) !==
|
|
182
|
+
"require"
|
|
183
|
+
) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Check if this match is after a // comment marker on the same line
|
|
188
|
+
const beforeMatch = strippedLine.substring(0, match.index);
|
|
189
|
+
if (beforeMatch.includes("//")) {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
imports.push({
|
|
194
|
+
importPath: match[2],
|
|
195
|
+
lineNum: i + 1,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if ((strippedLine.match(/(?<!\\)`/g) ?? []).length % 2 === 1) {
|
|
200
|
+
inTemplateLiteral = true;
|
|
201
|
+
}
|
|
117
202
|
}
|
|
118
203
|
|
|
119
204
|
return imports;
|
|
@@ -23,6 +23,7 @@ import { homedir } from "node:os";
|
|
|
23
23
|
import { resolve } from "node:path";
|
|
24
24
|
import type { TaskRow } from "./db-task-slice-rows.js";
|
|
25
25
|
import type { PreExecutionCheckJSON } from "./verification-evidence.ts";
|
|
26
|
+
import { validateVerificationCommand } from "./verification-gate.js";
|
|
26
27
|
|
|
27
28
|
const NPM_COMMAND = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
28
29
|
|
|
@@ -37,6 +38,35 @@ export interface PreExecutionResult {
|
|
|
37
38
|
durationMs: number;
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
export function checkVerificationCommands(tasks: TaskRow[]): PreExecutionCheckJSON[] {
|
|
42
|
+
const results: PreExecutionCheckJSON[] = [];
|
|
43
|
+
|
|
44
|
+
for (const task of tasks) {
|
|
45
|
+
const verify = task.verify.trim();
|
|
46
|
+
if (!verify) continue;
|
|
47
|
+
|
|
48
|
+
const commands = verify
|
|
49
|
+
.split("&&")
|
|
50
|
+
.map((command) => command.trim())
|
|
51
|
+
.filter(Boolean);
|
|
52
|
+
|
|
53
|
+
for (const command of commands) {
|
|
54
|
+
const validation = validateVerificationCommand(command);
|
|
55
|
+
if (!validation.ok) {
|
|
56
|
+
results.push({
|
|
57
|
+
category: "tool",
|
|
58
|
+
target: `${task.id} Verify`,
|
|
59
|
+
passed: false,
|
|
60
|
+
message: `Unsafe or non-runnable Verify command: ${command} (${validation.reason})`,
|
|
61
|
+
blocking: true,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return results;
|
|
68
|
+
}
|
|
69
|
+
|
|
40
70
|
// ─── Package Existence Check ─────────────────────────────────────────────────
|
|
41
71
|
|
|
42
72
|
/**
|
|
@@ -757,8 +787,9 @@ export async function runPreExecutionChecks(
|
|
|
757
787
|
const fileChecks = checkFilePathConsistency(tasks, basePath);
|
|
758
788
|
const orderingChecks = checkTaskOrdering(tasks, basePath);
|
|
759
789
|
const contractChecks = checkInterfaceContracts(tasks, basePath);
|
|
790
|
+
const verificationChecks = checkVerificationCommands(tasks);
|
|
760
791
|
|
|
761
|
-
allChecks.push(...fileChecks, ...orderingChecks, ...contractChecks);
|
|
792
|
+
allChecks.push(...fileChecks, ...orderingChecks, ...contractChecks, ...verificationChecks);
|
|
762
793
|
|
|
763
794
|
// Run async package checks
|
|
764
795
|
const packageChecks = await checkPackageExistence(tasks, basePath);
|
|
@@ -200,7 +200,7 @@ export function loadPrompt(name: string, vars: Record<string, string> = {}): str
|
|
|
200
200
|
if (missing.length > 0) {
|
|
201
201
|
throw new GSDError(
|
|
202
202
|
GSD_PARSE_ERROR,
|
|
203
|
-
`loadPrompt("${name}"): template declares {{${missing.join("}}, {{")}}}
|
|
203
|
+
`loadPrompt("${name}"): template declares {{${missing.join("}}, {{")}}} but no value was provided. ` +
|
|
204
204
|
`This usually means the extension code in memory is older than the template on disk. ` +
|
|
205
205
|
`Restart pi to reload the extension.`,
|
|
206
206
|
);
|
|
@@ -57,7 +57,7 @@ Subagents report only; they do not write user source. Fold any findings into Dec
|
|
|
57
57
|
**Success path** (all verifications passed):
|
|
58
58
|
|
|
59
59
|
10. For each requirement whose status changed in step 9, call `gsd_requirement_update` with the requirement ID and updated `status` and `validation` fields — the tool regenerates `.gsd/REQUIREMENTS.md` automatically. Do this BEFORE completing the milestone so requirement updates are persisted.
|
|
60
|
-
11.
|
|
60
|
+
11. Refresh the project state through `gsd_summary_save` with `artifact_type: "PROJECT"` and the full updated project markdown as `content`; omit `milestone_id`. The tool persists the DB-backed PROJECT artifact and renders `.gsd/PROJECT.md`. Do not write or edit `.gsd/PROJECT.md` directly.
|
|
61
61
|
12. Extract structured learnings from this milestone and persist them to the GSD memory store. Follow the procedure block immediately below — it writes `{{milestoneId}}-LEARNINGS.md` as the audit trail and persists Patterns, Lessons, and Decisions via `capture_thought` (categories: pattern, gotcha/convention, architecture). The memory store is the single source of truth for cross-session durable knowledge (ADR-013).
|
|
62
62
|
|
|
63
63
|
{{extractLearningsSteps}}
|
|
@@ -34,7 +34,7 @@ Use `subagent` only for fresh-context review when useful: reviewer for cross-cut
|
|
|
34
34
|
12. Review the inlined task-summary excerpts for DECISIONS.md and KNOWLEDGE.md-worthy decisions, patterns, and gotchas. Read full `*-SUMMARY.md` files only when an excerpt is absent, truncated, or lacks the specific evidence needed for the slice narrative. Capture significant items with `capture_thought`; do not append knowledge files directly.
|
|
35
35
|
13. When verification passes, call `gsd_slice_complete`. The DB-backed tool is the canonical write path. Do **not** manually write `{{sliceSummaryPath}}`. Do **not** manually write `{{sliceUatPath}}`. Do not edit roadmap checkboxes; the tool renders files and updates projections.
|
|
36
36
|
14. Do not run git commands.
|
|
37
|
-
15.
|
|
37
|
+
15. If the current project state needs refresh, call `gsd_summary_save` with `artifact_type: "PROJECT"` and the full updated project markdown as `content`; omit `milestone_id`. Do not write or edit `.gsd/PROJECT.md` directly.
|
|
38
38
|
|
|
39
39
|
**Autonomous execution:** no human is available. Do not call `ask_user_questions` or `secure_env_collect`; make reasonable assumptions and document them.
|
|
40
40
|
|