@cydm/pie 2.4.0 → 2.5.1
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/builtin/extensions/ask-user/index.js +1 -1
- package/dist/builtin/extensions/computer-use/prebuilt/macos/arm64/pie-computer-use +0 -0
- package/dist/builtin/extensions/computer-use/prebuilt/macos/universal/pie-computer-use.app/Contents/MacOS/pie-computer-use +0 -0
- package/dist/builtin/extensions/computer-use/prebuilt/macos/x64/pie-computer-use +0 -0
- package/dist/builtin/extensions/herdr-agent-state/index.js +39 -3
- package/dist/builtin/extensions/mcp-adapter/index.js +52 -12
- package/dist/builtin/extensions/plan-mode/index.js +1 -1
- package/dist/builtin/extensions/subagent/index.js +3 -2
- package/dist/builtin/extensions/todo/index.js +1 -1
- package/dist/chunks/{chunk-XVUV3IM2.js → chunk-N2MK46AE.js} +19 -14
- package/dist/chunks/{chunk-FKUEIYFQ.js → chunk-REP6QANY.js} +77 -16
- package/dist/cli.js +106 -9
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
createAskUserCapability
|
|
4
|
-
} from "../../../chunks/chunk-
|
|
4
|
+
} from "../../../chunks/chunk-REP6QANY.js";
|
|
5
5
|
import "../../../chunks/chunk-ZKHMNEXL.js";
|
|
6
6
|
import "../../../chunks/chunk-YRXXRLMQ.js";
|
|
7
7
|
import "../../../chunks/chunk-XXGYUYXI.js";
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -136,7 +136,42 @@ function spawnHerdrReport(binPath, args, timeoutMs = REPORT_TIMEOUT_MS) {
|
|
|
136
136
|
} catch {
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
|
-
|
|
139
|
+
var KILL_GRACE_MS = 1e3;
|
|
140
|
+
async function runHerdrReportBounded(binPath, args, timeoutMs = REPORT_TIMEOUT_MS) {
|
|
141
|
+
let child;
|
|
142
|
+
try {
|
|
143
|
+
child = spawn(binPath, args, { detached: true, stdio: "ignore" });
|
|
144
|
+
} catch {
|
|
145
|
+
return { outcome: "spawn-error", exitCode: null };
|
|
146
|
+
}
|
|
147
|
+
return await new Promise((resolve) => {
|
|
148
|
+
let killTimer;
|
|
149
|
+
let settled = false;
|
|
150
|
+
const finish = (outcome, exitCode) => {
|
|
151
|
+
if (settled) return;
|
|
152
|
+
settled = true;
|
|
153
|
+
clearTimeout(timer);
|
|
154
|
+
if (killTimer) clearTimeout(killTimer);
|
|
155
|
+
resolve({ outcome, exitCode });
|
|
156
|
+
};
|
|
157
|
+
const timer = setTimeout(() => {
|
|
158
|
+
try {
|
|
159
|
+
child.kill("SIGTERM");
|
|
160
|
+
} catch {
|
|
161
|
+
}
|
|
162
|
+
killTimer = setTimeout(() => {
|
|
163
|
+
try {
|
|
164
|
+
if (child.exitCode === null && child.signalCode === null) child.kill("SIGKILL");
|
|
165
|
+
} catch {
|
|
166
|
+
}
|
|
167
|
+
killTimer = setTimeout(() => finish("escalated", child.exitCode), 250);
|
|
168
|
+
}, KILL_GRACE_MS);
|
|
169
|
+
}, timeoutMs);
|
|
170
|
+
child.on("error", () => finish("spawn-error", null));
|
|
171
|
+
child.on("exit", (code) => finish("exited", code));
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
function attachHerdrReporter(host, herdr, transport = (args) => spawnHerdrReport(herdr.binPath, args), sequencer = createReportSequencer(), shutdownTransport = (args) => runHerdrReportBounded(herdr.binPath, args)) {
|
|
140
175
|
const nextSeq = sequencer;
|
|
141
176
|
let agentActive = false;
|
|
142
177
|
const blockingToolCalls = /* @__PURE__ */ new Map();
|
|
@@ -238,10 +273,10 @@ function attachHerdrReporter(host, herdr, transport = (args) => spawnHerdrReport
|
|
|
238
273
|
}
|
|
239
274
|
publishState();
|
|
240
275
|
});
|
|
241
|
-
host.registerCleanup?.((reason) => {
|
|
276
|
+
host.registerCleanup?.(async (reason) => {
|
|
242
277
|
if (reason !== "shutdown") return;
|
|
243
278
|
if (!heldPane) return;
|
|
244
|
-
|
|
279
|
+
await shutdownTransport(
|
|
245
280
|
buildReleaseReportArgs({
|
|
246
281
|
paneId: herdr.paneId,
|
|
247
282
|
source: SOURCE_ID,
|
|
@@ -267,6 +302,7 @@ export {
|
|
|
267
302
|
createReportSequencer,
|
|
268
303
|
herdrAgentStateExtension as default,
|
|
269
304
|
readHerdrEnvironment,
|
|
305
|
+
runHerdrReportBounded,
|
|
270
306
|
spawnHerdrReport,
|
|
271
307
|
summarizeAskUserQuestion
|
|
272
308
|
};
|
|
@@ -24724,11 +24724,13 @@ var McpServerManager = class {
|
|
|
24724
24724
|
};
|
|
24725
24725
|
for (const tools of Object.values(this.readCacheFile())) {
|
|
24726
24726
|
for (const tool of tools) {
|
|
24727
|
-
|
|
24727
|
+
const definition = this.definitions.get(tool.server);
|
|
24728
|
+
if (!definition || definition.disabled) continue;
|
|
24728
24729
|
claim2(tool, false);
|
|
24729
24730
|
}
|
|
24730
24731
|
}
|
|
24731
24732
|
for (const runtime of this.runtimes.values()) {
|
|
24733
|
+
if (runtime.definition.disabled) continue;
|
|
24732
24734
|
for (const tool of runtime.tools ?? []) claim2(tool, true);
|
|
24733
24735
|
}
|
|
24734
24736
|
for (const name of conflicts) {
|
|
@@ -24849,6 +24851,20 @@ ${tail}` : "")
|
|
|
24849
24851
|
error: `MCP call "${prefixedName}" was cancelled before the request was sent; nothing was executed.`
|
|
24850
24852
|
};
|
|
24851
24853
|
}
|
|
24854
|
+
const postConnectCatalog = this.loadCatalog();
|
|
24855
|
+
if (this.conflictedNames.has(prefixedName)) {
|
|
24856
|
+
return {
|
|
24857
|
+
delivery: "not_sent",
|
|
24858
|
+
error: `MCP tool name "${prefixedName}" became claimed by more than one server during connection. Rename one of the servers so every tool name is unambiguous; the call was NOT sent.`
|
|
24859
|
+
};
|
|
24860
|
+
}
|
|
24861
|
+
const postDescriptor = postConnectCatalog.find((tool) => tool.prefixedName === prefixedName);
|
|
24862
|
+
if (postDescriptor && (postDescriptor.server !== server || postDescriptor.tool !== toolName)) {
|
|
24863
|
+
return {
|
|
24864
|
+
delivery: "not_sent",
|
|
24865
|
+
error: `MCP tool "${prefixedName}" resolved to ${postDescriptor.server}/${postDescriptor.tool} after connecting; refusing to send the stale target ${server}/${toolName}. Retry the call.`
|
|
24866
|
+
};
|
|
24867
|
+
}
|
|
24852
24868
|
try {
|
|
24853
24869
|
const result = await withTimeout(
|
|
24854
24870
|
client.callTool({ name: toolName, arguments: args }, void 0, signal !== void 0 ? { signal } : void 0),
|
|
@@ -25266,19 +25282,26 @@ function mcpAdapter(ctx) {
|
|
|
25266
25282
|
ctx.log
|
|
25267
25283
|
);
|
|
25268
25284
|
async function reloadManager() {
|
|
25269
|
-
|
|
25285
|
+
let replacement;
|
|
25270
25286
|
try {
|
|
25271
|
-
|
|
25272
|
-
|
|
25273
|
-
|
|
25274
|
-
ctx.log
|
|
25275
|
-
|
|
25287
|
+
const resolved = resolveMcpAdapterConfig(ctx.cwd, configDir);
|
|
25288
|
+
if (resolved.problems.length > 0) {
|
|
25289
|
+
const message = `config layers failed to parse: ${resolved.problems.join("; ")}`;
|
|
25290
|
+
ctx.log(`mcp: config reload failed, keeping the previous manager: ${message}`);
|
|
25291
|
+
if (ctx.hasUI) ctx.ui.notify(`MCP adapter config error (previous servers kept): ${message}`, "error");
|
|
25292
|
+
return { ok: false, error: message };
|
|
25293
|
+
}
|
|
25294
|
+
replacement = new McpServerManager(resolved.servers, metadataCacheDir, ctx.log);
|
|
25276
25295
|
} catch (error2) {
|
|
25277
25296
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
25278
|
-
ctx.log(`mcp: config reload failed: ${message}`);
|
|
25279
|
-
if (ctx.hasUI) ctx.ui.notify(`MCP adapter config error: ${message}`, "error");
|
|
25280
|
-
|
|
25297
|
+
ctx.log(`mcp: config reload failed, keeping the previous manager: ${message}`);
|
|
25298
|
+
if (ctx.hasUI) ctx.ui.notify(`MCP adapter config error (previous servers kept): ${message}`, "error");
|
|
25299
|
+
return { ok: false, error: message };
|
|
25281
25300
|
}
|
|
25301
|
+
const previous = manager;
|
|
25302
|
+
manager = replacement;
|
|
25303
|
+
await previous.dispose().catch(() => void 0);
|
|
25304
|
+
return { ok: true };
|
|
25282
25305
|
}
|
|
25283
25306
|
ctx.registerCleanup?.(() => manager.dispose().catch(() => void 0));
|
|
25284
25307
|
function readProjectOverride() {
|
|
@@ -25359,6 +25382,7 @@ function mcpAdapter(ctx) {
|
|
|
25359
25382
|
}
|
|
25360
25383
|
const overrides = readProjectOverride().mcpServers;
|
|
25361
25384
|
const forceEnabled = overrides?.[definition.name]?.disabled === false;
|
|
25385
|
+
const previousOverride = overrides?.[definition.name]?.disabled;
|
|
25362
25386
|
const filePath = writeProjectOverride(
|
|
25363
25387
|
definition.name,
|
|
25364
25388
|
// enable must lift a source-level disabled:true with an explicit
|
|
@@ -25367,8 +25391,24 @@ function mcpAdapter(ctx) {
|
|
|
25367
25391
|
// existing force-enable on repeated enable commands too.
|
|
25368
25392
|
sub === "disable" ? true : definition.disabled || forceEnabled ? false : null
|
|
25369
25393
|
);
|
|
25370
|
-
await reloadManager();
|
|
25371
|
-
|
|
25394
|
+
const reload = await reloadManager();
|
|
25395
|
+
if (!reload.ok) {
|
|
25396
|
+
writeProjectOverride(definition.name, previousOverride === void 0 ? null : previousOverride);
|
|
25397
|
+
commandCtx.ui.notify(
|
|
25398
|
+
`MCP server "${definition.name}" NOT ${sub === "disable" ? "disabled" : "enabled"}: config reload failed (${reload.error}); previous servers kept and the override was rolled back.`,
|
|
25399
|
+
"error"
|
|
25400
|
+
);
|
|
25401
|
+
return;
|
|
25402
|
+
}
|
|
25403
|
+
const reloaded = manager.getDefinition(definition.name);
|
|
25404
|
+
if (!reloaded) {
|
|
25405
|
+
commandCtx.ui.notify(
|
|
25406
|
+
`MCP server "${definition.name}" disappeared from the reloaded config (wrote ${filePath}); check project/global config merges.`,
|
|
25407
|
+
"error"
|
|
25408
|
+
);
|
|
25409
|
+
return;
|
|
25410
|
+
}
|
|
25411
|
+
const effectiveDisabled = reloaded.disabled;
|
|
25372
25412
|
const stateLabel = effectiveDisabled ? "disabled" : sub === "disable" ? "still enabled" : "enabled";
|
|
25373
25413
|
commandCtx.ui.notify(
|
|
25374
25414
|
`MCP server "${definition.name}" ${stateLabel} (wrote ${filePath}). ` + (eagerRegistered.length > 0 ? "Restart or /reload to resync direct tools." : "Effective immediately."),
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
isPlanModeSafeCommand,
|
|
8
8
|
markCompletedPlanSteps,
|
|
9
9
|
restoreExecutionState
|
|
10
|
-
} from "../../../chunks/chunk-
|
|
10
|
+
} from "../../../chunks/chunk-REP6QANY.js";
|
|
11
11
|
import "../../../chunks/chunk-ZKHMNEXL.js";
|
|
12
12
|
import "../../../chunks/chunk-YRXXRLMQ.js";
|
|
13
13
|
import {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
createCliHostCapabilities
|
|
4
|
-
} from "../../../chunks/chunk-
|
|
4
|
+
} from "../../../chunks/chunk-N2MK46AE.js";
|
|
5
5
|
import {
|
|
6
6
|
createSharedFileSystemTools,
|
|
7
7
|
createSubagentCapability
|
|
8
|
-
} from "../../../chunks/chunk-
|
|
8
|
+
} from "../../../chunks/chunk-REP6QANY.js";
|
|
9
9
|
import "../../../chunks/chunk-ZKHMNEXL.js";
|
|
10
10
|
import "../../../chunks/chunk-YRXXRLMQ.js";
|
|
11
11
|
import "../../../chunks/chunk-5353DEEC.js";
|
|
@@ -38,6 +38,7 @@ function subagentExtension(ctx) {
|
|
|
38
38
|
notify: ctx.hasUI ? (message, type) => ctx.ui.notify(message, type === "success" ? "info" : type) : void 0,
|
|
39
39
|
debugLog: (module, message, data) => ctx.log(`[subagent:${module}] ${message}${data !== void 0 ? ` ${JSON.stringify(data)}` : ""}`),
|
|
40
40
|
resolveModelClass: (modelClass) => ctx.resolveModelClass?.(modelClass),
|
|
41
|
+
resolveModelRef: (modelRef) => ctx.resolveModelRef?.(modelRef),
|
|
41
42
|
createRuntimeTools: () => {
|
|
42
43
|
const parentRuntimeTools = ctx.getRuntimeTools();
|
|
43
44
|
if (Array.isArray(parentRuntimeTools) && parentRuntimeTools.length > 0) {
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
executeManageTodoList,
|
|
9
9
|
executionStateToTodos,
|
|
10
10
|
restoreExecutionState
|
|
11
|
-
} from "../../../chunks/chunk-
|
|
11
|
+
} from "../../../chunks/chunk-REP6QANY.js";
|
|
12
12
|
import "../../../chunks/chunk-ZKHMNEXL.js";
|
|
13
13
|
import "../../../chunks/chunk-YRXXRLMQ.js";
|
|
14
14
|
import "../../../chunks/chunk-XXGYUYXI.js";
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
createSharedWebSearchTool,
|
|
9
9
|
interpretShellExit,
|
|
10
10
|
requestInteraction
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-REP6QANY.js";
|
|
12
12
|
import {
|
|
13
13
|
getBuiltinDir,
|
|
14
14
|
getConfigDir
|
|
@@ -543,9 +543,24 @@ function createBashTool(defaultCwd, options) {
|
|
|
543
543
|
totalNewlines += data.reduce((count, byte) => count + (byte === 10 ? 1 : 0), 0);
|
|
544
544
|
if (headBytes >= maxHeadBytes) return;
|
|
545
545
|
const prefix = data.subarray(0, maxHeadBytes - headBytes);
|
|
546
|
-
headChunks.push(prefix);
|
|
546
|
+
headChunks.push(Buffer.from(prefix));
|
|
547
547
|
headBytes += prefix.length;
|
|
548
548
|
};
|
|
549
|
+
const appendRollingChunk = (data) => {
|
|
550
|
+
const owned = Buffer.from(data);
|
|
551
|
+
chunks.push(owned);
|
|
552
|
+
chunksBytes += owned.length;
|
|
553
|
+
while (chunksBytes > maxChunksBytes && chunks.length > 1) {
|
|
554
|
+
const removed = chunks.shift();
|
|
555
|
+
chunksBytes -= removed.length;
|
|
556
|
+
}
|
|
557
|
+
if (chunks.length === 1 && chunksBytes > maxChunksBytes) {
|
|
558
|
+
const only = chunks[0];
|
|
559
|
+
const tail = only.subarray(only.length - maxChunksBytes);
|
|
560
|
+
chunks[0] = Buffer.from(tail);
|
|
561
|
+
chunksBytes = tail.length;
|
|
562
|
+
}
|
|
563
|
+
};
|
|
549
564
|
let timedOut = false;
|
|
550
565
|
let processExited = false;
|
|
551
566
|
let exitCode = null;
|
|
@@ -641,12 +656,7 @@ function createBashTool(defaultCwd, options) {
|
|
|
641
656
|
return;
|
|
642
657
|
}
|
|
643
658
|
}
|
|
644
|
-
|
|
645
|
-
chunksBytes += data.length;
|
|
646
|
-
while (chunksBytes > maxChunksBytes && chunks.length > 1) {
|
|
647
|
-
const removed = chunks.shift();
|
|
648
|
-
chunksBytes -= removed.length;
|
|
649
|
-
}
|
|
659
|
+
appendRollingChunk(data);
|
|
650
660
|
if (onUpdate) {
|
|
651
661
|
const fullBuffer = Buffer.concat(chunks);
|
|
652
662
|
const fullText = fullBuffer.toString("utf-8");
|
|
@@ -700,12 +710,7 @@ function createBashTool(defaultCwd, options) {
|
|
|
700
710
|
return;
|
|
701
711
|
}
|
|
702
712
|
}
|
|
703
|
-
|
|
704
|
-
chunksBytes += data.length;
|
|
705
|
-
while (chunksBytes > maxChunksBytes && chunks.length > 1) {
|
|
706
|
-
const removed = chunks.shift();
|
|
707
|
-
chunksBytes -= removed.length;
|
|
708
|
-
}
|
|
713
|
+
appendRollingChunk(data);
|
|
709
714
|
});
|
|
710
715
|
const finishExecution = async (code, sig, stdioIncomplete = false) => {
|
|
711
716
|
if (settled) return;
|
|
@@ -1322,6 +1322,8 @@ function formatSkillSummariesForPrompt(skills) {
|
|
|
1322
1322
|
|
|
1323
1323
|
// ../../packages/shared-headless-capabilities/src/subagent.ts
|
|
1324
1324
|
var DEFAULT_SUBAGENT_TIMEOUT_SECONDS = 1200;
|
|
1325
|
+
var DEFAULT_SUBAGENT_THINKING_LEVEL = "medium";
|
|
1326
|
+
var SUBAGENT_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
1325
1327
|
function formatSkillsForPrompt(skills) {
|
|
1326
1328
|
return formatSkillSummariesForPrompt(skills);
|
|
1327
1329
|
}
|
|
@@ -1411,21 +1413,28 @@ function filterToolsForSubagent(runtimeTools, parentTools, plan) {
|
|
|
1411
1413
|
}
|
|
1412
1414
|
return filtered;
|
|
1413
1415
|
}
|
|
1414
|
-
function buildSubagentPlan(deps, task, name, priority, timeoutSeconds) {
|
|
1416
|
+
function buildSubagentPlan(deps, task, name, priority, timeoutSeconds, modelOverride, thinkingLevel = DEFAULT_SUBAGENT_THINKING_LEVEL) {
|
|
1415
1417
|
const complexity = inferComplexity(task, priority);
|
|
1416
1418
|
const modelClass = selectModelClass(complexity, priority);
|
|
1417
|
-
const
|
|
1419
|
+
const overrideResolution = modelOverride ? deps.resolveModelRef?.(modelOverride) ?? { model: void 0, fallbackReason: `model override "${modelOverride}" is not supported by this host` } : void 0;
|
|
1420
|
+
const overridePair = overrideResolution?.model && overrideResolution?.apiKey ? { model: overrideResolution.model, apiKey: overrideResolution.apiKey } : void 0;
|
|
1421
|
+
const modelResolution = overridePair ? void 0 : deps.resolveModelClass?.(modelClass);
|
|
1418
1422
|
const resolvedPair = modelResolution?.model && modelResolution?.apiKey ? { model: modelResolution.model, apiKey: modelResolution.apiKey } : void 0;
|
|
1419
|
-
const model = resolvedPair?.model ?? deps.model;
|
|
1420
|
-
const apiKey = resolvedPair?.apiKey ?? deps.apiKey;
|
|
1423
|
+
const model = overridePair?.model ?? resolvedPair?.model ?? deps.model;
|
|
1424
|
+
const apiKey = overridePair?.apiKey ?? resolvedPair?.apiKey ?? deps.apiKey;
|
|
1425
|
+
const overrideMissReason = overrideResolution?.fallbackReason ?? `model override "${modelOverride}" could not be resolved`;
|
|
1426
|
+
const modelFallbackReason = modelOverride ? overridePair ? void 0 : modelResolution?.fallbackReason ? `${overrideMissReason}; ${modelResolution.fallbackReason}` : overrideMissReason : modelResolution?.fallbackReason;
|
|
1421
1427
|
const partialPlan = {
|
|
1422
1428
|
task,
|
|
1423
1429
|
name,
|
|
1424
1430
|
priority,
|
|
1425
1431
|
complexity,
|
|
1426
1432
|
modelClass,
|
|
1433
|
+
modelOverride,
|
|
1434
|
+
modelOverrideApplied: Boolean(overridePair),
|
|
1435
|
+
thinkingLevel,
|
|
1427
1436
|
modelId: `${model?.provider ? `${model.provider}/` : ""}${model?.id ?? "unknown"}`,
|
|
1428
|
-
modelFallbackReason
|
|
1437
|
+
modelFallbackReason,
|
|
1429
1438
|
toolsExcluded: [],
|
|
1430
1439
|
timeoutSeconds,
|
|
1431
1440
|
outputContract: "Return a concise answer with evidence, uncertainty, and any parent follow-up needed."
|
|
@@ -1438,13 +1447,14 @@ function buildSubagentPlan(deps, task, name, priority, timeoutSeconds) {
|
|
|
1438
1447
|
};
|
|
1439
1448
|
return { plan, tools: filteredTools, apiKey, model };
|
|
1440
1449
|
}
|
|
1441
|
-
function createAgentInstance(deps, systemPrompt, tools, model, apiKey) {
|
|
1450
|
+
function createAgentInstance(deps, systemPrompt, tools, model, apiKey, thinkingLevel) {
|
|
1442
1451
|
if (deps.createAgent) {
|
|
1443
1452
|
return deps.createAgent({
|
|
1444
1453
|
systemPrompt,
|
|
1445
1454
|
model,
|
|
1446
1455
|
tools,
|
|
1447
|
-
apiKey
|
|
1456
|
+
apiKey,
|
|
1457
|
+
thinkingLevel
|
|
1448
1458
|
});
|
|
1449
1459
|
}
|
|
1450
1460
|
return new Agent({
|
|
@@ -1452,7 +1462,7 @@ function createAgentInstance(deps, systemPrompt, tools, model, apiKey) {
|
|
|
1452
1462
|
systemPrompt,
|
|
1453
1463
|
model,
|
|
1454
1464
|
tools,
|
|
1455
|
-
thinkingLevel
|
|
1465
|
+
thinkingLevel
|
|
1456
1466
|
},
|
|
1457
1467
|
apiKey
|
|
1458
1468
|
});
|
|
@@ -1501,7 +1511,7 @@ async function runSubagentWithProgress(deps, task, reportProgress, signal) {
|
|
|
1501
1511
|
deps.debugLog?.("run", "runSubagentWithProgress START", { taskName: task.name, yoloMode: deps.yoloMode });
|
|
1502
1512
|
try {
|
|
1503
1513
|
reportProgress({ message: `[${task.name}] Starting...`, increment: 5 });
|
|
1504
|
-
const { plan, tools, apiKey, model } = buildSubagentPlan(deps, task.task, task.name, task.priority, task.timeoutSeconds);
|
|
1514
|
+
const { plan, tools, apiKey, model } = buildSubagentPlan(deps, task.task, task.name, task.priority, task.timeoutSeconds, task.modelOverride, task.thinkingLevel);
|
|
1505
1515
|
task.plan = plan;
|
|
1506
1516
|
task.needsParentWrite = needsParentWrite(task.task);
|
|
1507
1517
|
for (const excluded of plan.toolsExcluded) {
|
|
@@ -1521,7 +1531,7 @@ async function runSubagentWithProgress(deps, task, reportProgress, signal) {
|
|
|
1521
1531
|
if (signal?.aborted) {
|
|
1522
1532
|
throw new Error("Subagent aborted by parent");
|
|
1523
1533
|
}
|
|
1524
|
-
deps.log(`[Subagent ${task.name}] Plan: ${plan.complexity}/${plan.modelClass}, ${tools.length} tools`);
|
|
1534
|
+
deps.log(`[Subagent ${task.name}] Plan: ${plan.complexity}/${plan.modelClass}${plan.modelOverride ? `, model=${plan.modelOverrideApplied ? plan.modelOverride : "override failed"}` : ""}, ${tools.length} tools`);
|
|
1525
1535
|
deps.debugLog?.("plan", "SubagentPlan", plan);
|
|
1526
1536
|
const systemPrompt = `You are a specialized subagent focused on one bounded task.
|
|
1527
1537
|
|
|
@@ -1538,7 +1548,7 @@ Output:
|
|
|
1538
1548
|
- Parent follow-up needed, if any
|
|
1539
1549
|
|
|
1540
1550
|
${formatSkillsForPrompt(deps.skills ?? [])}`;
|
|
1541
|
-
const subagent = createAgentInstance(deps, systemPrompt, tools, model, apiKey);
|
|
1551
|
+
const subagent = createAgentInstance(deps, systemPrompt, tools, model, apiKey, plan.thinkingLevel);
|
|
1542
1552
|
let assistantTurns = 0;
|
|
1543
1553
|
let toolCalls = 0;
|
|
1544
1554
|
let rejectTimeout = () => void 0;
|
|
@@ -1660,6 +1670,12 @@ function buildParallelResult(tasks, totalDuration) {
|
|
|
1660
1670
|
resultText += `**${task.name}** (${statusLabel}`;
|
|
1661
1671
|
if (task.plan) {
|
|
1662
1672
|
resultText += `, ${task.plan.complexity}/${task.plan.modelClass}`;
|
|
1673
|
+
if (task.plan.thinkingLevel !== DEFAULT_SUBAGENT_THINKING_LEVEL) {
|
|
1674
|
+
resultText += `, thinking=${task.plan.thinkingLevel}`;
|
|
1675
|
+
}
|
|
1676
|
+
if (task.plan.modelOverride) {
|
|
1677
|
+
resultText += task.plan.modelOverrideApplied ? `, model=${task.plan.modelOverride}` : `, model=${task.plan.modelOverride} (unresolved, fell back)`;
|
|
1678
|
+
}
|
|
1663
1679
|
}
|
|
1664
1680
|
if (task.details) {
|
|
1665
1681
|
resultText += `, ${task.details.durationMs}ms, ${task.details.toolCalls} tools`;
|
|
@@ -1699,7 +1715,7 @@ function normalizeTaskDefs(args) {
|
|
|
1699
1715
|
return { error: "Invalid spawn_subagents_parallel arguments: tasks must be a non-empty array." };
|
|
1700
1716
|
}
|
|
1701
1717
|
const normalized = [];
|
|
1702
|
-
const allowedFields = [...TASK_FIELD_ALIASES, "name", "priority", "timeout"];
|
|
1718
|
+
const allowedFields = [...TASK_FIELD_ALIASES, "name", "priority", "timeout", "model", "thinkingLevel"];
|
|
1703
1719
|
for (const [index, def] of taskDefs.entries()) {
|
|
1704
1720
|
if (!def || typeof def !== "object") {
|
|
1705
1721
|
return { error: `Invalid task #${index + 1}: expected an object with the objective in "task" (aliases "description"/"prompt"/"objective" accepted).` };
|
|
@@ -1722,11 +1738,20 @@ function normalizeTaskDefs(args) {
|
|
|
1722
1738
|
return { error: `Invalid task #${index + 1}: timeout must be a positive number of seconds.` };
|
|
1723
1739
|
}
|
|
1724
1740
|
const priority = def.priority === "thorough" ? "thorough" : "fast";
|
|
1741
|
+
const modelOverride = typeof def.model === "string" ? def.model.trim() : void 0;
|
|
1742
|
+
if (def.model !== void 0 && !modelOverride) {
|
|
1743
|
+
return { error: `Invalid task #${index + 1}: "model" must be a non-empty model reference such as "provider/model-id".` };
|
|
1744
|
+
}
|
|
1745
|
+
if (def.thinkingLevel !== void 0 && (typeof def.thinkingLevel !== "string" || !SUBAGENT_THINKING_LEVELS.includes(def.thinkingLevel))) {
|
|
1746
|
+
return { error: `Invalid task #${index + 1}: "thinkingLevel" must be one of ${SUBAGENT_THINKING_LEVELS.map((level) => `"${level}"`).join(", ")}.` };
|
|
1747
|
+
}
|
|
1725
1748
|
normalized.push({
|
|
1726
1749
|
name: typeof def.name === "string" && def.name.trim() ? def.name.trim() : void 0,
|
|
1727
1750
|
task,
|
|
1728
1751
|
priority,
|
|
1729
|
-
timeoutSeconds
|
|
1752
|
+
timeoutSeconds,
|
|
1753
|
+
modelOverride,
|
|
1754
|
+
thinkingLevel: def.thinkingLevel
|
|
1730
1755
|
});
|
|
1731
1756
|
}
|
|
1732
1757
|
return normalized;
|
|
@@ -1770,7 +1795,11 @@ function createSubagentCapability(deps) {
|
|
|
1770
1795
|
Use this for independent investigation, search, review, or triage work. Provide each task as a plain objective. Pie chooses the model class automatically. Use timeout only for unusually long tasks.
|
|
1771
1796
|
|
|
1772
1797
|
Arguments shape (each tasks[] item puts the objective in "task" \u2014 "description"/"prompt"/"objective" are accepted as aliases):
|
|
1773
|
-
{ "tasks": [{ "task": "<objective text>", "name": "<optional short label>", "priority": "fast" | "thorough", "timeout": 600 }] }
|
|
1798
|
+
{ "tasks": [{ "task": "<objective text>", "name": "<optional short label>", "priority": "fast" | "thorough", "model": "<optional explicit model override>", "thinkingLevel": "<optional off|minimal|low|medium|high|xhigh, default medium>", "timeout": 600 }] }
|
|
1799
|
+
|
|
1800
|
+
"model" overrides the automatic model-class selection for that task when the user explicitly asks for a specific model (e.g. "anthropic/claude-..."). Prefer "provider/model-id"; a bare model id works only when it is unambiguous across providers. When the override cannot be resolved, the task falls back to automatic selection and reports why.
|
|
1801
|
+
|
|
1802
|
+
"thinkingLevel" defaults to "medium"; set it only when the user asks (e.g. "xhigh" for deep review) or for cheap lookup tasks ("off"). Non-reasoning models ignore it.`,
|
|
1774
1803
|
parameters: Type.Object({
|
|
1775
1804
|
tasks: Type.Array(
|
|
1776
1805
|
Type.Object(
|
|
@@ -1781,9 +1810,11 @@ Arguments shape (each tasks[] item puts the objective in "task" \u2014 "descript
|
|
|
1781
1810
|
objective: Type.Optional(Type.String({ description: "Alias for task." })),
|
|
1782
1811
|
name: Type.Optional(Type.String({ description: "Short name for this subagent, shown in progress updates." })),
|
|
1783
1812
|
priority: Type.Optional(Type.Union([Type.Literal("fast"), Type.Literal("thorough")], { description: "fast uses lower-cost defaults; thorough raises model class when needed." })),
|
|
1813
|
+
model: Type.Optional(Type.String({ description: 'Explicit model override for this task, e.g. "provider/model-id". Only set when the user explicitly requests a specific model; otherwise Pie picks the model class automatically.' })),
|
|
1814
|
+
thinkingLevel: Type.Optional(Type.Union([Type.Literal("off"), Type.Literal("minimal"), Type.Literal("low"), Type.Literal("medium"), Type.Literal("high"), Type.Literal("xhigh")], { description: `Reasoning level for this task. Default: "medium". Only override when the user asks (e.g. "xhigh" for deep review tasks, "off" for cheap lookups). Ignored by non-reasoning models.` })),
|
|
1784
1815
|
timeout: Type.Optional(Type.Number({ description: "Timeout in seconds. Default: 1200s (20 minutes). For longer tasks, explicitly set a higher value, e.g. 3600." }))
|
|
1785
1816
|
},
|
|
1786
|
-
{ additionalProperties: false, description: "Objective goes in 'task' (or an accepted alias); plus optional name/priority/timeout." }
|
|
1817
|
+
{ additionalProperties: false, description: "Objective goes in 'task' (or an accepted alias); plus optional name/priority/model/thinkingLevel/timeout." }
|
|
1787
1818
|
),
|
|
1788
1819
|
{ description: "Array of tasks to run in parallel; at least one of task/description/prompt/objective must be a non-empty string per item.", minItems: 1, maxItems: 10 }
|
|
1789
1820
|
)
|
|
@@ -1816,6 +1847,8 @@ Arguments shape (each tasks[] item puts the objective in "task" \u2014 "descript
|
|
|
1816
1847
|
task: def.task,
|
|
1817
1848
|
priority: def.priority,
|
|
1818
1849
|
timeoutSeconds: def.timeoutSeconds,
|
|
1850
|
+
modelOverride: def.modelOverride,
|
|
1851
|
+
thinkingLevel: def.thinkingLevel,
|
|
1819
1852
|
evidence: [],
|
|
1820
1853
|
confidenceSignals: [],
|
|
1821
1854
|
uncertainty: "medium",
|
|
@@ -1866,6 +1899,8 @@ Arguments shape (each tasks[] item puts the objective in "task" \u2014 "descript
|
|
|
1866
1899
|
task: task.task,
|
|
1867
1900
|
timeoutSeconds: task.timeoutSeconds,
|
|
1868
1901
|
plan: task.plan,
|
|
1902
|
+
modelOverride: task.modelOverride,
|
|
1903
|
+
thinkingLevel: task.plan?.thinkingLevel,
|
|
1869
1904
|
evidence: task.evidence,
|
|
1870
1905
|
confidenceSignals: task.confidenceSignals,
|
|
1871
1906
|
runtimeEvidence: task.runtimeEvidence,
|
|
@@ -2932,6 +2967,9 @@ var FileSessionStore = class {
|
|
|
2932
2967
|
throw new Error(`Session directory is a symbolic link; ${operation} refused: ${dir}`);
|
|
2933
2968
|
}
|
|
2934
2969
|
headStatus(sessionId) {
|
|
2970
|
+
if (sessionDirIsSymlink(this.pathsFor(sessionId).dir)) {
|
|
2971
|
+
return "missing";
|
|
2972
|
+
}
|
|
2935
2973
|
const head = this.tryReadHeadFile(sessionId);
|
|
2936
2974
|
if (head === "corrupt") {
|
|
2937
2975
|
return "corrupt";
|
|
@@ -2987,6 +3025,9 @@ var FileSessionStore = class {
|
|
|
2987
3025
|
* never reinitialize a damaged session to sequence 0.
|
|
2988
3026
|
*/
|
|
2989
3027
|
tryReadHeadFile(sessionId) {
|
|
3028
|
+
if (sessionDirIsSymlink(this.pathsFor(sessionId).dir)) {
|
|
3029
|
+
return null;
|
|
3030
|
+
}
|
|
2990
3031
|
const headPath = this.pathsFor(sessionId).headPath;
|
|
2991
3032
|
const durable = readDurableFileSync(this.gateway, headPath, (content) => this.parseHeadContent(content));
|
|
2992
3033
|
if (durable !== null) {
|
|
@@ -8579,6 +8620,7 @@ function createFileObservationState(options = {}) {
|
|
|
8579
8620
|
const files = /* @__PURE__ */ new Map();
|
|
8580
8621
|
const maxFiles = Math.max(1, Math.floor(options.maxFiles ?? 100));
|
|
8581
8622
|
const maxRangesPerFile = Math.max(0, Math.floor(options.maxRangesPerFile ?? 8));
|
|
8623
|
+
let generation = 0;
|
|
8582
8624
|
function touchFile(absolutePath, observed) {
|
|
8583
8625
|
files.delete(absolutePath);
|
|
8584
8626
|
files.set(absolutePath, observed);
|
|
@@ -8695,8 +8737,12 @@ function createFileObservationState(options = {}) {
|
|
|
8695
8737
|
invalidate(absolutePath) {
|
|
8696
8738
|
files.delete(absolutePath);
|
|
8697
8739
|
},
|
|
8740
|
+
getGeneration() {
|
|
8741
|
+
return generation;
|
|
8742
|
+
},
|
|
8698
8743
|
clear() {
|
|
8699
8744
|
files.clear();
|
|
8745
|
+
generation++;
|
|
8700
8746
|
}
|
|
8701
8747
|
};
|
|
8702
8748
|
}
|
|
@@ -8716,6 +8762,7 @@ function createReadErrorResult(message, details) {
|
|
|
8716
8762
|
function createReadTool(cwd, options) {
|
|
8717
8763
|
const fs2 = getFileSystem();
|
|
8718
8764
|
const fileObservationState = options?.fileObservationState ?? createFileObservationState();
|
|
8765
|
+
const callerObservations = /* @__PURE__ */ new WeakMap();
|
|
8719
8766
|
const rootSchema = buildRootParameterSchema(cwd, options);
|
|
8720
8767
|
const readSchema = Type.Object({
|
|
8721
8768
|
path: Type.String({ description: "Path to the file to read. Example: 'Scripts/PlayerController.cs' or 'Assets/Gen/config.json'." }),
|
|
@@ -8950,7 +8997,18 @@ function createReadTool(cwd, options) {
|
|
|
8950
8997
|
const readStartsAtBeginning = offset === void 0 || offset === 1;
|
|
8951
8998
|
const readReachedEndOfFile = startLine + range2.selectedLines >= range2.totalLines;
|
|
8952
8999
|
const isCompleteTextKnown = readStartsAtBeginning && readReachedEndOfFile && !truncation.truncated && !truncation.firstLineExceedsLimit;
|
|
8953
|
-
|
|
9000
|
+
let callerObservation = fileObservationState;
|
|
9001
|
+
if (signal) {
|
|
9002
|
+
const generation = fileObservationState.getGeneration();
|
|
9003
|
+
const existing = callerObservations.get(signal);
|
|
9004
|
+
if (existing?.generation === generation) {
|
|
9005
|
+
callerObservation = existing.state;
|
|
9006
|
+
} else {
|
|
9007
|
+
callerObservation = createFileObservationState();
|
|
9008
|
+
callerObservations.set(signal, { generation, state: callerObservation });
|
|
9009
|
+
}
|
|
9010
|
+
}
|
|
9011
|
+
if (fileObservationState.isUnchangedReadRange(absolutePath, rangeKey, snapshot, range2.selectedContentHash) && callerObservation.isUnchangedReadRange(absolutePath, rangeKey, snapshot, range2.selectedContentHash)) {
|
|
8954
9012
|
if (signal) {
|
|
8955
9013
|
signal.removeEventListener("abort", onAbort);
|
|
8956
9014
|
}
|
|
@@ -9017,6 +9075,9 @@ Base directory: ${nodePath.dirname(absolutePath)}
|
|
|
9017
9075
|
totalLines: range2.totalLines
|
|
9018
9076
|
}
|
|
9019
9077
|
);
|
|
9078
|
+
if (callerObservation !== fileObservationState) {
|
|
9079
|
+
callerObservation.recordTextRead(absolutePath, rangeKey, snapshot, range2.selectedContentHash, isCompleteTextKnown);
|
|
9080
|
+
}
|
|
9020
9081
|
outputText = sourceHeader + outputText;
|
|
9021
9082
|
const textContent = [{ type: "text", text: outputText }];
|
|
9022
9083
|
if (aborted) return;
|
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
createCliWebResearchHealthStore,
|
|
8
8
|
formatSize,
|
|
9
9
|
truncateHeadTail
|
|
10
|
-
} from "./chunks/chunk-
|
|
10
|
+
} from "./chunks/chunk-N2MK46AE.js";
|
|
11
11
|
import {
|
|
12
12
|
AGENTS_CONTEXT_FILE_NAME,
|
|
13
13
|
AgentSessionController,
|
|
@@ -60,7 +60,7 @@ import {
|
|
|
60
60
|
setExtensionEnabledInSettings,
|
|
61
61
|
shouldPreserveExecutionStateForUserText,
|
|
62
62
|
supersedeExecutionState
|
|
63
|
-
} from "./chunks/chunk-
|
|
63
|
+
} from "./chunks/chunk-REP6QANY.js";
|
|
64
64
|
import "./chunks/chunk-ZKHMNEXL.js";
|
|
65
65
|
import {
|
|
66
66
|
Deref,
|
|
@@ -53356,6 +53356,46 @@ var ModelRegistry = class {
|
|
|
53356
53356
|
}
|
|
53357
53357
|
return { model, apiKey };
|
|
53358
53358
|
}
|
|
53359
|
+
/** Resolve an explicit model reference for user-requested overrides.
|
|
53360
|
+
* Accepts "provider/model-id" (exact lookup) or a bare model id (only
|
|
53361
|
+
* when it matches exactly one configured model). Never guesses across
|
|
53362
|
+
* providers; ambiguity and missing keys are reported as fallback reasons. */
|
|
53363
|
+
resolveModelRef(ref) {
|
|
53364
|
+
const trimmed = ref.trim();
|
|
53365
|
+
if (!trimmed) {
|
|
53366
|
+
return { fallbackReason: "empty model reference" };
|
|
53367
|
+
}
|
|
53368
|
+
const separator = trimmed.indexOf("/");
|
|
53369
|
+
if (separator >= 0) {
|
|
53370
|
+
if (separator === 0 || separator === trimmed.length - 1) {
|
|
53371
|
+
return { fallbackReason: `invalid model reference "${trimmed}"; expected provider/model-id` };
|
|
53372
|
+
}
|
|
53373
|
+
const provider = trimmed.slice(0, separator);
|
|
53374
|
+
const modelId = trimmed.slice(separator + 1);
|
|
53375
|
+
const model2 = this.find(provider, modelId);
|
|
53376
|
+
if (!model2) {
|
|
53377
|
+
return { fallbackReason: `model "${trimmed}" is not configured` };
|
|
53378
|
+
}
|
|
53379
|
+
const apiKey2 = this.getApiKey(model2);
|
|
53380
|
+
if (!apiKey2) {
|
|
53381
|
+
return { model: model2, fallbackReason: `no API key available for model "${trimmed}"` };
|
|
53382
|
+
}
|
|
53383
|
+
return { model: model2, apiKey: apiKey2 };
|
|
53384
|
+
}
|
|
53385
|
+
const matches = this.getAll().filter((model2) => model2.id === trimmed);
|
|
53386
|
+
if (matches.length === 0) {
|
|
53387
|
+
return { fallbackReason: `model "${trimmed}" is not configured; use provider/model-id` };
|
|
53388
|
+
}
|
|
53389
|
+
if (matches.length > 1) {
|
|
53390
|
+
return { fallbackReason: `model "${trimmed}" is ambiguous across providers (${matches.map((model2) => `${model2.provider}/${model2.id}`).join(", ")}); use provider/model-id` };
|
|
53391
|
+
}
|
|
53392
|
+
const model = matches[0];
|
|
53393
|
+
const apiKey = this.getApiKey(model);
|
|
53394
|
+
if (!apiKey) {
|
|
53395
|
+
return { model, fallbackReason: `no API key available for model "${model.provider}/${model.id}"` };
|
|
53396
|
+
}
|
|
53397
|
+
return { model, apiKey };
|
|
53398
|
+
}
|
|
53359
53399
|
hasExternalProviderConfig() {
|
|
53360
53400
|
return this.usingExternalProviders;
|
|
53361
53401
|
}
|
|
@@ -55169,11 +55209,44 @@ function canonicalSessionDir(sessionsDir, sessionId) {
|
|
|
55169
55209
|
function publishJournalPath(sessionsDir, safeTargetId) {
|
|
55170
55210
|
return path7.join(sessionsDir, PUBLISH_JOURNAL_DIR, `${safeTargetId}.json`);
|
|
55171
55211
|
}
|
|
55212
|
+
var FSYNC_UNSUPPORTED_CODES = /* @__PURE__ */ new Set(["EPERM", "EINVAL", "ENOTSUP", "EOPNOTSUPP", "EACCES", "EBADF"]);
|
|
55213
|
+
function fsyncDirectory(dirPath) {
|
|
55214
|
+
try {
|
|
55215
|
+
const fd = fs7.openSync(dirPath, "r");
|
|
55216
|
+
try {
|
|
55217
|
+
fs7.fsyncSync(fd);
|
|
55218
|
+
} finally {
|
|
55219
|
+
fs7.closeSync(fd);
|
|
55220
|
+
}
|
|
55221
|
+
} catch (error) {
|
|
55222
|
+
const code = error?.code;
|
|
55223
|
+
if (code !== void 0 && FSYNC_UNSUPPORTED_CODES.has(code)) return;
|
|
55224
|
+
throw error;
|
|
55225
|
+
}
|
|
55226
|
+
}
|
|
55172
55227
|
function writePublishJournal(journalPath, record) {
|
|
55173
|
-
|
|
55228
|
+
const journalDir = path7.dirname(journalPath);
|
|
55229
|
+
fs7.mkdirSync(journalDir, { recursive: true });
|
|
55174
55230
|
const tempPath = `${journalPath}.tmp`;
|
|
55175
55231
|
fs7.writeFileSync(tempPath, JSON.stringify(record, void 0, " "));
|
|
55232
|
+
const tempFd = fs7.openSync(tempPath, "r+");
|
|
55233
|
+
try {
|
|
55234
|
+
fs7.fsyncSync(tempFd);
|
|
55235
|
+
} finally {
|
|
55236
|
+
fs7.closeSync(tempFd);
|
|
55237
|
+
}
|
|
55176
55238
|
fs7.renameSync(tempPath, journalPath);
|
|
55239
|
+
fsyncDirectory(journalDir);
|
|
55240
|
+
fsyncDirectory(path7.dirname(journalDir));
|
|
55241
|
+
}
|
|
55242
|
+
function markPublishJournalFailed(journalPath) {
|
|
55243
|
+
if (!journalPath) return;
|
|
55244
|
+
try {
|
|
55245
|
+
const record = JSON.parse(fs7.readFileSync(journalPath, "utf8"));
|
|
55246
|
+
if (record?.v !== 1 || typeof record.failedAt === "number") return;
|
|
55247
|
+
writePublishJournal(journalPath, { ...record, failedAt: Date.now() });
|
|
55248
|
+
} catch {
|
|
55249
|
+
}
|
|
55177
55250
|
}
|
|
55178
55251
|
function clearPublishJournal(journalPath) {
|
|
55179
55252
|
if (!journalPath) return;
|
|
@@ -55226,6 +55299,7 @@ async function rewindStoredSession(params) {
|
|
|
55226
55299
|
}
|
|
55227
55300
|
async function forkStoredSession(params) {
|
|
55228
55301
|
let stagingId;
|
|
55302
|
+
let preserveStagingForRecovery = false;
|
|
55229
55303
|
try {
|
|
55230
55304
|
const sanitizedTargetId = params.targetSessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
55231
55305
|
if (sanitizedTargetId.startsWith(STAGING_SESSION_ID_PREFIX)) {
|
|
@@ -55356,6 +55430,7 @@ async function forkStoredSession(params) {
|
|
|
55356
55430
|
if (hadPreviousTarget) {
|
|
55357
55431
|
try {
|
|
55358
55432
|
params.store.moveSession(params.targetSessionId, backupId);
|
|
55433
|
+
if (params.sessionsDir) fsyncDirectory(params.sessionsDir);
|
|
55359
55434
|
} catch (error) {
|
|
55360
55435
|
clearPublishJournal(journalPath);
|
|
55361
55436
|
throw error;
|
|
@@ -55363,6 +55438,7 @@ async function forkStoredSession(params) {
|
|
|
55363
55438
|
}
|
|
55364
55439
|
try {
|
|
55365
55440
|
params.store.moveSession(stagingId, params.targetSessionId);
|
|
55441
|
+
if (params.sessionsDir) fsyncDirectory(params.sessionsDir);
|
|
55366
55442
|
} catch (error) {
|
|
55367
55443
|
if (hadPreviousTarget) {
|
|
55368
55444
|
try {
|
|
@@ -55370,8 +55446,11 @@ async function forkStoredSession(params) {
|
|
|
55370
55446
|
throw new Error("target path is occupied");
|
|
55371
55447
|
}
|
|
55372
55448
|
params.store.moveSession(backupId, params.targetSessionId);
|
|
55449
|
+
if (params.sessionsDir) fsyncDirectory(params.sessionsDir);
|
|
55373
55450
|
clearPublishJournal(journalPath);
|
|
55374
55451
|
} catch (restoreError) {
|
|
55452
|
+
markPublishJournalFailed(journalPath);
|
|
55453
|
+
preserveStagingForRecovery = true;
|
|
55375
55454
|
throw new SessionControlError(
|
|
55376
55455
|
"session_io_error",
|
|
55377
55456
|
`Fork publication failed; previous session is preserved as ${backupId}. Restore failed: ${String(restoreError)}`,
|
|
@@ -55406,7 +55485,7 @@ async function forkStoredSession(params) {
|
|
|
55406
55485
|
} catch (error) {
|
|
55407
55486
|
throw toIoError(error);
|
|
55408
55487
|
} finally {
|
|
55409
|
-
if (stagingId) {
|
|
55488
|
+
if (stagingId && !preserveStagingForRecovery) {
|
|
55410
55489
|
try {
|
|
55411
55490
|
params.store.delete(stagingId);
|
|
55412
55491
|
} catch {
|
|
@@ -55479,7 +55558,7 @@ function recoverOnePublishJournal(params) {
|
|
|
55479
55558
|
try {
|
|
55480
55559
|
const parsed = JSON.parse(fs7.readFileSync(params.journalPath, "utf8"));
|
|
55481
55560
|
const safeId = /^[a-zA-Z0-9_-]+$/;
|
|
55482
|
-
if (parsed?.v !== 1 || !safeId.test(parsed.targetId ?? "") || !safeId.test(parsed.stagingId ?? "") || !((parsed.backupDir ?? null) === null || safeId.test(parsed.backupDir))) {
|
|
55561
|
+
if (parsed?.v !== 1 || !safeId.test(parsed.targetId ?? "") || !safeId.test(parsed.stagingId ?? "") || !((parsed.backupDir ?? null) === null || safeId.test(parsed.backupDir)) || !((parsed.failedAt ?? void 0) === void 0 || typeof parsed.failedAt === "number")) {
|
|
55483
55562
|
throw new Error("journal record has unexpected shape");
|
|
55484
55563
|
}
|
|
55485
55564
|
record = parsed;
|
|
@@ -55505,7 +55584,7 @@ function recoverOnePublishJournal(params) {
|
|
|
55505
55584
|
const backupExists = record.backupDir ? dirExists(record.backupDir) : false;
|
|
55506
55585
|
const stagingExists = dirExists(record.stagingId);
|
|
55507
55586
|
try {
|
|
55508
|
-
if (targetExists && !stagingExists) {
|
|
55587
|
+
if (targetExists && !stagingExists && record.failedAt === void 0) {
|
|
55509
55588
|
if (backupExists && record.backupDir) removeSessionDir(record.backupDir);
|
|
55510
55589
|
removeJournal();
|
|
55511
55590
|
return { action: "publish-completed", targetId: record.targetId };
|
|
@@ -55515,22 +55594,32 @@ function recoverOnePublishJournal(params) {
|
|
|
55515
55594
|
path7.join(params.sessionsDir, record.backupDir),
|
|
55516
55595
|
path7.join(params.sessionsDir, record.targetId)
|
|
55517
55596
|
);
|
|
55518
|
-
|
|
55597
|
+
fsyncDirectory(params.sessionsDir);
|
|
55519
55598
|
if (stagingExists) {
|
|
55520
55599
|
try {
|
|
55521
55600
|
removeSessionDir(record.stagingId);
|
|
55522
55601
|
} catch (error) {
|
|
55523
55602
|
warn(`[session-control] Restored ${record.targetId} but could not remove its abandoned staging copy ${record.stagingId}: ${String(error)}`);
|
|
55603
|
+
return { action: "ambiguous-preserved", targetId: record.targetId, message: `Staging cleanup failed after restore; journal preserved: ${String(error)}` };
|
|
55524
55604
|
}
|
|
55525
55605
|
}
|
|
55606
|
+
removeJournal();
|
|
55526
55607
|
return { action: "restored-previous-target", targetId: record.targetId };
|
|
55527
55608
|
}
|
|
55528
55609
|
if (!targetExists && !backupExists) {
|
|
55529
|
-
if (stagingExists)
|
|
55610
|
+
if (stagingExists) {
|
|
55611
|
+
try {
|
|
55612
|
+
removeSessionDir(record.stagingId);
|
|
55613
|
+
} catch (error) {
|
|
55614
|
+
warn(`[session-control] Could not remove abandoned staging copy ${record.stagingId}: ${String(error)}`);
|
|
55615
|
+
return { action: "ambiguous-preserved", targetId: record.targetId, message: `Staging cleanup failed; journal preserved: ${String(error)}` };
|
|
55616
|
+
}
|
|
55617
|
+
}
|
|
55530
55618
|
removeJournal();
|
|
55531
55619
|
return stagingExists ? { action: "discarded-incomplete-fork", targetId: record.targetId } : { action: "nothing-to-recover", targetId: record.targetId };
|
|
55532
55620
|
}
|
|
55533
|
-
const
|
|
55621
|
+
const reason = record.failedAt !== void 0 ? "the publish failed in-process (restore failed) and the backup was preserved" : `target=${targetExists}, backup=${backupExists}, staging=${stagingExists}`;
|
|
55622
|
+
const message = `[session-control] Ambiguous interrupted publish for target ${record.targetId} (${reason}); nothing was deleted \u2014 inspect ${params.sessionsDir} and ${journalName} manually`;
|
|
55534
55623
|
warn(message);
|
|
55535
55624
|
return { action: "ambiguous-preserved", targetId: record.targetId, message };
|
|
55536
55625
|
} catch (error) {
|
|
@@ -56206,6 +56295,9 @@ function createExtensionContext(extension, cwd, uiContext, abortFn, isIdleFn, ha
|
|
|
56206
56295
|
resolveModelClass(modelClass) {
|
|
56207
56296
|
return actions?.resolveModelClass?.(modelClass) ?? {};
|
|
56208
56297
|
},
|
|
56298
|
+
resolveModelRef(modelRef) {
|
|
56299
|
+
return actions?.resolveModelRef?.(modelRef) ?? {};
|
|
56300
|
+
},
|
|
56209
56301
|
getMessages() {
|
|
56210
56302
|
return actions?.getMessages?.() ?? [];
|
|
56211
56303
|
},
|
|
@@ -63885,6 +63977,7 @@ var ExtensionRunner = class {
|
|
|
63885
63977
|
getAllTools: () => runner.actions.getAllTools(),
|
|
63886
63978
|
getRuntimeTools: () => runner.actions.getRuntimeTools(),
|
|
63887
63979
|
resolveModelClass: (modelClass) => runner.actions.resolveModelClass?.(modelClass) ?? {},
|
|
63980
|
+
resolveModelRef: (modelRef) => runner.actions.resolveModelRef?.(modelRef) ?? {},
|
|
63888
63981
|
getMessages: () => runner.actions.getMessages(),
|
|
63889
63982
|
getSessionMetadata: () => runner.actions.getSessionMetadata(),
|
|
63890
63983
|
setSessionMetadata: (key, value) => runner.actions.setSessionMetadata(key, value),
|
|
@@ -74159,6 +74252,7 @@ function createExtensionContextForCommands(host) {
|
|
|
74159
74252
|
},
|
|
74160
74253
|
getRuntimeTools: () => host.agent.state.tools,
|
|
74161
74254
|
resolveModelClass: (modelClass) => host.options.modelRegistry.resolveModelClass(modelClass),
|
|
74255
|
+
resolveModelRef: (modelRef) => host.options.modelRegistry.resolveModelRef(modelRef),
|
|
74162
74256
|
getMessages: () => host.agent.state.messages,
|
|
74163
74257
|
getSessionMetadata: () => ({ ...host.sessionManager.getActiveSession()?.metadata ?? {} }),
|
|
74164
74258
|
setSessionMetadata: (key, value) => {
|
|
@@ -79434,6 +79528,7 @@ async function loadInteractiveExtensions(host) {
|
|
|
79434
79528
|
fallbackReason: resolved.fallbackReason
|
|
79435
79529
|
};
|
|
79436
79530
|
},
|
|
79531
|
+
resolveModelRef: (modelRef) => host.options.modelRegistry.resolveModelRef(modelRef),
|
|
79437
79532
|
getMessages: () => host.agent.state.messages,
|
|
79438
79533
|
getSessionMetadata: () => ({ ...host.sessionManager.getActiveSession()?.metadata ?? {} }),
|
|
79439
79534
|
setSessionMetadata: (key, value) => {
|
|
@@ -80657,6 +80752,7 @@ async function loadPrintModeExtensions(params) {
|
|
|
80657
80752
|
})),
|
|
80658
80753
|
getRuntimeTools: () => params.getAgent()?.state.tools ?? [],
|
|
80659
80754
|
resolveModelClass: (modelClass) => params.modelRegistry.resolveModelClass(modelClass),
|
|
80755
|
+
resolveModelRef: (modelRef) => params.modelRegistry.resolveModelRef(modelRef),
|
|
80660
80756
|
getMessages: () => params.getAgent()?.state.messages ?? [],
|
|
80661
80757
|
getSessionMetadata: () => ({ ...params.sessionManager.getActiveSession()?.metadata ?? {} }),
|
|
80662
80758
|
setSessionMetadata: (key, value) => {
|
|
@@ -81145,6 +81241,7 @@ async function loadJsonModeExtensions(params) {
|
|
|
81145
81241
|
})),
|
|
81146
81242
|
getRuntimeTools: () => params.getAgent()?.state.tools ?? [],
|
|
81147
81243
|
resolveModelClass: (modelClass) => params.runtime.modelRegistry.resolveModelClass(modelClass),
|
|
81244
|
+
resolveModelRef: (modelRef) => params.runtime.modelRegistry.resolveModelRef(modelRef),
|
|
81148
81245
|
getMessages: () => params.getAgent()?.state.messages ?? [],
|
|
81149
81246
|
getSessionMetadata: () => ({ ...params.runtime.sessionManager.getActiveSession()?.metadata ?? {} }),
|
|
81150
81247
|
setSessionMetadata: (key, value) => {
|