@cydm/pie 2.7.12 → 2.7.13

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/README.md CHANGED
@@ -211,11 +211,14 @@ Main key bindings:
211
211
  - `Enter` submit message
212
212
  - `Shift+Enter` insert a new line
213
213
  - `\` + `Enter` insert a new line in terminals without modified-enter support
214
- - `Ctrl+C` exit
215
- - `Ctrl+D` exit
214
+ - `Ctrl+C` clear the editor; press twice within 500 ms to exit
215
+ - `Ctrl+D` exit when the editor is empty; forward-delete otherwise
216
+ - `Ctrl+V` / `Alt+V` / `Cmd+V` paste an image from the clipboard when the main chat editor owns focus (terminal clipboard first, OS helper fallback). Plan refinement, extension input/editor/custom UI, visible overlays, and the mention picker retain their own paste keys.
216
217
  - `Ctrl+O` expand or collapse tool output
217
218
  - `/` open the slash command menu
218
219
 
220
+ OS clipboard images are staged in per-read private temporary directories (0700 directories and exclusively reserved 0600 files on POSIX), including subprocess output, and removed after staging or on failure. Windows uses the user's temporary directory and inherited OS access controls. Terminal OSC 5522 frames and CSI 5522 support replies are incrementally framed, size-bounded, and never flushed as keyboard input while recognized: the default inter-chunk deadline is 1s, with a 10s absolute frame deadline. Failed frames discard their tails through the terminator or until 1s of idle recovery. An ambiguous lone Escape keeps its normal keyboard timeout unless a clipboard request is active; even then it is eventually delivered as Escape. After idle recovery, arbitrarily late bare payload bytes cannot be distinguished from new typing.
221
+
219
222
  Direct shell mode:
220
223
 
221
224
  ```text
@@ -333,17 +336,13 @@ Run `pie doctor` to check whether chrome-devtools-axi and a Chrome browser are d
333
336
 
334
337
  ## Terminal UI Automation
335
338
 
336
- The built-in `tui-use` skill drives interactive terminal programs - REPLs, pdb/gdb debugger sessions, and full-screen TUI apps - through Pie's packaged PTY runtime. Run `node <skill-baseDir>/tui-use-cli.js --help`; no first-use dependency download or global CLI is required. Windows uses native PowerShell and ConPTY. State lives in `~/.pie/tui-use`, or a dedicated `PIE_TUI_USE_STATE_DIR`. Always target sessions with `--session <id>`, confirm termination with `wait --exit`, and clean up only sessions and daemons you own. Use plain `bash` for non-interactive commands.
339
+ The built-in `tui-use` skill drives interactive terminal programs - REPLs, pdb/gdb debugger sessions, and full-screen TUI apps - through Pie's packaged PTY runtime. Run `node <skill-baseDir>/tui-use-cli.js --help`; no first-use dependency download or global CLI is required. Windows uses native PowerShell and ConPTY. State lives in `~/.pie/tui-use`, or a dedicated `PIE_TUI_USE_STATE_DIR`. Always target sessions with `--session <id>`, confirm termination with `wait --exit`, and clean up only sessions and daemons you own. Use the `shell` tool for non-interactive commands.
337
340
 
338
341
  ## Desktop Control (computer-use)
339
342
 
340
- The built-in `computer-use` extension (vendored from `@injaneity/pi-computer-use@0.5.1`, frozen and self-maintained by Pie) controls real desktop applications on macOS, Windows, and Linux through a native accessibility helper. Desktop control is a last resort - prefer API, CLI, or web tools whenever they can accomplish the task.
341
-
342
- Tools are tiered:
343
+ The built-in `computer-use-axi` skill controls real desktop applications on macOS, Windows, and Linux through a native accessibility helper. Desktop control is a last resort - prefer API, CLI, or web tools whenever they can accomplish the task. Invoke the skill's CLI through the `shell` tool (`node <skill-baseDir>/computer-use-axi-cli.js <command>`); observation commands read UI state, while `act` synthesizes real input. These are CLI operations, not a separate model-visible extension tool tier, so normal shell confirmation policy applies.
343
344
 
344
- - **Observe tier (default)** - `find_roots`, `observe_ui`, `search_ui`, `expand_ui`, `inspect_ui`, `read_text`, `wait_for` read screen/UI state.
345
- - **Browser tier (default)** - `launch_browser`, `navigate_browser`, `evaluate_browser` control a managed CDP context. Navigation and JavaScript evaluation can have side effects; these are not read-only tools.
346
- - **Act tier (first-use confirmation)** - `act_ui` synthesizes real input (click, type, scroll, keypress, drag). The first `act_ui` call in each session asks for confirmation (class `computer_use_act`); YOLO mode bypasses it, and non-interactive hosts block it deterministically.
345
+ Read `builtin/skills/computer-use-axi/SKILL.md` for `roots`, bounded observation, checked actions and browser workflows. On macOS, run the CLI's `permissions setup` and then `permissions recheck` after granting Accessibility and Screen Recording; starting Pie interactively is not a substitute for that setup flow.
347
346
 
348
347
  Platform notes:
349
348
 
@@ -351,7 +350,7 @@ Platform notes:
351
350
  - **Windows**: the helper installs to `~/.pie/helpers/computer-use/windows-bridge.exe` and needs an interactive desktop session.
352
351
  - **Linux**: the helper installs to `~/.pie/helpers/computer-use/linux-bridge` and needs an AT-SPI2 bus (a running desktop session; headless servers are not supported).
353
352
 
354
- Config: `~/.pie/extensions/computer-use.json` (user) or `.pie/computer-use.json` (project) with `browser_use`, `headless`, `cursor_overlay`, `managed_browser`; env overrides `PIE_COMPUTER_USE_BROWSER_USE` / `PIE_COMPUTER_USE_HEADLESS` / `PIE_COMPUTER_USE_CURSOR_OVERLAY` / `PIE_COMPUTER_USE_MANAGED_BROWSER`. The engine ships as the `computer-use-axi` skill: invoke it through bash (`node <skill baseDir>/computer-use-axi-cli.js <command>`) per its SKILL.md, and run `pie doctor` for helper install status.
353
+ Config: `~/.pie/extensions/computer-use.json` (user) or `.pie/computer-use.json` (project) with `browser_use`, `headless`, `cursor_overlay`, `managed_browser`; env overrides `PIE_COMPUTER_USE_BROWSER_USE` / `PIE_COMPUTER_USE_HEADLESS` / `PIE_COMPUTER_USE_CURSOR_OVERLAY` / `PIE_COMPUTER_USE_MANAGED_BROWSER`. Run `pie doctor` for helper install status.
355
354
 
356
355
  ## Web Research
357
356
 
@@ -363,13 +362,13 @@ Pie exposes one default model-visible web tool: `web_research`. Use it for publi
363
362
 
364
363
  ## Permissions
365
364
 
366
- Pie's default tools operate from the current workspace. File tools are workspace-scoped, `~/.pie` is allowlisted for Pie configuration/session support, and shell commands return structured timeout/truncation/error details. The canonical shell tool is still named `bash` for compatibility; on Windows `shell:auto` uses PowerShell, and callers can explicitly request `bash`, `powershell`, or `cmd`. High-risk shell commands require confirmation outside YOLO mode; the confirmation dialog also offers a time-boxed `Yolo (5 min)` option that suppresses further high-risk prompts for five minutes without enabling full YOLO mode. `/settings/yolo` relaxes filesystem sandbox directory restrictions and should only be used in trusted workspaces. `pie permissions` prints the current policy-derived safety summary.
365
+ Pie's default tools operate from the current workspace. File tools are workspace-scoped, `~/.pie` is allowlisted for Pie configuration/session support, and shell commands return structured timeout/truncation/error details. The canonical executable tool is named `shell`; `bash` remains only a historical replay/rendering and policy identifier, not a second executable alias. On Windows `shell:auto` uses PowerShell, and callers can explicitly request the `bash`, `powershell`, or `cmd` dialect. High-risk shell commands require confirmation outside YOLO mode; the confirmation dialog also offers a time-boxed `Yolo (5 min)` option that suppresses further high-risk prompts for five minutes without enabling full YOLO mode. Explicitly turning `/settings/yolo off` revokes both persistent YOLO and any live temporary grant; status reports a remaining grant separately. `/settings/yolo` relaxes filesystem sandbox directory restrictions and should only be used in trusted workspaces. `pie permissions` prints the current policy-derived safety summary.
367
366
 
368
- In interactive Plan mode (`/tools/plan`), workspace editing tools are unavailable. The `bash` guard accepts simple read commands and read-only pipelines such as `rg 'TODO' . | head -20`; it blocks redirects, command substitution, and write-capable subcommands. Use `plan_scratch` to write, read, or list temporary text drafts in a directory dedicated to the current session. Shell redirection to `/tmp` remains blocked in Plan mode. When the plan is ready, the agent submits the ordered steps with `plan_submit` and you choose to execute immediately (progress is tracked through `[DONE:n]` markers in responses), keep planning, or refine the plan in a prefilled editor; a plan written as plain text under a `Plan:`/`计划:` heading is still detected as a fallback. Leave Plan mode before changing workspace files.
367
+ In interactive Plan mode (`/tools/plan`), workspace editing tools are unavailable. The Plan-mode `shell` guard accepts simple read commands and read-only pipelines such as `rg 'TODO' . | head -20`; it blocks redirects, command substitution, and write-capable subcommands. Use `plan_scratch` to write, read, or list temporary text drafts in a directory dedicated to the current session. Shell redirection to `/tmp` remains blocked in Plan mode. When the plan is ready, the agent submits the ordered steps with `plan_submit` and you choose to execute immediately (progress is tracked through `[DONE:n]` markers in responses), keep planning, or refine the plan in a prefilled editor; a plan written as plain text under a `Plan:`/`计划:` heading is still detected as a fallback. Leave Plan mode before changing workspace files.
369
368
 
370
369
  ## Code Intelligence
371
370
 
372
- `code_intel` provides read-only JS/TS diagnostics, definition, references, symbols, and hover. CLI uses an isolated TypeScript worker by default and falls back to bounded lightweight text analysis on worker startup/OOM/crash/timeout failures; aborts, permission errors, and path escapes do not fallback. Unity uses a Node sidecar contract for TypeScript intelligence so the PuerTS bundle does not import Node-only parser dependencies.
371
+ The CLI's former TypeScript-service `code_intel` tool has been retired. Unity currently exposes a lightweight provider for read-only JS/TS diagnostics, definition, references, symbols, and hover; do not infer a CLI TypeScript worker or a Unity Node sidecar from the old documentation.
373
372
 
374
373
  ## Diagnostics
375
374
 
@@ -405,7 +404,7 @@ Every management command (`sessions`, `doctor`, `models`, `extensions`, `permiss
405
404
  - Errors are structured on stdout: `{"v":1,"ok":false,"kind":"...","error":{"code":"session_not_found","message":"...","hint":"..."}}`.
406
405
  - Exit codes: `0` success, `1` business failure, `2` usage error. Unknown flags fail loudly; every subcommand supports `--help`.
407
406
  - `sessions list --json` defaults to the current project (`--all` lists every project). Rows are minimal (`id`, `name`, `updatedAt`, `count`) with `--fields` and `--full` opt-ins; `sessions read` truncates content by default with the same opt-ins.
408
- - JSONL protocol mode (`--json-events`) identifies entries by `entryId` only (the legacy `checkpointId` alias is gone) and caps large tool results and turn summaries by default; pass `--event-detail full` for untruncated payloads. Truncation always carries `truncated`/`fullLength` markers.
407
+ - JSONL protocol mode (`--json-events`) identifies entries by `entryId` only (the legacy `checkpointId` alias is gone) and caps large tool results and turn summaries by default; pass `--event-detail full` for larger but still bounded payloads (including a 4,000-character string cap, depth/item/key limits). Affected tool-result strings carry `truncated`/`fullLength`; other bounded structures may use only `truncated`.
409
408
 
410
409
  Run `pie capabilities --json` to discover the full command surface, flags, and exit-code contract programmatically.
411
410
 
@@ -1,9 +1,9 @@
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-AFPRX5XI.js";
5
- import "../../../chunks/chunk-2NBUFVUQ.js";
6
- import "../../../chunks/chunk-EN47TIBG.js";
4
+ } from "../../../chunks/chunk-CIFC6QVB.js";
5
+ import "../../../chunks/chunk-HGUYS5SF.js";
6
+ import "../../../chunks/chunk-R46YPPTU.js";
7
7
  import "../../../chunks/chunk-XXGYUYXI.js";
8
8
  import "../../../chunks/chunk-LZQXQOPJ.js";
9
9
 
@@ -6,9 +6,9 @@ import {
6
6
  extractPlanTodoItems,
7
7
  markCompletedPlanSteps,
8
8
  restoreExecutionState
9
- } from "../../../chunks/chunk-AFPRX5XI.js";
10
- import "../../../chunks/chunk-2NBUFVUQ.js";
11
- import "../../../chunks/chunk-EN47TIBG.js";
9
+ } from "../../../chunks/chunk-CIFC6QVB.js";
10
+ import "../../../chunks/chunk-HGUYS5SF.js";
11
+ import "../../../chunks/chunk-R46YPPTU.js";
12
12
  import {
13
13
  Type
14
14
  } from "../../../chunks/chunk-XXGYUYXI.js";
@@ -6,15 +6,15 @@ import {
6
6
  formatTransportLifecycle,
7
7
  getConfigDir,
8
8
  logTransportLifecycle
9
- } from "../../../chunks/chunk-YI3CSQGD.js";
9
+ } from "../../../chunks/chunk-D7RMNFVM.js";
10
10
  import {
11
11
  SUBAGENT_SESSION_RECORD_VERSION,
12
12
  createPolicyEnforcedTools,
13
13
  createSharedFileSystemTools,
14
14
  createSubagentCapability
15
- } from "../../../chunks/chunk-AFPRX5XI.js";
16
- import "../../../chunks/chunk-2NBUFVUQ.js";
17
- import "../../../chunks/chunk-EN47TIBG.js";
15
+ } from "../../../chunks/chunk-CIFC6QVB.js";
16
+ import "../../../chunks/chunk-HGUYS5SF.js";
17
+ import "../../../chunks/chunk-R46YPPTU.js";
18
18
  import "../../../chunks/chunk-XXGYUYXI.js";
19
19
  import "../../../chunks/chunk-LZQXQOPJ.js";
20
20
 
@@ -8,9 +8,9 @@ import {
8
8
  executeManageTodoList,
9
9
  executionStateToTodos,
10
10
  restoreExecutionState
11
- } from "../../../chunks/chunk-AFPRX5XI.js";
12
- import "../../../chunks/chunk-2NBUFVUQ.js";
13
- import "../../../chunks/chunk-EN47TIBG.js";
11
+ } from "../../../chunks/chunk-CIFC6QVB.js";
12
+ import "../../../chunks/chunk-HGUYS5SF.js";
13
+ import "../../../chunks/chunk-R46YPPTU.js";
14
14
  import "../../../chunks/chunk-XXGYUYXI.js";
15
15
  import "../../../chunks/chunk-LZQXQOPJ.js";
16
16
 
@@ -5022,17 +5022,19 @@ function validateRequest(value) {
5022
5022
  const params = validateCommandParams(command, value.params);
5023
5023
  const cwd = value.cwd === void 0 ? process.cwd() : boundedString(value.cwd, "cwd", 4096);
5024
5024
  if (!path3.isAbsolute(cwd)) throw new BrokerProtocolError("invalid_request", "cwd must be absolute.");
5025
- const rawEnvironment = value.environment ?? {};
5026
- assertPlainRecord(rawEnvironment, "environment");
5027
- assertKeys(rawEnvironment, "environment", REQUEST_ENV_KEYS);
5028
- for (const entry of Object.values(rawEnvironment)) {
5029
- if (typeof entry !== "string") throw new BrokerProtocolError("invalid_request", "environment values must be strings.");
5030
- }
5031
- let environment;
5032
- try {
5033
- environment = captureComputerUseEnvironment(rawEnvironment);
5034
- } catch (error) {
5035
- throw new BrokerProtocolError("invalid_request", String(error));
5025
+ let environment = {};
5026
+ if (command !== "stop") {
5027
+ const rawEnvironment = value.environment ?? {};
5028
+ assertPlainRecord(rawEnvironment, "environment");
5029
+ assertKeys(rawEnvironment, "environment", REQUEST_ENV_KEYS);
5030
+ for (const entry of Object.values(rawEnvironment)) {
5031
+ if (typeof entry !== "string") throw new BrokerProtocolError("invalid_request", "environment values must be strings.");
5032
+ }
5033
+ try {
5034
+ environment = captureComputerUseEnvironment(rawEnvironment);
5035
+ } catch (error) {
5036
+ throw new BrokerProtocolError("invalid_request", String(error));
5037
+ }
5036
5038
  }
5037
5039
  const budgetMs = value.budgetMs === void 0 ? BROKER_DEFAULT_REQUEST_BUDGET_MS : Math.trunc(boundedNumber(value.budgetMs, "budgetMs", BROKER_MIN_REQUEST_BUDGET_MS, BROKER_MAX_REQUEST_BUDGET_MS));
5038
5040
  return {
@@ -378,7 +378,7 @@ function isBrokerResponse(value) {
378
378
  }
379
379
  async function callBroker(options) {
380
380
  if (options.command !== "stop") resolveTestOnlyBackend();
381
- const environment = captureComputerUseEnvironment();
381
+ const environment = options.command === "stop" ? {} : captureComputerUseEnvironment();
382
382
  const endpoint = resolveBrokerEndpoint();
383
383
  const budgetMs = Math.min(Math.max(options.budgetMs ?? BROKER_DEFAULT_REQUEST_BUDGET_MS, 100), 15 * 6e4);
384
384
  const spawnState = { spawned: false };
@@ -1,8 +1,10 @@
1
1
  import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
2
  import {
3
3
  Agent,
4
+ createAgentOperationError,
5
+ getAgentFailureMetadata,
4
6
  getToolCallerIdentity
5
- } from "./chunk-2NBUFVUQ.js";
7
+ } from "./chunk-HGUYS5SF.js";
6
8
  import {
7
9
  AssistantMessageEventStream,
8
10
  FileSystemGateway,
@@ -12,7 +14,7 @@ import {
12
14
  getPlatformConfig,
13
15
  hashText,
14
16
  streamSimple
15
- } from "./chunk-EN47TIBG.js";
17
+ } from "./chunk-R46YPPTU.js";
16
18
  import {
17
19
  Type
18
20
  } from "./chunk-XXGYUYXI.js";
@@ -1001,7 +1003,7 @@ var PLAN_POWERSHELL_READ_COMMANDS = new Set([
1001
1003
  "Compare-Object",
1002
1004
  "Test-Path"
1003
1005
  ].map((name) => name.toLowerCase()));
1004
- var PLAN_POWERSHELL_READ_ALIASES = /* @__PURE__ */ new Set(["cat", "ls", "pwd", "echo", "sort"]);
1006
+ var PLAN_POWERSHELL_READ_ALIASES = /* @__PURE__ */ new Set(["cat", "ls", "pwd", "echo"]);
1005
1007
  var PLAN_POWERSHELL_SAFE_PARAMETERS = /^(?:-(?:Raw|TotalCount|Head|Tail|First|Last|Wait|LiteralPath|Path|Name|Pattern|Recurse|Filter|Include|Exclude|SimpleMatch|CaseSensitive|Quiet|Word|Line|Character|Encoding|ErrorAction|WarningAction))$/i;
1006
1008
  var PLAN_POWERSHELL_SEPARATORS = /[;\n\r\t&<>|]/;
1007
1009
  var PLAN_POWERSHELL_NON_ASCII = /[^\x20-\x7E]/;
@@ -1698,12 +1700,7 @@ Return a text-only successor handoff. Do not call any tools.` }],
1698
1700
  ).result();
1699
1701
  throwIfAborted();
1700
1702
  if (response.stopReason === "error" && (!response.content.some((block) => block.type === "toolCall") || classifyRemoteFailure(response.remoteFailure, response.errorMessage ?? "") !== void 0)) {
1701
- const providerError = new Error(response.errorMessage || "Compaction provider error");
1702
- const explicitRetryable = response.retryable;
1703
- if (typeof explicitRetryable === "boolean") providerError.retryable = explicitRetryable;
1704
- if (response.replayEligible === true) providerError.replayEligible = true;
1705
- providerError.remoteFailure = response.remoteFailure;
1706
- throw providerError;
1703
+ throw Object.assign(new Error(response.errorMessage || "Compaction provider error"), getAgentFailureMetadata(response));
1707
1704
  }
1708
1705
  } catch (error) {
1709
1706
  throwIfAborted();
@@ -5208,7 +5205,11 @@ async function runPreRequestAutoCompact(params) {
5208
5205
  try {
5209
5206
  await params.runAutoCompact();
5210
5207
  } catch (error) {
5211
- if (boundary) throw error;
5208
+ if (boundary) throw createAgentOperationError(error, {
5209
+ origin: "tool-continuation",
5210
+ operation: "compaction",
5211
+ terminal: true
5212
+ });
5212
5213
  if (params.isCurrent?.() !== false) params.setRecoveryState("none");
5213
5214
  }
5214
5215
  }
@@ -5517,7 +5518,8 @@ function isAssistantTerminalCompletion(message) {
5517
5518
  return !message.content.some((block) => block.type === "toolCall");
5518
5519
  }
5519
5520
  function createFailureClassification(context, retry, classifyFailure) {
5520
- if (context.message?.role === "assistant" && context.message.replayEligible === true && context.message.stopReason === "error") {
5521
+ const terminalOperation = context.message?.role === "assistant" && context.message.operationFailure?.terminal === true;
5522
+ if (!terminalOperation && context.message?.role === "assistant" && context.message.replayEligible === true && context.message.stopReason === "error") {
5521
5523
  return {
5522
5524
  kind: "provider_transient",
5523
5525
  retryable: true,
@@ -5528,7 +5530,7 @@ function createFailureClassification(context, retry, classifyFailure) {
5528
5530
  replayExempt: true
5529
5531
  };
5530
5532
  }
5531
- if (context.message?.role === "assistant" && context.message.retryable === false) {
5533
+ if (context.message?.role === "assistant" && (terminalOperation || context.message.retryable === false)) {
5532
5534
  return { kind: "unknown", retryable: false, compactable: false, userAbort: context.message.stopReason === "aborted", terminal: true, message: context.errorMessage };
5533
5535
  }
5534
5536
  const remote = context.message?.role === "assistant" && context.message.stopReason === "error" ? classifyRemoteFailure(context.message.remoteFailure, context.errorMessage) : void 0;
@@ -6311,7 +6313,8 @@ async function handleAgentSessionTurnEndRuntimePolicies(params) {
6311
6313
  params.emit({ type: "turn_settled" });
6312
6314
  return;
6313
6315
  }
6314
- const compactDecision = params.getAutoCompactDecision?.({
6316
+ const recoveryClosed = failure?.terminal && params.message?.role === "assistant" && (params.message.retryable === false || params.message.operationFailure?.terminal === true);
6317
+ const compactDecision = recoveryClosed ? void 0 : params.getAutoCompactDecision?.({
6315
6318
  agent: params.agent,
6316
6319
  sessionManager: params.sessionManager,
6317
6320
  cwd: params.cwd,
@@ -9565,6 +9568,22 @@ function createAgentInstance(deps, systemPrompt, tools, model, apiKey, thinkingL
9565
9568
  agentRunHooks.set(agent, hooks);
9566
9569
  return agent;
9567
9570
  }
9571
+ function inFlightRequestSummary(observation, now) {
9572
+ const transport = observation?.transport;
9573
+ if (!transport || transport.length === 0) return void 0;
9574
+ const lastStartIndex = transport.map((event) => event.phase).lastIndexOf("request_start");
9575
+ if (lastStartIndex < 0) return void 0;
9576
+ const start = transport[lastStartIndex];
9577
+ const after = transport.slice(lastStartIndex + 1);
9578
+ const terminal = after.find((event) => event.phase === "terminal_accepted");
9579
+ if (terminal) {
9580
+ const gapMs = Math.max(0, now - terminal.at);
9581
+ return `last model response completed ${Math.round(gapMs / 100) / 10}s before the deadline; no request in flight at abort`;
9582
+ }
9583
+ const sawFirst = after.some((event) => event.phase === "first_application_message");
9584
+ const ageMs = Math.max(0, now - start.at);
9585
+ return `a model request was still in flight at abort (${Math.round(ageMs / 100) / 10}s old, ${sawFirst ? "receiving stream events" : "no application message yet"}) \u2014 the deadline cut an unfinished response, which usually means the budget is too small for this reasoning level, not a transport stall`;
9586
+ }
9568
9587
  function isParentHandoffRequired(task) {
9569
9588
  return task.report?.availability !== "available" || task.mode === "edit" || task.status === "timeout" || task.status === "failed" || task.confidenceSignals.some((signal) => signal.type === "tool_error" || signal.type === "no_tool_use" || signal.type === "no_text_report");
9570
9589
  }
@@ -10069,7 +10088,8 @@ ${DELEGATION_REPORT_INSTRUCTION}`;
10069
10088
  task.status = timedOut ? "timeout" : signal?.aborted ? "cancelled" : "failed";
10070
10089
  observeDelegationPhase(task.observation, timedOut ? "deadline" : signal?.aborted ? "cancelled" : "failed");
10071
10090
  phaseProgress(task.observation.phase);
10072
- task.error = errorMessage.slice(0, 2e3);
10091
+ const deadlineDetail = timedOut ? inFlightRequestSummary(task.observation, Date.now()) : void 0;
10092
+ task.error = `${errorMessage.slice(0, 2e3)}${deadlineDetail ? `; ${deadlineDetail}` : ""}`.slice(0, 2e3);
10073
10093
  const failureCarrier = error;
10074
10094
  if (failureCarrier?.subagentFailure) {
10075
10095
  task.failure = failureCarrier.subagentFailure;
@@ -10086,7 +10106,7 @@ ${DELEGATION_REPORT_INSTRUCTION}`;
10086
10106
  task.report ??= parseDelegationReport(void 0, task.id);
10087
10107
  task.parentHandoffRequired = isParentHandoffRequired(task);
10088
10108
  task.completedAt = Date.now();
10089
- report({ message: `[${task.name}] Failed: ${errorMessage.slice(0, 100)}`, increment: 100 });
10109
+ report({ message: `[${task.name}] Failed: ${(errorMessage + (deadlineDetail ? `; ${deadlineDetail}` : "")).slice(0, 160)}`, increment: 100 });
10090
10110
  } finally {
10091
10111
  if (heartbeat) {
10092
10112
  clearInterval(heartbeat);
@@ -10181,7 +10201,7 @@ function buildParallelResult(tasks, totalDuration) {
10181
10201
  `;
10182
10202
  }
10183
10203
  if (task.sessionId) {
10184
- resultText += task.sessionBusy ? `Session: ${task.sessionId} (busy \u2014 previous run is still settling; recall will fail until it settles` : `Session: ${task.sessionId} (resumable \u2014 pass as "sessionId" in a later spawn to continue this subagent with its accumulated context`;
10204
+ resultText += task.sessionBusy ? `Session: ${task.sessionId} (busy \u2014 previous run is still settling; recall will fail until it settles` : `Session: ${task.sessionId} (resumable \u2014 pass as "sessionId" in a later spawn to continue this subagent with its accumulated context; add resumeMode:"report" to reuse only its last report`;
10185
10205
  if (task.sessionRunCount) resultText += `; run ${task.sessionRunCount}`;
10186
10206
  if (task.sessionPersisted) resultText += "; persisted to disk, survives restarts";
10187
10207
  resultText += ")\n";
@@ -10357,7 +10377,7 @@ Default mode="read" is for investigation, search, review, or triage and cannot e
10357
10377
  priority: Type.Optional(Type.Union([Type.Literal("fast"), Type.Literal("thorough")], { description: "fast uses lower-cost defaults; thorough raises model class when needed." })),
10358
10378
  model: Type.Optional(Type.String({ description: 'Explicit model override, e.g. "provider/model-id". Only when the user names a specific model; otherwise automatic.' })),
10359
10379
  thinkingLevel: Type.Optional(Type.Union([Type.Literal("off"), Type.Literal("minimal"), Type.Literal("low"), Type.Literal("medium"), Type.Literal("high"), Type.Literal("xhigh")], { description: "off|minimal|low|medium|high|xhigh. Default medium; override only when the user asks or for cheap lookups (off)." })),
10360
- timeout: Type.Optional(Type.Number({ description: "Seconds. Default 1200; set higher for long tasks." })),
10380
+ timeout: Type.Optional(Type.Number({ description: "Seconds. Default 1200; set higher for long tasks. Note: high/xhigh reasoning tasks can spend minutes per response on thinking alone \u2014 budget accordingly or the deadline will cut an in-flight response mid-thought." })),
10361
10381
  resumeMode: Type.Optional(Type.Union([Type.Literal("full"), Type.Literal("report")], { description: "Default full retains prior transcript. Explicit report rebuilds with current tools/model/credentials and only the latest valid historical report as data plus the new task; fails if unavailable." })),
10362
10382
  sessionId: Type.Optional(Type.String({ description: "Continue a previous subagent session by id (from an earlier result's Session line); full mode retains historical input with unknown cost. Optional mode/model/thinkingLevel reconfigure it; one task at a time; recalls never replay on failure and must target an idle session; prefer a fresh task for independent reviews." }))
10363
10383
  }
@@ -7,12 +7,12 @@ import {
7
7
  defaultShellKindForPlatform,
8
8
  interpretShellExit,
9
9
  requestInteraction
10
- } from "./chunk-AFPRX5XI.js";
10
+ } from "./chunk-CIFC6QVB.js";
11
11
  import {
12
12
  EMPTY_ASSISTANT_CONTENT_ERROR,
13
13
  OPENAI_COMPAT_PROTOCOL_ERROR_CODE,
14
14
  getLogger
15
- } from "./chunk-EN47TIBG.js";
15
+ } from "./chunk-R46YPPTU.js";
16
16
  import {
17
17
  Type
18
18
  } from "./chunk-XXGYUYXI.js";
@@ -4,7 +4,27 @@ import {
4
4
  disposeModelTransports,
5
5
  streamSimple,
6
6
  validateToolArguments
7
- } from "./chunk-EN47TIBG.js";
7
+ } from "./chunk-R46YPPTU.js";
8
+
9
+ // ../../packages/agent-core/src/failure.ts
10
+ function getAgentFailureMetadata(error) {
11
+ if (!error || typeof error !== "object") return {};
12
+ const source = error;
13
+ return {
14
+ ...source.retryable === false ? { retryable: false } : {},
15
+ ...source.remoteFailure ? { remoteFailure: source.remoteFailure } : {},
16
+ ...source.replayEligible === true ? { replayEligible: true } : {},
17
+ ...typeof source.replayClass === "string" ? { replayClass: source.replayClass } : {},
18
+ ...source.operationFailure ? { operationFailure: source.operationFailure } : {}
19
+ };
20
+ }
21
+ function createAgentOperationError(error, failure) {
22
+ return Object.assign(
23
+ new Error(error instanceof Error ? error.message : String(error), { cause: error }),
24
+ getAgentFailureMetadata(error),
25
+ { operationFailure: failure }
26
+ );
27
+ }
8
28
 
9
29
  // ../../packages/agent-core/src/agent-loop.ts
10
30
  function createLoopErrorMessage(error, config, signal) {
@@ -25,6 +45,7 @@ function createLoopErrorMessage(error, config, signal) {
25
45
  },
26
46
  stopReason: signal?.aborted ? "aborted" : "error",
27
47
  errorMessage: message,
48
+ ...getAgentFailureMetadata(error),
28
49
  timestamp: Date.now()
29
50
  };
30
51
  }
@@ -1132,6 +1153,8 @@ var Agent = class {
1132
1153
  };
1133
1154
 
1134
1155
  export {
1156
+ getAgentFailureMetadata,
1157
+ createAgentOperationError,
1135
1158
  agentLoop,
1136
1159
  agentLoopContinue,
1137
1160
  createToolCallerIdentity,
@@ -3408,33 +3408,33 @@ function isPuertsReparsePoint(path) {
3408
3408
  }
3409
3409
  function containsPuertsReparsePoint(directory) {
3410
3410
  const slashed = directory.replace(/\\/g, "/");
3411
- const trimmed = slashed.replace(/\/+$/, "");
3412
- if (!trimmed || trimmed === "/") return false;
3413
- const unc = /^\/\/([^/]+)\/([^/]+)/.exec(trimmed);
3411
+ if (!slashed) return false;
3412
+ const unc = /^\/\/([^/]+)\/([^/]+)/.exec(slashed);
3414
3413
  let prefix;
3415
3414
  let rest;
3416
3415
  if (unc) {
3417
3416
  prefix = unc[0];
3418
- rest = trimmed.slice(prefix.length);
3417
+ rest = slashed.slice(prefix.length);
3419
3418
  } else {
3420
- const driveRoot = /^([a-zA-Z]:)\//.exec(trimmed);
3419
+ const driveRoot = /^([a-zA-Z]:)\//.exec(slashed);
3421
3420
  if (driveRoot) {
3422
3421
  prefix = `${driveRoot[1]}/`;
3423
- rest = trimmed.slice(prefix.length);
3422
+ rest = slashed.slice(prefix.length);
3424
3423
  } else {
3425
- const bareDrive = /^[a-zA-Z]:$/.test(trimmed);
3424
+ const bareDrive = /^[a-zA-Z]:$/.test(slashed);
3426
3425
  if (bareDrive) {
3427
- return isPuertsReparsePoint(trimmed);
3426
+ return isPuertsReparsePoint(slashed);
3428
3427
  }
3429
- if (trimmed.startsWith("/")) {
3428
+ if (slashed.startsWith("/")) {
3430
3429
  prefix = "/";
3431
- rest = trimmed.slice(1);
3430
+ rest = slashed.slice(1);
3432
3431
  } else {
3433
3432
  prefix = "";
3434
- rest = trimmed;
3433
+ rest = slashed;
3435
3434
  }
3436
3435
  }
3437
3436
  }
3437
+ if (prefix && isPuertsReparsePoint(prefix)) return true;
3438
3438
  let current = prefix;
3439
3439
  for (const part of rest.split("/").filter((segment) => segment.length > 0 && segment !== ".")) {
3440
3440
  current = current ? current.endsWith("/") ? `${current}${part}` : `${current}/${part}` : part;
@@ -4,10 +4,12 @@ import {
4
4
  agentLoop,
5
5
  agentLoopContinue,
6
6
  bindToolCallerIdentity,
7
+ createAgentOperationError,
7
8
  createToolCallerIdentity,
9
+ getAgentFailureMetadata,
8
10
  getToolCallerIdentity
9
- } from "./chunk-2NBUFVUQ.js";
10
- import "./chunk-EN47TIBG.js";
11
+ } from "./chunk-HGUYS5SF.js";
12
+ import "./chunk-R46YPPTU.js";
11
13
  import "./chunk-XXGYUYXI.js";
12
14
  import "./chunk-LZQXQOPJ.js";
13
15
  export {
@@ -15,6 +17,8 @@ export {
15
17
  agentLoop,
16
18
  agentLoopContinue,
17
19
  bindToolCallerIdentity,
20
+ createAgentOperationError,
18
21
  createToolCallerIdentity,
22
+ getAgentFailureMetadata,
19
23
  getToolCallerIdentity
20
24
  };
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
2
  import {
3
3
  EventStream
4
- } from "./chunk-EN47TIBG.js";
4
+ } from "./chunk-R46YPPTU.js";
5
5
  import "./chunk-XXGYUYXI.js";
6
6
  import "./chunk-LZQXQOPJ.js";
7
7
 
package/dist/cli.js CHANGED
@@ -29,7 +29,7 @@ import {
29
29
  migrateConfigFromAgentDir,
30
30
  setYoloGrantListener,
31
31
  truncateHeadTail
32
- } from "./chunks/chunk-YI3CSQGD.js";
32
+ } from "./chunks/chunk-D7RMNFVM.js";
33
33
  import {
34
34
  resolveCliProjectRoot
35
35
  } from "./chunks/chunk-WLFOBECN.js";
@@ -94,8 +94,8 @@ import {
94
94
  shouldPreserveExecutionStateForUserText,
95
95
  supersedeExecutionState,
96
96
  verifyPreparedCompactionCommit
97
- } from "./chunks/chunk-AFPRX5XI.js";
98
- import "./chunks/chunk-2NBUFVUQ.js";
97
+ } from "./chunks/chunk-CIFC6QVB.js";
98
+ import "./chunks/chunk-HGUYS5SF.js";
99
99
  import {
100
100
  Deref,
101
101
  Errors,
@@ -118,7 +118,7 @@ import {
118
118
  sortToolModelCandidatesByCapability,
119
119
  streamSimple,
120
120
  type_exports
121
- } from "./chunks/chunk-EN47TIBG.js";
121
+ } from "./chunks/chunk-R46YPPTU.js";
122
122
  import {
123
123
  IsArray,
124
124
  IsBigInt,
@@ -52611,18 +52611,18 @@ function validateRemoteModel(profileId, model) {
52611
52611
  validateWebSearchCapability(model.webSearch, `Remote profile "${profileId}" model "${model.id}" webSearch`);
52612
52612
  validateFileCapabilities(model.fileCapabilities, `Remote profile "${profileId}" model "${model.id}" fileCapabilities`);
52613
52613
  }
52614
- function assertHeadersShape(headers, label) {
52615
- if (headers === void 0) return;
52616
- if (!isPlainRecord(headers)) throw new Error(`${label} headers must be an object`);
52617
- for (const [name, value] of Object.entries(headers)) {
52614
+ function assertHeadersShape(headers2, label) {
52615
+ if (headers2 === void 0) return;
52616
+ if (!isPlainRecord(headers2)) throw new Error(`${label} headers must be an object`);
52617
+ for (const [name, value] of Object.entries(headers2)) {
52618
52618
  if (!/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(name)) throw new Error(`${label} header name ${name || "(empty)"} is invalid`);
52619
52619
  if (typeof value !== "string") throw new Error(`${label} header ${name} must be a string`);
52620
52620
  if (/[\0-\x08\x0A-\x1F\x7F]/.test(value)) throw new Error(`${label} header ${name} contains an invalid control character`);
52621
52621
  }
52622
52622
  }
52623
- function assertRemoteHeadersSafe(headers, label) {
52624
- assertHeadersShape(headers, label);
52625
- for (const name of Object.keys(headers || {})) {
52623
+ function assertRemoteHeadersSafe(headers2, label) {
52624
+ assertHeadersShape(headers2, label);
52625
+ for (const name of Object.keys(headers2 || {})) {
52626
52626
  if (/(?:authorization|cookie|api[-_]?key|token|secret|credential)/i.test(name)) {
52627
52627
  throw new Error(`${label} must not provide credential-bearing header ${name}`);
52628
52628
  }
@@ -53252,10 +53252,10 @@ var ModelRegistry = class {
53252
53252
  let payload = cached?.payload;
53253
53253
  let response;
53254
53254
  try {
53255
- const headers = { Authorization: `Bearer ${apiKey}` };
53256
- if (cached?.etag) headers["If-None-Match"] = cached.etag;
53255
+ const headers2 = { Authorization: `Bearer ${apiKey}` };
53256
+ if (cached?.etag) headers2["If-None-Match"] = cached.etag;
53257
53257
  response = await fetch(url, {
53258
- headers,
53258
+ headers: headers2,
53259
53259
  redirect: "manual",
53260
53260
  signal: AbortSignal.timeout(3e3)
53261
53261
  });
@@ -63659,10 +63659,37 @@ var Spacer = class {
63659
63659
 
63660
63660
  // ../../packages/tui/src/stdin-buffer.ts
63661
63661
  import { EventEmitter } from "events";
63662
+
63663
+ // ../../packages/tui/src/clipboard-framing.ts
63664
+ var headers = [
63665
+ { kind: "osc", prefix: "\x1B]5522" },
63666
+ { kind: "csi", prefix: "\x1B[?5522" }
63667
+ ];
63668
+ function clipboardFrameEnd(data, kind) {
63669
+ const match = kind === "osc" ? /\x07|\x1b\\/.exec(data) : /[\x40-\x7e]/.exec(data);
63670
+ return match ? match.index + match[0].length : void 0;
63671
+ }
63672
+ function classifyClipboardFragment(data, pending = false) {
63673
+ if (!data) return void 0;
63674
+ for (const { kind, prefix } of headers) {
63675
+ if (prefix.startsWith(data)) {
63676
+ const ambiguous = data === "\x1B" || data === "\x1B[";
63677
+ if (!ambiguous || pending) return { kind, valid: false };
63678
+ } else if (data.startsWith(prefix)) {
63679
+ const end = clipboardFrameEnd(data.slice(2), kind);
63680
+ const length = end === void 0 ? void 0 : end + 2;
63681
+ const frame = length === void 0 ? data : data.slice(0, length);
63682
+ const valid = kind === "osc" ? frame.startsWith(`${prefix};`) : /^\x1b\[\?5522;[0-4]\$y$/.test(frame);
63683
+ return { kind, length, valid };
63684
+ }
63685
+ }
63686
+ return void 0;
63687
+ }
63688
+
63689
+ // ../../packages/tui/src/stdin-buffer.ts
63662
63690
  var ESC = "\x1B";
63663
63691
  var BRACKETED_PASTE_START = "\x1B[200~";
63664
63692
  var BRACKETED_PASTE_END = "\x1B[201~";
63665
- var OSC_5522_PREFIX = "\x1B]5522;";
63666
63693
  var OSC_5522_MAX_FRAME = 70 * 1024 * 1024;
63667
63694
  function isCompleteSequence(data) {
63668
63695
  if (!data.startsWith(ESC)) {
@@ -63750,16 +63777,29 @@ function isCompleteApcSequence(data) {
63750
63777
  }
63751
63778
  return "incomplete";
63752
63779
  }
63753
- function extractCompleteSequences(buffer, maxClipboardFrame = OSC_5522_MAX_FRAME) {
63780
+ function extractCompleteSequences(buffer, maxClipboardFrame = OSC_5522_MAX_FRAME, pending = false) {
63754
63781
  const sequences = [];
63755
63782
  let pos = 0;
63756
63783
  while (pos < buffer.length) {
63757
63784
  const remaining = buffer.slice(pos);
63785
+ const clipboard = classifyClipboardFragment(remaining, pending);
63786
+ if (clipboard) {
63787
+ if (clipboard.length === void 0) return { sequences, remainder: remaining };
63788
+ if (clipboard.valid && clipboard.length <= Math.min(maxClipboardFrame, clipboard.kind === "csi" ? 64 : Infinity)) {
63789
+ sequences.push(remaining.slice(0, clipboard.length));
63790
+ }
63791
+ pos += clipboard.length;
63792
+ continue;
63793
+ }
63794
+ if (remaining.startsWith(BRACKETED_PASTE_START)) {
63795
+ sequences.push(BRACKETED_PASTE_START);
63796
+ return { sequences, remainder: remaining.slice(BRACKETED_PASTE_START.length) };
63797
+ }
63758
63798
  if (remaining.startsWith(`${ESC}]`)) {
63759
63799
  const end = /\x07|\x1b\\/.exec(remaining);
63760
63800
  if (!end) return { sequences, remainder: remaining };
63761
63801
  const length = end.index + end[0].length;
63762
- if (!remaining.startsWith(OSC_5522_PREFIX) || length <= maxClipboardFrame) sequences.push(remaining.slice(0, length));
63802
+ sequences.push(remaining.slice(0, length));
63763
63803
  pos += length;
63764
63804
  continue;
63765
63805
  }
@@ -63796,7 +63836,8 @@ var StdinBuffer = class extends EventEmitter {
63796
63836
  timeoutMs;
63797
63837
  pasteMode = false;
63798
63838
  pasteBuffer = "";
63799
- discardingClipboard = false;
63839
+ discardingClipboard;
63840
+ clipboardStarted = 0;
63800
63841
  discardEsc = false;
63801
63842
  options;
63802
63843
  constructor(options = {}) {
@@ -63825,19 +63866,26 @@ var StdinBuffer = class extends EventEmitter {
63825
63866
  return;
63826
63867
  }
63827
63868
  if (this.discardingClipboard) {
63828
- const discarded = (this.discardEsc ? ESC : "") + str2;
63829
- const end = /\x07|\x1b\\/.exec(discarded);
63830
- if (!end) {
63831
- this.discardEsc = discarded.endsWith(ESC);
63832
- this.timeout = setTimeout(() => {
63833
- this.discardingClipboard = false;
63834
- this.discardEsc = false;
63835
- }, this.options.clipboardFrameTimeout ?? 1e3);
63836
- return;
63869
+ const kind = this.discardingClipboard;
63870
+ const heldEscape = this.discardEsc;
63871
+ const discarded = (heldEscape ? ESC : "") + str2;
63872
+ const end = clipboardFrameEnd(discarded, kind);
63873
+ const escape = discarded.indexOf(ESC, heldEscape && str2.startsWith(ESC) ? 1 : 0);
63874
+ const resync = escape >= 0 && escape + 1 < discarded.length && (end === void 0 || escape < end - 1) && !(kind === "osc" && end !== void 0 && escape === end - 2 && discarded.startsWith(`${ESC}\\`, escape));
63875
+ if (resync) {
63876
+ this.discardingClipboard = void 0;
63877
+ this.discardEsc = false;
63878
+ str2 = discarded.slice(escape);
63879
+ } else {
63880
+ if (!end) {
63881
+ this.discardEsc = discarded.endsWith(ESC);
63882
+ this.scheduleDiscardRecovery();
63883
+ return;
63884
+ }
63885
+ this.discardingClipboard = void 0;
63886
+ this.discardEsc = false;
63887
+ str2 = discarded.slice(end);
63837
63888
  }
63838
- this.discardingClipboard = false;
63839
- this.discardEsc = false;
63840
- str2 = discarded.slice(end.index + end[0].length);
63841
63889
  }
63842
63890
  this.buffer += str2;
63843
63891
  if (this.pasteMode) {
@@ -63856,16 +63904,13 @@ var StdinBuffer = class extends EventEmitter {
63856
63904
  }
63857
63905
  return;
63858
63906
  }
63859
- const startIndex = this.buffer.indexOf(BRACKETED_PASTE_START);
63860
- if (startIndex !== -1) {
63861
- if (startIndex > 0) {
63862
- const beforePaste = this.buffer.slice(0, startIndex);
63863
- const result2 = extractCompleteSequences(beforePaste);
63864
- for (const sequence of result2.sequences) {
63865
- this.emit("data", sequence);
63866
- }
63867
- }
63868
- this.buffer = this.buffer.slice(startIndex + BRACKETED_PASTE_START.length);
63907
+ const result = extractCompleteSequences(this.buffer, this.options.clipboardMaxFrame, this.options.clipboardResponsePending?.());
63908
+ if (result.remainder.length < this.buffer.length) this.clipboardStarted = 0;
63909
+ this.buffer = result.remainder;
63910
+ for (const sequence of result.sequences) {
63911
+ if (sequence !== BRACKETED_PASTE_START) this.emit("data", sequence);
63912
+ }
63913
+ if (result.sequences.at(-1) === BRACKETED_PASTE_START) {
63869
63914
  this.pasteMode = true;
63870
63915
  this.pasteBuffer = this.buffer;
63871
63916
  this.buffer = "";
@@ -63882,40 +63927,29 @@ var StdinBuffer = class extends EventEmitter {
63882
63927
  }
63883
63928
  return;
63884
63929
  }
63885
- const result = extractCompleteSequences(this.buffer, this.options.clipboardMaxFrame);
63886
- this.buffer = result.remainder;
63887
- for (const sequence of result.sequences) {
63888
- this.emit("data", sequence);
63889
- }
63890
63930
  if (this.buffer.length > 0) {
63891
- const heldFor5522 = this.buffer.startsWith(OSC_5522_PREFIX) || this.buffer.length >= 2 && OSC_5522_PREFIX.startsWith(this.buffer) || this.buffer === ESC && this.options.clipboardResponsePending?.();
63892
- if (heldFor5522 && this.buffer.length <= (this.options.clipboardMaxFrame ?? OSC_5522_MAX_FRAME)) {
63931
+ const fragment = classifyClipboardFragment(this.buffer, this.options.clipboardResponsePending?.());
63932
+ if (fragment) {
63933
+ this.clipboardStarted ||= Date.now();
63934
+ const limit = Math.min(this.options.clipboardMaxFrame ?? OSC_5522_MAX_FRAME, fragment.kind === "csi" ? 64 : Infinity);
63935
+ if (this.buffer.length > limit) {
63936
+ this.discardClipboard(fragment.kind);
63937
+ return;
63938
+ }
63939
+ const deadline = Math.min(
63940
+ this.options.clipboardFrameTimeout ?? 1e3,
63941
+ (this.options.clipboardFrameMaxDuration ?? 1e4) - (Date.now() - this.clipboardStarted)
63942
+ );
63893
63943
  this.timeout = setTimeout(() => {
63894
- const ambiguousEscape = this.buffer === ESC;
63895
- this.discardEsc = this.buffer.endsWith(ESC);
63896
- this.buffer = "";
63897
- if (ambiguousEscape) {
63944
+ if (this.buffer === ESC) {
63945
+ this.buffer = "";
63946
+ this.clipboardStarted = 0;
63898
63947
  this.emit("data", ESC);
63899
- return;
63900
- }
63901
- this.discardingClipboard = true;
63902
- this.timeout = setTimeout(() => {
63903
- this.discardingClipboard = false;
63904
- this.discardEsc = false;
63905
- }, this.options.clipboardFrameTimeout ?? 1e3);
63906
- }, this.options.clipboardFrameTimeout ?? 1e3);
63907
- return;
63908
- }
63909
- if (heldFor5522) {
63910
- this.discardEsc = this.buffer.endsWith(ESC);
63911
- this.buffer = "";
63912
- this.discardingClipboard = true;
63913
- this.timeout = setTimeout(() => {
63914
- this.discardingClipboard = false;
63915
- this.discardEsc = false;
63916
- }, this.options.clipboardFrameTimeout ?? 1e3);
63948
+ } else this.discardClipboard(fragment.kind);
63949
+ }, Math.max(0, deadline));
63917
63950
  return;
63918
63951
  }
63952
+ this.clipboardStarted = 0;
63919
63953
  this.timeout = setTimeout(() => {
63920
63954
  const flushed = this.flush();
63921
63955
  for (const sequence of flushed) {
@@ -63924,6 +63958,19 @@ var StdinBuffer = class extends EventEmitter {
63924
63958
  }, this.timeoutMs);
63925
63959
  }
63926
63960
  }
63961
+ scheduleDiscardRecovery() {
63962
+ this.timeout = setTimeout(() => {
63963
+ this.discardingClipboard = void 0;
63964
+ this.discardEsc = false;
63965
+ }, this.options.clipboardFrameTimeout ?? 1e3);
63966
+ }
63967
+ discardClipboard(kind) {
63968
+ this.discardEsc = this.buffer.endsWith(ESC);
63969
+ this.buffer = "";
63970
+ this.clipboardStarted = 0;
63971
+ this.discardingClipboard = kind;
63972
+ this.scheduleDiscardRecovery();
63973
+ }
63927
63974
  flush() {
63928
63975
  if (this.timeout) {
63929
63976
  clearTimeout(this.timeout);
@@ -63932,7 +63979,13 @@ var StdinBuffer = class extends EventEmitter {
63932
63979
  if (this.buffer.length === 0) {
63933
63980
  return [];
63934
63981
  }
63935
- const sequences = this.buffer.startsWith(OSC_5522_PREFIX) || this.buffer.length >= 2 && OSC_5522_PREFIX.startsWith(this.buffer) ? [] : [this.buffer];
63982
+ const fragment = classifyClipboardFragment(this.buffer, this.options.clipboardResponsePending?.());
63983
+ if (fragment && this.buffer !== ESC) {
63984
+ this.discardClipboard(fragment.kind);
63985
+ return [];
63986
+ }
63987
+ const sequences = [this.buffer];
63988
+ this.clipboardStarted = 0;
63936
63989
  this.buffer = "";
63937
63990
  return sequences;
63938
63991
  }
@@ -63944,7 +63997,8 @@ var StdinBuffer = class extends EventEmitter {
63944
63997
  this.buffer = "";
63945
63998
  this.pasteMode = false;
63946
63999
  this.pasteBuffer = "";
63947
- this.discardingClipboard = false;
64000
+ this.clipboardStarted = 0;
64001
+ this.discardingClipboard = void 0;
63948
64002
  this.discardEsc = false;
63949
64003
  }
63950
64004
  getBuffer() {
@@ -63960,6 +64014,7 @@ import * as fs11 from "node:fs";
63960
64014
  import koffi from "koffi";
63961
64015
 
63962
64016
  // ../../packages/tui/src/osc-5522.ts
64017
+ import { randomBytes as randomBytes2 } from "node:crypto";
63963
64018
  var OSC = "\x1B]";
63964
64019
  var ST = "\x1B\\";
63965
64020
  var READ_TIMEOUT_MS = 8e3;
@@ -64016,13 +64071,14 @@ var Osc5522Client = class {
64016
64071
  return true;
64017
64072
  }
64018
64073
  const packet = parseOsc5522Packet(data);
64019
- if (!packet) return false;
64074
+ if (!packet) return data.startsWith(`${OSC}5522;`);
64020
64075
  const fields = parseMetadata(packet.metadata);
64021
64076
  const type = fields.get("type") ?? "";
64022
- if (!type.startsWith("read")) return false;
64077
+ if (!type.startsWith("read")) return true;
64023
64078
  const status = fields.get("status");
64024
64079
  const session = this.session;
64025
64080
  if (!session) return true;
64081
+ if (fields.get("id") !== session.id) return true;
64026
64082
  if (status === void 0) {
64027
64083
  this.finishFor(session, { ok: false, kind: "malformed", message: `OSC 5522 read packet without status: ${packet.metadata}` });
64028
64084
  return true;
@@ -64105,6 +64161,7 @@ var Osc5522Client = class {
64105
64161
  return { ok: false, kind: "busy", message: "Another OSC 5522 read is already in flight." };
64106
64162
  }
64107
64163
  const session = {
64164
+ id: `pie-${randomBytes2(8).toString("hex")}`,
64108
64165
  resolve: void 0,
64109
64166
  timer: void 0,
64110
64167
  chunks: [],
@@ -64124,7 +64181,7 @@ var Osc5522Client = class {
64124
64181
  }
64125
64182
  if (this.session !== session) return promise;
64126
64183
  const mimeList = Buffer.from("image/png image/jpeg").toString("base64");
64127
- this.write(`${OSC}5522;type=read;${mimeList}${ST}`);
64184
+ this.write(`${OSC}5522;id=${session.id}:type=read;${mimeList}${ST}`);
64128
64185
  return promise;
64129
64186
  }
64130
64187
  /** Finish only if `session` is still the live session (identity-bound). */
@@ -70296,12 +70353,21 @@ var YoloGrantTracker = class {
70296
70353
  isActive(now = Date.now()) {
70297
70354
  return this.untilMs > now;
70298
70355
  }
70356
+ remainingMs(now = Date.now()) {
70357
+ return Math.max(0, this.untilMs - now);
70358
+ }
70299
70359
  award(grantMs, now = Date.now()) {
70300
70360
  this.untilMs = now + Math.max(0, grantMs);
70301
70361
  }
70302
70362
  expire() {
70303
70363
  this.untilMs = 0;
70304
70364
  }
70365
+ /** Revoke the active grant and report whether revocation changed live state. */
70366
+ revoke() {
70367
+ const wasActive = this.isActive();
70368
+ this.expire();
70369
+ return wasActive;
70370
+ }
70305
70371
  /** Expiry timestamp (0 when no grant is held); useful for display. */
70306
70372
  get until() {
70307
70373
  return this.untilMs;
@@ -76576,7 +76642,9 @@ async function handleCalmCommand(host, args) {
76576
76642
  async function handleYoloCommand(host, args) {
76577
76643
  const mode = (args || "").trim().toLowerCase();
76578
76644
  if (mode === "status") {
76579
- host.showStatus(`YOLO mode is ${host.yoloMode ? "on" : "off"}`);
76645
+ const persistent = `YOLO mode is ${host.yoloMode ? "on" : "off"}`;
76646
+ const grantRemaining = host.getYoloGrantRemainingMs();
76647
+ host.showStatus(grantRemaining > 0 ? `${persistent}; temporary high-risk shell grant active for ${Math.max(1, Math.ceil(grantRemaining / 6e4))} more min` : persistent);
76580
76648
  return;
76581
76649
  }
76582
76650
  if (mode && !["on", "off", "enable", "enabled", "disable", "disabled", "true", "false", "1", "0"].includes(mode)) {
@@ -76584,9 +76652,10 @@ async function handleYoloCommand(host, args) {
76584
76652
  return;
76585
76653
  }
76586
76654
  const nextYoloMode = mode ? ["on", "enable", "enabled", "true", "1"].includes(mode) : !host.yoloMode;
76655
+ const revokedGrant = nextYoloMode ? false : host.revokeYoloGrant();
76587
76656
  if (host.yoloMode === nextYoloMode) {
76588
76657
  host.footer.setState({ yoloMode: host.yoloMode });
76589
- host.showStatus(`YOLO mode already ${host.yoloMode ? "on" : "off"}`);
76658
+ host.showStatus(`YOLO mode already ${host.yoloMode ? "on" : "off"}${revokedGrant ? "; temporary grant revoked" : ""}`);
76590
76659
  return;
76591
76660
  }
76592
76661
  host.yoloMode = nextYoloMode;
@@ -76604,6 +76673,7 @@ async function handleYoloCommand(host, args) {
76604
76673
  host.chatContainer.addChild(new Spacer(1));
76605
76674
  host.chatContainer.addChild(new Text(theme.fg("accent", "\u2713 YOLO mode disabled"), 1, 0));
76606
76675
  host.chatContainer.addChild(new Text(theme.fg("dim", " Sandbox directory restrictions restored."), 1, 0));
76676
+ if (revokedGrant) host.chatContainer.addChild(new Text(theme.fg("dim", " Temporary high-risk shell grant revoked."), 1, 0));
76607
76677
  host.chatContainer.addChild(new Spacer(1));
76608
76678
  }
76609
76679
  host.ui.requestRender();
@@ -79596,6 +79666,9 @@ async function selectMentionOption(host, option) {
79596
79666
  }
79597
79667
 
79598
79668
  // src/input/interactive-keybindings.ts
79669
+ function mainEditorOwnsInput(host) {
79670
+ return host.editor.focused === true && host.editorContainer.children.includes(host.editor) && !host.ui.hasOverlay() && !host.mentionPickerComponent;
79671
+ }
79599
79672
  function setupInteractiveKeybindings(host) {
79600
79673
  host.ui.addInputListener((data) => {
79601
79674
  if (isKeyRelease(data)) {
@@ -79653,7 +79726,7 @@ function setupInteractiveKeybindings(host) {
79653
79726
  host.handleInterrupt();
79654
79727
  return { consume: true };
79655
79728
  }
79656
- if (!host.mentionPickerComponent && host.keybindings.matches(data, "pasteImage")) {
79729
+ if (host.keybindings.matches(data, "pasteImage") && mainEditorOwnsInput(host)) {
79657
79730
  host.handlePasteImage();
79658
79731
  return { consume: true };
79659
79732
  }
@@ -79679,8 +79752,7 @@ function setupInteractiveKeybindings(host) {
79679
79752
 
79680
79753
  // src/clipboard/read-clipboard-image.ts
79681
79754
  import { spawn as spawn2 } from "node:child_process";
79682
- import { randomBytes as randomBytes2 } from "node:crypto";
79683
- import { existsSync as existsSync18, readFileSync as readFileSync17, statSync as statSync12, unlinkSync as unlinkSync8, writeFileSync as writeFileSync12 } from "node:fs";
79755
+ import { chmodSync as chmodSync2, closeSync as closeSync4, existsSync as existsSync18, fchmodSync, mkdtempSync, openSync as openSync4, readFileSync as readFileSync17, rmdirSync, statSync as statSync12, unlinkSync as unlinkSync8, writeFileSync as writeFileSync12 } from "node:fs";
79684
79756
  import { tmpdir } from "node:os";
79685
79757
  import { join as join20 } from "node:path";
79686
79758
  var MAX_IMAGE_BYTES = 50 * 1024 * 1024;
@@ -79746,14 +79818,67 @@ function defaultSpawnFn(file, args, spawnImpl = spawn2, maxBytes = MAX_IMAGE_BYT
79746
79818
  });
79747
79819
  });
79748
79820
  }
79749
- function defaultMkTempPath(ext) {
79750
- return join20(tmpdir(), `pie-clipboard-${randomBytes2(6).toString("hex")}${ext}`);
79751
- }
79821
+ var TempImageResources = class {
79822
+ constructor(injectedPath) {
79823
+ this.injectedPath = injectedPath;
79824
+ }
79825
+ injectedPath;
79826
+ directory;
79827
+ files = /* @__PURE__ */ new Set();
79828
+ create = (ext) => {
79829
+ if (!this.injectedPath && !this.directory) {
79830
+ this.directory = mkdtempSync(join20(tmpdir(), "pie-clipboard-"));
79831
+ if (process.platform !== "win32") chmodSync2(this.directory, 448);
79832
+ }
79833
+ const path34 = this.injectedPath ? this.injectedPath(ext) : join20(this.directory, `image${ext}`);
79834
+ const fd = openSync4(path34, "wx", 384);
79835
+ this.files.add(path34);
79836
+ try {
79837
+ if (process.platform !== "win32") fchmodSync(fd, 384);
79838
+ } finally {
79839
+ closeSync4(fd);
79840
+ }
79841
+ return path34;
79842
+ };
79843
+ cleanup = () => {
79844
+ for (const path34 of this.files) {
79845
+ try {
79846
+ unlinkSync8(path34);
79847
+ this.files.delete(path34);
79848
+ } catch (err) {
79849
+ if (err.code === "ENOENT") this.files.delete(path34);
79850
+ }
79851
+ }
79852
+ if (this.directory) {
79853
+ try {
79854
+ rmdirSync(this.directory);
79855
+ this.directory = void 0;
79856
+ } catch (err) {
79857
+ if (err.code === "ENOENT") this.directory = void 0;
79858
+ }
79859
+ }
79860
+ };
79861
+ };
79752
79862
  async function readClipboardImage(deps = {}) {
79753
79863
  const platform2 = deps.platform ?? process.platform;
79754
79864
  const env = deps.env ?? process.env;
79755
79865
  const spawnImpl = deps.spawnImpl ?? defaultSpawnFn;
79756
- const mkTempPath = deps.mkTempPath ?? defaultMkTempPath;
79866
+ const resources = new TempImageResources(deps.mkTempPath);
79867
+ let retained = false;
79868
+ try {
79869
+ const result = await readPlatformClipboard(platform2, env, spawnImpl, resources.create);
79870
+ if (result.ok === true) {
79871
+ retained = true;
79872
+ return { ...result, cleanup: resources.cleanup };
79873
+ }
79874
+ return result;
79875
+ } catch (err) {
79876
+ return { ok: false, kind: "failed", message: `Failed to read clipboard image: ${errorMessage4(err)}` };
79877
+ } finally {
79878
+ if (!retained) resources.cleanup();
79879
+ }
79880
+ }
79881
+ async function readPlatformClipboard(platform2, env, spawnImpl, mkTempPath) {
79757
79882
  switch (platform2) {
79758
79883
  case "darwin":
79759
79884
  return readMacClipboard(spawnImpl, mkTempPath);
@@ -79936,15 +80061,14 @@ function writeImageBytes(bytes, declaredMime, mkTempPath) {
79936
80061
  const mimeType = detectMimeFromMagic(bytes) ?? declaredMime;
79937
80062
  const targetPath = mkTempPath(extensionForMime(mimeType));
79938
80063
  try {
79939
- writeFileSync12(targetPath, bytes);
80064
+ writeFileSync12(targetPath, bytes, { flag: "r+", mode: 384 });
79940
80065
  } catch (err) {
79941
80066
  return { ok: false, kind: "failed", message: `Failed to write temp image: ${errorMessage4(err)}` };
79942
80067
  }
79943
80068
  return {
79944
80069
  ok: true,
79945
80070
  path: targetPath,
79946
- mimeType,
79947
- cleanup: makeCleanup(targetPath)
80071
+ mimeType
79948
80072
  };
79949
80073
  }
79950
80074
  function finalizeTempImage(path34, mimeType) {
@@ -79955,11 +80079,9 @@ function finalizeTempImage(path34, mimeType) {
79955
80079
  }
79956
80080
  const size = statSync12(path34).size;
79957
80081
  if (size === 0) {
79958
- makeCleanup(path34)();
79959
80082
  return { ok: false, kind: "no-image", message: "Clipboard does not contain an image." };
79960
80083
  }
79961
80084
  if (size > MAX_IMAGE_BYTES) {
79962
- makeCleanup(path34)();
79963
80085
  return { ok: false, kind: "too-large", message: `Clipboard image is too large (${formatBytes2(size)}).` };
79964
80086
  }
79965
80087
  bytes = readFileSync17(path34);
@@ -79968,10 +80090,9 @@ function finalizeTempImage(path34, mimeType) {
79968
80090
  }
79969
80091
  const detected = detectMimeFromMagic(bytes);
79970
80092
  if (!detected) {
79971
- makeCleanup(path34)();
79972
80093
  return { ok: false, kind: "no-image", message: "Clipboard does not contain a supported image (PNG/JPEG)." };
79973
80094
  }
79974
- return { ok: true, path: path34, mimeType: detected, cleanup: makeCleanup(path34) };
80095
+ return { ok: true, path: path34, mimeType: detected };
79975
80096
  }
79976
80097
  function detectMimeFromMagic(bytes) {
79977
80098
  if (bytes.length >= 8 && bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71) {
@@ -79982,14 +80103,6 @@ function detectMimeFromMagic(bytes) {
79982
80103
  }
79983
80104
  return void 0;
79984
80105
  }
79985
- function makeCleanup(path34) {
79986
- return () => {
79987
- try {
79988
- unlinkSync8(path34);
79989
- } catch {
79990
- }
79991
- };
79992
- }
79993
80106
  function spawnFailure(outcome, tool) {
79994
80107
  if (outcome.error === "too-large") {
79995
80108
  return { ok: false, kind: "too-large", message: "Clipboard image is too large." };
@@ -80019,7 +80132,7 @@ function formatBytes2(bytes) {
80019
80132
  }
80020
80133
 
80021
80134
  // src/input/image-paste.ts
80022
- import { mkdtempSync, writeFileSync as writeFileSync13, rmSync as rmSync3 } from "node:fs";
80135
+ import { mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync13, rmSync as rmSync3 } from "node:fs";
80023
80136
  import { tmpdir as tmpdir2 } from "node:os";
80024
80137
  import { join as join21 } from "node:path";
80025
80138
  var pastingHosts = /* @__PURE__ */ new WeakSet();
@@ -80046,7 +80159,7 @@ function terminalResultToClipboardResult(result) {
80046
80159
  const ext = result.mimeType === "image/jpeg" ? ".jpg" : ".png";
80047
80160
  let dir;
80048
80161
  try {
80049
- dir = mkdtempSync(join21(tmpdir2(), "pie-osc5522-"));
80162
+ dir = mkdtempSync2(join21(tmpdir2(), "pie-osc5522-"));
80050
80163
  const path34 = join21(dir, formatPastedImageName(/* @__PURE__ */ new Date(), ext));
80051
80164
  writeFileSync13(path34, result.bytes);
80052
80165
  return {
@@ -83026,6 +83139,12 @@ var InteractiveMode = class {
83026
83139
  get controllerSetupHost() {
83027
83140
  return this;
83028
83141
  }
83142
+ getYoloGrantRemainingMs() {
83143
+ return this.yoloGrant.remainingMs();
83144
+ }
83145
+ revokeYoloGrant() {
83146
+ return this.yoloGrant.revoke();
83147
+ }
83029
83148
  getPolicyContext = () => ({
83030
83149
  mode: this.planModeEnabled ? "plan" : "normal",
83031
83150
  yoloMode: this.yoloMode || this.yoloGrant.isActive(),
@@ -83183,7 +83302,7 @@ var InteractiveMode = class {
83183
83302
  async init() {
83184
83303
  const activeSession = this.sessionManager.getActiveSession();
83185
83304
  this.thinkingLevel = resolveInitialThinkingLevel({ session: activeSession, settingsManager: this.options.settingsManager });
83186
- const { Agent } = await import("./chunks/src-XDNJ3PHL.js");
83305
+ const { Agent } = await import("./chunks/src-5JJZZ5H7.js");
83187
83306
  this.agent = new Agent({
83188
83307
  initialState: {
83189
83308
  systemPrompt: this.buildSystemPrompt(),
@@ -84075,7 +84194,7 @@ async function runPrintMode(params) {
84075
84194
  `);
84076
84195
  console.log("Assistant: ");
84077
84196
  }
84078
- const { Agent: AgentClass } = await import("./chunks/src-XDNJ3PHL.js");
84197
+ const { Agent: AgentClass } = await import("./chunks/src-5JJZZ5H7.js");
84079
84198
  let agent;
84080
84199
  const printModeExtensions = await loadPrintModeExtensions({
84081
84200
  cwd: runtime.cwd,
@@ -84375,7 +84494,6 @@ function parseInput(line) {
84375
84494
  };
84376
84495
  }
84377
84496
  if (parsed.type === "sidechat.request" && typeof parsed.requestId === "string" && typeof parsed.prompt === "string") {
84378
- if (parsed.hostContext !== void 0 && !isHostContextBlock(parsed.hostContext)) return null;
84379
84497
  return {
84380
84498
  type: "sidechat.request",
84381
84499
  sessionId: typeof parsed.sessionId === "string" ? parsed.sessionId : void 0,
@@ -84385,7 +84503,6 @@ function parseInput(line) {
84385
84503
  };
84386
84504
  }
84387
84505
  if ((parsed.type === "turn.request" || parsed.type === "turn.input") && typeof parsed.turnId === "string" && typeof parsed.prompt === "string") {
84388
- if (parsed.hostContext !== void 0 && !isHostContextBlock(parsed.hostContext)) return null;
84389
84506
  const streamingBehavior = parsed.streamingBehavior;
84390
84507
  if (streamingBehavior !== void 0 && streamingBehavior !== "steer" && streamingBehavior !== "followUp") {
84391
84508
  return null;
@@ -84923,6 +85040,11 @@ async function runJsonEventsMode(params) {
84923
85040
  }
84924
85041
  const startedAt = Date.now();
84925
85042
  if (params.mockResponse !== void 0) {
85043
+ const hostContextFailure = validateIntakeHostContext(message);
85044
+ if (hostContextFailure) {
85045
+ writeSidechatFailure(message, hostContextFailure.message, hostContextFailure.code);
85046
+ return;
85047
+ }
84926
85048
  writeEvent({ type: "sidechat.started", sessionId, requestId });
84927
85049
  const event = {
84928
85050
  type: "sidechat.completed",
@@ -84967,7 +85089,7 @@ async function runJsonEventsMode(params) {
84967
85089
  const sideTrace = trace;
84968
85090
  const sideApiKey = runtime.apiKey;
84969
85091
  const snapshot = structuredClone(parent.state.messages);
84970
- const { Agent: AgentClass } = await import("./chunks/src-XDNJ3PHL.js");
85092
+ const { Agent: AgentClass } = await import("./chunks/src-5JJZZ5H7.js");
84971
85093
  const sideAgent = new AgentClass({
84972
85094
  initialState: {
84973
85095
  systemPrompt: parent.state.systemPrompt,
@@ -85331,7 +85453,7 @@ async function runJsonEventsMode(params) {
85331
85453
  if (runtime.initialModel.unconfigured || controller) {
85332
85454
  return;
85333
85455
  }
85334
- const { Agent: AgentClass } = await import("./chunks/src-XDNJ3PHL.js");
85456
+ const { Agent: AgentClass } = await import("./chunks/src-5JJZZ5H7.js");
85335
85457
  if (runtimeClosing) return;
85336
85458
  const compositionRegistry = createCliHostEnvelopeRegistry();
85337
85459
  const jsonModeExtensions = await loadJsonModeExtensions({ runtime, envelopeRegistry: compositionRegistry, getAgent: () => agent });
@@ -85523,7 +85645,7 @@ async function runJsonEventsMode(params) {
85523
85645
  return message.hostContext ? [message.hostContext, { type: "text", text: message.prompt }] : [{ type: "text", text: message.prompt }];
85524
85646
  }
85525
85647
  function validateIntakeHostContext(message) {
85526
- return message.hostContext ? intakeHostContextFailure(message.hostContext, envelopeRegistry) : void 0;
85648
+ return message.hostContext !== void 0 ? intakeHostContextFailure(message.hostContext, envelopeRegistry) : void 0;
85527
85649
  }
85528
85650
  async function runTurn(message) {
85529
85651
  if (isSessionMismatch(message)) {
@@ -85731,7 +85853,8 @@ async function runJsonEventsMode(params) {
85731
85853
  sessionId,
85732
85854
  turnId: message.turnId,
85733
85855
  error: failure.message,
85734
- hostContextKinds: cliHostEnvelopeKinds(envelopeRegistry)
85856
+ code: failure.code,
85857
+ ...failure.code === "host_context_unknown_projector" ? { hostContextKinds: cliHostEnvelopeKinds(envelopeRegistry) } : {}
85735
85858
  });
85736
85859
  return;
85737
85860
  }
@@ -86018,7 +86141,7 @@ async function runWithJsonEventsConsoleIsolation(fn) {
86018
86141
  }
86019
86142
  async function createCliTestStreamFnFromEnv() {
86020
86143
  if (!process.env.PIE_TEST_MOCK_STREAM_SEQUENCE) return void 0;
86021
- return (await import("./chunks/test-stream-LUUGOJMP.js")).createTestStreamFnFromSequenceEnv();
86144
+ return (await import("./chunks/test-stream-ZBTSPU7J.js")).createTestStreamFnFromSequenceEnv();
86022
86145
  }
86023
86146
  function resolveJsonEventsDetailFlag() {
86024
86147
  for (let index = 0; index < process.argv.length; index += 1) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cydm/pie",
3
- "version": "2.7.12",
3
+ "version": "2.7.13",
4
4
  "description": "Pie AI Agent CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -20,7 +20,7 @@
20
20
  "test:skill-regressions": "node --test --import tsx test/bash-lifecycle.test.ts test/bash-powershell-display.test.ts test/skill-creator-runner.test.ts test/tui-use-contract.test.ts test/tui-use-runtime.test.ts test/browser-runtime.test.ts test/axi-stop-semantics.test.ts test/computer-use-axi.test.ts test/computer-evidence.test.ts test/interactive-lifecycle.test.ts",
21
21
  "test:offline:post": "node --test --import tsx test/remote-model-catalog.test.ts",
22
22
  "test:offline": "node ../../scripts/run-cli-offline.mjs",
23
- "test:offline:main": "node --test --test-concurrency=4 --import tsx test/cli-attention.test.ts test/builtin-extensions.test.ts test/core-services.test.ts test/cli.test.ts test/cli-auto-compaction.test.ts test/execution-state-manager.test.ts test/queued-steer-execution-state.test.ts test/todo-steering-ownership.test.ts test/architecture-boundaries.test.ts test/attachment-resolver.test.ts test/kimi-attachment-provider.test.ts test/document-attachment-extension.test.ts test/auto-compact-overflow.test.ts test/auto-compaction-ui.test.ts test/tool-compaction-dogfood.terminal.test.ts test/hierarchical-command-system.test.ts test/mcp-adapter.test.ts test/herdr-agent-state.test.ts test/extensions-enablement.test.ts test/extension-selector-shortcuts.test.ts test/skill-tool-enablement.test.ts test/message-queue-unit.test.ts test/evals-harness.test.ts test/session-trace.test.ts test/json-events-sidechat-diagnostics.test.ts test/json-events-prewarm-shutdown.test.ts test/json-envelope-composition.test.ts test/subagent-session-store.test.ts test/runtime-mode-context.test.ts test/tool-policy.test.ts test/retry-policy.test.ts test/yolo-command.test.ts test/footer-lifecycle.test.ts test/footer-waiting-for-user.test.ts test/files-utils.test.ts test/source-size-guard.test.ts test/runtime-logger.test.ts test/release-readiness.test.ts test/package-artifacts.test.ts test/init-extension-contract.test.ts test/skills-runtime.test.ts test/skills-agents-discovery.test.ts test/skills-symlink.test.ts test/model-overrides.test.ts test/auth-storage.test.ts test/extension-register-provider.test.ts test/extension-reload.test.ts test/extension-terminal-input.test.ts test/extension-session-before-events.test.ts test/extension-widgets.test.ts test/extension-render-hint.test.ts test/extension-oauth-restore.test.ts test/cross-host-parity.test.ts test/tool-name-rendering.test.ts test/session-selector.test.ts test/tree-selector-pagination.test.ts test/context-report.test.ts test/context-signals.test.ts test/plan-cache-stability.test.ts test/cache-invalidation-trace.test.ts test/cache-retention.test.ts test/trace-report.test.ts test/boot-report.test.ts test/compaction-diff.test.ts test/entry-body-and-usage.test.ts test/session-control.test.ts test/terminal-title.test.ts test/interactive-controller-title.test.ts test/todo-title.terminal.test.ts test/host-envelope-dogfood.terminal.test.ts test/host-envelope-cross-mode.test.ts test/host-envelope-registry-lifecycle.test.ts test/host-envelope-migration-roundtrip.test.ts test/host-envelope-intake-order.test.ts test/plan-mode-extension.test.ts test/extension-interaction-signals.test.ts test/rendered-page-reader.test.ts test/tools-registry.test.ts test/system-prompt-contract.test.ts test/bash-yolo.test.ts test/bash-contract.test.ts test/bash-confirm-pending.test.ts test/interaction-status-lifecycle.test.ts test/bash-process-group.test.ts test/bash-artifact-sink.test.ts test/direct-bash.test.ts test/terminal-bell.test.ts test/ctrl-d-exit.test.ts test/session-display-title.test.ts test/calm-mode.test.ts test/stream-render-throttle.test.ts test/message-display-resync.test.ts test/project-root.test.ts test/guard-advisory-context.test.ts test/clear-command-usage.test.ts test/daily-agent-smoke.terminal.test.ts test/slash-menu-toggles.terminal.test.ts test/cli-args.test.ts test/extensions-configured-paths.test.ts test/extensions-loader-path.test.ts test/file-picker.test.ts test/interrupt-recovery.test.ts test/mention-insert-regression.test.ts test/image-paste.test.ts test/clipboard-read-image.test.ts test/clipboard-races.test.ts test/clipboard-dogfood.terminal.test.ts test/mention-picker-navigation.test.ts test/pie-unity-rpc-skill.test.ts test/skill-creator-scripts.test.ts test/interactive-compact-command.test.ts test/computer-use-broker.test.ts test/computer-use-review-regressions.test.ts test/computer-use-safety.test.ts ../../scripts/node-test-diagnostics.test.js ../../scripts/offline-test-runner.test.js ../../scripts/unity-consumer.test.mjs",
23
+ "test:offline:main": "node --test --test-concurrency=2 --import tsx test/cli-attention.test.ts test/builtin-extensions.test.ts test/core-services.test.ts test/cli.test.ts test/cli-auto-compaction.test.ts test/execution-state-manager.test.ts test/queued-steer-execution-state.test.ts test/todo-steering-ownership.test.ts test/architecture-boundaries.test.ts test/attachment-resolver.test.ts test/kimi-attachment-provider.test.ts test/document-attachment-extension.test.ts test/auto-compact-overflow.test.ts test/auto-compaction-ui.test.ts test/tool-compaction-dogfood.terminal.test.ts test/hierarchical-command-system.test.ts test/mcp-adapter.test.ts test/herdr-agent-state.test.ts test/extensions-enablement.test.ts test/extension-selector-shortcuts.test.ts test/skill-tool-enablement.test.ts test/message-queue-unit.test.ts test/evals-harness.test.ts test/session-trace.test.ts test/json-events-sidechat-diagnostics.test.ts test/json-events-prewarm-shutdown.test.ts test/json-envelope-composition.test.ts test/subagent-session-store.test.ts test/runtime-mode-context.test.ts test/tool-policy.test.ts test/retry-policy.test.ts test/yolo-command.test.ts test/footer-lifecycle.test.ts test/footer-waiting-for-user.test.ts test/files-utils.test.ts test/source-size-guard.test.ts test/runtime-logger.test.ts test/release-readiness.test.ts test/package-artifacts.test.ts test/init-extension-contract.test.ts test/skills-runtime.test.ts test/skills-agents-discovery.test.ts test/skills-symlink.test.ts test/model-overrides.test.ts test/auth-storage.test.ts test/extension-register-provider.test.ts test/extension-reload.test.ts test/extension-terminal-input.test.ts test/extension-session-before-events.test.ts test/extension-widgets.test.ts test/extension-render-hint.test.ts test/extension-oauth-restore.test.ts test/cross-host-parity.test.ts test/tool-name-rendering.test.ts test/session-selector.test.ts test/tree-selector-pagination.test.ts test/context-report.test.ts test/context-signals.test.ts test/plan-cache-stability.test.ts test/cache-invalidation-trace.test.ts test/cache-retention.test.ts test/trace-report.test.ts test/boot-report.test.ts test/compaction-diff.test.ts test/entry-body-and-usage.test.ts test/session-control.test.ts test/terminal-title.test.ts test/interactive-controller-title.test.ts test/todo-title.terminal.test.ts test/host-envelope-dogfood.terminal.test.ts test/host-envelope-cross-mode.test.ts test/host-envelope-registry-lifecycle.test.ts test/host-envelope-migration-roundtrip.test.ts test/host-envelope-intake-order.test.ts test/plan-mode-extension.test.ts test/extension-interaction-signals.test.ts test/rendered-page-reader.test.ts test/tools-registry.test.ts test/system-prompt-contract.test.ts test/bash-yolo.test.ts test/bash-contract.test.ts test/bash-confirm-pending.test.ts test/interaction-status-lifecycle.test.ts test/bash-process-group.test.ts test/bash-artifact-sink.test.ts test/direct-bash.test.ts test/terminal-bell.test.ts test/ctrl-d-exit.test.ts test/session-display-title.test.ts test/calm-mode.test.ts test/stream-render-throttle.test.ts test/message-display-resync.test.ts test/project-root.test.ts test/guard-advisory-context.test.ts test/clear-command-usage.test.ts test/daily-agent-smoke.terminal.test.ts test/slash-menu-toggles.terminal.test.ts test/cli-args.test.ts test/extensions-configured-paths.test.ts test/extensions-loader-path.test.ts test/file-picker.test.ts test/interrupt-recovery.test.ts test/mention-insert-regression.test.ts test/image-paste.test.ts test/clipboard-read-image.test.ts test/clipboard-races.test.ts test/clipboard-dogfood.terminal.test.ts test/mention-picker-navigation.test.ts test/pie-unity-rpc-skill.test.ts test/skill-creator-scripts.test.ts test/interactive-compact-command.test.ts test/computer-use-broker.test.ts test/computer-use-review-regressions.test.ts test/computer-use-safety.test.ts ../../scripts/node-test-diagnostics.test.js ../../scripts/offline-test-runner.test.js ../../scripts/unity-consumer.test.mjs ../../scripts/owned-process-cleanup.test.mjs",
24
24
  "test:all": "npm run test:offline && npm run test:terminal:vitest",
25
25
  "test:terminal:vitest": "vitest run test/mention-file-select.terminal.test.ts test/tool-partial-display.terminal.test.ts test/footer-plan-mode.test.ts test/viewport-position-final.test.ts test/resume-header.terminal.test.ts --no-file-parallelism",
26
26
  "test:todo-tui": "node ../../scripts/run-with-env.mjs PIE_REAL_TODO_TUI=1 -- --test --import tsx test/todo-closure.terminal.test.ts",