gsd-pi 2.76.0-dev.82e249f7b → 2.76.0-dev.97f5583d9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/claude-cli-check.js +32 -3
- package/dist/mcp-server.d.ts +7 -0
- package/dist/mcp-server.js +35 -1
- package/dist/resource-loader.d.ts +1 -1
- package/dist/resource-loader.js +2 -8
- package/dist/resources/extensions/claude-code-cli/readiness.js +4 -3
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +77 -17
- package/dist/resources/extensions/gsd/auto/phases.js +42 -1
- package/dist/resources/extensions/gsd/auto/run-unit.js +27 -0
- package/dist/resources/extensions/gsd/auto/session.js +12 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +16 -3
- package/dist/resources/extensions/gsd/auto-model-selection.js +1 -1
- package/dist/resources/extensions/gsd/auto-post-unit.js +25 -2
- package/dist/resources/extensions/gsd/auto-prompts.js +14 -0
- package/dist/resources/extensions/gsd/auto-recovery.js +13 -0
- package/dist/resources/extensions/gsd/auto-start.js +27 -18
- package/dist/resources/extensions/gsd/auto-worktree.js +51 -53
- package/dist/resources/extensions/gsd/auto.js +55 -27
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +17 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +39 -9
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +93 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +51 -5
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +34 -2
- package/dist/resources/extensions/gsd/clean-root-preflight.js +93 -0
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +968 -23
- package/dist/resources/extensions/gsd/compaction-snapshot.js +121 -0
- package/dist/resources/extensions/gsd/error-classifier.js +10 -3
- package/dist/resources/extensions/gsd/exec-history.js +120 -0
- package/dist/resources/extensions/gsd/exec-sandbox.js +258 -0
- package/dist/resources/extensions/gsd/gsd-db.js +115 -7
- package/dist/resources/extensions/gsd/guided-flow.js +189 -0
- package/dist/resources/extensions/gsd/health-widget.js +4 -1
- package/dist/resources/extensions/gsd/init-wizard.js +15 -1
- package/dist/resources/extensions/gsd/key-manager.js +6 -0
- package/dist/resources/extensions/gsd/model-router.js +36 -3
- package/dist/resources/extensions/gsd/pre-execution-checks.js +35 -9
- package/dist/resources/extensions/gsd/preferences-types.js +9 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +83 -0
- package/dist/resources/extensions/gsd/preferences.js +17 -17
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
- package/dist/resources/extensions/gsd/prompts/discuss.md +29 -2
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +96 -0
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +13 -5
- package/dist/resources/extensions/gsd/safety/safety-harness.js +5 -1
- package/dist/resources/extensions/gsd/token-counter.js +22 -5
- package/dist/resources/extensions/gsd/tools/exec-search-tool.js +59 -0
- package/dist/resources/extensions/gsd/tools/exec-tool.js +126 -0
- package/dist/resources/extensions/gsd/tools/resume-tool.js +23 -0
- package/dist/resources/extensions/gsd/uok/plan-v2.js +20 -3
- package/dist/resources/extensions/gsd/workflow-mcp.js +3 -0
- package/dist/resources/skills/verify-before-complete/SKILL.md +2 -1
- package/dist/resources/skills/write-docs/SKILL.md +2 -1
- 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 +10 -10
- 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/required-server-files.json +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.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 +10 -10
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- 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/server.js +1 -1
- package/package.json +1 -1
- package/packages/mcp-server/dist/remote-questions.d.ts +45 -0
- package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -0
- package/packages/mcp-server/dist/remote-questions.js +732 -0
- package/packages/mcp-server/dist/remote-questions.js.map +1 -0
- package/packages/mcp-server/dist/server.d.ts +7 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +41 -4
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +64 -25
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +2 -1
- package/packages/mcp-server/src/mcp-server.test.ts +30 -0
- package/packages/mcp-server/src/remote-questions.test.ts +294 -0
- package/packages/mcp-server/src/remote-questions.ts +916 -0
- package/packages/mcp-server/src/server.ts +62 -10
- package/packages/mcp-server/src/workflow-tools.test.ts +146 -1
- package/packages/mcp-server/src/workflow-tools.ts +84 -43
- package/packages/mcp-server/tsconfig.test.json +19 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js +1 -1
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +27 -4
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +8 -3
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +80 -0
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.d.ts +10 -0
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +16 -1
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/src/providers/anthropic-auth.test.ts +1 -1
- package/packages/pi-ai/src/providers/anthropic-shared.ts +26 -5
- package/packages/pi-ai/src/providers/anthropic.ts +9 -3
- package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +98 -0
- package/packages/pi-ai/src/providers/simple-options.ts +17 -1
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js +203 -0
- package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +14 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.js +49 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.test.js +67 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.js +9 -5
- package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.test.js +25 -1
- package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +5 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts +7 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +29 -21
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.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 +13 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/src/core/model-registry-custom-caps.test.ts +245 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +16 -0
- package/packages/pi-coding-agent/src/core/redact-secrets.test.ts +86 -0
- package/packages/pi-coding-agent/src/core/redact-secrets.ts +58 -0
- package/packages/pi-coding-agent/src/core/session-manager.test.ts +36 -1
- package/packages/pi-coding-agent/src/core/session-manager.ts +9 -5
- package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +6 -6
- package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +36 -22
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +13 -1
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/src/resources/extensions/claude-code-cli/readiness.ts +4 -3
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +78 -17
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +149 -5
- package/src/resources/extensions/gsd/auto/loop-deps.ts +13 -0
- package/src/resources/extensions/gsd/auto/phases.ts +66 -1
- package/src/resources/extensions/gsd/auto/run-unit.ts +29 -0
- package/src/resources/extensions/gsd/auto/session.ts +22 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +16 -3
- package/src/resources/extensions/gsd/auto-model-selection.ts +1 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +29 -3
- package/src/resources/extensions/gsd/auto-prompts.ts +28 -1
- package/src/resources/extensions/gsd/auto-recovery.ts +15 -0
- package/src/resources/extensions/gsd/auto-start.ts +29 -19
- package/src/resources/extensions/gsd/auto-worktree.ts +62 -63
- package/src/resources/extensions/gsd/auto.ts +58 -27
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +23 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +40 -9
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +109 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +53 -5
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +35 -2
- package/src/resources/extensions/gsd/clean-root-preflight.ts +111 -0
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +898 -32
- package/src/resources/extensions/gsd/compaction-snapshot.ts +165 -0
- package/src/resources/extensions/gsd/error-classifier.ts +10 -3
- package/src/resources/extensions/gsd/exec-history.ts +153 -0
- package/src/resources/extensions/gsd/exec-sandbox.ts +326 -0
- package/src/resources/extensions/gsd/gsd-db.ts +122 -7
- package/src/resources/extensions/gsd/guided-flow.ts +221 -0
- package/src/resources/extensions/gsd/health-widget.ts +3 -1
- package/src/resources/extensions/gsd/init-wizard.ts +15 -1
- package/src/resources/extensions/gsd/journal.ts +2 -1
- package/src/resources/extensions/gsd/key-manager.ts +6 -0
- package/src/resources/extensions/gsd/model-router.ts +42 -1
- package/src/resources/extensions/gsd/pre-execution-checks.ts +36 -10
- package/src/resources/extensions/gsd/preferences-types.ts +46 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +79 -0
- package/src/resources/extensions/gsd/preferences.ts +17 -17
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
- package/src/resources/extensions/gsd/prompts/discuss.md +29 -2
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +119 -0
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +17 -4
- package/src/resources/extensions/gsd/safety/safety-harness.ts +9 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +119 -1
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +123 -0
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/escalation.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/exec-history.test.ts +124 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +210 -0
- package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +152 -1
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/issue-4540-regressions.test.ts +288 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/key-manager.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +272 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +234 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +110 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +388 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +9 -3
- package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +205 -0
- package/src/resources/extensions/gsd/tests/save-gate-result-render.test.ts +95 -0
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +32 -40
- package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/token-counter.test.ts +105 -1
- package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +65 -2
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +3 -1
- package/src/resources/extensions/gsd/token-counter.ts +22 -5
- package/src/resources/extensions/gsd/tools/exec-search-tool.ts +81 -0
- package/src/resources/extensions/gsd/tools/exec-tool.ts +183 -0
- package/src/resources/extensions/gsd/tools/resume-tool.ts +40 -0
- package/src/resources/extensions/gsd/uok/plan-v2.ts +26 -3
- package/src/resources/extensions/gsd/workflow-logger.ts +3 -1
- package/src/resources/extensions/gsd/workflow-mcp.ts +3 -0
- package/src/resources/skills/verify-before-complete/SKILL.md +2 -1
- package/src/resources/skills/write-docs/SKILL.md +2 -1
- /package/dist/web/standalone/.next/static/{ecSsu49rxxcpbNmVP4mLD → lLdDRDspgYzfz0bJAmUSz}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{ecSsu49rxxcpbNmVP4mLD → lLdDRDspgYzfz0bJAmUSz}/_ssgManifest.js +0 -0
|
@@ -30,8 +30,7 @@ import { initRoutingHistory } from "./routing-history.js";
|
|
|
30
30
|
import { restoreHookState, resetHookState } from "./post-unit-hooks.js";
|
|
31
31
|
import { resetProactiveHealing, setLevelChangeCallback } from "./doctor-proactive.js";
|
|
32
32
|
import { snapshotSkills } from "./skill-discovery.js";
|
|
33
|
-
import { isDbAvailable, getMilestone, openDatabase } from "./gsd-db.js";
|
|
34
|
-
import { hideFooter } from "./auto-dashboard.js";
|
|
33
|
+
import { isDbAvailable, getMilestone, openDatabase, getDbStatus } from "./gsd-db.js";
|
|
35
34
|
import { debugLog, enableDebug, isDebugEnabled, getDebugLogPath, } from "./debug-logger.js";
|
|
36
35
|
import { logWarning, logError } from "./workflow-logger.js";
|
|
37
36
|
import { existsSync, mkdirSync, readdirSync, rmSync, statSync, unlinkSync, } from "node:fs";
|
|
@@ -247,7 +246,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
247
246
|
// the parent git root). See #2393 and related issue.
|
|
248
247
|
const hasLocalGit = existsSync(join(base, ".git"));
|
|
249
248
|
if (!hasLocalGit || isInheritedRepo(base)) {
|
|
250
|
-
const mainBranch = loadEffectiveGSDPreferences()?.preferences?.git?.main_branch || "main";
|
|
249
|
+
const mainBranch = loadEffectiveGSDPreferences(base)?.preferences?.git?.main_branch || "main";
|
|
251
250
|
nativeInit(base, mainBranch);
|
|
252
251
|
}
|
|
253
252
|
// Migrate legacy in-project .gsd/ to external state directory.
|
|
@@ -263,7 +262,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
263
262
|
// Ensure .gitignore has baseline patterns.
|
|
264
263
|
// ensureGitignore checks for git-tracked .gsd/ files and skips the
|
|
265
264
|
// ".gsd" pattern if the project intentionally tracks .gsd/ in git.
|
|
266
|
-
const gitPrefs = loadEffectiveGSDPreferences()?.preferences?.git;
|
|
265
|
+
const gitPrefs = loadEffectiveGSDPreferences(base)?.preferences?.git;
|
|
267
266
|
const manageGitignore = gitPrefs?.manage_gitignore;
|
|
268
267
|
ensureGitignore(base, { manageGitignore });
|
|
269
268
|
if (manageGitignore !== false)
|
|
@@ -289,7 +288,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
289
288
|
prepareWorkflowMcpForProject(ctx, base);
|
|
290
289
|
}
|
|
291
290
|
// Initialize GitServiceImpl
|
|
292
|
-
s.gitService = new GitServiceImpl(s.basePath, loadEffectiveGSDPreferences()?.preferences?.git ?? {});
|
|
291
|
+
s.gitService = new GitServiceImpl(s.basePath, loadEffectiveGSDPreferences(base)?.preferences?.git ?? {});
|
|
293
292
|
// ── Debug mode ──
|
|
294
293
|
if (!isDebugEnabled() && process.env.GSD_DEBUG === "1") {
|
|
295
294
|
enableDebug(base);
|
|
@@ -322,7 +321,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
322
321
|
// was lost due to session ending between completion and teardown.
|
|
323
322
|
// Must run after DB open and before worktree entry.
|
|
324
323
|
try {
|
|
325
|
-
const auditResult = auditOrphanedMilestoneBranches(base, getIsolationMode());
|
|
324
|
+
const auditResult = auditOrphanedMilestoneBranches(base, getIsolationMode(base));
|
|
326
325
|
for (const msg of auditResult.recovered) {
|
|
327
326
|
ctx.ui.notify(`Orphan audit: ${msg}`, "info");
|
|
328
327
|
}
|
|
@@ -340,7 +339,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
340
339
|
let state = await deriveState(base);
|
|
341
340
|
// Stale worktree state recovery (#654)
|
|
342
341
|
if (state.activeMilestone &&
|
|
343
|
-
shouldUseWorktreeIsolation() &&
|
|
342
|
+
shouldUseWorktreeIsolation(base) &&
|
|
344
343
|
!detectWorktreeName(base)) {
|
|
345
344
|
const wtPath = getAutoWorktreePath(base, state.activeMilestone.id);
|
|
346
345
|
if (wtPath) {
|
|
@@ -355,7 +354,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
355
354
|
let hasSurvivorBranch = false;
|
|
356
355
|
if (state.activeMilestone &&
|
|
357
356
|
(state.phase === "pre-planning" || state.phase === "complete") &&
|
|
358
|
-
getIsolationMode() !== "none" &&
|
|
357
|
+
getIsolationMode(base) !== "none" &&
|
|
359
358
|
!detectWorktreeName(base) &&
|
|
360
359
|
!base.includes(`${pathSep}.gsd${pathSep}worktrees${pathSep}`)) {
|
|
361
360
|
const milestoneBranch = `milestone/${state.activeMilestone.id}`;
|
|
@@ -516,7 +515,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
516
515
|
registerSigtermHandler(base);
|
|
517
516
|
// Capture integration branch
|
|
518
517
|
if (s.currentMilestoneId) {
|
|
519
|
-
if (getIsolationMode() !== "none") {
|
|
518
|
+
if (getIsolationMode(base) !== "none") {
|
|
520
519
|
captureIntegrationBranch(base, s.currentMilestoneId);
|
|
521
520
|
}
|
|
522
521
|
setActiveMilestoneId(base, s.currentMilestoneId);
|
|
@@ -524,7 +523,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
524
523
|
// Guard against stale milestone branch when isolation:none (#3613).
|
|
525
524
|
// A prior session with isolation:branch/worktree may have left HEAD on
|
|
526
525
|
// milestone/<MID>. Auto-checkout back to the integration branch.
|
|
527
|
-
if (getIsolationMode() === "none" && nativeIsRepo(base)) {
|
|
526
|
+
if (getIsolationMode(base) === "none" && nativeIsRepo(base)) {
|
|
528
527
|
try {
|
|
529
528
|
const currentBranch = nativeGetCurrentBranch(base);
|
|
530
529
|
if (currentBranch.startsWith("milestone/")) {
|
|
@@ -552,7 +551,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
552
551
|
return symlinkRe.test(p);
|
|
553
552
|
};
|
|
554
553
|
if (s.currentMilestoneId &&
|
|
555
|
-
getIsolationMode() !== "none" &&
|
|
554
|
+
getIsolationMode(base) !== "none" &&
|
|
556
555
|
!detectWorktreeName(base) &&
|
|
557
556
|
!isUnderGsdWorktrees(base)) {
|
|
558
557
|
buildResolver().enterMilestone(s.currentMilestoneId, {
|
|
@@ -597,8 +596,21 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
597
596
|
// call returns "db_unavailable", triggering artifact-retry which
|
|
598
597
|
// re-dispatches the same task — producing an infinite loop (#2419).
|
|
599
598
|
if (existsSync(gsdDbPath) && !isDbAvailable()) {
|
|
600
|
-
|
|
601
|
-
|
|
599
|
+
const dbStatus = getDbStatus();
|
|
600
|
+
const phaseHint = dbStatus.lastPhase === "open"
|
|
601
|
+
? "The database file could not be opened"
|
|
602
|
+
: dbStatus.lastPhase === "initSchema"
|
|
603
|
+
? "The database schema could not be initialized"
|
|
604
|
+
: dbStatus.lastPhase === "vacuum-recovery"
|
|
605
|
+
? "Corruption recovery (VACUUM) failed"
|
|
606
|
+
: dbStatus.attempted
|
|
607
|
+
? "The database could not be opened (phase unknown)"
|
|
608
|
+
: "The database provider could not be loaded";
|
|
609
|
+
const errorDetail = dbStatus.lastError ? ` (${dbStatus.lastError.message})` : "";
|
|
610
|
+
const providerHint = dbStatus.provider
|
|
611
|
+
? ` Provider: ${dbStatus.provider}.`
|
|
612
|
+
: " No SQLite provider available — check Node >= 22 or install better-sqlite3.";
|
|
613
|
+
ctx.ui.notify(`SQLite database exists but failed to open: ${gsdDbPath}. ${phaseHint}${errorDetail}.${providerHint}`, "error");
|
|
602
614
|
return releaseLockAndReturn();
|
|
603
615
|
}
|
|
604
616
|
// Initialize metrics
|
|
@@ -633,13 +645,10 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
633
645
|
}
|
|
634
646
|
}
|
|
635
647
|
// Snapshot installed skills
|
|
636
|
-
if (resolveSkillDiscoveryMode() !== "off") {
|
|
648
|
+
if (resolveSkillDiscoveryMode(base) !== "off") {
|
|
637
649
|
snapshotSkills();
|
|
638
650
|
}
|
|
639
651
|
ctx.ui.setStatus("gsd-auto", s.stepMode ? "next" : "auto");
|
|
640
|
-
ctx.ui.setFooter(hideFooter);
|
|
641
|
-
// Hide gsd-health during AUTO — gsd-progress is the single source of truth
|
|
642
|
-
// for last-commit / cost / health signal while auto is running.
|
|
643
652
|
ctx.ui.setWidget("gsd-health", undefined);
|
|
644
653
|
const modeLabel = s.stepMode ? "Step-mode" : "Auto-mode";
|
|
645
654
|
const pendingCount = (state.registry ?? []).filter((m) => m.status !== "complete" && m.status !== "parked").length;
|
|
@@ -661,7 +670,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
661
670
|
// FlatRateContext used by selectAndApplyModel so user-declared
|
|
662
671
|
// flat-rate providers and externalCli auto-detection are respected.
|
|
663
672
|
const { isFlatRateProvider, buildFlatRateContext } = await import("./auto-model-selection.js");
|
|
664
|
-
const bannerPrefs = loadEffectiveGSDPreferences()?.preferences;
|
|
673
|
+
const bannerPrefs = loadEffectiveGSDPreferences(base)?.preferences;
|
|
665
674
|
const effectiveProvider = s.autoModeStartModel?.provider ?? ctx.model?.provider;
|
|
666
675
|
const effectivelyEnabled = routingConfig.enabled
|
|
667
676
|
&& (routingConfig.allow_flat_rate_providers
|
|
@@ -180,14 +180,6 @@ function clearProjectRootStateFiles(basePath, milestoneId) {
|
|
|
180
180
|
}
|
|
181
181
|
}
|
|
182
182
|
}
|
|
183
|
-
function isProjectGsdSymlink(basePath) {
|
|
184
|
-
try {
|
|
185
|
-
return lstatSyncFn(join(basePath, ".gsd")).isSymbolicLink();
|
|
186
|
-
}
|
|
187
|
-
catch {
|
|
188
|
-
return false;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
183
|
// ─── Build Artifact Auto-Resolve ─────────────────────────────────────────────
|
|
192
184
|
/** Patterns for machine-generated build artifacts that can be safely
|
|
193
185
|
* auto-resolved by accepting --theirs during merge. These files are
|
|
@@ -1429,50 +1421,15 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1429
1421
|
});
|
|
1430
1422
|
}
|
|
1431
1423
|
}
|
|
1432
|
-
// 7.
|
|
1433
|
-
// blocked by unrelated local changes (#2151). clearProjectRootStateFiles
|
|
1434
|
-
// only removes untracked .gsd/ files; tracked dirty files elsewhere (e.g.
|
|
1435
|
-
// .planning/work-state.json with stash conflict markers) are invisible to
|
|
1436
|
-
// that cleanup but will cause `git merge --squash` to reject.
|
|
1437
|
-
let stashed = false;
|
|
1438
|
-
try {
|
|
1439
|
-
const status = execFileSync("git", ["status", "--porcelain"], {
|
|
1440
|
-
cwd: originalBasePath_,
|
|
1441
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
1442
|
-
encoding: "utf-8",
|
|
1443
|
-
}).trim();
|
|
1444
|
-
if (status) {
|
|
1445
|
-
// Use --include-untracked to stash untracked files that would block
|
|
1446
|
-
// the squash merge, but EXCLUDE .gsd/milestones/ (#2505).
|
|
1447
|
-
// --include-untracked without exclusion sweeps queued milestone
|
|
1448
|
-
// CONTEXT files into the stash. If stash pop later fails, those files
|
|
1449
|
-
// are permanently trapped in the stash entry and lost on the next
|
|
1450
|
-
// stash push or drop.
|
|
1451
|
-
//
|
|
1452
|
-
// When `.gsd` itself is a symlink, Git rejects pathspecs below it
|
|
1453
|
-
// ("beyond a symbolic link"). In that layout, exclude the whole symlink
|
|
1454
|
-
// and keep stashing real project files that could block the merge.
|
|
1455
|
-
const stashPathspecs = isProjectGsdSymlink(originalBasePath_)
|
|
1456
|
-
? [".", ":(exclude).gsd"]
|
|
1457
|
-
: [":(exclude).gsd/milestones"];
|
|
1458
|
-
execFileSync("git", [
|
|
1459
|
-
"stash", "push", "--include-untracked",
|
|
1460
|
-
"-m", `gsd: pre-merge stash for ${milestoneId}`,
|
|
1461
|
-
"--", ...stashPathspecs,
|
|
1462
|
-
], { cwd: originalBasePath_, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" });
|
|
1463
|
-
stashed = true;
|
|
1464
|
-
}
|
|
1465
|
-
}
|
|
1466
|
-
catch (err) {
|
|
1467
|
-
// Stash failure is non-fatal — proceed without stash and let the merge
|
|
1468
|
-
// report the dirty tree if it fails.
|
|
1469
|
-
logWarning("worktree", `git stash failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1470
|
-
}
|
|
1471
|
-
// 7a. Shelter queued milestone directories before the squash merge (#2505).
|
|
1424
|
+
// 7. Shelter queued milestone directories before the squash merge (#2505).
|
|
1472
1425
|
// The milestone branch may contain copies of queued milestone dirs (via
|
|
1473
1426
|
// copyPlanningArtifacts), so `git merge --squash` rejects when those same
|
|
1474
1427
|
// files exist as untracked in the working tree. Temporarily move them to
|
|
1475
1428
|
// a backup location, then restore after the merge+commit.
|
|
1429
|
+
//
|
|
1430
|
+
// MUST run BEFORE the pre-merge stash (step 7a) so `--include-untracked`
|
|
1431
|
+
// does not sweep queued CONTEXT files into the stash. If stash pop later
|
|
1432
|
+
// fails, files trapped inside the stash are permanently lost (#2505).
|
|
1476
1433
|
const milestonesDir = join(gsdRoot(originalBasePath_), "milestones");
|
|
1477
1434
|
const shelterDir = join(gsdRoot(originalBasePath_), ".milestone-shelter");
|
|
1478
1435
|
const shelteredDirs = [];
|
|
@@ -1526,6 +1483,31 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1526
1483
|
// Non-fatal — proceed with merge; untracked files may block it
|
|
1527
1484
|
logWarning("worktree", `milestone shelter operation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1528
1485
|
}
|
|
1486
|
+
// 7a. Stash pre-existing dirty files so the squash merge is not blocked by
|
|
1487
|
+
// unrelated local changes (#2151). Includes untracked files to handle
|
|
1488
|
+
// locally-added files that conflict with tracked files on the milestone
|
|
1489
|
+
// branch. Passing NO pathspec lets git skip gitignored paths silently;
|
|
1490
|
+
// adding an explicit pathspec trips a `git add`-style fatal on ignored
|
|
1491
|
+
// entries (e.g. a gitignored `.gsd` symlink under ADR-002) (#4573).
|
|
1492
|
+
// Queued CONTEXT files under `.gsd/milestones/*` are already sheltered
|
|
1493
|
+
// in step 7 above, so they won't be swept into the stash.
|
|
1494
|
+
let stashed = false;
|
|
1495
|
+
try {
|
|
1496
|
+
const status = execFileSync("git", ["status", "--porcelain"], {
|
|
1497
|
+
cwd: originalBasePath_,
|
|
1498
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1499
|
+
encoding: "utf-8",
|
|
1500
|
+
}).trim();
|
|
1501
|
+
if (status) {
|
|
1502
|
+
execFileSync("git", ["stash", "push", "--include-untracked", "-m", `gsd: pre-merge stash for ${milestoneId}`], { cwd: originalBasePath_, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" });
|
|
1503
|
+
stashed = true;
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
catch (err) {
|
|
1507
|
+
// Stash failure is non-fatal — proceed without stash and let the merge
|
|
1508
|
+
// report the dirty tree if it fails.
|
|
1509
|
+
logWarning("worktree", `git stash failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1510
|
+
}
|
|
1529
1511
|
// 7b. Clean up stale merge state before attempting squash merge (#2912).
|
|
1530
1512
|
// A leftover MERGE_HEAD (from a previous failed merge, libgit2 native path,
|
|
1531
1513
|
// or interrupted operation) causes `git merge --squash` to refuse with
|
|
@@ -1761,16 +1743,32 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1761
1743
|
// When a milestone only produced .gsd/ metadata (summaries, roadmaps) but no
|
|
1762
1744
|
// real code, the user sees "milestone complete" but nothing changed in their
|
|
1763
1745
|
// codebase. Surface this so the caller can warn the user.
|
|
1746
|
+
//
|
|
1747
|
+
// Bug #4385 fix: use `git diff-tree --root` instead of `git diff HEAD~1 HEAD`.
|
|
1748
|
+
// `HEAD~1` does not exist on initial commits and is unreliable on shallow clones
|
|
1749
|
+
// and merge commits. `diff-tree --root` handles all three cases correctly.
|
|
1750
|
+
// The empty-tree hash (4b825dc…) is the universal fallback for refs that don't exist.
|
|
1751
|
+
const GIT_EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
|
1764
1752
|
let codeFilesChanged = false;
|
|
1765
1753
|
if (!nothingToCommit) {
|
|
1766
1754
|
try {
|
|
1767
|
-
const
|
|
1768
|
-
|
|
1755
|
+
const diffTreeOutput = execFileSync("git", ["diff-tree", "--root", "--no-commit-id", "-r", "--name-only", "HEAD"], { cwd: originalBasePath_, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
|
|
1756
|
+
const mergedFiles = diffTreeOutput ? diffTreeOutput.split("\n").filter(Boolean) : [];
|
|
1757
|
+
codeFilesChanged = mergedFiles.some((f) => !f.startsWith(".gsd/"));
|
|
1769
1758
|
}
|
|
1770
1759
|
catch (e) {
|
|
1771
|
-
//
|
|
1772
|
-
|
|
1773
|
-
|
|
1760
|
+
// diff-tree failed (e.g. unborn HEAD in a brand-new repo) — fall back to
|
|
1761
|
+
// comparing against the empty tree so initial-commit repos still report changes.
|
|
1762
|
+
try {
|
|
1763
|
+
const fallbackOutput = execFileSync("git", ["diff", "--name-only", GIT_EMPTY_TREE, "HEAD"], { cwd: originalBasePath_, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
|
|
1764
|
+
const fallbackFiles = fallbackOutput ? fallbackOutput.split("\n").filter(Boolean) : [];
|
|
1765
|
+
codeFilesChanged = fallbackFiles.some((f) => !f.startsWith(".gsd/"));
|
|
1766
|
+
}
|
|
1767
|
+
catch {
|
|
1768
|
+
// Truly unable to determine — assume code was changed to avoid silent data loss
|
|
1769
|
+
logWarning("worktree", `diff-tree and empty-tree fallback both failed (assuming code changed): ${e.message}`);
|
|
1770
|
+
codeFilesChanged = true;
|
|
1771
|
+
}
|
|
1774
1772
|
}
|
|
1775
1773
|
}
|
|
1776
1774
|
// 10. Auto-push if enabled
|
|
@@ -37,8 +37,9 @@ import { getRtkSessionSavings } from "../shared/rtk-session-stats.js";
|
|
|
37
37
|
import { deactivateGSD } from "../shared/gsd-phase-state.js";
|
|
38
38
|
import { initMetrics, resetMetrics, getLedger, getProjectTotals, formatCost, formatTokenCount, } from "./metrics.js";
|
|
39
39
|
import { setLogBasePath, logWarning } from "./workflow-logger.js";
|
|
40
|
+
import { preflightCleanRoot, postflightPopStash } from "./clean-root-preflight.js";
|
|
40
41
|
import { homedir } from "node:os";
|
|
41
|
-
import { join } from "node:path";
|
|
42
|
+
import { isAbsolute, join } from "node:path";
|
|
42
43
|
import { pathToFileURL } from "node:url";
|
|
43
44
|
import { readFileSync, existsSync, mkdirSync, writeFileSync, unlinkSync } from "node:fs";
|
|
44
45
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
@@ -55,7 +56,7 @@ import { getErrorMessage } from "./error-utils.js";
|
|
|
55
56
|
import { recoverFailedMigration } from "./migrate-external.js";
|
|
56
57
|
import { initRegistry, convertDispatchRules } from "./rule-registry.js";
|
|
57
58
|
import { emitJournalEvent as _emitJournalEvent } from "./journal.js";
|
|
58
|
-
import { updateProgressWidget as _updateProgressWidget, updateSliceProgressCache, clearSliceProgressCache,
|
|
59
|
+
import { updateProgressWidget as _updateProgressWidget, updateSliceProgressCache, clearSliceProgressCache, } from "./auto-dashboard.js";
|
|
59
60
|
import { registerSigtermHandler as _registerSigtermHandler, deregisterSigtermHandler as _deregisterSigtermHandler, } from "./auto-supervisor.js";
|
|
60
61
|
import { isDbAvailable, getMilestone } from "./gsd-db.js";
|
|
61
62
|
import { countPendingCaptures } from "./captures.js";
|
|
@@ -136,6 +137,24 @@ function restoreMilestoneLockEnv() {
|
|
|
136
137
|
s.hadMilestoneLockEnv = false;
|
|
137
138
|
s.milestoneLockEnvCaptured = false;
|
|
138
139
|
}
|
|
140
|
+
function normalizeSessionFilePath(raw) {
|
|
141
|
+
if (typeof raw !== "string")
|
|
142
|
+
return null;
|
|
143
|
+
const trimmed = raw.trim();
|
|
144
|
+
if (!trimmed)
|
|
145
|
+
return null;
|
|
146
|
+
const firstLine = trimmed.split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
147
|
+
if (!firstLine)
|
|
148
|
+
return null;
|
|
149
|
+
// Guard against accidental message concatenation by trimming to .jsonl.
|
|
150
|
+
const jsonlIndex = firstLine.toLowerCase().indexOf(".jsonl");
|
|
151
|
+
const candidate = jsonlIndex >= 0 ? firstLine.slice(0, jsonlIndex + ".jsonl".length) : firstLine;
|
|
152
|
+
if (!isAbsolute(candidate))
|
|
153
|
+
return null;
|
|
154
|
+
if (!candidate.toLowerCase().endsWith(".jsonl"))
|
|
155
|
+
return null;
|
|
156
|
+
return candidate;
|
|
157
|
+
}
|
|
139
158
|
export function startAutoDetached(ctx, pi, base, verboseMode, options) {
|
|
140
159
|
void startAuto(ctx, pi, base, verboseMode, options).catch((err) => {
|
|
141
160
|
const message = getErrorMessage(err);
|
|
@@ -145,8 +164,8 @@ export function startAutoDetached(ctx, pi, base, verboseMode, options) {
|
|
|
145
164
|
});
|
|
146
165
|
}
|
|
147
166
|
/** Returns true if the project is configured for `isolation:worktree` mode. */
|
|
148
|
-
export function shouldUseWorktreeIsolation() {
|
|
149
|
-
const prefs = loadEffectiveGSDPreferences()?.preferences?.git;
|
|
167
|
+
export function shouldUseWorktreeIsolation(basePath) {
|
|
168
|
+
const prefs = loadEffectiveGSDPreferences(basePath)?.preferences?.git;
|
|
150
169
|
if (prefs?.isolation === "worktree")
|
|
151
170
|
return true;
|
|
152
171
|
// Default is false — worktree isolation requires explicit opt-in
|
|
@@ -215,7 +234,7 @@ export function getAutoDashboardData() {
|
|
|
215
234
|
const rtkSavings = sessionId && s.basePath
|
|
216
235
|
? getRtkSessionSavings(s.basePath, sessionId)
|
|
217
236
|
: null;
|
|
218
|
-
const rtkEnabled = loadEffectiveGSDPreferences()?.preferences.experimental?.rtk === true;
|
|
237
|
+
const rtkEnabled = loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences.experimental?.rtk === true;
|
|
219
238
|
// Pending capture count — lazy check, non-fatal
|
|
220
239
|
let pendingCaptureCount = 0;
|
|
221
240
|
try {
|
|
@@ -393,7 +412,7 @@ function clearUnitTimeout() {
|
|
|
393
412
|
}
|
|
394
413
|
/** Build snapshot metric opts. */
|
|
395
414
|
function buildSnapshotOpts(_unitType, _unitId) {
|
|
396
|
-
const prefs = loadEffectiveGSDPreferences()?.preferences;
|
|
415
|
+
const prefs = loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences;
|
|
397
416
|
const uokFlags = resolveUokFlags(prefs);
|
|
398
417
|
return {
|
|
399
418
|
...(s.autoStartTime > 0 ? { autoSessionKey: String(s.autoStartTime) } : {}),
|
|
@@ -427,7 +446,7 @@ function handleLostSessionLock(ctx, lockStatus) {
|
|
|
427
446
|
restoreProjectRootEnv();
|
|
428
447
|
restoreMilestoneLockEnv();
|
|
429
448
|
deregisterSigtermHandler();
|
|
430
|
-
clearCmuxSidebar(loadEffectiveGSDPreferences()?.preferences);
|
|
449
|
+
clearCmuxSidebar(loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences);
|
|
431
450
|
const base = lockBase();
|
|
432
451
|
const lockFilePath = base ? join(gsdRoot(base), "auto.lock") : "unknown";
|
|
433
452
|
const recoverySuggestion = "\nTo recover, run: gsd doctor --fix";
|
|
@@ -443,7 +462,6 @@ function handleLostSessionLock(ctx, lockStatus) {
|
|
|
443
462
|
ctx?.ui.notify(message, "error");
|
|
444
463
|
ctx?.ui.setStatus("gsd-auto", undefined);
|
|
445
464
|
ctx?.ui.setWidget("gsd-progress", undefined);
|
|
446
|
-
ctx?.ui.setFooter(undefined);
|
|
447
465
|
if (ctx)
|
|
448
466
|
initHealthWidget(ctx);
|
|
449
467
|
}
|
|
@@ -480,7 +498,6 @@ function cleanupAfterLoopExit(ctx) {
|
|
|
480
498
|
if (!s.paused) {
|
|
481
499
|
ctx.ui.setStatus("gsd-auto", undefined);
|
|
482
500
|
ctx.ui.setWidget("gsd-progress", undefined);
|
|
483
|
-
ctx.ui.setFooter(undefined);
|
|
484
501
|
initHealthWidget(ctx);
|
|
485
502
|
}
|
|
486
503
|
// Restore CWD out of worktree back to original project root
|
|
@@ -498,7 +515,7 @@ function cleanupAfterLoopExit(ctx) {
|
|
|
498
515
|
export async function stopAuto(ctx, pi, reason) {
|
|
499
516
|
if (!s.active && !s.paused)
|
|
500
517
|
return;
|
|
501
|
-
const loadedPreferences = loadEffectiveGSDPreferences()?.preferences;
|
|
518
|
+
const loadedPreferences = loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences;
|
|
502
519
|
const reasonSuffix = reason ? ` — ${reason}` : "";
|
|
503
520
|
try {
|
|
504
521
|
// ── Step 1: Timers and locks ──
|
|
@@ -743,7 +760,6 @@ export async function stopAuto(ctx, pi, reason) {
|
|
|
743
760
|
// UI cleanup
|
|
744
761
|
ctx?.ui.setStatus("gsd-auto", undefined);
|
|
745
762
|
ctx?.ui.setWidget("gsd-progress", undefined);
|
|
746
|
-
ctx?.ui.setFooter(undefined);
|
|
747
763
|
if (ctx)
|
|
748
764
|
initHealthWidget(ctx);
|
|
749
765
|
restoreProjectRootEnv();
|
|
@@ -778,7 +794,7 @@ export async function pauseAuto(ctx, _pi, _errorContext) {
|
|
|
778
794
|
// Pass errorContext so runUnitPhase can distinguish user-initiated pause
|
|
779
795
|
// from provider-error pause and avoid hard-stopping (#2762).
|
|
780
796
|
resolveAgentEndCancelled(_errorContext);
|
|
781
|
-
s.pausedSessionFile = ctx?.sessionManager?.getSessionFile() ?? null;
|
|
797
|
+
s.pausedSessionFile = normalizeSessionFilePath(ctx?.sessionManager?.getSessionFile() ?? null);
|
|
782
798
|
// Persist paused-session metadata so resume survives /exit (#1383).
|
|
783
799
|
// The fresh-start bootstrap checks for this file and restores worktree context.
|
|
784
800
|
try {
|
|
@@ -832,7 +848,6 @@ export async function pauseAuto(ctx, _pi, _errorContext) {
|
|
|
832
848
|
s.verificationRetryCount.clear();
|
|
833
849
|
ctx?.ui.setStatus("gsd-auto", "paused");
|
|
834
850
|
ctx?.ui.setWidget("gsd-progress", undefined);
|
|
835
|
-
ctx?.ui.setFooter(undefined);
|
|
836
851
|
if (ctx)
|
|
837
852
|
initHealthWidget(ctx);
|
|
838
853
|
const resumeCmd = s.stepMode ? "/gsd next" : "/gsd auto";
|
|
@@ -978,6 +993,9 @@ function buildLoopDeps() {
|
|
|
978
993
|
},
|
|
979
994
|
// Journal
|
|
980
995
|
emitJournalEvent: (entry) => _emitJournalEvent(s.basePath, entry),
|
|
996
|
+
// Clean-root preflight gate (#2909)
|
|
997
|
+
preflightCleanRoot,
|
|
998
|
+
postflightPopStash,
|
|
981
999
|
};
|
|
982
1000
|
}
|
|
983
1001
|
/**
|
|
@@ -1034,7 +1052,9 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1034
1052
|
unlinkSync(pausedPath);
|
|
1035
1053
|
}
|
|
1036
1054
|
catch (e) {
|
|
1037
|
-
|
|
1055
|
+
if (e.code !== "ENOENT") {
|
|
1056
|
+
logWarning("session", `pause file cleanup failed: ${e instanceof Error ? e.message : String(e)}`, { file: "auto.ts" });
|
|
1057
|
+
}
|
|
1038
1058
|
}
|
|
1039
1059
|
ctx.ui.notify(`Resuming paused custom workflow${meta.activeRunDir ? ` (${meta.activeRunDir})` : ""}.`, "info");
|
|
1040
1060
|
}
|
|
@@ -1052,7 +1072,9 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1052
1072
|
unlinkSync(pausedPath);
|
|
1053
1073
|
}
|
|
1054
1074
|
catch (err) {
|
|
1055
|
-
|
|
1075
|
+
if (err.code !== "ENOENT") {
|
|
1076
|
+
logWarning("session", `pause file cleanup failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
1077
|
+
}
|
|
1056
1078
|
}
|
|
1057
1079
|
ctx.ui.notify(`Paused milestone ${meta.milestoneId} is ${!mDir ? "missing" : "already complete"}. Starting fresh.`, "info");
|
|
1058
1080
|
}
|
|
@@ -1060,7 +1082,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1060
1082
|
s.currentMilestoneId = meta.milestoneId;
|
|
1061
1083
|
s.originalBasePath = meta.originalBasePath || base;
|
|
1062
1084
|
s.stepMode = meta.stepMode ?? requestedStepMode;
|
|
1063
|
-
s.pausedSessionFile = meta.sessionFile ?? null;
|
|
1085
|
+
s.pausedSessionFile = normalizeSessionFilePath(meta.sessionFile ?? null);
|
|
1064
1086
|
s.pausedUnitType = meta.unitType ?? null;
|
|
1065
1087
|
s.pausedUnitId = meta.unitId ?? null;
|
|
1066
1088
|
s.autoStartTime = meta.autoStartTime || Date.now();
|
|
@@ -1070,7 +1092,9 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1070
1092
|
unlinkSync(pausedPath);
|
|
1071
1093
|
}
|
|
1072
1094
|
catch (e) {
|
|
1073
|
-
|
|
1095
|
+
if (e.code !== "ENOENT") {
|
|
1096
|
+
logWarning("session", `pause file cleanup failed: ${e instanceof Error ? e.message : String(e)}`, { file: "auto.ts" });
|
|
1097
|
+
}
|
|
1074
1098
|
}
|
|
1075
1099
|
ctx.ui.notify(`Resuming paused session for ${meta.milestoneId}${meta.worktreePath && existsSync(meta.worktreePath) ? ` (worktree)` : ""}.`, "info");
|
|
1076
1100
|
}
|
|
@@ -1080,7 +1104,9 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1080
1104
|
unlinkSync(pausedPath);
|
|
1081
1105
|
}
|
|
1082
1106
|
catch (e) {
|
|
1083
|
-
|
|
1107
|
+
if (e.code !== "ENOENT") {
|
|
1108
|
+
logWarning("session", `stale pause file cleanup failed: ${e instanceof Error ? e.message : String(e)}`, { file: "auto.ts" });
|
|
1109
|
+
}
|
|
1084
1110
|
}
|
|
1085
1111
|
}
|
|
1086
1112
|
}
|
|
@@ -1136,7 +1162,9 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1136
1162
|
unlinkSync(s.pausedSessionFile);
|
|
1137
1163
|
}
|
|
1138
1164
|
catch (err) {
|
|
1139
|
-
|
|
1165
|
+
if (err.code !== "ENOENT") {
|
|
1166
|
+
logWarning("session", `pause file cleanup failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
1167
|
+
}
|
|
1140
1168
|
}
|
|
1141
1169
|
s.pausedSessionFile = null;
|
|
1142
1170
|
}
|
|
@@ -1164,7 +1192,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1164
1192
|
});
|
|
1165
1193
|
// ── Auto-worktree / branch-mode: re-enter on resume ──
|
|
1166
1194
|
if (s.currentMilestoneId &&
|
|
1167
|
-
getIsolationMode() !== "none" &&
|
|
1195
|
+
getIsolationMode(s.originalBasePath || s.basePath) !== "none" &&
|
|
1168
1196
|
s.originalBasePath &&
|
|
1169
1197
|
!isInAutoWorktree(s.basePath) &&
|
|
1170
1198
|
!detectWorktreeName(s.basePath) &&
|
|
@@ -1175,7 +1203,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1175
1203
|
}
|
|
1176
1204
|
registerSigtermHandler(lockBase());
|
|
1177
1205
|
ctx.ui.setStatus("gsd-auto", s.stepMode ? "next" : "auto");
|
|
1178
|
-
ctx.ui.
|
|
1206
|
+
ctx.ui.setWidget("gsd-health", undefined);
|
|
1179
1207
|
ctx.ui.notify(s.stepMode ? "Step-mode resumed." : "Auto-mode resumed.", "info");
|
|
1180
1208
|
restoreHookState(s.basePath);
|
|
1181
1209
|
// Re-sync managed resources on resume so long-lived auto sessions pick up
|
|
@@ -1197,7 +1225,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1197
1225
|
await openProjectDbIfPresent(s.basePath);
|
|
1198
1226
|
try {
|
|
1199
1227
|
await rebuildState(s.basePath);
|
|
1200
|
-
syncCmuxSidebar(loadEffectiveGSDPreferences()?.preferences, await deriveState(s.basePath));
|
|
1228
|
+
syncCmuxSidebar(loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, await deriveState(s.basePath));
|
|
1201
1229
|
}
|
|
1202
1230
|
catch (e) {
|
|
1203
1231
|
debugLog("resume-rebuild-state-failed", {
|
|
@@ -1227,7 +1255,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1227
1255
|
}
|
|
1228
1256
|
updateSessionLock(lockBase(), "resuming", s.currentMilestoneId ?? "unknown");
|
|
1229
1257
|
writeLock(lockBase(), "resuming", s.currentMilestoneId ?? "unknown");
|
|
1230
|
-
logCmuxEvent(loadEffectiveGSDPreferences()?.preferences, s.stepMode ? "Step-mode resumed." : "Auto-mode resumed.", "progress");
|
|
1258
|
+
logCmuxEvent(loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, s.stepMode ? "Step-mode resumed." : "Auto-mode resumed.", "progress");
|
|
1231
1259
|
captureProjectRootEnv(s.originalBasePath || s.basePath);
|
|
1232
1260
|
startAutoCommandPolling(s.basePath);
|
|
1233
1261
|
await runAutoLoopWithUok({
|
|
@@ -1253,13 +1281,13 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1253
1281
|
return;
|
|
1254
1282
|
captureProjectRootEnv(s.originalBasePath || s.basePath);
|
|
1255
1283
|
try {
|
|
1256
|
-
syncCmuxSidebar(loadEffectiveGSDPreferences()?.preferences, await deriveState(s.basePath));
|
|
1284
|
+
syncCmuxSidebar(loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, await deriveState(s.basePath));
|
|
1257
1285
|
}
|
|
1258
1286
|
catch (err) {
|
|
1259
1287
|
// Best-effort only — sidebar sync must never block auto-mode startup
|
|
1260
1288
|
logWarning("engine", `cmux sync failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
1261
1289
|
}
|
|
1262
|
-
logCmuxEvent(loadEffectiveGSDPreferences()?.preferences, requestedStepMode ? "Step-mode started." : "Auto-mode started.", "progress");
|
|
1290
|
+
logCmuxEvent(loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, requestedStepMode ? "Step-mode started." : "Auto-mode started.", "progress");
|
|
1263
1291
|
startAutoCommandPolling(s.basePath);
|
|
1264
1292
|
// Dispatch the first unit
|
|
1265
1293
|
await runAutoLoopWithUok({
|
|
@@ -1364,8 +1392,8 @@ export async function dispatchHookUnit(ctx, pi, hookName, triggerUnitType, trigg
|
|
|
1364
1392
|
`Ensure the model is defined in models.json and has auth configured.`, "warning");
|
|
1365
1393
|
}
|
|
1366
1394
|
}
|
|
1367
|
-
const sessionFile = ctx.sessionManager.getSessionFile();
|
|
1368
|
-
writeLock(lockBase(), hookUnitType, triggerUnitId, sessionFile);
|
|
1395
|
+
const sessionFile = normalizeSessionFilePath(ctx.sessionManager.getSessionFile());
|
|
1396
|
+
writeLock(lockBase(), hookUnitType, triggerUnitId, sessionFile ?? undefined);
|
|
1369
1397
|
clearUnitTimeout();
|
|
1370
1398
|
const supervisor = resolveAutoSupervisorConfig();
|
|
1371
1399
|
const hookHardTimeoutMs = (supervisor.hard_timeout_minutes ?? 30) * 60 * 1000;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { logWarning } from "../workflow-logger.js";
|
|
2
|
-
import { checkAutoStartAfterDiscuss } from "../guided-flow.js";
|
|
2
|
+
import { checkAutoStartAfterDiscuss, maybeHandleReadyPhraseWithoutFiles, maybeHandleEmptyIntentTurn, resetEmptyTurnCounter, } from "../guided-flow.js";
|
|
3
3
|
import { getAutoDashboardData, getAutoModeStartModel, isAutoActive, pauseAuto, setCurrentDispatchedModelId } from "../auto.js";
|
|
4
4
|
import { getNextFallbackModel, resolveModelWithFallbacksForUnit } from "../preferences.js";
|
|
5
5
|
import { pauseAutoForProviderError } from "../provider-error-pause.js";
|
|
@@ -53,6 +53,19 @@ export async function handleAgentEnd(pi, event, ctx) {
|
|
|
53
53
|
clearDiscussionFlowState();
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
56
|
+
// #4573 — When the LLM emits "Milestone X ready." but the required files
|
|
57
|
+
// are missing, `checkAutoStartAfterDiscuss` returns false silently. Surface
|
|
58
|
+
// that and nudge the LLM to complete the writes before the user hits the
|
|
59
|
+
// downstream "All milestones complete" warning loop.
|
|
60
|
+
if (maybeHandleReadyPhraseWithoutFiles(event))
|
|
61
|
+
return;
|
|
62
|
+
// #4573 — Empty-turn recovery: if the LLM announced intent in prose but
|
|
63
|
+
// emitted no tool calls, nudge it to execute. Fires only when auto-mode is
|
|
64
|
+
// active or a discussion autostart is pending (non-auto interactive discuss
|
|
65
|
+
// is user-driven). Runs before `isAutoActive` early return so pending
|
|
66
|
+
// discussions (where isAutoActive may be false) still get recovered.
|
|
67
|
+
if (maybeHandleEmptyIntentTurn(event, isAutoActive()))
|
|
68
|
+
return;
|
|
56
69
|
if (!isAutoActive())
|
|
57
70
|
return;
|
|
58
71
|
if (isSessionSwitchInFlight())
|
|
@@ -286,6 +299,9 @@ export async function handleAgentEnd(pi, event, ctx) {
|
|
|
286
299
|
// ── Success path ─────────────────────────────────────────────────────────
|
|
287
300
|
try {
|
|
288
301
|
resetRetryState(retryState);
|
|
302
|
+
// #4573 — Reset the empty-turn counter on any successful agent turn so
|
|
303
|
+
// transient stalls don't accumulate across independent units.
|
|
304
|
+
resetEmptyTurnCounter();
|
|
289
305
|
resolveAgentEnd(event);
|
|
290
306
|
}
|
|
291
307
|
catch (err) {
|