gsd-pi 2.76.0-dev.b072ebb73 → 2.76.0-dev.fe143342a
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/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/stream-adapter.js +66 -4
- package/dist/resources/extensions/gsd/auto/phases.js +4 -1
- package/dist/resources/extensions/gsd/auto/session.js +4 -0
- package/dist/resources/extensions/gsd/auto-model-selection.js +39 -13
- package/dist/resources/extensions/gsd/auto-start.js +39 -21
- package/dist/resources/extensions/gsd/auto.js +15 -12
- package/dist/resources/extensions/gsd/blocked-models.js +68 -0
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +76 -0
- 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 +35 -0
- package/dist/resources/extensions/gsd/compaction-snapshot.js +121 -0
- package/dist/resources/extensions/gsd/complexity-classifier.js +5 -3
- package/dist/resources/extensions/gsd/error-classifier.js +31 -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 +62 -4
- 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/pre-execution-checks.js +13 -3
- 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/prompt-loader.js +22 -7
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +1 -1
- 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/extensions/search-the-web/command-search-provider.js +5 -4
- package/dist/resources/extensions/search-the-web/native-search.js +45 -13
- 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 +8 -8
- 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 +8 -8
- 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/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/src/workflow-tools.test.ts +146 -1
- package/packages/mcp-server/src/workflow-tools.ts +84 -43
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +60 -15
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/providers/think-tag-parser.d.ts +17 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.js +75 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.js.map +1 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.test.js +41 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.test.js.map +1 -0
- package/packages/pi-ai/src/providers/openai-completions.ts +57 -16
- package/packages/pi-ai/src/providers/think-tag-parser.test.ts +44 -0
- package/packages/pi-ai/src/providers/think-tag-parser.ts +94 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.d.ts +3 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.js +92 -12
- package/packages/pi-coding-agent/dist/core/model-discovery.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.test.js +16 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js +61 -1
- package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +5 -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 +76 -10
- 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/provider-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +13 -7
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.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/src/core/model-discovery.test.ts +19 -0
- package/packages/pi-coding-agent/src/core/model-discovery.ts +99 -12
- package/packages/pi-coding-agent/src/core/model-registry-discovery.test.ts +75 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +86 -10
- 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/provider-manager.ts +16 -7
- package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +36 -22
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/scripts/link-workspace-packages.cjs +1 -0
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +67 -4
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +137 -2
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/phases.ts +4 -0
- package/src/resources/extensions/gsd/auto/session.ts +7 -1
- package/src/resources/extensions/gsd/auto-model-selection.ts +50 -12
- package/src/resources/extensions/gsd/auto-start.ts +40 -22
- package/src/resources/extensions/gsd/auto.ts +15 -12
- package/src/resources/extensions/gsd/blocked-models.ts +98 -0
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +97 -0
- 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 +36 -0
- package/src/resources/extensions/gsd/compaction-snapshot.ts +165 -0
- package/src/resources/extensions/gsd/complexity-classifier.ts +5 -3
- package/src/resources/extensions/gsd/error-classifier.ts +36 -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 +68 -4
- package/src/resources/extensions/gsd/init-wizard.ts +15 -1
- package/src/resources/extensions/gsd/key-manager.ts +6 -0
- package/src/resources/extensions/gsd/pre-execution-checks.ts +13 -3
- package/src/resources/extensions/gsd/preferences-types.ts +38 -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/prompt-loader.ts +30 -7
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +33 -3
- package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/blocked-models.test.ts +98 -0
- package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +123 -0
- package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +3 -3
- 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 +20 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +151 -0
- 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/key-manager.test.ts +7 -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 +19 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +110 -0
- package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +91 -0
- package/src/resources/extensions/gsd/tests/save-gate-result-render.test.ts +95 -0
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +3 -1
- 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/extensions/search-the-web/command-search-provider.ts +5 -4
- package/src/resources/extensions/search-the-web/native-search.ts +48 -12
- /package/dist/web/standalone/.next/static/{pBwmOoye64ZrRp-_rf0v1 → n21VtX2hZlkpdEUO_nU4z}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{pBwmOoye64ZrRp-_rf0v1 → n21VtX2hZlkpdEUO_nU4z}/_ssgManifest.js +0 -0
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');
|
|
@@ -637,6 +637,68 @@ function normalizeToolResultContent(content) {
|
|
|
637
637
|
}
|
|
638
638
|
return blocks.length > 0 ? blocks : [{ type: "text", text: "" }];
|
|
639
639
|
}
|
|
640
|
+
/**
|
|
641
|
+
* Extract a `details` payload from an MCP tool-result block.
|
|
642
|
+
*
|
|
643
|
+
* MCP's `CallToolResult` carries structured data in `structuredContent` — the
|
|
644
|
+
* protocol's supported channel for non-text payloads. Claude Code's synthetic
|
|
645
|
+
* user message may surface that field in one of two shapes depending on SDK
|
|
646
|
+
* version: as a sibling on the `mcp_tool_result` block itself, or as a
|
|
647
|
+
* dedicated content sub-block with `type: "structuredContent"`. Snake-case
|
|
648
|
+
* (`structured_content`) is accepted defensively in case a transport hop
|
|
649
|
+
* rewrites casing. All other shapes fall back to an empty object so callers
|
|
650
|
+
* can rely on `details` being present.
|
|
651
|
+
*/
|
|
652
|
+
function extractStructuredDetailsFromBlock(block) {
|
|
653
|
+
const sibling = block.structuredContent ?? block.structured_content;
|
|
654
|
+
if (sibling && typeof sibling === "object" && !Array.isArray(sibling)) {
|
|
655
|
+
return sibling;
|
|
656
|
+
}
|
|
657
|
+
if (Array.isArray(block.content)) {
|
|
658
|
+
for (const item of block.content) {
|
|
659
|
+
if (!item || typeof item !== "object")
|
|
660
|
+
continue;
|
|
661
|
+
const sub = item;
|
|
662
|
+
if (sub.type !== "structuredContent" && sub.type !== "structured_content")
|
|
663
|
+
continue;
|
|
664
|
+
const payload = sub.structuredContent ?? sub.structured_content ?? sub.data ?? sub.value;
|
|
665
|
+
if (payload && typeof payload === "object" && !Array.isArray(payload)) {
|
|
666
|
+
return payload;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
// Return undefined (not {}) when no structured payload is present, matching
|
|
671
|
+
// the pre-#4477 contract where `details` was nullable. An empty-object
|
|
672
|
+
// sentinel is truthy and breaks downstream consumers that gate on
|
|
673
|
+
// `if (details)`. `undefined` matches the type of the field these results
|
|
674
|
+
// flow into (`Record<string, unknown> | undefined`).
|
|
675
|
+
return undefined;
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* True for items that are MCP `structuredContent` pseudo-blocks living inside
|
|
679
|
+
* a tool-result `content[]` array. These blocks carry the structured payload
|
|
680
|
+
* (extracted separately by `extractStructuredDetailsFromBlock`) and must NOT
|
|
681
|
+
* leak into the visible content rendered to the user — otherwise the renderer
|
|
682
|
+
* stringifies the JSON pseudo-block and shows it next to the actual tool
|
|
683
|
+
* output. See PR #4477 review (CodeRabbit, post-fix-round).
|
|
684
|
+
*/
|
|
685
|
+
function isStructuredContentPseudoBlock(item) {
|
|
686
|
+
if (!item || typeof item !== "object")
|
|
687
|
+
return false;
|
|
688
|
+
const type = item.type;
|
|
689
|
+
return type === "structuredContent" || type === "structured_content";
|
|
690
|
+
}
|
|
691
|
+
/**
|
|
692
|
+
* Strip `structuredContent` pseudo-blocks from a tool-result content array
|
|
693
|
+
* before normalization. The structured payload is extracted via the sibling
|
|
694
|
+
* `structuredContent` field (or a dedicated extractor pass on the raw block);
|
|
695
|
+
* the visible content path must not include the pseudo-block itself.
|
|
696
|
+
*/
|
|
697
|
+
function stripStructuredContentPseudoBlocks(content) {
|
|
698
|
+
if (!Array.isArray(content))
|
|
699
|
+
return content;
|
|
700
|
+
return content.filter((item) => !isStructuredContentPseudoBlock(item));
|
|
701
|
+
}
|
|
640
702
|
/** Extract tool result payloads from an SDK synthetic user message, keyed by tool-use ID. */
|
|
641
703
|
export function extractToolResultsFromSdkUserMessage(message) {
|
|
642
704
|
const extracted = [];
|
|
@@ -657,8 +719,8 @@ export function extractToolResultsFromSdkUserMessage(message) {
|
|
|
657
719
|
extracted.push({
|
|
658
720
|
toolUseId,
|
|
659
721
|
result: {
|
|
660
|
-
content: normalizeToolResultContent(block.content),
|
|
661
|
-
details:
|
|
722
|
+
content: normalizeToolResultContent(stripStructuredContentPseudoBlocks(block.content)),
|
|
723
|
+
details: extractStructuredDetailsFromBlock(block),
|
|
662
724
|
isError: block.is_error === true,
|
|
663
725
|
},
|
|
664
726
|
});
|
|
@@ -672,8 +734,8 @@ export function extractToolResultsFromSdkUserMessage(message) {
|
|
|
672
734
|
extracted.push({
|
|
673
735
|
toolUseId,
|
|
674
736
|
result: {
|
|
675
|
-
content: normalizeToolResultContent(toolResult.content),
|
|
676
|
-
details:
|
|
737
|
+
content: normalizeToolResultContent(stripStructuredContentPseudoBlocks(toolResult.content)),
|
|
738
|
+
details: extractStructuredDetailsFromBlock(toolResult),
|
|
677
739
|
isError: toolResult.is_error === true,
|
|
678
740
|
},
|
|
679
741
|
});
|
|
@@ -1094,7 +1094,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1094
1094
|
logWarning("engine", "Prompt reorder failed", { error: msg });
|
|
1095
1095
|
}
|
|
1096
1096
|
// Select and apply model (with tier escalation on retry — normal units only)
|
|
1097
|
-
const modelResult = await deps.selectAndApplyModel(ctx, pi, unitType, unitId, s.basePath, prefs, s.verbose, s.autoModeStartModel, sidecarItem ? undefined : { isRetry, previousTier }, undefined, s.manualSessionModelOverride);
|
|
1097
|
+
const modelResult = await deps.selectAndApplyModel(ctx, pi, unitType, unitId, s.basePath, prefs, s.verbose, s.autoModeStartModel, sidecarItem ? undefined : { isRetry, previousTier }, undefined, s.manualSessionModelOverride, s.autoModeStartThinkingLevel);
|
|
1098
1098
|
s.currentUnitRouting =
|
|
1099
1099
|
modelResult.routing;
|
|
1100
1100
|
s.currentUnitModel =
|
|
@@ -1107,6 +1107,9 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1107
1107
|
if (match) {
|
|
1108
1108
|
const ok = await pi.setModel(match, { persist: false });
|
|
1109
1109
|
if (ok) {
|
|
1110
|
+
if (s.autoModeStartThinkingLevel) {
|
|
1111
|
+
pi.setThinkingLevel(s.autoModeStartThinkingLevel);
|
|
1112
|
+
}
|
|
1110
1113
|
s.currentUnitModel = match;
|
|
1111
1114
|
ctx.ui.notify(`Hook model override: ${match.provider}/${match.id}`, "info");
|
|
1112
1115
|
}
|
|
@@ -65,6 +65,8 @@ export class AutoSession {
|
|
|
65
65
|
currentDispatchedModelId = null;
|
|
66
66
|
originalModelId = null;
|
|
67
67
|
originalModelProvider = null;
|
|
68
|
+
autoModeStartThinkingLevel = null;
|
|
69
|
+
originalThinkingLevel = null;
|
|
68
70
|
lastBudgetAlertLevel = 0;
|
|
69
71
|
// ── Recovery ─────────────────────────────────────────────────────────────
|
|
70
72
|
pendingCrashRecovery = null;
|
|
@@ -177,6 +179,8 @@ export class AutoSession {
|
|
|
177
179
|
this.currentDispatchedModelId = null;
|
|
178
180
|
this.originalModelId = null;
|
|
179
181
|
this.originalModelProvider = null;
|
|
182
|
+
this.autoModeStartThinkingLevel = null;
|
|
183
|
+
this.originalThinkingLevel = null;
|
|
180
184
|
this.lastBudgetAlertLevel = 0;
|
|
181
185
|
// Recovery
|
|
182
186
|
this.pendingCrashRecovery = null;
|
|
@@ -12,6 +12,12 @@ import { getSessionModelOverride } from "./session-model-override.js";
|
|
|
12
12
|
import { logWarning } from "./workflow-logger.js";
|
|
13
13
|
import { resolveUokFlags } from "./uok/flags.js";
|
|
14
14
|
import { applyModelPolicyFilter } from "./uok/model-policy.js";
|
|
15
|
+
import { isModelBlocked } from "./blocked-models.js";
|
|
16
|
+
function reapplyThinkingLevel(pi, level) {
|
|
17
|
+
if (!level)
|
|
18
|
+
return;
|
|
19
|
+
pi.setThinkingLevel(level);
|
|
20
|
+
}
|
|
15
21
|
export function resolvePreferredModelConfig(unitType, autoModeStartModel, isAutoMode = true) {
|
|
16
22
|
const explicitConfig = resolveModelWithFallbacksForUnit(unitType);
|
|
17
23
|
if (explicitConfig) {
|
|
@@ -57,7 +63,9 @@ export async function selectAndApplyModel(ctx, pi, unitType, unitId, basePath, p
|
|
|
57
63
|
* Dynamic routing only applies in auto-mode where cost optimization is expected. (#3962) */
|
|
58
64
|
isAutoMode = true,
|
|
59
65
|
/** Explicit /gsd model pin captured at bootstrap for long-running auto loops. */
|
|
60
|
-
sessionModelOverride
|
|
66
|
+
sessionModelOverride,
|
|
67
|
+
/** Thinking level captured at auto-mode start and re-applied after model swaps. */
|
|
68
|
+
autoModeStartThinkingLevel) {
|
|
61
69
|
const uokFlags = resolveUokFlags(prefs);
|
|
62
70
|
const effectiveSessionModelOverride = sessionModelOverride === undefined
|
|
63
71
|
? getSessionModelOverride(ctx.sessionManager.getSessionId())
|
|
@@ -260,6 +268,14 @@ sessionModelOverride) {
|
|
|
260
268
|
}
|
|
261
269
|
attemptedPolicyEligible = true;
|
|
262
270
|
}
|
|
271
|
+
// Skip models the provider has previously rejected for this account
|
|
272
|
+
// (issue #4513). The block is persisted in .gsd/runtime/blocked-models.json
|
|
273
|
+
// so it survives /gsd auto restarts — without this, the same dead model
|
|
274
|
+
// gets reselected after every restart.
|
|
275
|
+
if (isModelBlocked(basePath, model.provider, model.id)) {
|
|
276
|
+
ctx.ui.notify(`Skipping blocked model ${model.provider}/${model.id} (provider rejected it for this account).`, "warning");
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
263
279
|
// Warn if the ID is ambiguous across providers
|
|
264
280
|
if (!modelId.includes("/")) {
|
|
265
281
|
const providers = availableModels.filter(m => m.id === modelId).map(m => m.provider);
|
|
@@ -271,6 +287,7 @@ sessionModelOverride) {
|
|
|
271
287
|
const ok = await pi.setModel(model, { persist: false });
|
|
272
288
|
if (ok) {
|
|
273
289
|
appliedModel = model;
|
|
290
|
+
reapplyThinkingLevel(pi, autoModeStartThinkingLevel);
|
|
274
291
|
// ADR-005: Adjust active tool set for the selected model's provider capabilities.
|
|
275
292
|
// Hard-filter incompatible tools, then let extensions override via adjust_tool_set hook.
|
|
276
293
|
const activeToolNames = pi.getActiveTools();
|
|
@@ -325,19 +342,28 @@ sessionModelOverride) {
|
|
|
325
342
|
// No model preference for this unit type — re-apply the model captured
|
|
326
343
|
// at auto-mode start to prevent bleed from shared global settings.json (#650).
|
|
327
344
|
const availableModels = ctx.modelRegistry.getAvailable();
|
|
328
|
-
const
|
|
329
|
-
if (
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
345
|
+
const startBlocked = isModelBlocked(basePath, autoModeStartModel.provider, autoModeStartModel.id);
|
|
346
|
+
if (startBlocked) {
|
|
347
|
+
ctx.ui.notify(`Auto-mode start model ${autoModeStartModel.provider}/${autoModeStartModel.id} is blocked for this account. Using current session model instead.`, "warning");
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
const startModel = availableModels.find(m => m.provider === autoModeStartModel.provider && m.id === autoModeStartModel.id);
|
|
351
|
+
if (startModel) {
|
|
352
|
+
const ok = await pi.setModel(startModel, { persist: false });
|
|
353
|
+
if (!ok) {
|
|
354
|
+
const byId = availableModels.find(m => m.id === autoModeStartModel.id && !isModelBlocked(basePath, m.provider, m.id));
|
|
355
|
+
if (byId) {
|
|
356
|
+
const fallbackOk = await pi.setModel(byId, { persist: false });
|
|
357
|
+
if (fallbackOk) {
|
|
358
|
+
appliedModel = byId;
|
|
359
|
+
reapplyThinkingLevel(pi, autoModeStartThinkingLevel);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
appliedModel = startModel;
|
|
365
|
+
reapplyThinkingLevel(pi, autoModeStartThinkingLevel);
|
|
337
366
|
}
|
|
338
|
-
}
|
|
339
|
-
else {
|
|
340
|
-
appliedModel = startModel;
|
|
341
367
|
}
|
|
342
368
|
}
|
|
343
369
|
}
|
|
@@ -30,7 +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";
|
|
33
|
+
import { isDbAvailable, getMilestone, openDatabase, getDbStatus } from "./gsd-db.js";
|
|
34
34
|
import { hideFooter } from "./auto-dashboard.js";
|
|
35
35
|
import { debugLog, enableDebug, isDebugEnabled, getDebugLogPath, } from "./debug-logger.js";
|
|
36
36
|
import { logWarning, logError } from "./workflow-logger.js";
|
|
@@ -190,8 +190,8 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
190
190
|
//
|
|
191
191
|
// Precedence:
|
|
192
192
|
// 1) Explicit session override via /gsd model (this session)
|
|
193
|
-
// 2)
|
|
194
|
-
// 3)
|
|
193
|
+
// 2) Current session model from settings/session restore (if provider ready)
|
|
194
|
+
// 3) GSD model preferences from PREFERENCES.md (validated against live auth)
|
|
195
195
|
//
|
|
196
196
|
// This preserves #3517 defaults while honoring explicit runtime model
|
|
197
197
|
// selection for subsequent /gsd runs in the same session.
|
|
@@ -224,11 +224,14 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
224
224
|
}
|
|
225
225
|
}
|
|
226
226
|
const sessionModelReady = ctx.model && ctx.modelRegistry.isProviderRequestReady(ctx.model.provider);
|
|
227
|
+
const currentSessionModel = (sessionModelReady && ctx.model)
|
|
228
|
+
? { provider: ctx.model.provider, id: ctx.model.id }
|
|
229
|
+
: null;
|
|
230
|
+
const startThinkingSnapshot = pi.getThinkingLevel();
|
|
227
231
|
const startModelSnapshot = manualSessionOverride
|
|
232
|
+
?? currentSessionModel
|
|
228
233
|
?? validatedPreferredModel
|
|
229
|
-
??
|
|
230
|
-
? { provider: ctx.model.provider, id: ctx.model.id }
|
|
231
|
-
: null);
|
|
234
|
+
?? null;
|
|
232
235
|
try {
|
|
233
236
|
// Validate GSD_PROJECT_ID early so the user gets immediate feedback
|
|
234
237
|
const customProjectId = process.env.GSD_PROJECT_ID;
|
|
@@ -244,7 +247,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
244
247
|
// the parent git root). See #2393 and related issue.
|
|
245
248
|
const hasLocalGit = existsSync(join(base, ".git"));
|
|
246
249
|
if (!hasLocalGit || isInheritedRepo(base)) {
|
|
247
|
-
const mainBranch = loadEffectiveGSDPreferences()?.preferences?.git?.main_branch || "main";
|
|
250
|
+
const mainBranch = loadEffectiveGSDPreferences(base)?.preferences?.git?.main_branch || "main";
|
|
248
251
|
nativeInit(base, mainBranch);
|
|
249
252
|
}
|
|
250
253
|
// Migrate legacy in-project .gsd/ to external state directory.
|
|
@@ -260,7 +263,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
260
263
|
// Ensure .gitignore has baseline patterns.
|
|
261
264
|
// ensureGitignore checks for git-tracked .gsd/ files and skips the
|
|
262
265
|
// ".gsd" pattern if the project intentionally tracks .gsd/ in git.
|
|
263
|
-
const gitPrefs = loadEffectiveGSDPreferences()?.preferences?.git;
|
|
266
|
+
const gitPrefs = loadEffectiveGSDPreferences(base)?.preferences?.git;
|
|
264
267
|
const manageGitignore = gitPrefs?.manage_gitignore;
|
|
265
268
|
ensureGitignore(base, { manageGitignore });
|
|
266
269
|
if (manageGitignore !== false)
|
|
@@ -286,7 +289,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
286
289
|
prepareWorkflowMcpForProject(ctx, base);
|
|
287
290
|
}
|
|
288
291
|
// Initialize GitServiceImpl
|
|
289
|
-
s.gitService = new GitServiceImpl(s.basePath, loadEffectiveGSDPreferences()?.preferences?.git ?? {});
|
|
292
|
+
s.gitService = new GitServiceImpl(s.basePath, loadEffectiveGSDPreferences(base)?.preferences?.git ?? {});
|
|
290
293
|
// ── Debug mode ──
|
|
291
294
|
if (!isDebugEnabled() && process.env.GSD_DEBUG === "1") {
|
|
292
295
|
enableDebug(base);
|
|
@@ -319,7 +322,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
319
322
|
// was lost due to session ending between completion and teardown.
|
|
320
323
|
// Must run after DB open and before worktree entry.
|
|
321
324
|
try {
|
|
322
|
-
const auditResult = auditOrphanedMilestoneBranches(base, getIsolationMode());
|
|
325
|
+
const auditResult = auditOrphanedMilestoneBranches(base, getIsolationMode(base));
|
|
323
326
|
for (const msg of auditResult.recovered) {
|
|
324
327
|
ctx.ui.notify(`Orphan audit: ${msg}`, "info");
|
|
325
328
|
}
|
|
@@ -337,7 +340,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
337
340
|
let state = await deriveState(base);
|
|
338
341
|
// Stale worktree state recovery (#654)
|
|
339
342
|
if (state.activeMilestone &&
|
|
340
|
-
shouldUseWorktreeIsolation() &&
|
|
343
|
+
shouldUseWorktreeIsolation(base) &&
|
|
341
344
|
!detectWorktreeName(base)) {
|
|
342
345
|
const wtPath = getAutoWorktreePath(base, state.activeMilestone.id);
|
|
343
346
|
if (wtPath) {
|
|
@@ -352,7 +355,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
352
355
|
let hasSurvivorBranch = false;
|
|
353
356
|
if (state.activeMilestone &&
|
|
354
357
|
(state.phase === "pre-planning" || state.phase === "complete") &&
|
|
355
|
-
getIsolationMode() !== "none" &&
|
|
358
|
+
getIsolationMode(base) !== "none" &&
|
|
356
359
|
!detectWorktreeName(base) &&
|
|
357
360
|
!base.includes(`${pathSep}.gsd${pathSep}worktrees${pathSep}`)) {
|
|
358
361
|
const milestoneBranch = `milestone/${state.activeMilestone.id}`;
|
|
@@ -506,13 +509,14 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
506
509
|
s.pendingQuickTasks = [];
|
|
507
510
|
s.currentUnit = null;
|
|
508
511
|
s.currentMilestoneId = state.activeMilestone?.id ?? null;
|
|
509
|
-
s.originalModelId = ctx.model?.id ?? null;
|
|
510
|
-
s.originalModelProvider = ctx.model?.provider ?? null;
|
|
512
|
+
s.originalModelId = startModelSnapshot?.id ?? ctx.model?.id ?? null;
|
|
513
|
+
s.originalModelProvider = startModelSnapshot?.provider ?? ctx.model?.provider ?? null;
|
|
514
|
+
s.originalThinkingLevel = startThinkingSnapshot ?? null;
|
|
511
515
|
// Register SIGTERM handler
|
|
512
516
|
registerSigtermHandler(base);
|
|
513
517
|
// Capture integration branch
|
|
514
518
|
if (s.currentMilestoneId) {
|
|
515
|
-
if (getIsolationMode() !== "none") {
|
|
519
|
+
if (getIsolationMode(base) !== "none") {
|
|
516
520
|
captureIntegrationBranch(base, s.currentMilestoneId);
|
|
517
521
|
}
|
|
518
522
|
setActiveMilestoneId(base, s.currentMilestoneId);
|
|
@@ -520,7 +524,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
520
524
|
// Guard against stale milestone branch when isolation:none (#3613).
|
|
521
525
|
// A prior session with isolation:branch/worktree may have left HEAD on
|
|
522
526
|
// milestone/<MID>. Auto-checkout back to the integration branch.
|
|
523
|
-
if (getIsolationMode() === "none" && nativeIsRepo(base)) {
|
|
527
|
+
if (getIsolationMode(base) === "none" && nativeIsRepo(base)) {
|
|
524
528
|
try {
|
|
525
529
|
const currentBranch = nativeGetCurrentBranch(base);
|
|
526
530
|
if (currentBranch.startsWith("milestone/")) {
|
|
@@ -548,7 +552,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
548
552
|
return symlinkRe.test(p);
|
|
549
553
|
};
|
|
550
554
|
if (s.currentMilestoneId &&
|
|
551
|
-
getIsolationMode() !== "none" &&
|
|
555
|
+
getIsolationMode(base) !== "none" &&
|
|
552
556
|
!detectWorktreeName(base) &&
|
|
553
557
|
!isUnderGsdWorktrees(base)) {
|
|
554
558
|
buildResolver().enterMilestone(s.currentMilestoneId, {
|
|
@@ -593,8 +597,21 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
593
597
|
// call returns "db_unavailable", triggering artifact-retry which
|
|
594
598
|
// re-dispatches the same task — producing an infinite loop (#2419).
|
|
595
599
|
if (existsSync(gsdDbPath) && !isDbAvailable()) {
|
|
596
|
-
|
|
597
|
-
|
|
600
|
+
const dbStatus = getDbStatus();
|
|
601
|
+
const phaseHint = dbStatus.lastPhase === "open"
|
|
602
|
+
? "The database file could not be opened"
|
|
603
|
+
: dbStatus.lastPhase === "initSchema"
|
|
604
|
+
? "The database schema could not be initialized"
|
|
605
|
+
: dbStatus.lastPhase === "vacuum-recovery"
|
|
606
|
+
? "Corruption recovery (VACUUM) failed"
|
|
607
|
+
: dbStatus.attempted
|
|
608
|
+
? "The database could not be opened (phase unknown)"
|
|
609
|
+
: "The database provider could not be loaded";
|
|
610
|
+
const errorDetail = dbStatus.lastError ? ` (${dbStatus.lastError.message})` : "";
|
|
611
|
+
const providerHint = dbStatus.provider
|
|
612
|
+
? ` Provider: ${dbStatus.provider}.`
|
|
613
|
+
: " No SQLite provider available — check Node >= 22 or install better-sqlite3.";
|
|
614
|
+
ctx.ui.notify(`SQLite database exists but failed to open: ${gsdDbPath}. ${phaseHint}${errorDetail}.${providerHint}`, "error");
|
|
598
615
|
return releaseLockAndReturn();
|
|
599
616
|
}
|
|
600
617
|
// Initialize metrics
|
|
@@ -608,6 +625,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
608
625
|
id: startModelSnapshot.id,
|
|
609
626
|
};
|
|
610
627
|
}
|
|
628
|
+
s.autoModeStartThinkingLevel = startThinkingSnapshot ?? null;
|
|
611
629
|
s.manualSessionModelOverride = manualSessionOverride ?? null;
|
|
612
630
|
// Apply worker model override from parallel orchestrator (#worker-model).
|
|
613
631
|
// GSD_WORKER_MODEL is injected by the coordinator when parallel.worker_model
|
|
@@ -628,7 +646,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
628
646
|
}
|
|
629
647
|
}
|
|
630
648
|
// Snapshot installed skills
|
|
631
|
-
if (resolveSkillDiscoveryMode() !== "off") {
|
|
649
|
+
if (resolveSkillDiscoveryMode(base) !== "off") {
|
|
632
650
|
snapshotSkills();
|
|
633
651
|
}
|
|
634
652
|
ctx.ui.setStatus("gsd-auto", s.stepMode ? "next" : "auto");
|
|
@@ -656,7 +674,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
656
674
|
// FlatRateContext used by selectAndApplyModel so user-declared
|
|
657
675
|
// flat-rate providers and externalCli auto-detection are respected.
|
|
658
676
|
const { isFlatRateProvider, buildFlatRateContext } = await import("./auto-model-selection.js");
|
|
659
|
-
const bannerPrefs = loadEffectiveGSDPreferences()?.preferences;
|
|
677
|
+
const bannerPrefs = loadEffectiveGSDPreferences(base)?.preferences;
|
|
660
678
|
const effectiveProvider = s.autoModeStartModel?.provider ?? ctx.model?.provider;
|
|
661
679
|
const effectivelyEnabled = routingConfig.enabled
|
|
662
680
|
&& (routingConfig.allow_flat_rate_providers
|
|
@@ -145,8 +145,8 @@ export function startAutoDetached(ctx, pi, base, verboseMode, options) {
|
|
|
145
145
|
});
|
|
146
146
|
}
|
|
147
147
|
/** Returns true if the project is configured for `isolation:worktree` mode. */
|
|
148
|
-
export function shouldUseWorktreeIsolation() {
|
|
149
|
-
const prefs = loadEffectiveGSDPreferences()?.preferences?.git;
|
|
148
|
+
export function shouldUseWorktreeIsolation(basePath) {
|
|
149
|
+
const prefs = loadEffectiveGSDPreferences(basePath)?.preferences?.git;
|
|
150
150
|
if (prefs?.isolation === "worktree")
|
|
151
151
|
return true;
|
|
152
152
|
// Default is false — worktree isolation requires explicit opt-in
|
|
@@ -215,7 +215,7 @@ export function getAutoDashboardData() {
|
|
|
215
215
|
const rtkSavings = sessionId && s.basePath
|
|
216
216
|
? getRtkSessionSavings(s.basePath, sessionId)
|
|
217
217
|
: null;
|
|
218
|
-
const rtkEnabled = loadEffectiveGSDPreferences()?.preferences.experimental?.rtk === true;
|
|
218
|
+
const rtkEnabled = loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences.experimental?.rtk === true;
|
|
219
219
|
// Pending capture count — lazy check, non-fatal
|
|
220
220
|
let pendingCaptureCount = 0;
|
|
221
221
|
try {
|
|
@@ -393,7 +393,7 @@ function clearUnitTimeout() {
|
|
|
393
393
|
}
|
|
394
394
|
/** Build snapshot metric opts. */
|
|
395
395
|
function buildSnapshotOpts(_unitType, _unitId) {
|
|
396
|
-
const prefs = loadEffectiveGSDPreferences()?.preferences;
|
|
396
|
+
const prefs = loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences;
|
|
397
397
|
const uokFlags = resolveUokFlags(prefs);
|
|
398
398
|
return {
|
|
399
399
|
...(s.autoStartTime > 0 ? { autoSessionKey: String(s.autoStartTime) } : {}),
|
|
@@ -427,7 +427,7 @@ function handleLostSessionLock(ctx, lockStatus) {
|
|
|
427
427
|
restoreProjectRootEnv();
|
|
428
428
|
restoreMilestoneLockEnv();
|
|
429
429
|
deregisterSigtermHandler();
|
|
430
|
-
clearCmuxSidebar(loadEffectiveGSDPreferences()?.preferences);
|
|
430
|
+
clearCmuxSidebar(loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences);
|
|
431
431
|
const base = lockBase();
|
|
432
432
|
const lockFilePath = base ? join(gsdRoot(base), "auto.lock") : "unknown";
|
|
433
433
|
const recoverySuggestion = "\nTo recover, run: gsd doctor --fix";
|
|
@@ -498,7 +498,7 @@ function cleanupAfterLoopExit(ctx) {
|
|
|
498
498
|
export async function stopAuto(ctx, pi, reason) {
|
|
499
499
|
if (!s.active && !s.paused)
|
|
500
500
|
return;
|
|
501
|
-
const loadedPreferences = loadEffectiveGSDPreferences()?.preferences;
|
|
501
|
+
const loadedPreferences = loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences;
|
|
502
502
|
const reasonSuffix = reason ? ` — ${reason}` : "";
|
|
503
503
|
try {
|
|
504
504
|
// ── Step 1: Timers and locks ──
|
|
@@ -695,13 +695,16 @@ export async function stopAuto(ctx, pi, reason) {
|
|
|
695
695
|
catch (err) { /* non-fatal */
|
|
696
696
|
logWarning("engine", `file unlink failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
697
697
|
}
|
|
698
|
-
// ── Step 13: Restore original model (before reset clears IDs) ──
|
|
698
|
+
// ── Step 13: Restore original model + thinking (before reset clears IDs) ──
|
|
699
699
|
try {
|
|
700
700
|
if (pi && ctx && s.originalModelId && s.originalModelProvider) {
|
|
701
701
|
const original = ctx.modelRegistry.find(s.originalModelProvider, s.originalModelId);
|
|
702
702
|
if (original)
|
|
703
703
|
await pi.setModel(original);
|
|
704
704
|
}
|
|
705
|
+
if (pi && s.originalThinkingLevel) {
|
|
706
|
+
pi.setThinkingLevel(s.originalThinkingLevel);
|
|
707
|
+
}
|
|
705
708
|
}
|
|
706
709
|
catch (e) {
|
|
707
710
|
debugLog("stop-cleanup-model", { error: e instanceof Error ? e.message : String(e) });
|
|
@@ -1161,7 +1164,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1161
1164
|
});
|
|
1162
1165
|
// ── Auto-worktree / branch-mode: re-enter on resume ──
|
|
1163
1166
|
if (s.currentMilestoneId &&
|
|
1164
|
-
getIsolationMode() !== "none" &&
|
|
1167
|
+
getIsolationMode(s.originalBasePath || s.basePath) !== "none" &&
|
|
1165
1168
|
s.originalBasePath &&
|
|
1166
1169
|
!isInAutoWorktree(s.basePath) &&
|
|
1167
1170
|
!detectWorktreeName(s.basePath) &&
|
|
@@ -1194,7 +1197,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1194
1197
|
await openProjectDbIfPresent(s.basePath);
|
|
1195
1198
|
try {
|
|
1196
1199
|
await rebuildState(s.basePath);
|
|
1197
|
-
syncCmuxSidebar(loadEffectiveGSDPreferences()?.preferences, await deriveState(s.basePath));
|
|
1200
|
+
syncCmuxSidebar(loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, await deriveState(s.basePath));
|
|
1198
1201
|
}
|
|
1199
1202
|
catch (e) {
|
|
1200
1203
|
debugLog("resume-rebuild-state-failed", {
|
|
@@ -1224,7 +1227,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1224
1227
|
}
|
|
1225
1228
|
updateSessionLock(lockBase(), "resuming", s.currentMilestoneId ?? "unknown");
|
|
1226
1229
|
writeLock(lockBase(), "resuming", s.currentMilestoneId ?? "unknown");
|
|
1227
|
-
logCmuxEvent(loadEffectiveGSDPreferences()?.preferences, s.stepMode ? "Step-mode resumed." : "Auto-mode resumed.", "progress");
|
|
1230
|
+
logCmuxEvent(loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, s.stepMode ? "Step-mode resumed." : "Auto-mode resumed.", "progress");
|
|
1228
1231
|
captureProjectRootEnv(s.originalBasePath || s.basePath);
|
|
1229
1232
|
startAutoCommandPolling(s.basePath);
|
|
1230
1233
|
await runAutoLoopWithUok({
|
|
@@ -1250,13 +1253,13 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1250
1253
|
return;
|
|
1251
1254
|
captureProjectRootEnv(s.originalBasePath || s.basePath);
|
|
1252
1255
|
try {
|
|
1253
|
-
syncCmuxSidebar(loadEffectiveGSDPreferences()?.preferences, await deriveState(s.basePath));
|
|
1256
|
+
syncCmuxSidebar(loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, await deriveState(s.basePath));
|
|
1254
1257
|
}
|
|
1255
1258
|
catch (err) {
|
|
1256
1259
|
// Best-effort only — sidebar sync must never block auto-mode startup
|
|
1257
1260
|
logWarning("engine", `cmux sync failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
1258
1261
|
}
|
|
1259
|
-
logCmuxEvent(loadEffectiveGSDPreferences()?.preferences, requestedStepMode ? "Step-mode started." : "Auto-mode started.", "progress");
|
|
1262
|
+
logCmuxEvent(loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, requestedStepMode ? "Step-mode started." : "Auto-mode started.", "progress");
|
|
1260
1263
|
startAutoCommandPolling(s.basePath);
|
|
1261
1264
|
// Dispatch the first unit
|
|
1262
1265
|
await runAutoLoopWithUok({
|