gsd-pi 2.76.0-dev.82e249f7b → 2.76.0-dev.97807402
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 +14 -0
- package/dist/resources/extensions/gsd/auto/run-unit.js +27 -0
- package/dist/resources/extensions/gsd/auto-model-selection.js +1 -1
- package/dist/resources/extensions/gsd/auto-post-unit.js +1 -1
- 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 +30 -48
- package/dist/resources/extensions/gsd/auto.js +13 -17
- 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 +40 -4
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +12 -1
- 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/file-change-validator.js +10 -4
- package/dist/resources/extensions/gsd/safety/safety-harness.js +4 -0
- 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/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 +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/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 +7 -7
- 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.map +1 -1
- package/packages/mcp-server/dist/server.js +18 -1
- 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/remote-questions.test.ts +294 -0
- package/packages/mcp-server/src/remote-questions.ts +916 -0
- package/packages/mcp-server/src/server.ts +19 -1
- 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-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +2 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- 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-shared.ts +3 -1
- 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/phases.ts +14 -0
- package/src/resources/extensions/gsd/auto/run-unit.ts +29 -0
- package/src/resources/extensions/gsd/auto-model-selection.ts +1 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +1 -2
- 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 +34 -52
- package/src/resources/extensions/gsd/auto.ts +12 -17
- 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 +42 -4
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +13 -1
- 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/file-change-validator.ts +14 -3
- package/src/resources/extensions/gsd/safety/safety-harness.ts +6 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +49 -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/doctor-providers.test.ts +31 -0
- 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/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-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/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/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/workflow-logger.ts +2 -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 → pI48IF3dgfs0CBrYi2bh_}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{ecSsu49rxxcpbNmVP4mLD → pI48IF3dgfs0CBrYi2bh_}/_ssgManifest.js +0 -0
package/dist/claude-cli-check.js
CHANGED
|
@@ -12,12 +12,41 @@ import { execFileSync } from 'node:child_process';
|
|
|
12
12
|
* `src/resources/extensions/gsd/pre-execution-checks.ts`.
|
|
13
13
|
*/
|
|
14
14
|
export const CLAUDE_COMMAND = process.platform === 'win32' ? 'claude.cmd' : 'claude';
|
|
15
|
+
/**
|
|
16
|
+
* Ordered list of binary names to probe for the Claude Code CLI.
|
|
17
|
+
*
|
|
18
|
+
* Windows installs vary: npm-global installs produce a `claude.cmd` shim,
|
|
19
|
+
* direct binary installs produce `claude.exe`, and Git Bash wrappers may
|
|
20
|
+
* expose a bare `claude` shim. Try all three so no valid install is missed.
|
|
21
|
+
*/
|
|
22
|
+
const CLAUDE_COMMAND_CANDIDATES = process.platform === 'win32' ? [CLAUDE_COMMAND, 'claude.exe', 'claude'] : [CLAUDE_COMMAND];
|
|
23
|
+
/**
|
|
24
|
+
* Try to run `args` against each candidate binary.
|
|
25
|
+
* Returns the output buffer on first success, throws the last error if all fail.
|
|
26
|
+
*/
|
|
27
|
+
function execClaudeCheck(args) {
|
|
28
|
+
let lastError;
|
|
29
|
+
for (const command of CLAUDE_COMMAND_CANDIDATES) {
|
|
30
|
+
try {
|
|
31
|
+
return execFileSync(command, args, { timeout: 5_000, stdio: 'pipe' });
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
lastError = error;
|
|
35
|
+
const code = error?.code;
|
|
36
|
+
// EINVAL can surface on Windows Git Bash for .cmd spawn failures.
|
|
37
|
+
if (code === 'ENOENT' || code === 'EINVAL')
|
|
38
|
+
continue;
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
throw lastError ?? new Error(`Claude CLI not found (tried: ${CLAUDE_COMMAND_CANDIDATES.join(', ')})`);
|
|
43
|
+
}
|
|
15
44
|
/**
|
|
16
45
|
* Check if the `claude` binary is installed (regardless of auth state).
|
|
17
46
|
*/
|
|
18
47
|
export function isClaudeBinaryInstalled() {
|
|
19
48
|
try {
|
|
20
|
-
|
|
49
|
+
execClaudeCheck(['--version']);
|
|
21
50
|
return true;
|
|
22
51
|
}
|
|
23
52
|
catch {
|
|
@@ -29,13 +58,13 @@ export function isClaudeBinaryInstalled() {
|
|
|
29
58
|
*/
|
|
30
59
|
export function isClaudeCliReady() {
|
|
31
60
|
try {
|
|
32
|
-
|
|
61
|
+
execClaudeCheck(['--version']);
|
|
33
62
|
}
|
|
34
63
|
catch {
|
|
35
64
|
return false;
|
|
36
65
|
}
|
|
37
66
|
try {
|
|
38
|
-
const output =
|
|
67
|
+
const output = execClaudeCheck(['auth', 'status'])
|
|
39
68
|
.toString()
|
|
40
69
|
.toLowerCase();
|
|
41
70
|
return !(/not logged in|no credentials|unauthenticated|not authenticated/i.test(output));
|
package/dist/mcp-server.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Minimal tool interface matching GSD's AgentTool shape.
|
|
3
3
|
* Avoids a direct dependency on @gsd/pi-agent-core from this compiled module.
|
|
4
|
+
*
|
|
5
|
+
* `details` and `isError` are optional fields that runtime tool implementations
|
|
6
|
+
* may populate. The MCP transport drops non-standard fields, so the wrapper at
|
|
7
|
+
* the call site mirrors `details` into `structuredContent` and forwards
|
|
8
|
+
* `isError` directly. See #4472.
|
|
4
9
|
*/
|
|
5
10
|
export interface McpToolDef {
|
|
6
11
|
name: string;
|
|
@@ -13,6 +18,8 @@ export interface McpToolDef {
|
|
|
13
18
|
data?: string;
|
|
14
19
|
mimeType?: string;
|
|
15
20
|
}>;
|
|
21
|
+
details?: Record<string, unknown>;
|
|
22
|
+
isError?: boolean;
|
|
16
23
|
}>;
|
|
17
24
|
}
|
|
18
25
|
/**
|
package/dist/mcp-server.js
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strict plain-object guard. True only for object literals and
|
|
3
|
+
* `Object.create(null)` — not for `Date`, `URL`, `Map`, `Set`, class instances,
|
|
4
|
+
* or arrays. Used to gate `structuredContent` forwarding so the MCP transport
|
|
5
|
+
* receives only true JSON objects (the protocol contract). See #4477 review.
|
|
6
|
+
*
|
|
7
|
+
* Mirrored in `packages/mcp-server/src/workflow-tools.ts` for the
|
|
8
|
+
* `adaptExecutorResult` adapter on the workflow path. Keep both copies in
|
|
9
|
+
* sync if the contract definition needs to evolve.
|
|
10
|
+
*/
|
|
11
|
+
function isPlainObject(value) {
|
|
12
|
+
if (value === null || typeof value !== 'object')
|
|
13
|
+
return false;
|
|
14
|
+
if (Array.isArray(value))
|
|
15
|
+
return false;
|
|
16
|
+
const proto = Object.getPrototypeOf(value);
|
|
17
|
+
return proto === null || proto === Object.prototype;
|
|
18
|
+
}
|
|
1
19
|
// MCP SDK subpath imports use wildcard exports (./*) in @modelcontextprotocol/sdk's
|
|
2
20
|
// package.json export map. The wildcard maps "./foo" → "./dist/cjs/foo" (no .js
|
|
3
21
|
// suffix), so bare subpath specifiers like `${MCP_PKG}/server/stdio` resolve to
|
|
@@ -83,7 +101,23 @@ export async function startMcpServer(options) {
|
|
|
83
101
|
// by stringifying into a text block so clients see the payload.
|
|
84
102
|
return { type: 'text', text: JSON.stringify(block) };
|
|
85
103
|
});
|
|
86
|
-
|
|
104
|
+
// Forward a tool's runtime `details` field to MCP's `structuredContent`
|
|
105
|
+
// channel. The protocol drops non-standard fields on the wire, so tools
|
|
106
|
+
// that populate `details` for client-side renderers (e.g. save_gate_result)
|
|
107
|
+
// would otherwise arrive empty on the other side. See #4472.
|
|
108
|
+
//
|
|
109
|
+
// Use a strict plain-object guard (prototype-chain check) rather than just
|
|
110
|
+
// `typeof === 'object' && !Array.isArray()` — Date, URL, Map, Set, and
|
|
111
|
+
// class instances would otherwise pass through and end up as
|
|
112
|
+
// `structuredContent`, violating the protocol's JSON-object contract.
|
|
113
|
+
// The mirror discipline applies in `workflow-tools.ts adaptExecutorResult`.
|
|
114
|
+
const base = { content };
|
|
115
|
+
if (isPlainObject(result.details)) {
|
|
116
|
+
base.structuredContent = result.details;
|
|
117
|
+
}
|
|
118
|
+
if (result.isError === true)
|
|
119
|
+
base.isError = true;
|
|
120
|
+
return base;
|
|
87
121
|
}
|
|
88
122
|
catch (err) {
|
|
89
123
|
// AbortError from a cancelled tool surfaces as a normal error — MCP
|
|
@@ -21,6 +21,6 @@ export declare function getNewerManagedResourceVersion(agentDir: string, current
|
|
|
21
21
|
*
|
|
22
22
|
* Inspectable: `ls ~/.gsd/agent/extensions/`
|
|
23
23
|
*/
|
|
24
|
-
export declare function initResources(agentDir: string): void;
|
|
24
|
+
export declare function initResources(agentDir: string, skillsDir?: string): void;
|
|
25
25
|
export declare function hasStaleCompiledExtensionSiblings(extensionsDir: string, sourceDir?: string): boolean;
|
|
26
26
|
export declare function buildResourceLoader(agentDir: string): DefaultResourceLoader;
|
package/dist/resource-loader.js
CHANGED
|
@@ -506,7 +506,7 @@ function pruneRemovedBundledExtensions(manifest, agentDir) {
|
|
|
506
506
|
*
|
|
507
507
|
* Inspectable: `ls ~/.gsd/agent/extensions/`
|
|
508
508
|
*/
|
|
509
|
-
export function initResources(agentDir) {
|
|
509
|
+
export function initResources(agentDir, skillsDir = join(homedir(), '.agents', 'skills')) {
|
|
510
510
|
mkdirSync(agentDir, { recursive: true });
|
|
511
511
|
const currentVersion = getBundledGsdVersion();
|
|
512
512
|
const manifest = readManagedResourceManifest(agentDir);
|
|
@@ -538,13 +538,7 @@ export function initResources(agentDir) {
|
|
|
538
538
|
// Sync bundled resources — overwrite so updates land on next launch.
|
|
539
539
|
syncResourceDir(bundledExtensionsDir, join(agentDir, 'extensions'));
|
|
540
540
|
syncResourceDir(join(resourcesDir, 'agents'), join(agentDir, 'agents'));
|
|
541
|
-
|
|
542
|
-
// skills.sh CLI (`npx skills add <repo>`) into ~/.agents/skills/ which
|
|
543
|
-
// is the industry-standard Agent Skills ecosystem directory.
|
|
544
|
-
//
|
|
545
|
-
// Migration from the legacy ~/.gsd/agent/skills/ directory is handled
|
|
546
|
-
// above the manifest check so it runs on every launch (including retries
|
|
547
|
-
// after partial copy failures).
|
|
541
|
+
syncResourceDir(join(resourcesDir, 'skills'), skillsDir);
|
|
548
542
|
// Sync GSD-WORKFLOW.md to agentDir as a fallback for when GSD_WORKFLOW_PATH
|
|
549
543
|
// env var is not set (e.g. fork/dev builds, alternative entry points).
|
|
550
544
|
const workflowSrc = join(resourcesDir, 'GSD-WORKFLOW.md');
|
|
@@ -18,10 +18,11 @@ import { execFileSync } from "node:child_process";
|
|
|
18
18
|
const CLAUDE_COMMAND = process.platform === "win32" ? "claude.cmd" : "claude";
|
|
19
19
|
/**
|
|
20
20
|
* Windows installs vary: some environments expose `claude.cmd` (npm shim),
|
|
21
|
-
*
|
|
22
|
-
* Try
|
|
21
|
+
* `claude.exe` (direct binary install), or a bare `claude` shim on PATH
|
|
22
|
+
* (for example Git Bash wrappers). Try all three to avoid false "not
|
|
23
|
+
* installed" results in readiness checks.
|
|
23
24
|
*/
|
|
24
|
-
const CLAUDE_COMMAND_CANDIDATES = process.platform === "win32" ? [CLAUDE_COMMAND, "claude"] : [CLAUDE_COMMAND];
|
|
25
|
+
const CLAUDE_COMMAND_CANDIDATES = process.platform === "win32" ? [CLAUDE_COMMAND, "claude.exe", "claude"] : [CLAUDE_COMMAND];
|
|
25
26
|
function execClaude(args) {
|
|
26
27
|
let lastError;
|
|
27
28
|
for (const command of CLAUDE_COMMAND_CANDIDATES) {
|
|
@@ -484,25 +484,23 @@ export function makeAbortedMessage(model, lastTextContent) {
|
|
|
484
484
|
/**
|
|
485
485
|
* Resolve the Claude Code permission mode for the current run.
|
|
486
486
|
*
|
|
487
|
-
*
|
|
488
|
-
*
|
|
489
|
-
*
|
|
490
|
-
*
|
|
491
|
-
*
|
|
492
|
-
*
|
|
493
|
-
* users opt into a stricter mode (`acceptEdits`, `default`, `plan`).
|
|
487
|
+
* Defaults to `acceptEdits`, which auto-approves file reads/edits but
|
|
488
|
+
* surfaces a permission dialog for dangerous operations (e.g. general Bash,
|
|
489
|
+
* Agent, WebFetch). This prevents tools outside the allowlist from being
|
|
490
|
+
* silently denied — the SDK emits an `extension_ui_request` event so the
|
|
491
|
+
* user sees a prompt instead of a silent refusal that Claude Code mistakes
|
|
492
|
+
* for user rejection (#4383).
|
|
494
493
|
*
|
|
495
|
-
*
|
|
496
|
-
*
|
|
497
|
-
*
|
|
498
|
-
* (#4099) is continuous approval fatigue that blocks real work.
|
|
494
|
+
* Set `GSD_CLAUDE_CODE_PERMISSION_MODE` to `bypassPermissions` to restore
|
|
495
|
+
* the old always-approve behaviour, or to `default` / `plan` for stricter
|
|
496
|
+
* modes.
|
|
499
497
|
*/
|
|
500
498
|
export async function resolveClaudePermissionMode(env = process.env) {
|
|
501
499
|
const override = env.GSD_CLAUDE_CODE_PERMISSION_MODE?.trim();
|
|
502
500
|
if (override === "bypassPermissions" || override === "acceptEdits" || override === "default" || override === "plan") {
|
|
503
501
|
return override;
|
|
504
502
|
}
|
|
505
|
-
return "
|
|
503
|
+
return "acceptEdits";
|
|
506
504
|
}
|
|
507
505
|
// NOTE: These helpers intentionally mirror @gsd/pi-ai anthropic-shared
|
|
508
506
|
// behavior so this extension remains typecheck-stable even when the published
|
|
@@ -554,7 +552,7 @@ function mapThinkingLevelToAnthropicEffort(level, modelId) {
|
|
|
554
552
|
export function buildSdkOptions(modelId, prompt, overrides, extraOptions = {}) {
|
|
555
553
|
const { reasoning, ...sdkExtraOptions } = extraOptions;
|
|
556
554
|
const mcpServers = buildWorkflowMcpServers();
|
|
557
|
-
const permissionMode = overrides?.permissionMode ?? "
|
|
555
|
+
const permissionMode = overrides?.permissionMode ?? "acceptEdits";
|
|
558
556
|
const disallowedTools = ["AskUserQuestion"];
|
|
559
557
|
// Pre-authorize the safe built-ins and every registered workflow MCP
|
|
560
558
|
// server's tools. `acceptEdits` mode (the interactive default) only
|
|
@@ -637,6 +635,68 @@ function normalizeToolResultContent(content) {
|
|
|
637
635
|
}
|
|
638
636
|
return blocks.length > 0 ? blocks : [{ type: "text", text: "" }];
|
|
639
637
|
}
|
|
638
|
+
/**
|
|
639
|
+
* Extract a `details` payload from an MCP tool-result block.
|
|
640
|
+
*
|
|
641
|
+
* MCP's `CallToolResult` carries structured data in `structuredContent` — the
|
|
642
|
+
* protocol's supported channel for non-text payloads. Claude Code's synthetic
|
|
643
|
+
* user message may surface that field in one of two shapes depending on SDK
|
|
644
|
+
* version: as a sibling on the `mcp_tool_result` block itself, or as a
|
|
645
|
+
* dedicated content sub-block with `type: "structuredContent"`. Snake-case
|
|
646
|
+
* (`structured_content`) is accepted defensively in case a transport hop
|
|
647
|
+
* rewrites casing. All other shapes fall back to an empty object so callers
|
|
648
|
+
* can rely on `details` being present.
|
|
649
|
+
*/
|
|
650
|
+
function extractStructuredDetailsFromBlock(block) {
|
|
651
|
+
const sibling = block.structuredContent ?? block.structured_content;
|
|
652
|
+
if (sibling && typeof sibling === "object" && !Array.isArray(sibling)) {
|
|
653
|
+
return sibling;
|
|
654
|
+
}
|
|
655
|
+
if (Array.isArray(block.content)) {
|
|
656
|
+
for (const item of block.content) {
|
|
657
|
+
if (!item || typeof item !== "object")
|
|
658
|
+
continue;
|
|
659
|
+
const sub = item;
|
|
660
|
+
if (sub.type !== "structuredContent" && sub.type !== "structured_content")
|
|
661
|
+
continue;
|
|
662
|
+
const payload = sub.structuredContent ?? sub.structured_content ?? sub.data ?? sub.value;
|
|
663
|
+
if (payload && typeof payload === "object" && !Array.isArray(payload)) {
|
|
664
|
+
return payload;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
// Return undefined (not {}) when no structured payload is present, matching
|
|
669
|
+
// the pre-#4477 contract where `details` was nullable. An empty-object
|
|
670
|
+
// sentinel is truthy and breaks downstream consumers that gate on
|
|
671
|
+
// `if (details)`. `undefined` matches the type of the field these results
|
|
672
|
+
// flow into (`Record<string, unknown> | undefined`).
|
|
673
|
+
return undefined;
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* True for items that are MCP `structuredContent` pseudo-blocks living inside
|
|
677
|
+
* a tool-result `content[]` array. These blocks carry the structured payload
|
|
678
|
+
* (extracted separately by `extractStructuredDetailsFromBlock`) and must NOT
|
|
679
|
+
* leak into the visible content rendered to the user — otherwise the renderer
|
|
680
|
+
* stringifies the JSON pseudo-block and shows it next to the actual tool
|
|
681
|
+
* output. See PR #4477 review (CodeRabbit, post-fix-round).
|
|
682
|
+
*/
|
|
683
|
+
function isStructuredContentPseudoBlock(item) {
|
|
684
|
+
if (!item || typeof item !== "object")
|
|
685
|
+
return false;
|
|
686
|
+
const type = item.type;
|
|
687
|
+
return type === "structuredContent" || type === "structured_content";
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Strip `structuredContent` pseudo-blocks from a tool-result content array
|
|
691
|
+
* before normalization. The structured payload is extracted via the sibling
|
|
692
|
+
* `structuredContent` field (or a dedicated extractor pass on the raw block);
|
|
693
|
+
* the visible content path must not include the pseudo-block itself.
|
|
694
|
+
*/
|
|
695
|
+
function stripStructuredContentPseudoBlocks(content) {
|
|
696
|
+
if (!Array.isArray(content))
|
|
697
|
+
return content;
|
|
698
|
+
return content.filter((item) => !isStructuredContentPseudoBlock(item));
|
|
699
|
+
}
|
|
640
700
|
/** Extract tool result payloads from an SDK synthetic user message, keyed by tool-use ID. */
|
|
641
701
|
export function extractToolResultsFromSdkUserMessage(message) {
|
|
642
702
|
const extracted = [];
|
|
@@ -657,8 +717,8 @@ export function extractToolResultsFromSdkUserMessage(message) {
|
|
|
657
717
|
extracted.push({
|
|
658
718
|
toolUseId,
|
|
659
719
|
result: {
|
|
660
|
-
content: normalizeToolResultContent(block.content),
|
|
661
|
-
details:
|
|
720
|
+
content: normalizeToolResultContent(stripStructuredContentPseudoBlocks(block.content)),
|
|
721
|
+
details: extractStructuredDetailsFromBlock(block),
|
|
662
722
|
isError: block.is_error === true,
|
|
663
723
|
},
|
|
664
724
|
});
|
|
@@ -672,8 +732,8 @@ export function extractToolResultsFromSdkUserMessage(message) {
|
|
|
672
732
|
extracted.push({
|
|
673
733
|
toolUseId,
|
|
674
734
|
result: {
|
|
675
|
-
content: normalizeToolResultContent(toolResult.content),
|
|
676
|
-
details:
|
|
735
|
+
content: normalizeToolResultContent(stripStructuredContentPseudoBlocks(toolResult.content)),
|
|
736
|
+
details: extractStructuredDetailsFromBlock(toolResult),
|
|
677
737
|
isError: toolResult.is_error === true,
|
|
678
738
|
},
|
|
679
739
|
});
|
|
@@ -1430,6 +1430,20 @@ export async function runFinalize(ic, iterData, loopState, sidecarItem) {
|
|
|
1430
1430
|
}
|
|
1431
1431
|
else {
|
|
1432
1432
|
// s.pendingVerificationRetry was set by postUnitPreVerification.
|
|
1433
|
+
// Emit a dedicated journal event so forensics can distinguish bounded
|
|
1434
|
+
// verification retries from genuine stuck-loop dispatch repetitions (#4540).
|
|
1435
|
+
const retryInfo = s.pendingVerificationRetry;
|
|
1436
|
+
deps.emitJournalEvent({
|
|
1437
|
+
ts: new Date().toISOString(),
|
|
1438
|
+
flowId: ic.flowId,
|
|
1439
|
+
seq: ic.nextSeq(),
|
|
1440
|
+
eventType: "artifact-verification-retry",
|
|
1441
|
+
data: {
|
|
1442
|
+
unitType: preUnitSnapshot?.type,
|
|
1443
|
+
unitId: retryInfo?.unitId,
|
|
1444
|
+
attempt: retryInfo?.attempt,
|
|
1445
|
+
},
|
|
1446
|
+
});
|
|
1433
1447
|
// Continue the loop — next iteration will inject the retry context into the prompt.
|
|
1434
1448
|
debugLog("autoLoop", { phase: "artifact-verification-retry", iteration: ic.iteration });
|
|
1435
1449
|
return { action: "continue" };
|
|
@@ -92,6 +92,33 @@ export async function runUnit(ctx, pi, s, unitType, unitId, prompt) {
|
|
|
92
92
|
catch (e) {
|
|
93
93
|
logWarning("engine", "Failed to chdir to basePath before dispatch", { basePath: s.basePath, error: String(e) });
|
|
94
94
|
}
|
|
95
|
+
// ── Provider request-readiness pre-check (#4555) ──
|
|
96
|
+
// Verify the provider can accept requests before dispatching. If the token
|
|
97
|
+
// has expired since bootstrap, return cancelled immediately so the unit is
|
|
98
|
+
// not wasted on a guaranteed 401.
|
|
99
|
+
{
|
|
100
|
+
const provider = s.currentUnitModel?.provider ?? ctx.model?.provider;
|
|
101
|
+
const registry = ctx.modelRegistry;
|
|
102
|
+
if (provider && registry != null && typeof registry.isProviderRequestReady === "function") {
|
|
103
|
+
let ready = false;
|
|
104
|
+
try {
|
|
105
|
+
ready = registry.isProviderRequestReady(provider);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
ready = false;
|
|
109
|
+
}
|
|
110
|
+
if (!ready) {
|
|
111
|
+
return {
|
|
112
|
+
status: "cancelled",
|
|
113
|
+
errorContext: {
|
|
114
|
+
message: `Provider ${provider} is not request-ready (login/token expired)`,
|
|
115
|
+
category: "provider",
|
|
116
|
+
isTransient: false,
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
95
122
|
// ── Send the prompt ──
|
|
96
123
|
debugLog("runUnit", { phase: "send-message", unitType, unitId });
|
|
97
124
|
pi.sendMessage({ customType: "gsd-auto", content: prompt, display: s.verbose }, { triggerTurn: true });
|
|
@@ -291,7 +291,7 @@ autoModeStartThinkingLevel) {
|
|
|
291
291
|
// ADR-005: Adjust active tool set for the selected model's provider capabilities.
|
|
292
292
|
// Hard-filter incompatible tools, then let extensions override via adjust_tool_set hook.
|
|
293
293
|
const activeToolNames = pi.getActiveTools();
|
|
294
|
-
const { toolNames: compatibleTools, removedTools } = adjustToolSet(activeToolNames, model.api);
|
|
294
|
+
const { toolNames: compatibleTools, removedTools } = adjustToolSet(activeToolNames, model.api, model.provider);
|
|
295
295
|
let finalToolNames = compatibleTools;
|
|
296
296
|
// Fire adjust_tool_set hook — extensions can override the filtered tool set
|
|
297
297
|
if (routingConfig.hooks !== false) {
|
|
@@ -535,7 +535,7 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
535
535
|
if (taskRow) {
|
|
536
536
|
const expectedOutput = taskRow.expected_output ?? [];
|
|
537
537
|
const plannedFiles = taskRow.files ?? [];
|
|
538
|
-
const audit = validateFileChanges(s.basePath, expectedOutput, plannedFiles);
|
|
538
|
+
const audit = validateFileChanges(s.basePath, expectedOutput, plannedFiles, safetyConfig.file_change_allowlist);
|
|
539
539
|
if (audit && audit.violations.length > 0) {
|
|
540
540
|
const warnings = audit.violations.filter(v => v.severity === "warning");
|
|
541
541
|
for (const v of warnings) {
|
|
@@ -220,12 +220,25 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
|
|
|
220
220
|
// RESEARCH file. Without this, resolveExpectedArtifactPath returns null and
|
|
221
221
|
// the retry/escalation machinery silently re-dispatches forever.
|
|
222
222
|
//
|
|
223
|
+
// #4068: Also treat a PARALLEL-BLOCKER placeholder as a terminal completion
|
|
224
|
+
// so that timeout-recovery can write the blocker, have verifyExpectedArtifact
|
|
225
|
+
// return true, and let the dispatch loop advance past this unit. Without
|
|
226
|
+
// this, the blocker is written but verification still returns false, the unit
|
|
227
|
+
// is never cleared from unitDispatchCount, and on the next iteration the
|
|
228
|
+
// dispatch rule (which correctly skips parallel-research when PARALLEL-BLOCKER
|
|
229
|
+
// exists) returns null — leaving the loop stuck re-deriving indefinitely.
|
|
230
|
+
//
|
|
223
231
|
// NOTE: this predicate mirrors the dispatch rule at
|
|
224
232
|
// auto-dispatch.ts parallel-research-slices — keep the two in sync.
|
|
225
233
|
if (unitType === "research-slice" && unitId.endsWith("/parallel-research")) {
|
|
226
234
|
const { milestone: mid } = parseUnitId(unitId);
|
|
227
235
|
if (!mid)
|
|
228
236
|
return false;
|
|
237
|
+
// #4068: PARALLEL-BLOCKER written by timeout-recovery is a terminal state.
|
|
238
|
+
const blockerPath = resolveExpectedArtifactPath(unitType, unitId, base);
|
|
239
|
+
if (blockerPath && existsSync(blockerPath)) {
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
229
242
|
const roadmapFile = resolveMilestoneFile(base, mid, "ROADMAP");
|
|
230
243
|
if (!roadmapFile || !existsSync(roadmapFile)) {
|
|
231
244
|
logWarning("recovery", `verify-fail ${unitType} ${unitId}: roadmap missing`);
|
|
@@ -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
|