zidane 5.10.0 → 5.10.2

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.
Files changed (79) hide show
  1. package/dist/{agent-AnumGPWj.d.ts → agent-Bt123Fdy.d.ts} +103 -3
  2. package/dist/agent-Bt123Fdy.d.ts.map +1 -0
  3. package/dist/chat/pure.d.ts +3 -3
  4. package/dist/chat/pure.js +1 -1
  5. package/dist/chat.d.ts +6 -6
  6. package/dist/chat.js +3 -3
  7. package/dist/contexts/docker.d.ts +1 -1
  8. package/dist/{contexts-CbI8dRfI.js → contexts-GKAWYq07.js} +113 -7
  9. package/dist/contexts-GKAWYq07.js.map +1 -0
  10. package/dist/contexts.d.ts +3 -3
  11. package/dist/contexts.js +2 -2
  12. package/dist/eval.d.ts +1 -1
  13. package/dist/eval.js +3 -3
  14. package/dist/{headless-D0qfvzG9.js → headless-Cn6XXmr3.js} +4 -4
  15. package/dist/{headless-D0qfvzG9.js.map → headless-Cn6XXmr3.js.map} +1 -1
  16. package/dist/headless.d.ts +1 -1
  17. package/dist/headless.js +1 -1
  18. package/dist/{index-B65HjjKZ.d.ts → index-4pQUnr2W.d.ts} +2 -2
  19. package/dist/{index-B65HjjKZ.d.ts.map → index-4pQUnr2W.d.ts.map} +1 -1
  20. package/dist/{index-DsvHiyYU.d.ts → index-BodGKXBV.d.ts} +3 -3
  21. package/dist/{index-DsvHiyYU.d.ts.map → index-BodGKXBV.d.ts.map} +1 -1
  22. package/dist/{index-LX8KCBXU.d.ts → index-C7BvI1Hi.d.ts} +14 -4
  23. package/dist/index-C7BvI1Hi.d.ts.map +1 -0
  24. package/dist/index.d.ts +6 -6
  25. package/dist/index.js +7 -7
  26. package/dist/{login-DocBwMVo.js → login-DoGslmKC.js} +2 -2
  27. package/dist/{login-DocBwMVo.js.map → login-DoGslmKC.js.map} +1 -1
  28. package/dist/{mcp-DzuTfq-I.js → mcp-BdN9UjTO.js} +32 -7
  29. package/dist/mcp-BdN9UjTO.js.map +1 -0
  30. package/dist/mcp.d.ts +1 -1
  31. package/dist/mcp.js +1 -1
  32. package/dist/output/stream-json.d.ts +2 -2
  33. package/dist/output/stream-json.js +1 -1
  34. package/dist/output/terminal.d.ts +2 -2
  35. package/dist/{presets-CTNbWXWz.js → presets-DCrQmY3b.js} +3 -2
  36. package/dist/presets-DCrQmY3b.js.map +1 -0
  37. package/dist/presets.d.ts +2 -2
  38. package/dist/presets.js +1 -1
  39. package/dist/providers.d.ts +1 -1
  40. package/dist/restate.d.ts +192 -16
  41. package/dist/restate.d.ts.map +1 -1
  42. package/dist/restate.js +133 -5
  43. package/dist/restate.js.map +1 -1
  44. package/dist/session/sqlite.d.ts +1 -1
  45. package/dist/session.d.ts +1 -1
  46. package/dist/skills.d.ts +2 -2
  47. package/dist/{tool-formatters-5nr1eXPn.d.ts → tool-formatters-BuB31L-c.d.ts} +2 -2
  48. package/dist/{tool-formatters-5nr1eXPn.d.ts.map → tool-formatters-BuB31L-c.d.ts.map} +1 -1
  49. package/dist/tools/fetch-url.d.ts +1 -1
  50. package/dist/tools/web-search.d.ts +1 -1
  51. package/dist/{tools-ycHDeHBZ.js → tools-Bk9TqmCV.js} +225 -18
  52. package/dist/tools-Bk9TqmCV.js.map +1 -0
  53. package/dist/tools.d.ts +3 -3
  54. package/dist/tools.js +2 -2
  55. package/dist/{transcript-anchors-D6Sw-Gzk.js → transcript-anchors-Bkuspqgn.js} +5 -5
  56. package/dist/{transcript-anchors-D6Sw-Gzk.js.map → transcript-anchors-Bkuspqgn.js.map} +1 -1
  57. package/dist/{transcript-anchors-DezrH1sp.d.ts → transcript-anchors-DhVgKmEl.d.ts} +4 -4
  58. package/dist/{transcript-anchors-DezrH1sp.d.ts.map → transcript-anchors-DhVgKmEl.d.ts.map} +1 -1
  59. package/dist/tui.d.ts +3 -3
  60. package/dist/tui.js +7 -7
  61. package/dist/{turn-operations-C70p-7Nn.js → turn-operations-DLWN2J7f.js} +13 -1
  62. package/dist/{turn-operations-C70p-7Nn.js.map → turn-operations-DLWN2J7f.js.map} +1 -1
  63. package/dist/{turn-operations-CICEEhrU.d.ts → turn-operations-DYKtoVd9.d.ts} +3 -3
  64. package/dist/{turn-operations-CICEEhrU.d.ts.map → turn-operations-DYKtoVd9.d.ts.map} +1 -1
  65. package/dist/{types-CRf_uTpK.d.ts → types-BMwiYRIJ.d.ts} +100 -6
  66. package/dist/types-BMwiYRIJ.d.ts.map +1 -0
  67. package/dist/types-BiobHM1D.js.map +1 -1
  68. package/dist/types.d.ts +5 -5
  69. package/docs/RESTATE.md +79 -5
  70. package/docs/RUN_IN_BACKGROUND.md +10 -1
  71. package/docs/SKILL.md +11 -4
  72. package/package.json +1 -1
  73. package/dist/agent-AnumGPWj.d.ts.map +0 -1
  74. package/dist/contexts-CbI8dRfI.js.map +0 -1
  75. package/dist/index-LX8KCBXU.d.ts.map +0 -1
  76. package/dist/mcp-DzuTfq-I.js.map +0 -1
  77. package/dist/presets-CTNbWXWz.js.map +0 -1
  78. package/dist/tools-ycHDeHBZ.js.map +0 -1
  79. package/dist/types-CRf_uTpK.d.ts.map +0 -1
@@ -4,13 +4,13 @@ import { a as formatTaskStatus, i as formatDuration, o as formatTaskSummary, s a
4
4
  import { a as createCursorOAuthProvider, c as arcee, f as ANTHROPIC_EXTRA_MODELS, l as anthropic, n as openai, o as generatePkce, p as FAST_MODE_OPTIONS, r as local, s as cerebras, t as openrouter } from "./providers-BxHepM_P.js";
5
5
  import { i as AgentProviderError, l as errorMessage, n as AgentBudgetExceededError, o as AgentToolPairingError, p as toTypedError, t as AgentAbortedError } from "./errors-B-GeaKTX.js";
6
6
  import { E as appendStaticSection, a as detectTurnInterruption, c as filterUnresolvedToolUses, k as renderSystemForWire, n as SYNTHETIC_TOOL_RESULT_PLACEHOLDER, o as ensureEndsWithUserMessage, s as ensureToolResultPairing } from "./messages-DdfOKKx_.js";
7
- import { i as toolOutputByteLength, n as documentBlockMarker, r as toolOutputBudgetByteLength, t as DEFAULT_AGENT_CLOCK } from "./types-BiobHM1D.js";
7
+ import { a as toolResultToText, i as toolOutputByteLength, n as documentBlockMarker, r as toolOutputBudgetByteLength, t as DEFAULT_AGENT_CLOCK } from "./types-BiobHM1D.js";
8
8
  import { t as reconcileImageMediaType } from "./image-sniff-B7uFSNO1.js";
9
- import { n as createProcessContext } from "./contexts-CbI8dRfI.js";
9
+ import { r as createProcessContext, t as resolveDetachedTasksCapability } from "./contexts-GKAWYq07.js";
10
10
  import { i as styleReplacementForVia, n as resolveOldString, r as stripLineNumberPrefixes, t as describeVia } from "./edit-utils-EGosADZq.js";
11
11
  import { a as invalidateReadStatePath, n as getToolDedupState, o as readStateKey, r as hashContent, s as resolveReadStateMap } from "./read-state-CDVYj7q-.js";
12
12
  import { S as escapeXml, d as buildCatalog, n as stripShellInterpolations, p as installAllowedToolsGate, r as resolveSkills, t as interpolateShellCommands, v as validateResourcePathReal, x as createSkillActivationState } from "./interpolate-DwVIJpB3.js";
13
- import { n as connectMcpServers } from "./mcp-DzuTfq-I.js";
13
+ import { n as connectMcpServers } from "./mcp-BdN9UjTO.js";
14
14
  import { n as flattenTurns, r as formatTokenUsage, t as effectiveInputFromTurn } from "./stats-DAKBEKjc.js";
15
15
  import { dirname, isAbsolute, join, resolve } from "node:path";
16
16
  import { createHooks } from "hookable";
@@ -4660,7 +4660,7 @@ function buildShellDescription({ allowBackground, registeredCanonicals, toolAlia
4660
4660
  }
4661
4661
  if (swaps.length > 0) lines.push("", "When a dedicated tool fits, prefer it over shell:", ...swaps, "", "Re-running `ls`/`cat` on the same path is not useful — the prior result is still current unless you wrote to that path since.");
4662
4662
  }
4663
- if (allowBackground) lines.push("", "Long-running commands (`npm run dev`, `python train.py`, anything that would otherwise block your turn for minutes) → `run_in_background: true`. The call returns immediately with `{ task_id, output_path, pid }`; stdout + stderr stream to the log file at `output_path`.", "", "After spawning a background task: end your current turn (do NOT keep iterating). A `<task-notification>` arrives on the agent's NEXT user-turn with the final status. Polling the log file in a loop wastes tokens and blocks your turn — the notification IS the wake-up. If you NEED to check progress immediately (rare), call `read_file({ path: output_path, ... })` exactly once and decide. To terminate, use `shell_kill({ task_id })`.", "", "When called from inside a `spawn`'d subagent: you have NO next user-turn — your `agent.run` ends as soon as you finish responding. Start the background task, return a brief summary including the `task_id`, and end your turn. Ownership of the task is transferred to the parent agent when your run finishes; the parent will see the notification on ITS next user-turn.");
4663
+ if (allowBackground) lines.push("", "Long-running commands (`npm run dev`, `python train.py`, anything that would otherwise block your turn for minutes) → `run_in_background: true`. The call returns immediately with `{ task_id, output_path, pid }`; stdout + stderr stream to the log file at `output_path`.", "", "After spawning a background task: end your current turn (do NOT keep iterating). A `<task-notification>` arrives on the agent's NEXT user-turn with the final status. Polling the log file in a loop wastes tokens and blocks your turn — the notification IS the wake-up. If you NEED to check progress immediately (rare), call `read_file({ path: output_path, ... })` exactly once and decide. To terminate, use `shell_kill({ task_id })`. If — and only if — your very next step depends on the task's outcome, block on it with `wait_task({ task_id })` instead of polling.", "", "When called from inside a `spawn`'d subagent: you have NO next user-turn — your `agent.run` ends as soon as you finish responding. Start the background task, return a brief summary including the `task_id`, and end your turn. Ownership of the task is transferred to the parent agent when your run finishes; the parent will see the notification on ITS next user-turn.");
4664
4664
  return lines.join("\n");
4665
4665
  }
4666
4666
  /**
@@ -4802,13 +4802,24 @@ async function runBackground(command, ctx) {
4802
4802
  if (typeof tasksDir !== "string" || tasksDir.length === 0) return "shell error: background mode requires `behavior.tasksDir` to be set on the agent. The host has not opted into background tasks — either fall back to foreground (drop `run_in_background`) or ask the user to enable it.";
4803
4803
  if (!ctx.execution.execBackground) return `shell error: the active execution context (${ctx.execution.type}) does not support background tasks. Fall back to foreground (drop \`run_in_background\`).`;
4804
4804
  try {
4805
+ const outputCap = ctx.behavior?.backgroundOutputCap;
4806
+ const stallWatchdogMs = ctx.behavior?.backgroundStallWatchdogMs;
4805
4807
  const handle = await ctx.execution.execBackground(ctx.handle, command, {
4806
4808
  outputDir: tasksDir,
4807
4809
  onExit: (info) => {
4808
4810
  Promise.resolve(ctx.hooks.callHook("background:exit", info)).catch((err) => {
4809
4811
  if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/shell] background:exit hook rejected: ${err instanceof Error ? err.message : String(err)}\n`);
4810
4812
  });
4811
- }
4813
+ },
4814
+ ...typeof outputCap === "number" && outputCap > 0 ? { maxOutputBytes: outputCap } : {},
4815
+ ...typeof stallWatchdogMs === "number" && stallWatchdogMs > 0 ? {
4816
+ stallTimeoutMs: stallWatchdogMs,
4817
+ onStall: (info) => {
4818
+ Promise.resolve(ctx.hooks.callHook("background:stall", info)).catch((err) => {
4819
+ if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/shell] background:stall hook rejected: ${err instanceof Error ? err.message : String(err)}\n`);
4820
+ });
4821
+ }
4822
+ } : {}
4812
4823
  });
4813
4824
  Promise.resolve(ctx.hooks.callHook("background:start", {
4814
4825
  taskId: handle.taskId,
@@ -5332,6 +5343,60 @@ function createToolSearchTool(options) {
5332
5343
  };
5333
5344
  }
5334
5345
  //#endregion
5346
+ //#region src/tools/wait-task.ts
5347
+ /**
5348
+ * Stable prefix on the timed-out result. The agent's notification
5349
+ * suppression keys on it: results carrying this prefix mean the task is
5350
+ * still running, so the pending `<task-notification>` must survive.
5351
+ */
5352
+ const WAIT_TASK_TIMED_OUT_PREFIX = "wait_task: timed out";
5353
+ const DEFAULT_TIMEOUT_MS = 12e4;
5354
+ const MAX_TIMEOUT_MS = 30 * 6e4;
5355
+ const waitTask = {
5356
+ spec: {
5357
+ name: "wait_task",
5358
+ description: [
5359
+ "Wait for a background task started by `shell({ run_in_background: true })` to exit, then return its final status.",
5360
+ "Returns immediately when the task has already terminated. On timeout the task keeps running and you can wait again, keep working, or `shell_kill` it.",
5361
+ "Prefer ending your turn and receiving the `<task-notification>` when you have other useful work or nothing depends on the result; use wait_task only when the next step genuinely needs the task's outcome."
5362
+ ].join("\n"),
5363
+ inputSchema: {
5364
+ type: "object",
5365
+ properties: {
5366
+ task_id: {
5367
+ type: "string",
5368
+ description: "The task id returned by a prior `shell({ run_in_background: true })` call."
5369
+ },
5370
+ timeout_ms: {
5371
+ type: "integer",
5372
+ description: `Max milliseconds to wait before giving up (task keeps running). Default: ${DEFAULT_TIMEOUT_MS}. Capped at ${MAX_TIMEOUT_MS}.`
5373
+ }
5374
+ },
5375
+ required: ["task_id"],
5376
+ additionalProperties: false
5377
+ }
5378
+ },
5379
+ async execute(input, ctx) {
5380
+ const taskId = input.task_id;
5381
+ if (!ctx.execution.waitBackground) return `wait_task error: the active execution context (${ctx.execution.type}) does not support waiting on background tasks.`;
5382
+ if (ctx.execution.listBackground) {
5383
+ if (!(await ctx.execution.listBackground(ctx.handle)).some((e) => e.taskId === taskId)) return `wait_task: no such task "${taskId}". It may have already exited and been cleaned up, or it was never started in this session.`;
5384
+ }
5385
+ const requested = typeof input.timeout_ms === "number" && Number.isFinite(input.timeout_ms) && input.timeout_ms > 0 ? input.timeout_ms : DEFAULT_TIMEOUT_MS;
5386
+ const timeoutMs = Math.min(requested, MAX_TIMEOUT_MS);
5387
+ const info = await ctx.execution.waitBackground(ctx.handle, taskId, {
5388
+ timeoutMs,
5389
+ signal: ctx.signal
5390
+ });
5391
+ if (!info) return [`${WAIT_TASK_TIMED_OUT_PREFIX} after ${formatDuration(timeoutMs)} — ${taskId} is still running.`, "You can wait again with a longer timeout, continue with other work (a `<task-notification>` arrives when it exits), or terminate it with `shell_kill`."].join("\n");
5392
+ return [
5393
+ `Task ${info.taskId} ${formatTaskStatus(info)} after ${formatDuration(info.durationMs)}.`,
5394
+ ` command: ${previewLine(info.command, 60)}`,
5395
+ ` output: ${info.outputPath}`
5396
+ ].join("\n");
5397
+ }
5398
+ };
5399
+ //#endregion
5335
5400
  //#region src/agent.ts
5336
5401
  /**
5337
5402
  * Single builder for a {@link ContextAssembly}, shared by the per-run snapshot
@@ -5441,6 +5506,69 @@ function renderTaskNotificationXml(info) {
5441
5506
  "</task-notification>"
5442
5507
  ].join("\n");
5443
5508
  }
5509
+ /**
5510
+ * Safety margin for the read-ack ordering comparison, which crosses two
5511
+ * clock domains: `turn.createdAt` comes from the host's `AgentClock`
5512
+ * (possibly a journaled clock) while `TaskEntry.endedAt` comes from the
5513
+ * execution context's wall clock (possibly a remote runner). The turn
5514
+ * timestamp already UNDERSTATES the actual read time (the assistant turn
5515
+ * is created before its tool executes), so the only false-suppression
5516
+ * window is the runner clock lagging the host clock. Requiring the read
5517
+ * to land this many ms after the exit absorbs that skew: within the
5518
+ * margin we fail open (redundant notification — harmless), and false
5519
+ * suppression needs cross-machine skew beyond it (broken NTP territory).
5520
+ */
5521
+ const READ_ACK_CLOCK_SKEW_MARGIN_MS = 5e3;
5522
+ function collectTaskAcksFromTurns(turns) {
5523
+ const taskIds = /* @__PURE__ */ new Set();
5524
+ const outputPaths = /* @__PURE__ */ new Map();
5525
+ const pendingWaits = /* @__PURE__ */ new Map();
5526
+ for (const turn of turns) for (const block of turn.content) {
5527
+ if (block.type === "text") {
5528
+ if (block.text.startsWith("<task-notification>")) {
5529
+ const match = block.text.match(/<task-id>([^<]+)<\/task-id>/);
5530
+ if (match) taskIds.add(match[1]);
5531
+ }
5532
+ continue;
5533
+ }
5534
+ if (block.type === "tool_call") {
5535
+ if (block.name === "shell_kill" && typeof block.input.task_id === "string") taskIds.add(block.input.task_id);
5536
+ else if (block.name === "wait_task" && typeof block.input.task_id === "string") pendingWaits.set(block.id, block.input.task_id);
5537
+ else if ((block.name === "read_file" || block.name === "read") && typeof block.input.path === "string" && block.input.path.length > 0) {
5538
+ const path = resolve(block.input.path);
5539
+ outputPaths.set(path, Math.max(outputPaths.get(path) ?? 0, turn.createdAt));
5540
+ }
5541
+ continue;
5542
+ }
5543
+ if (block.type === "tool_result" && !block.isError) {
5544
+ const waitedTaskId = pendingWaits.get(block.callId);
5545
+ if (waitedTaskId !== void 0) {
5546
+ if ((typeof block.output === "string" ? block.output : toolResultToText(block.output)).startsWith("Task ")) taskIds.add(waitedTaskId);
5547
+ }
5548
+ }
5549
+ }
5550
+ return {
5551
+ taskIds,
5552
+ outputPaths
5553
+ };
5554
+ }
5555
+ /**
5556
+ * Wire format for a stall-watchdog signal. Distinct outer tag from
5557
+ * `<task-notification>` so the model can tell "still running, but quiet"
5558
+ * apart from "terminated". Fields mirror {@link TaskStallInfo}.
5559
+ */
5560
+ function renderTaskStallXml(info) {
5561
+ return [
5562
+ "<task-stall>",
5563
+ ` <task-id>${escapeXml(info.taskId)}</task-id>`,
5564
+ ` <command>${escapeXml(info.command)}</command>`,
5565
+ ` <output-file>${escapeXml(info.outputPath)}</output-file>`,
5566
+ ` <stalled-for-ms>${info.stalledForMs}</stalled-for-ms>`,
5567
+ ` <bytes-written>${info.bytesWritten}</bytes-written>`,
5568
+ ` <hint>The task is still running but has produced no output for the reported window. It may be stuck at an interactive prompt — read the output file tail; if it ends in a question, kill it with shell_kill and re-run with piped input or a --yes flag.</hint>`,
5569
+ "</task-stall>"
5570
+ ].join("\n");
5571
+ }
5444
5572
  const HOOK_EVENT_SET = new Set([
5445
5573
  "system:before",
5446
5574
  "agent:start",
@@ -5496,6 +5624,7 @@ const HOOK_EVENT_SET = new Set([
5496
5624
  "mcp:close",
5497
5625
  "mcp:bootstrap:start",
5498
5626
  "mcp:bootstrap:end",
5627
+ "mcp:bootstrap:settled",
5499
5628
  "mcp:tools:list",
5500
5629
  "mcp:auth:required",
5501
5630
  "mcp:auth:url",
@@ -5510,6 +5639,8 @@ const HOOK_EVENT_SET = new Set([
5510
5639
  "background:start",
5511
5640
  "background:exit",
5512
5641
  "background:reassign",
5642
+ "background:stall",
5643
+ "background:reconcile",
5513
5644
  "skills:resolve",
5514
5645
  "skills:catalog",
5515
5646
  "skills:activate",
@@ -5624,6 +5755,12 @@ function resolveBehavior(agentBehavior, runBehavior) {
5624
5755
  persistMaxBytes: runBehavior?.persistMaxBytes ?? agentBehavior?.persistMaxBytes,
5625
5756
  tasksDir: runBehavior?.tasksDir ?? agentBehavior?.tasksDir,
5626
5757
  disableBackgroundTasks: runBehavior?.disableBackgroundTasks ?? agentBehavior?.disableBackgroundTasks,
5758
+ backgroundOutputCap: runBehavior?.backgroundOutputCap ?? agentBehavior?.backgroundOutputCap,
5759
+ backgroundStallWatchdogMs: runBehavior?.backgroundStallWatchdogMs ?? agentBehavior?.backgroundStallWatchdogMs,
5760
+ extensions: runBehavior?.extensions || agentBehavior?.extensions ? {
5761
+ ...agentBehavior?.extensions,
5762
+ ...runBehavior?.extensions
5763
+ } : void 0,
5627
5764
  strictToolPairing: runBehavior?.strictToolPairing ?? agentBehavior?.strictToolPairing ?? false,
5628
5765
  maxConsecutivePauseTurns: runBehavior?.maxConsecutivePauseTurns ?? agentBehavior?.maxConsecutivePauseTurns,
5629
5766
  persistTurns: runBehavior?.persistTurns ?? agentBehavior?.persistTurns
@@ -5874,6 +6011,8 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
5874
6011
  idleResolve = void 0;
5875
6012
  }
5876
6013
  const pendingTaskNotifications = /* @__PURE__ */ new Map();
6014
+ const pendingStallNotifications = /* @__PURE__ */ new Map();
6015
+ const notifiedTaskIds = /* @__PURE__ */ new Set();
5877
6016
  const pendingToolCancels = /* @__PURE__ */ new Map();
5878
6017
  let executionHandle = null;
5879
6018
  let mcpConnection = null;
@@ -6068,11 +6207,15 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
6068
6207
  } : runBaseTools;
6069
6208
  const toolsPreSearch = {};
6070
6209
  for (const tool of Object.values(mergedWithSkills)) toolsPreSearch[tool.spec.name] = tool;
6071
- if (toolsPreSearch.shell === shell) toolsPreSearch.shell = createShellTool({
6072
- allowBackground: typeof resolvedBehavior?.tasksDir === "string" && resolvedBehavior.tasksDir.length > 0 && resolvedBehavior.disableBackgroundTasks !== true,
6073
- registeredCanonicals: new Set(Object.keys(toolsPreSearch)),
6074
- ...effectiveToolAliases ? { toolAliases: effectiveToolAliases } : {}
6075
- });
6210
+ if (toolsPreSearch.shell === shell) {
6211
+ const detachedTasks = resolveDetachedTasksCapability(executionContext);
6212
+ const bgDisabled = resolvedBehavior?.disableBackgroundTasks === true || resolvedBehavior?.disableBackgroundTasks === "non-durable" && detachedTasks !== "durable";
6213
+ toolsPreSearch.shell = createShellTool({
6214
+ allowBackground: typeof resolvedBehavior?.tasksDir === "string" && resolvedBehavior.tasksDir.length > 0 && !bgDisabled && detachedTasks !== "none",
6215
+ registeredCanonicals: new Set(Object.keys(toolsPreSearch)),
6216
+ ...effectiveToolAliases ? { toolAliases: effectiveToolAliases } : {}
6217
+ });
6218
+ }
6076
6219
  const disclosure = partitionToolDisclosure(toolsPreSearch, mcpToolNames, mcpServers, toolDisclosure, effectiveToolAliases);
6077
6220
  const unlocked = new Set(disclosure.eagerCanonicalNames);
6078
6221
  const initialUnlocked = new Set(disclosure.eagerCanonicalNames);
@@ -6197,13 +6340,48 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
6197
6340
  }
6198
6341
  const runTurnStart = turns.length;
6199
6342
  if (options.system) await hooks.callHook("system:before", { system: options.system });
6343
+ const reconciled = new Map(pendingTaskNotifications);
6344
+ pendingTaskNotifications.clear();
6345
+ if (executionContext.listBackground && executionHandle && typeof resolvedBehavior?.tasksDir === "string" && resolvedBehavior.tasksDir.length > 0) try {
6346
+ const entries = await executionContext.listBackground(executionHandle);
6347
+ const acks = entries.some((e) => e.status !== "running") ? collectTaskAcksFromTurns(session ? session.turns : turns) : void 0;
6348
+ for (const entry of entries) {
6349
+ if (entry.status === "running" || notifiedTaskIds.has(entry.taskId) || reconciled.has(entry.taskId)) continue;
6350
+ if (acks) {
6351
+ if (acks.taskIds.has(entry.taskId)) continue;
6352
+ const readAt = acks.outputPaths.get(resolve(entry.outputPath));
6353
+ if (readAt !== void 0 && entry.endedAt !== void 0 && readAt >= entry.endedAt + READ_ACK_CLOCK_SKEW_MARGIN_MS) continue;
6354
+ }
6355
+ reconciled.set(entry.taskId, {
6356
+ taskId: entry.taskId,
6357
+ status: entry.status,
6358
+ exitCode: entry.exitCode ?? 0,
6359
+ ...entry.signal ? { signal: entry.signal } : {},
6360
+ outputPath: entry.outputPath,
6361
+ durationMs: Math.max(0, (entry.endedAt ?? entry.startedAt) - entry.startedAt),
6362
+ command: entry.command
6363
+ });
6364
+ }
6365
+ } catch (err) {
6366
+ if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/agent] background reconcile failed: ${err instanceof Error ? err.message : String(err)}\n`);
6367
+ }
6368
+ const reconcileCtx = { exits: [...reconciled.values()] };
6369
+ if (reconcileCtx.exits.length > 0) await hooks.callHook("background:reconcile", reconcileCtx);
6370
+ for (const taskId of reconciled.keys()) {
6371
+ notifiedTaskIds.add(taskId);
6372
+ pendingStallNotifications.delete(taskId);
6373
+ }
6200
6374
  const drainedNotifications = [];
6201
- if (pendingTaskNotifications.size > 0) {
6202
- for (const notif of pendingTaskNotifications.values()) drainedNotifications.push({
6375
+ for (const notif of reconcileCtx.exits) drainedNotifications.push({
6376
+ type: "text",
6377
+ text: renderTaskNotificationXml(notif)
6378
+ });
6379
+ if (pendingStallNotifications.size > 0) {
6380
+ for (const stall of pendingStallNotifications.values()) drainedNotifications.push({
6203
6381
  type: "text",
6204
- text: renderTaskNotificationXml(notif)
6382
+ text: renderTaskStallXml(stall)
6205
6383
  });
6206
- pendingTaskNotifications.clear();
6384
+ pendingStallNotifications.clear();
6207
6385
  }
6208
6386
  let lastPersistedTurnCount = turns.length;
6209
6387
  const promptParts = canonicalizePrompt(options.prompt);
@@ -6521,6 +6699,7 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
6521
6699
  followUpQueue.length = 0;
6522
6700
  lastContextAssembly = null;
6523
6701
  pendingTaskNotifications.clear();
6702
+ pendingStallNotifications.clear();
6524
6703
  const cleared = skillActivationState.clear();
6525
6704
  for (const record of cleared) await hooks.callHook("skills:deactivate", {
6526
6705
  skill: record.skill,
@@ -6559,11 +6738,32 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
6559
6738
  durationMs: ctx.durationMs,
6560
6739
  command: ctx.command
6561
6740
  });
6741
+ pendingStallNotifications.delete(ctx.taskId);
6742
+ });
6743
+ hooks.hook("background:stall", (ctx) => {
6744
+ pendingStallNotifications.set(ctx.taskId, {
6745
+ taskId: ctx.taskId,
6746
+ command: ctx.command,
6747
+ outputPath: ctx.outputPath,
6748
+ stalledForMs: ctx.stalledForMs,
6749
+ bytesWritten: ctx.bytesWritten
6750
+ });
6562
6751
  });
6752
+ const suppressTaskNotification = (taskId) => {
6753
+ pendingTaskNotifications.delete(taskId);
6754
+ pendingStallNotifications.delete(taskId);
6755
+ notifiedTaskIds.add(taskId);
6756
+ };
6563
6757
  hooks.hook("tool:after", (ctx) => {
6564
6758
  if (ctx.name === "shell_kill") {
6565
6759
  const taskId = ctx.input?.task_id;
6566
- if (typeof taskId === "string") pendingTaskNotifications.delete(taskId);
6760
+ if (typeof taskId === "string") suppressTaskNotification(taskId);
6761
+ return;
6762
+ }
6763
+ if (ctx.name === "wait_task") {
6764
+ const taskId = ctx.input?.task_id;
6765
+ const timedOut = typeof ctx.result === "string" && ctx.result.startsWith("wait_task: timed out");
6766
+ if (typeof taskId === "string" && !timedOut && typeof ctx.result === "string" && ctx.result.startsWith("Task ")) suppressTaskNotification(taskId);
6567
6767
  return;
6568
6768
  }
6569
6769
  if (ctx.name === "read_file" || ctx.name === "read") {
@@ -6571,7 +6771,11 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
6571
6771
  if (typeof rawPath !== "string" || rawPath.length === 0) return;
6572
6772
  const requested = resolve(rawPath);
6573
6773
  for (const notif of pendingTaskNotifications.values()) if (resolve(notif.outputPath) === requested) {
6574
- pendingTaskNotifications.delete(notif.taskId);
6774
+ suppressTaskNotification(notif.taskId);
6775
+ return;
6776
+ }
6777
+ for (const stall of pendingStallNotifications.values()) if (resolve(stall.outputPath) === requested) {
6778
+ pendingStallNotifications.delete(stall.taskId);
6575
6779
  return;
6576
6780
  }
6577
6781
  }
@@ -6628,6 +6832,7 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
6628
6832
  if (destroyed) return;
6629
6833
  destroyed = true;
6630
6834
  pendingTaskNotifications.clear();
6835
+ pendingStallNotifications.clear();
6631
6836
  if (abortController && !abortController.signal.aborted) abortController.abort("agent-destroyed");
6632
6837
  for (const controller of pendingToolCancels.values()) if (!controller.signal.aborted) controller.abort("agent-destroyed");
6633
6838
  pendingToolCancels.clear();
@@ -6643,6 +6848,8 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
6643
6848
  executionHandle = null;
6644
6849
  }
6645
6850
  pendingTaskNotifications.clear();
6851
+ pendingStallNotifications.clear();
6852
+ notifiedTaskIds.clear();
6646
6853
  skillsCleanup();
6647
6854
  skillsCleanup = () => {};
6648
6855
  lastContextAssembly = null;
@@ -8376,6 +8583,6 @@ const writeFile$1 = {
8376
8583
  }
8377
8584
  };
8378
8585
  //#endregion
8379
- export { resolvePersistDir as A, getModelInfo as B, validateToolArgs as C, cleanupPersistedSession as D, buildPersistedStub as E, cerebrasDescriptor as F, openaiDescriptor as G, modelOptionsFor as H, credKeyOf as I, restoreModelOptions as J, openrouterDescriptor as K, effectiveContextWindow as L, BUILTIN_PROVIDERS as M, OUTPUT_RESERVE_TOKENS as N, maybePersistToolResult as O, anthropicDescriptor as P, enabledModelOptions as R, TOOL_USE_SKIPPED_MESSAGE as S, PERSISTENCE_PREVIEW_BYTES as T, modelSupportsReasoning as U, localDescriptor as V, modelsForDescriptor as W, createShellTool as _, multiEdit as a, SHELL_CASCADE_CANCEL_MESSAGE as b, grep as c, createAgent as d, createToolSearchTool as f, createSkillsReadTool as g, alwaysQuote as h, readFile$1 as i, resolveTasksDir as j, resolveMcpWarningsDir as k, glob$1 as l, createSkillsRunScriptTool as m, createSpawnTool as n, listFiles as o, createSkillsUseTool as p, piIdOf as q, shellKill as r, createInteractionTool as s, writeFile$1 as t, edit as u, shell as v, PERSISTED_STUB_PREFIX as w, TOOL_USE_CANCELLED_MESSAGE as x, INTERRUPT_MESSAGE_FOR_TOOL_USE as y, getContextWindow as z };
8586
+ export { maybePersistToolResult as A, enabledModelOptions as B, TOOL_USE_CANCELLED_MESSAGE as C, PERSISTENCE_PREVIEW_BYTES as D, PERSISTED_STUB_PREFIX as E, OUTPUT_RESERVE_TOKENS as F, modelSupportsReasoning as G, getModelInfo as H, anthropicDescriptor as I, openrouterDescriptor as J, modelsForDescriptor as K, cerebrasDescriptor as L, resolvePersistDir as M, resolveTasksDir as N, buildPersistedStub as O, BUILTIN_PROVIDERS as P, credKeyOf as R, SHELL_CASCADE_CANCEL_MESSAGE as S, validateToolArgs as T, localDescriptor as U, getContextWindow as V, modelOptionsFor as W, restoreModelOptions as X, piIdOf as Y, alwaysQuote as _, multiEdit as a, shell as b, grep as c, createAgent as d, WAIT_TASK_TIMED_OUT_PREFIX as f, createSkillsRunScriptTool as g, createSkillsUseTool as h, readFile$1 as i, resolveMcpWarningsDir as j, cleanupPersistedSession as k, glob$1 as l, createToolSearchTool as m, createSpawnTool as n, listFiles as o, waitTask as p, openaiDescriptor as q, shellKill as r, createInteractionTool as s, writeFile$1 as t, edit as u, createSkillsReadTool as v, TOOL_USE_SKIPPED_MESSAGE as w, INTERRUPT_MESSAGE_FOR_TOOL_USE as x, createShellTool as y, effectiveContextWindow as z };
8380
8587
 
8381
- //# sourceMappingURL=tools-ycHDeHBZ.js.map
8588
+ //# sourceMappingURL=tools-Bk9TqmCV.js.map