gsd-pi 2.80.0-dev.c5c38454b → 2.80.0-dev.cf9433f56
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 +4 -2
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +2 -2
- package/dist/resources/extensions/gsd/auto/loop.js +32 -1
- package/dist/resources/extensions/gsd/auto/phases.js +66 -45
- package/dist/resources/extensions/gsd/auto/resolve.js +17 -0
- package/dist/resources/extensions/gsd/auto/run-unit.js +13 -1
- package/dist/resources/extensions/gsd/auto-post-unit.js +10 -10
- package/dist/resources/extensions/gsd/auto-prompts.js +124 -2
- package/dist/resources/extensions/gsd/auto-recovery.js +43 -1
- package/dist/resources/extensions/gsd/auto-supervisor.js +8 -1
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +2 -2
- package/dist/resources/extensions/gsd/auto.js +77 -5
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +21 -2
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +27 -20
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +21 -0
- package/dist/resources/extensions/gsd/clean-root-preflight.js +42 -4
- package/dist/resources/extensions/gsd/commands/dispatcher.js +5 -0
- package/dist/resources/extensions/gsd/context-budget.js +37 -2
- package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +39 -0
- package/dist/resources/extensions/gsd/db-base-schema.js +4 -2
- package/dist/resources/extensions/gsd/db-migration-steps.js +6 -0
- package/dist/resources/extensions/gsd/detection.js +106 -0
- package/dist/resources/extensions/gsd/git-service.js +36 -4
- package/dist/resources/extensions/gsd/gsd-db.js +46 -13
- package/dist/resources/extensions/gsd/guided-flow.js +80 -14
- package/dist/resources/extensions/gsd/memory-store.js +69 -12
- package/dist/resources/extensions/gsd/migrate/command.js +40 -1
- package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
- package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
- package/dist/resources/extensions/gsd/pre-execution-checks.js +7 -0
- package/dist/resources/extensions/gsd/prompt-loader.js +28 -2
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +19 -19
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
- package/dist/resources/extensions/gsd/quick.js +34 -2
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +10 -2
- package/dist/resources/extensions/gsd/tools/context-mode-tool-result.js +15 -0
- package/dist/resources/extensions/gsd/tools/exec-search-tool.js +5 -0
- package/dist/resources/extensions/gsd/tools/exec-tool.js +3 -15
- package/dist/resources/extensions/gsd/tools/memory-tools.js +1 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
- package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
- package/dist/resources/extensions/gsd/tools/resume-tool.js +5 -0
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +1 -1
- package/dist/resources/extensions/gsd/unit-context-composer.js +12 -3
- package/dist/resources/extensions/gsd/unit-runtime.js +22 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +16 -14
- package/dist/resources/extensions/gsd/worktree-resolver.js +33 -17
- 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 +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/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/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 +3 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +22 -17
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/workflow-tools.test.ts +75 -2
- package/packages/mcp-server/src/workflow-tools.ts +30 -16
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +32 -0
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +8 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +32 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +3 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +7 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +25 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +15 -5
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +53 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +10 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +36 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +8 -0
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +38 -0
- package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
- package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
- package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
- package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +2 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +3 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +7 -0
- package/packages/pi-coding-agent/src/core/settings-manager.ts +39 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +4 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +56 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +24 -7
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +3 -0
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +14 -0
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +18 -8
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/tui.ts +20 -8
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/src/resources/GSD-WORKFLOW.md +2 -2
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/loop.ts +50 -8
- package/src/resources/extensions/gsd/auto/phases.ts +77 -48
- package/src/resources/extensions/gsd/auto/resolve.ts +23 -1
- package/src/resources/extensions/gsd/auto/run-unit.ts +18 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +10 -10
- package/src/resources/extensions/gsd/auto-prompts.ts +133 -2
- package/src/resources/extensions/gsd/auto-recovery.ts +54 -0
- package/src/resources/extensions/gsd/auto-supervisor.ts +7 -0
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +2 -2
- package/src/resources/extensions/gsd/auto.ts +92 -4
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +21 -1
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +27 -19
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +22 -0
- package/src/resources/extensions/gsd/clean-root-preflight.ts +41 -3
- package/src/resources/extensions/gsd/commands/dispatcher.ts +6 -0
- package/src/resources/extensions/gsd/context-budget.ts +44 -2
- package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +41 -0
- package/src/resources/extensions/gsd/db-base-schema.ts +4 -2
- package/src/resources/extensions/gsd/db-migration-steps.ts +8 -0
- package/src/resources/extensions/gsd/detection.ts +128 -0
- package/src/resources/extensions/gsd/git-service.ts +46 -8
- package/src/resources/extensions/gsd/gsd-db.ts +50 -13
- package/src/resources/extensions/gsd/guided-flow.ts +96 -14
- package/src/resources/extensions/gsd/memory-store.ts +77 -12
- package/src/resources/extensions/gsd/migrate/command.ts +47 -1
- package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
- package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
- package/src/resources/extensions/gsd/pre-execution-checks.ts +7 -0
- package/src/resources/extensions/gsd/preferences-types.ts +1 -1
- package/src/resources/extensions/gsd/prompt-loader.ts +27 -2
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +19 -19
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
- package/src/resources/extensions/gsd/quick.ts +37 -2
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -2
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +72 -1
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +56 -13
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +14 -1
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +88 -2
- package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +14 -1
- package/src/resources/extensions/gsd/tests/context-budget.test.ts +10 -1
- package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/detection.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +313 -0
- package/src/resources/extensions/gsd/tests/exec-history.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +234 -0
- package/src/resources/extensions/gsd/tests/memory-decay-factor.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/right-sized-workflow-prompts.test.ts +192 -0
- package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +156 -0
- package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -1
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +101 -2
- package/src/resources/extensions/gsd/tests/status-db-open.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +136 -4
- package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +37 -6
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +9 -2
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +63 -1
- package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
- package/src/resources/extensions/gsd/tools/exec-search-tool.ts +7 -7
- package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -23
- package/src/resources/extensions/gsd/tools/memory-tools.ts +1 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
- package/src/resources/extensions/gsd/tools/resume-tool.ts +7 -7
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-composer.ts +19 -4
- package/src/resources/extensions/gsd/unit-runtime.ts +25 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +15 -4
- package/src/resources/extensions/gsd/worktree-resolver.ts +36 -15
- /package/dist/web/standalone/.next/static/{TCSim36ZpcPu2WgeoC45g → -5nHJWzSdG-WkPMul_khA}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{TCSim36ZpcPu2WgeoC45g → -5nHJWzSdG-WkPMul_khA}/_ssgManifest.js +0 -0
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* flow to show when entering a project directory.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { execFileSync } from "node:child_process";
|
|
9
10
|
import { existsSync, openSync, readSync, closeSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
10
11
|
import { dirname, join, parse as parsePath } from "node:path";
|
|
11
12
|
import { homedir } from "node:os";
|
|
@@ -72,6 +73,22 @@ export interface ProjectSignals {
|
|
|
72
73
|
verificationCommands: string[];
|
|
73
74
|
}
|
|
74
75
|
|
|
76
|
+
export type ProjectClassificationKind =
|
|
77
|
+
| "invalid-repo"
|
|
78
|
+
| "greenfield"
|
|
79
|
+
| "untyped-existing"
|
|
80
|
+
| "typed-existing";
|
|
81
|
+
|
|
82
|
+
export interface ProjectClassification {
|
|
83
|
+
kind: ProjectClassificationKind;
|
|
84
|
+
signals: ProjectSignals;
|
|
85
|
+
trackedFiles: string[];
|
|
86
|
+
untrackedFiles: string[];
|
|
87
|
+
contentFiles: string[];
|
|
88
|
+
markers: string[];
|
|
89
|
+
reason: string;
|
|
90
|
+
}
|
|
91
|
+
|
|
75
92
|
// ─── Project File Markers ───────────────────────────────────────────────────────
|
|
76
93
|
|
|
77
94
|
export const PROJECT_FILES = [
|
|
@@ -243,6 +260,7 @@ const TEST_MARKERS = [
|
|
|
243
260
|
const RECURSIVE_SCAN_IGNORED_DIRS = new Set([
|
|
244
261
|
".git",
|
|
245
262
|
".gsd",
|
|
263
|
+
".bg-shell",
|
|
246
264
|
".planning",
|
|
247
265
|
".plans",
|
|
248
266
|
".claude",
|
|
@@ -267,6 +285,8 @@ const RECURSIVE_SCAN_IGNORED_DIRS = new Set([
|
|
|
267
285
|
"out",
|
|
268
286
|
]) as ReadonlySet<string>;
|
|
269
287
|
|
|
288
|
+
const PROJECT_CONTENT_EXCLUDE_DIRS = RECURSIVE_SCAN_IGNORED_DIRS;
|
|
289
|
+
|
|
270
290
|
/** Project file markers safe to detect recursively via suffix matching. */
|
|
271
291
|
const ROOT_ONLY_PROJECT_FILES = new Set<string>([
|
|
272
292
|
".github/workflows",
|
|
@@ -536,6 +556,114 @@ export function detectProjectSignals(basePath: string): ProjectSignals {
|
|
|
536
556
|
};
|
|
537
557
|
}
|
|
538
558
|
|
|
559
|
+
function normalizeGitPath(file: string): string {
|
|
560
|
+
return file.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
function isProjectContentFile(file: string): boolean {
|
|
564
|
+
const normalized = normalizeGitPath(file);
|
|
565
|
+
if (!normalized || normalized.endsWith("/")) return false;
|
|
566
|
+
if (normalized === ".gitignore" || normalized === ".gitattributes") return false;
|
|
567
|
+
const parts = normalized.split("/");
|
|
568
|
+
if (parts.some((part) => PROJECT_CONTENT_EXCLUDE_DIRS.has(part))) return false;
|
|
569
|
+
if (normalized.endsWith(".DS_Store")) return false;
|
|
570
|
+
return true;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
function runGitLines(basePath: string, args: string[]): string[] {
|
|
574
|
+
try {
|
|
575
|
+
const output = execFileSync("git", args, {
|
|
576
|
+
cwd: basePath,
|
|
577
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
578
|
+
encoding: "utf-8",
|
|
579
|
+
}).trim();
|
|
580
|
+
return output ? output.split("\n").map((line) => line.trim()).filter(Boolean) : [];
|
|
581
|
+
} catch {
|
|
582
|
+
return [];
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
function listTrackedProjectFiles(basePath: string): string[] {
|
|
587
|
+
return runGitLines(basePath, ["ls-files"])
|
|
588
|
+
.map(normalizeGitPath)
|
|
589
|
+
.filter(isProjectContentFile);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
function listUntrackedProjectFiles(basePath: string): string[] {
|
|
593
|
+
return runGitLines(basePath, ["ls-files", "--others", "--exclude-standard"])
|
|
594
|
+
.map(normalizeGitPath)
|
|
595
|
+
.filter(isProjectContentFile);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
function hasKnownProjectMarkers(basePath: string, signals: ProjectSignals): boolean {
|
|
599
|
+
if (signals.detectedFiles.length > 0) return true;
|
|
600
|
+
if (signals.xcodePlatforms.length > 0) return true;
|
|
601
|
+
return false;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Classify repo presence separately from ecosystem/tooling markers.
|
|
606
|
+
*
|
|
607
|
+
* Known project files identify tooling. Git-tracked/non-ignored content
|
|
608
|
+
* identifies whether this is an existing project at all. This keeps small
|
|
609
|
+
* static or documentation repos from being mislabeled as greenfield.
|
|
610
|
+
*/
|
|
611
|
+
export function classifyProject(basePath: string): ProjectClassification {
|
|
612
|
+
const signals = detectProjectSignals(basePath);
|
|
613
|
+
const markers = [...signals.detectedFiles];
|
|
614
|
+
|
|
615
|
+
if (!signals.isGitRepo) {
|
|
616
|
+
return {
|
|
617
|
+
kind: "invalid-repo",
|
|
618
|
+
signals,
|
|
619
|
+
trackedFiles: [],
|
|
620
|
+
untrackedFiles: [],
|
|
621
|
+
contentFiles: [],
|
|
622
|
+
markers,
|
|
623
|
+
reason: "missing .git",
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
const trackedFiles = listTrackedProjectFiles(basePath);
|
|
628
|
+
const untrackedFiles = listUntrackedProjectFiles(basePath);
|
|
629
|
+
const contentFiles = [...new Set([...trackedFiles, ...untrackedFiles])];
|
|
630
|
+
const hasMarkers = hasKnownProjectMarkers(basePath, signals);
|
|
631
|
+
|
|
632
|
+
if (hasMarkers) {
|
|
633
|
+
return {
|
|
634
|
+
kind: "typed-existing",
|
|
635
|
+
signals,
|
|
636
|
+
trackedFiles,
|
|
637
|
+
untrackedFiles,
|
|
638
|
+
contentFiles,
|
|
639
|
+
markers,
|
|
640
|
+
reason: markers.length > 0 ? `detected markers: ${markers.join(", ")}` : "detected project structure",
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
if (contentFiles.length > 0) {
|
|
645
|
+
return {
|
|
646
|
+
kind: "untyped-existing",
|
|
647
|
+
signals,
|
|
648
|
+
trackedFiles,
|
|
649
|
+
untrackedFiles,
|
|
650
|
+
contentFiles,
|
|
651
|
+
markers,
|
|
652
|
+
reason: "project content exists but no recognized tooling markers were found",
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
return {
|
|
657
|
+
kind: "greenfield",
|
|
658
|
+
signals,
|
|
659
|
+
trackedFiles,
|
|
660
|
+
untrackedFiles,
|
|
661
|
+
contentFiles,
|
|
662
|
+
markers,
|
|
663
|
+
reason: "no tracked or non-ignored project content",
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
|
|
539
667
|
// ─── Xcode Platform Detection ───────────────────────────────────────────────────
|
|
540
668
|
|
|
541
669
|
/** Known SDKROOT values → canonical platform names. */
|
|
@@ -14,6 +14,7 @@ import { isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
|
|
|
14
14
|
import { gsdRoot } from "./paths.js";
|
|
15
15
|
import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
|
|
16
16
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
17
|
+
import { logWarning } from "./workflow-logger.js";
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
import {
|
|
@@ -722,16 +723,53 @@ export class GitServiceImpl {
|
|
|
722
723
|
if (keyFiles.length === 0) return false;
|
|
723
724
|
|
|
724
725
|
const allExclusions = [...RUNTIME_EXCLUSION_PATHS, ...extraExclusions];
|
|
725
|
-
const
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
726
|
+
const normalized = keyFiles
|
|
727
|
+
.map(file => normalizeRepoRelativePath(this.basePath, file))
|
|
728
|
+
.filter((file): file is string => file !== null)
|
|
729
|
+
.filter(file => !isExcludedScopedPath(file, allExclusions));
|
|
730
|
+
|
|
731
|
+
// Drop entries that don't exist on disk. The LLM occasionally lists files
|
|
732
|
+
// it intended to write but didn't (or names them with wrong casing/path).
|
|
733
|
+
// Pre-`b304f738b` `git add -A` swallowed these silently; the scoped
|
|
734
|
+
// pathspec form passes each path explicitly, so a single bad entry made
|
|
735
|
+
// the whole commit fail (see #5500). Filter so valid paths still commit.
|
|
736
|
+
const missing: string[] = [];
|
|
737
|
+
const existing: string[] = [];
|
|
738
|
+
for (const path of normalized) {
|
|
739
|
+
if (existsSync(join(this.basePath, path))) {
|
|
740
|
+
existing.push(path);
|
|
741
|
+
} else {
|
|
742
|
+
missing.push(path);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
if (missing.length > 0) {
|
|
746
|
+
logWarning(
|
|
747
|
+
"engine",
|
|
748
|
+
`scoped stage: dropping ${missing.length} non-existent keyFile(s) from task commit: ${missing.join(", ")}`,
|
|
749
|
+
{ file: "git-service.ts" },
|
|
750
|
+
);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
const paths = Array.from(new Set(existing));
|
|
731
754
|
if (paths.length === 0) return false;
|
|
732
755
|
|
|
733
|
-
|
|
734
|
-
|
|
756
|
+
try {
|
|
757
|
+
nativeAddPaths(this.basePath, paths);
|
|
758
|
+
return true;
|
|
759
|
+
} catch (err) {
|
|
760
|
+
// Defense-in-depth: even after existence filtering, libgit2/git can
|
|
761
|
+
// still reject paths (gitignore matches, case-only differences on
|
|
762
|
+
// case-insensitive FS, submodule boundaries). Returning false lets
|
|
763
|
+
// autoCommit fall through to smartStage so the commit still goes out
|
|
764
|
+
// — restoring the resilience the unscoped path used to provide.
|
|
765
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
766
|
+
logWarning(
|
|
767
|
+
"engine",
|
|
768
|
+
`scoped stage failed (${msg}); falling back to smartStage`,
|
|
769
|
+
{ file: "git-service.ts" },
|
|
770
|
+
);
|
|
771
|
+
return false;
|
|
772
|
+
}
|
|
735
773
|
}
|
|
736
774
|
|
|
737
775
|
/** Tracks whether runtime file cleanup has run this session. */
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
// excluded from this invariant.
|
|
24
24
|
|
|
25
25
|
import { createRequire } from "node:module";
|
|
26
|
+
import { createHash } from "node:crypto";
|
|
26
27
|
import { existsSync, copyFileSync, mkdirSync, realpathSync } from "node:fs";
|
|
27
28
|
import { dirname } from "node:path";
|
|
28
29
|
import type { Decision, Requirement, GateRow, GateId, GateScope, GateStatus, GateVerdict } from "./types.js";
|
|
@@ -78,6 +79,8 @@ import {
|
|
|
78
79
|
applyMigrationV22QualityGateRepair,
|
|
79
80
|
applyMigrationV23MilestoneQueue,
|
|
80
81
|
applyMigrationV26MilestoneCommitAttributions,
|
|
82
|
+
applyMigrationV27ArtifactHash,
|
|
83
|
+
applyMigrationV28MemoryLastHitAt,
|
|
81
84
|
} from "./db-migration-steps.js";
|
|
82
85
|
import { isMemoriesFtsAvailableSchema, tryCreateMemoriesFtsSchema } from "./db-memory-fts-schema.js";
|
|
83
86
|
import { createDbOpenState, type DbOpenPhase } from "./db-open-state.js";
|
|
@@ -106,7 +109,7 @@ const providerLoader = createSqliteProviderLoader({
|
|
|
106
109
|
writeStderr: (message: string) => process.stderr.write(message),
|
|
107
110
|
});
|
|
108
111
|
|
|
109
|
-
export const SCHEMA_VERSION =
|
|
112
|
+
export const SCHEMA_VERSION = 28;
|
|
110
113
|
|
|
111
114
|
function initSchema(db: DbAdapter, fileBacked: boolean): void {
|
|
112
115
|
if (fileBacked) db.exec("PRAGMA journal_mode=WAL");
|
|
@@ -335,6 +338,16 @@ function migrateSchema(db: DbAdapter): void {
|
|
|
335
338
|
recordSchemaVersion(db, 26);
|
|
336
339
|
}
|
|
337
340
|
|
|
341
|
+
if (currentVersion < 27) {
|
|
342
|
+
applyMigrationV27ArtifactHash(db);
|
|
343
|
+
recordSchemaVersion(db, 27);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (currentVersion < 28) {
|
|
347
|
+
applyMigrationV28MemoryLastHitAt(db);
|
|
348
|
+
recordSchemaVersion(db, 28);
|
|
349
|
+
}
|
|
350
|
+
|
|
338
351
|
db.exec("COMMIT");
|
|
339
352
|
} catch (err) {
|
|
340
353
|
db.exec("ROLLBACK");
|
|
@@ -913,9 +926,10 @@ export function insertArtifact(a: {
|
|
|
913
926
|
full_content: string;
|
|
914
927
|
}): void {
|
|
915
928
|
if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
929
|
+
const contentHash = createHash("sha256").update(a.full_content).digest("hex");
|
|
916
930
|
currentDb.prepare(
|
|
917
|
-
`INSERT OR REPLACE INTO artifacts (path, artifact_type, milestone_id, slice_id, task_id, full_content, imported_at)
|
|
918
|
-
VALUES (:path, :artifact_type, :milestone_id, :slice_id, :task_id, :full_content, :imported_at)`,
|
|
931
|
+
`INSERT OR REPLACE INTO artifacts (path, artifact_type, milestone_id, slice_id, task_id, full_content, imported_at, content_hash)
|
|
932
|
+
VALUES (:path, :artifact_type, :milestone_id, :slice_id, :task_id, :full_content, :imported_at, :content_hash)`,
|
|
919
933
|
).run({
|
|
920
934
|
":path": a.path,
|
|
921
935
|
":artifact_type": a.artifact_type,
|
|
@@ -924,6 +938,7 @@ export function insertArtifact(a: {
|
|
|
924
938
|
":task_id": a.task_id,
|
|
925
939
|
":full_content": a.full_content,
|
|
926
940
|
":imported_at": new Date().toISOString(),
|
|
941
|
+
":content_hash": contentHash,
|
|
927
942
|
});
|
|
928
943
|
}
|
|
929
944
|
|
|
@@ -1795,6 +1810,13 @@ export function reconcileWorktreeDb(
|
|
|
1795
1810
|
const hasEscalationAwaiting = wtTaskInfo.some((col) => col["name"] === "escalation_awaiting_review");
|
|
1796
1811
|
const hasEscalationArtifact = wtTaskInfo.some((col) => col["name"] === "escalation_artifact_path");
|
|
1797
1812
|
const hasEscalationOverride = wtTaskInfo.some((col) => col["name"] === "escalation_override_applied_at");
|
|
1813
|
+
const wtArtifactInfo = adapter.prepare("PRAGMA wt.table_info('artifacts')").all();
|
|
1814
|
+
const hasArtifactContentHash = wtArtifactInfo.some((col) => col["name"] === "content_hash");
|
|
1815
|
+
const wtMemoryInfo = adapter.prepare("PRAGMA wt.table_info('memories')").all();
|
|
1816
|
+
const hasMemoryScope = wtMemoryInfo.some((col) => col["name"] === "scope");
|
|
1817
|
+
const hasMemoryTags = wtMemoryInfo.some((col) => col["name"] === "tags");
|
|
1818
|
+
const hasMemoryStructuredFields = wtMemoryInfo.some((col) => col["name"] === "structured_fields");
|
|
1819
|
+
const hasMemoryLastHitAt = wtMemoryInfo.some((col) => col["name"] === "last_hit_at");
|
|
1798
1820
|
|
|
1799
1821
|
const decConf = adapter.prepare(
|
|
1800
1822
|
`SELECT m.id FROM decisions m INNER JOIN wt.decisions w ON m.id = w.id WHERE m.decision != w.decision OR m.choice != w.choice OR m.rationale != w.rationale OR ${
|
|
@@ -1842,12 +1864,17 @@ export function reconcileWorktreeDb(
|
|
|
1842
1864
|
FROM wt.requirements
|
|
1843
1865
|
`).run());
|
|
1844
1866
|
|
|
1867
|
+
// V27: preserve content_hash. If the worktree predates V27 (no column),
|
|
1868
|
+
// fall back to the main DB's existing hash so reconcile doesn't null
|
|
1869
|
+
// out integrity fingerprints on artifacts that were unchanged in wt.
|
|
1845
1870
|
merged.artifacts = countChanges(adapter.prepare(`
|
|
1846
1871
|
INSERT OR REPLACE INTO artifacts (
|
|
1847
|
-
path, artifact_type, milestone_id, slice_id, task_id, full_content, imported_at
|
|
1872
|
+
path, artifact_type, milestone_id, slice_id, task_id, full_content, imported_at, content_hash
|
|
1848
1873
|
)
|
|
1849
|
-
SELECT path, artifact_type, milestone_id, slice_id, task_id, full_content, imported_at
|
|
1850
|
-
|
|
1874
|
+
SELECT w.path, w.artifact_type, w.milestone_id, w.slice_id, w.task_id, w.full_content, w.imported_at,
|
|
1875
|
+
${hasArtifactContentHash ? "w.content_hash" : "m.content_hash"}
|
|
1876
|
+
FROM wt.artifacts w
|
|
1877
|
+
LEFT JOIN artifacts m ON m.path = w.path
|
|
1851
1878
|
`).run());
|
|
1852
1879
|
|
|
1853
1880
|
// Merge milestones — worktree may have updated status/planning fields.
|
|
@@ -1949,15 +1976,25 @@ export function reconcileWorktreeDb(
|
|
|
1949
1976
|
LEFT JOIN tasks m ON m.milestone_id = w.milestone_id AND m.slice_id = w.slice_id AND m.id = w.id
|
|
1950
1977
|
`).run());
|
|
1951
1978
|
|
|
1952
|
-
// Merge memories — keep worktree-learned insights
|
|
1979
|
+
// Merge memories — keep worktree-learned insights.
|
|
1980
|
+
// V18 (scope, tags), V21 (structured_fields), V28 (last_hit_at): for each
|
|
1981
|
+
// column the wt may not yet have (older worktree DB), fall back to the
|
|
1982
|
+
// main DB's existing value via LEFT JOIN so reconcile never silently
|
|
1983
|
+
// resets these fields to defaults on rows that already had them.
|
|
1953
1984
|
merged.memories = countChanges(adapter.prepare(`
|
|
1954
1985
|
INSERT OR REPLACE INTO memories (
|
|
1955
1986
|
seq, id, category, content, confidence, source_unit_type, source_unit_id,
|
|
1956
|
-
created_at, updated_at, superseded_by, hit_count
|
|
1987
|
+
created_at, updated_at, superseded_by, hit_count,
|
|
1988
|
+
scope, tags, structured_fields, last_hit_at
|
|
1957
1989
|
)
|
|
1958
|
-
SELECT seq, id, category, content, confidence, source_unit_type, source_unit_id,
|
|
1959
|
-
created_at, updated_at, superseded_by, hit_count
|
|
1960
|
-
|
|
1990
|
+
SELECT w.seq, w.id, w.category, w.content, w.confidence, w.source_unit_type, w.source_unit_id,
|
|
1991
|
+
w.created_at, w.updated_at, w.superseded_by, w.hit_count,
|
|
1992
|
+
${hasMemoryScope ? "w.scope" : "COALESCE(m.scope, 'project')"},
|
|
1993
|
+
${hasMemoryTags ? "w.tags" : "COALESCE(m.tags, '[]')"},
|
|
1994
|
+
${hasMemoryStructuredFields ? "w.structured_fields" : "m.structured_fields"},
|
|
1995
|
+
${hasMemoryLastHitAt ? "w.last_hit_at" : "m.last_hit_at"}
|
|
1996
|
+
FROM wt.memories w
|
|
1997
|
+
LEFT JOIN memories m ON m.id = w.id
|
|
1961
1998
|
`).run());
|
|
1962
1999
|
|
|
1963
2000
|
// Merge verification evidence — append-only, use INSERT OR IGNORE to avoid duplicates
|
|
@@ -3062,8 +3099,8 @@ export function updateMemoryContentRow(
|
|
|
3062
3099
|
export function incrementMemoryHitCount(id: string, updatedAt: string): void {
|
|
3063
3100
|
if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
3064
3101
|
currentDb.prepare(
|
|
3065
|
-
"UPDATE memories SET hit_count = hit_count + 1, updated_at = :updated_at WHERE id = :id",
|
|
3066
|
-
).run({ ":updated_at": updatedAt, ":id": id });
|
|
3102
|
+
"UPDATE memories SET hit_count = hit_count + 1, updated_at = :updated_at, last_hit_at = :last_hit_at WHERE id = :id",
|
|
3103
|
+
).run({ ":updated_at": updatedAt, ":last_hit_at": updatedAt, ":id": id });
|
|
3067
3104
|
}
|
|
3068
3105
|
|
|
3069
3106
|
export function supersedeMemoryRow(oldId: string, newId: string, updatedAt: string): void {
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
formatInterruptedSessionRunningMessage,
|
|
31
31
|
formatInterruptedSessionSummary,
|
|
32
32
|
} from "./interrupted-session.js";
|
|
33
|
-
import { listUnitRuntimeRecords, clearUnitRuntimeRecord } from "./unit-runtime.js";
|
|
33
|
+
import { listUnitRuntimeRecords, clearUnitRuntimeRecord, isInFlightRuntimePhase } from "./unit-runtime.js";
|
|
34
34
|
import { resolveExpectedArtifactPath } from "./auto.js";
|
|
35
35
|
import { gsdHome } from "./gsd-home.js";
|
|
36
36
|
import {
|
|
@@ -87,6 +87,34 @@ import { logWarning } from "./workflow-logger.js";
|
|
|
87
87
|
import { deleteRuntimeKv } from "./db/runtime-kv.js";
|
|
88
88
|
import { PAUSED_SESSION_KV_KEY } from "./interrupted-session.js";
|
|
89
89
|
|
|
90
|
+
type AutoStartOptions = Parameters<typeof startAutoDetached>[4];
|
|
91
|
+
type AutoStartLauncher = typeof startAutoDetached;
|
|
92
|
+
|
|
93
|
+
function scheduleAutoStartAfterIdle(
|
|
94
|
+
ctx: ExtensionCommandContext,
|
|
95
|
+
pi: ExtensionAPI,
|
|
96
|
+
basePath: string,
|
|
97
|
+
verboseMode: boolean,
|
|
98
|
+
options?: AutoStartOptions,
|
|
99
|
+
launch: AutoStartLauncher = startAutoDetached,
|
|
100
|
+
): void {
|
|
101
|
+
const waitForIdle =
|
|
102
|
+
typeof (ctx as { waitForIdle?: unknown }).waitForIdle === "function"
|
|
103
|
+
? ctx.waitForIdle.bind(ctx)
|
|
104
|
+
: async () => {};
|
|
105
|
+
void waitForIdle()
|
|
106
|
+
.then(() => {
|
|
107
|
+
setTimeout(() => launch(ctx, pi, basePath, verboseMode, options), 0);
|
|
108
|
+
})
|
|
109
|
+
.catch((err) => {
|
|
110
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
111
|
+
ctx.ui.notify(`Auto-start failed while waiting for the prior turn to settle: ${message}`, "error");
|
|
112
|
+
logWarning("guided", `auto-start idle wait failed: ${message}`);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export const _scheduleAutoStartAfterIdleForTest = scheduleAutoStartAfterIdle;
|
|
117
|
+
|
|
90
118
|
// ─── Scope-based validator wrappers ──────────────────────────────────────────
|
|
91
119
|
// These thin wrappers accept a MilestoneScope so callers that already hold a
|
|
92
120
|
// pinned scope never have to re-derive (basePath, milestoneId) separately.
|
|
@@ -118,6 +146,22 @@ export function resolveExpectedArtifactPathForScope(
|
|
|
118
146
|
return resolveExpectedArtifactPath(unitType, unitId, scope.workspace.projectRoot);
|
|
119
147
|
}
|
|
120
148
|
|
|
149
|
+
async function runQuickTaskChoice(ctx: ExtensionCommandContext, pi: ExtensionAPI): Promise<void> {
|
|
150
|
+
if (!ctx.hasUI) {
|
|
151
|
+
ctx.ui.notify("Run /gsd quick <task> for small bounded work, or /gsd do <task> for natural-language routing.", "info");
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const task = (await ctx.ui.input("Quick task", "Describe the small task to run with /gsd quick"))?.trim();
|
|
156
|
+
if (!task) {
|
|
157
|
+
ctx.ui.notify("Quick task cancelled.", "info");
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const { handleQuick } = await import("./quick.js");
|
|
162
|
+
await handleQuick(task, ctx, pi);
|
|
163
|
+
}
|
|
164
|
+
|
|
121
165
|
/**
|
|
122
166
|
* Scope-based overload of isGhostMilestone.
|
|
123
167
|
* Binds basePath and milestoneId from the scope, ensuring path resolution
|
|
@@ -430,7 +474,7 @@ async function dispatchNextDeepProjectSetupStage(entry: PendingDeepProjectSetupE
|
|
|
430
474
|
|
|
431
475
|
if (!hasPendingDeepStage(prefs, entry.basePath)) {
|
|
432
476
|
pendingDeepProjectSetupMap.delete(entry.basePath);
|
|
433
|
-
|
|
477
|
+
scheduleAutoStartAfterIdle(entry.ctx, entry.pi, entry.basePath, false, { step: entry.step });
|
|
434
478
|
return true;
|
|
435
479
|
}
|
|
436
480
|
|
|
@@ -463,7 +507,7 @@ async function dispatchNextDeepProjectSetupStage(entry: PendingDeepProjectSetupE
|
|
|
463
507
|
entry.ctx.ui.notify(result.reason, result.level);
|
|
464
508
|
} else if (hasPendingDeepStage(prefs, entry.basePath)) {
|
|
465
509
|
pendingDeepProjectSetupMap.delete(entry.basePath);
|
|
466
|
-
|
|
510
|
+
scheduleAutoStartAfterIdle(entry.ctx, entry.pi, entry.basePath, false, { step: entry.step });
|
|
467
511
|
return true;
|
|
468
512
|
}
|
|
469
513
|
return false;
|
|
@@ -471,7 +515,7 @@ async function dispatchNextDeepProjectSetupStage(entry: PendingDeepProjectSetupE
|
|
|
471
515
|
|
|
472
516
|
if (!USER_DRIVEN_DEEP_SETUP_UNITS.has(result.unitType)) {
|
|
473
517
|
pendingDeepProjectSetupMap.delete(entry.basePath);
|
|
474
|
-
|
|
518
|
+
scheduleAutoStartAfterIdle(entry.ctx, entry.pi, entry.basePath, false, { step: entry.step });
|
|
475
519
|
return true;
|
|
476
520
|
}
|
|
477
521
|
|
|
@@ -677,7 +721,7 @@ export function checkAutoStartAfterDiscuss(): boolean {
|
|
|
677
721
|
|
|
678
722
|
pendingAutoStartMap.delete(basePath);
|
|
679
723
|
ctx.ui.notify(`Milestone ${milestoneId} ready.`, "success");
|
|
680
|
-
|
|
724
|
+
scheduleAutoStartAfterIdle(ctx, pi, basePath, false, { step });
|
|
681
725
|
return true;
|
|
682
726
|
}
|
|
683
727
|
|
|
@@ -1786,8 +1830,8 @@ function selfHealRuntimeRecords(basePath: string, ctx: ExtensionContext): { clea
|
|
|
1786
1830
|
cleared++;
|
|
1787
1831
|
continue;
|
|
1788
1832
|
}
|
|
1789
|
-
// Clear records stuck in
|
|
1790
|
-
if (phase
|
|
1833
|
+
// Clear records stuck in an in-flight phase (process died mid-unit).
|
|
1834
|
+
if (isInFlightRuntimePhase(phase)) {
|
|
1791
1835
|
clearUnitRuntimeRecord(basePath, unitType, unitId);
|
|
1792
1836
|
cleared++;
|
|
1793
1837
|
}
|
|
@@ -2042,6 +2086,23 @@ export async function showSmartEntry(
|
|
|
2042
2086
|
}
|
|
2043
2087
|
}
|
|
2044
2088
|
|
|
2089
|
+
if (interrupted.classification !== "recoverable") {
|
|
2090
|
+
try {
|
|
2091
|
+
const { autoImportMarkdownHierarchyIfDbMismatch } = await import("./migration-auto-check.js");
|
|
2092
|
+
const result = await autoImportMarkdownHierarchyIfDbMismatch(basePath);
|
|
2093
|
+
if (result.action === "imported") {
|
|
2094
|
+
ctx.ui.notify(
|
|
2095
|
+
`Recovered migrated planning state into gsd.db (${result.reason}): ${result.afterDb.milestones} milestone(s), ${result.afterDb.slices} slice(s), ${result.afterDb.tasks} task(s).`,
|
|
2096
|
+
"info",
|
|
2097
|
+
);
|
|
2098
|
+
}
|
|
2099
|
+
} catch (err) {
|
|
2100
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2101
|
+
ctx.ui.notify(`GSD could not auto-import existing planning state into gsd.db: ${message}`, "warning");
|
|
2102
|
+
logWarning("guided", `planning state auto-import failed: ${message}`, { file: "guided-flow.ts" });
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2045
2106
|
// Always derive from the project root — the assessment may have derived
|
|
2046
2107
|
// state from a worktree path that was cleaned up in the stale branch above.
|
|
2047
2108
|
const state = await deriveState(basePath);
|
|
@@ -2134,17 +2195,24 @@ export async function showSmartEntry(
|
|
|
2134
2195
|
title: "GSD — Get Shit Done",
|
|
2135
2196
|
summary: ["No active milestone."],
|
|
2136
2197
|
actions: [
|
|
2198
|
+
{
|
|
2199
|
+
id: "quick_task",
|
|
2200
|
+
label: "Quick task",
|
|
2201
|
+
description: "For small bounded work, run /gsd quick <task> or /gsd do <task>.",
|
|
2202
|
+
recommended: true,
|
|
2203
|
+
},
|
|
2137
2204
|
{
|
|
2138
2205
|
id: "new_milestone",
|
|
2139
2206
|
label: "Create next milestone",
|
|
2140
|
-
description: "Define
|
|
2141
|
-
recommended: true,
|
|
2207
|
+
description: "Define a larger body of work with planning artifacts.",
|
|
2142
2208
|
},
|
|
2143
2209
|
],
|
|
2144
2210
|
notYetMessage: "Run /gsd when ready.",
|
|
2145
2211
|
});
|
|
2146
2212
|
|
|
2147
|
-
if (choice === "
|
|
2213
|
+
if (choice === "quick_task") {
|
|
2214
|
+
await runQuickTaskChoice(ctx, pi);
|
|
2215
|
+
} else if (choice === "new_milestone") {
|
|
2148
2216
|
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode });
|
|
2149
2217
|
await dispatchWorkflow(pi, await prepareAndBuildDiscussPrompt(ctx, pi, nextId,
|
|
2150
2218
|
`New milestone ${nextId}.`,
|
|
@@ -2181,11 +2249,16 @@ export async function showSmartEntry(
|
|
|
2181
2249
|
title: `GSD — ${milestoneId}: ${milestoneTitle}`,
|
|
2182
2250
|
summary: ["All milestones complete."],
|
|
2183
2251
|
actions: [
|
|
2252
|
+
{
|
|
2253
|
+
id: "quick_task",
|
|
2254
|
+
label: "Quick task",
|
|
2255
|
+
description: "Do a small bounded task without opening a milestone.",
|
|
2256
|
+
recommended: true,
|
|
2257
|
+
},
|
|
2184
2258
|
{
|
|
2185
2259
|
id: "new_milestone",
|
|
2186
2260
|
label: "Start new milestone",
|
|
2187
2261
|
description: "Define and plan the next milestone.",
|
|
2188
|
-
recommended: true,
|
|
2189
2262
|
},
|
|
2190
2263
|
{
|
|
2191
2264
|
id: "status",
|
|
@@ -2196,7 +2269,9 @@ export async function showSmartEntry(
|
|
|
2196
2269
|
notYetMessage: "Run /gsd when ready.",
|
|
2197
2270
|
});
|
|
2198
2271
|
|
|
2199
|
-
if (choice === "
|
|
2272
|
+
if (choice === "quick_task") {
|
|
2273
|
+
await runQuickTaskChoice(ctx, pi);
|
|
2274
|
+
} else if (choice === "new_milestone") {
|
|
2200
2275
|
const milestoneIds = findMilestoneIds(basePath);
|
|
2201
2276
|
const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
|
|
2202
2277
|
const nextId = nextMilestoneIdReserved(milestoneIds, uniqueMilestoneIds, basePath);
|
|
@@ -2300,13 +2375,18 @@ export async function showSmartEntry(
|
|
|
2300
2375
|
const hasContext = !!(contextFile && await loadFile(contextFile));
|
|
2301
2376
|
|
|
2302
2377
|
const actions = [
|
|
2378
|
+
{
|
|
2379
|
+
id: "quick_task",
|
|
2380
|
+
label: "Quick task instead",
|
|
2381
|
+
description: "Use this when the work is small and should not become a milestone.",
|
|
2382
|
+
recommended: true,
|
|
2383
|
+
},
|
|
2303
2384
|
{
|
|
2304
2385
|
id: "plan",
|
|
2305
2386
|
label: "Create roadmap",
|
|
2306
2387
|
description: hasContext
|
|
2307
2388
|
? "Context captured. Decompose into slices with a boundary map."
|
|
2308
2389
|
: "Decompose the milestone into slices with a boundary map.",
|
|
2309
|
-
recommended: true,
|
|
2310
2390
|
},
|
|
2311
2391
|
...(!hasContext ? [{
|
|
2312
2392
|
id: "discuss",
|
|
@@ -2332,7 +2412,9 @@ export async function showSmartEntry(
|
|
|
2332
2412
|
notYetMessage: "Run /gsd when ready.",
|
|
2333
2413
|
});
|
|
2334
2414
|
|
|
2335
|
-
if (choice === "
|
|
2415
|
+
if (choice === "quick_task") {
|
|
2416
|
+
await runQuickTaskChoice(ctx, pi);
|
|
2417
|
+
} else if (choice === "plan") {
|
|
2336
2418
|
setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId, step: stepMode });
|
|
2337
2419
|
await dispatchWorkflow(
|
|
2338
2420
|
pi,
|