@cydm/pie 2.5.2 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2191,15 +2191,120 @@ var FileSystemGateway = class {
2191
2191
  return true;
2192
2192
  }
2193
2193
  }
2194
- return false;
2194
+ return this.allowedViaCaseAlias(path, normalized);
2195
2195
  }
2196
2196
  /**
2197
- * Normalize path for comparison
2197
+ * Normalize path for comparison.
2198
+ *
2199
+ * Both sides of every comparison get the identical structural
2200
+ * transformation (backslashes to slashes, repeated separators collapsed,
2201
+ * trailing separators trimmed) so boundary checks stay segment-exact.
2202
+ * Case is folded only where the compared path is Windows-shaped: a drive
2203
+ * letter, a backslash UNC root (`\\server\share`), or any path on a win32
2204
+ * host. POSIX paths keep their case — on a case-sensitive volume a
2205
+ * different-case spelling is a different directory, and a leading "//" on
2206
+ * a POSIX host is an ordinary POSIX path, not a UNC share, so it must never
2207
+ * earn case-insensitive treatment there (that would let `//Tmp/...`-style
2208
+ * spellings borrow the identity of case-distinct siblings).
2198
2209
  */
2199
2210
  normalizePath(path) {
2200
- const normalized = path.replace(/\\/g, "/").replace(/\/+/g, "/");
2201
- if (normalized === "/") return normalized;
2202
- return normalized.replace(/\/+$/, "").toLowerCase();
2211
+ const slashed = path.replace(/\\/g, "/");
2212
+ const collapsed = slashed.replace(/\/+/g, "/");
2213
+ const trimmed = collapsed === "/" ? collapsed : collapsed.replace(/\/+$/, "");
2214
+ return this.usesCaseInsensitiveComparison(path, trimmed) ? trimmed.toLowerCase() : trimmed;
2215
+ }
2216
+ /**
2217
+ * Windows compares all path names case-insensitively; UNC roots are
2218
+ * recognized by their backslash form. Forward-slash "//" prefixes on a
2219
+ * POSIX host stay case-sensitive POSIX paths.
2220
+ */
2221
+ usesCaseInsensitiveComparison(rawPath, normalizedPath) {
2222
+ if (rawPath.startsWith("\\\\")) return true;
2223
+ if (/^[a-zA-Z]:/.test(normalizedPath)) return true;
2224
+ return typeof process !== "undefined" && process.platform === "win32";
2225
+ }
2226
+ /**
2227
+ * Slow path for POSIX hosts: preserve legitimate case aliases (the default
2228
+ * macOS volume resolves `/Users/alice` and `/Users/Alice` to the same
2229
+ * directory) without blanket darwin case-folding and without probing the
2230
+ * filesystem with writes. A candidate is allowed only when the canonical
2231
+ * identity of its nearest existing ancestor — rebuilt segment by segment
2232
+ * with read-only stat/readdir probes — lands inside the canonical identity
2233
+ * of an allowed root. On a case-sensitive volume a case-variant spelling of
2234
+ * a different directory never resolves through this walk (the exact
2235
+ * spelling wins whenever it exists), so it stays denied. Windows-shaped
2236
+ * candidates skip this path: their comparison is already case-folded.
2237
+ */
2238
+ allowedViaCaseAlias(rawPath, normalizedPath) {
2239
+ if (!normalizedPath.startsWith("/")) return false;
2240
+ if (this.usesCaseInsensitiveComparison(rawPath, normalizedPath)) return false;
2241
+ if (typeof process !== "undefined" && process.platform === "win32") return false;
2242
+ if (detectPlatform() === "puerts") return false;
2243
+ let fs;
2244
+ try {
2245
+ fs = nodeRequire("fs");
2246
+ } catch {
2247
+ return false;
2248
+ }
2249
+ let resolved;
2250
+ try {
2251
+ resolved = this.resolveCaseAlias(fs, normalizedPath);
2252
+ } catch {
2253
+ return false;
2254
+ }
2255
+ for (const root of this.allowedRoots) {
2256
+ const normalizedRoot = this.normalizePath(root);
2257
+ if (!normalizedRoot.startsWith("/")) continue;
2258
+ try {
2259
+ const resolvedRoot = this.resolveCaseAlias(fs, normalizedRoot);
2260
+ if (resolved === resolvedRoot || resolved.startsWith(this.withTrailingSep(resolvedRoot))) {
2261
+ return true;
2262
+ }
2263
+ } catch {
2264
+ }
2265
+ }
2266
+ return false;
2267
+ }
2268
+ /**
2269
+ * Rebuild a POSIX path with its true on-disk case. The canonical prefix
2270
+ * grows only through segments the filesystem itself accepts in the
2271
+ * requested spelling (a read-only stat probe): on a case-insensitive
2272
+ * volume a different-case spelling still resolves and is rewritten to the
2273
+ * directory's actual entry name; on a case-sensitive volume it does not
2274
+ * resolve, the walk stops, and the remaining segments stay verbatim — so
2275
+ * they can never borrow a sibling directory's identity.
2276
+ */
2277
+ resolveCaseAlias(fs, normalizedPath) {
2278
+ const segments = normalizedPath.slice(1).split("/").filter((segment) => segment.length > 0 && segment !== ".");
2279
+ let canonical = "";
2280
+ let index = 0;
2281
+ while (index < segments.length) {
2282
+ const segment = segments[index];
2283
+ const probe = `${canonical}/${segment}`;
2284
+ if (!fs.statSync(probe, { throwIfNoEntry: false })) break;
2285
+ canonical = `${canonical}/${this.trueCaseName(fs, canonical, segment)}`;
2286
+ index += 1;
2287
+ }
2288
+ const tail = segments.slice(index).join("/");
2289
+ return tail ? `${canonical}/${tail}` : canonical;
2290
+ }
2291
+ /**
2292
+ * Actual directory-entry name for a segment the filesystem already
2293
+ * resolved. Exact spelling wins; a different-case entry can only be the
2294
+ * same file (case-insensitive volume), otherwise statSync above would have
2295
+ * failed. Read-only; never falls back to writing a probe.
2296
+ */
2297
+ trueCaseName(fs, directory, name) {
2298
+ try {
2299
+ const entries = fs.readdirSync(directory === "" ? "/" : directory);
2300
+ if (entries.includes(name)) return name;
2301
+ const lowered = name.toLowerCase();
2302
+ for (const entry of entries) {
2303
+ if (entry.toLowerCase() === lowered) return entry;
2304
+ }
2305
+ } catch {
2306
+ }
2307
+ return name;
2203
2308
  }
2204
2309
  /**
2205
2310
  * Normalize root path for prefix comparison
@@ -2914,7 +3019,7 @@ function convertMessages(model, context, compat) {
2914
3019
  if (typeof msg.content === "string") {
2915
3020
  params.push({ role: "user", content: msg.content });
2916
3021
  } else {
2917
- const content = msg.content.flatMap((item) => convertUserContentItem(item));
3022
+ const content = msg.content.flatMap((item) => convertCheckedContent(item, model));
2918
3023
  const filteredContent = content.filter((c) => {
2919
3024
  if (c.type === "text") return true;
2920
3025
  if (c.type === "image_url") return model.input.includes("image");
@@ -2971,11 +3076,17 @@ function convertMessages(model, context, compat) {
2971
3076
  };
2972
3077
  if (compat.requiresToolResultName && toolMsg.toolName) toolResultMsg.name = toolMsg.toolName;
2973
3078
  params.push(toolResultMsg);
2974
- if (model.input.includes("image")) {
2975
- const images = toolMsg.content.filter((c) => c.type === "image");
3079
+ {
3080
+ const images = toolMsg.content.filter((c) => c.type !== "text");
2976
3081
  if (images.length > 0) {
2977
3082
  attachments.push({ type: "text", text: `Images from tool ${toolMsg.toolName ?? "unknown"} (call ${toolMsg.toolCallId}):` });
2978
- for (const image of images) attachments.push(...convertUserContentItem(image));
3083
+ for (const image of images) {
3084
+ const kind = image.type;
3085
+ const capability = kind === "audio" || kind === "video" ? model.fileCapabilities?.[kind] : void 0;
3086
+ if ((kind === "audio" || kind === "video") && !(capability && typeof capability === "object" && capability.supported !== false && capability.nativeInline === true)) {
3087
+ attachments.push({ type: "text", text: `[${kind} attachment omitted: endpoint nativeInline transport is not enabled. Re-read with a compatible model.]` });
3088
+ } else attachments.push(...convertCheckedContent(image, model));
3089
+ }
2979
3090
  }
2980
3091
  }
2981
3092
  }
@@ -2985,6 +3096,30 @@ function convertMessages(model, context, compat) {
2985
3096
  }
2986
3097
  return params;
2987
3098
  }
3099
+ function convertCheckedContent(item, model) {
3100
+ const modality = item.type === "fileRef" ? item.modality : item.type;
3101
+ if (modality === "image" || modality === "video" || modality === "audio") {
3102
+ if (!model.input.includes(modality)) return [{ type: "text", text: `[${modality} attachment omitted: current model does not support this modality. Re-read with a compatible model.]` }];
3103
+ if (item.type === "audio") {
3104
+ const audio = item;
3105
+ if (audioFormatFor(audio.mimeType) === void 0) {
3106
+ return [{ type: "text", text: `[audio attachment omitted: unsupported format ${audio.mimeType}. Convert to WAV or MP3 first.]` }];
3107
+ }
3108
+ }
3109
+ }
3110
+ return convertUserContentItem(item);
3111
+ }
3112
+ function audioFormatFor(mimeType) {
3113
+ const mime = mimeType.toLowerCase().split(";")[0].trim();
3114
+ if (["audio/wav", "audio/x-wav", "audio/wave", "audio/vnd.wave"].includes(mime)) return "wav";
3115
+ if (["audio/mpeg", "audio/mp3"].includes(mime)) return "mp3";
3116
+ return void 0;
3117
+ }
3118
+ function audioFormat(mimeType) {
3119
+ const format = audioFormatFor(mimeType);
3120
+ if (format === void 0) throw new Error(`Unsupported audio attachment format: ${mimeType}. Convert to WAV or MP3 first.`);
3121
+ return format;
3122
+ }
2988
3123
  function convertUserContentItem(item) {
2989
3124
  if (item.type === "text") return [{ type: "text", text: item.text }];
2990
3125
  if (item.type === "image") return [{ type: "image_url", image_url: { url: `data:${item.mimeType};base64,${item.data}` } }];
@@ -2994,7 +3129,7 @@ function convertUserContentItem(item) {
2994
3129
  }
2995
3130
  if (item.type === "audio") {
2996
3131
  const audio = item;
2997
- return [{ type: "input_audio", input_audio: { data: audio.data, format: audio.mimeType.includes("wav") ? "wav" : "mp3" } }];
3132
+ return [{ type: "input_audio", input_audio: { data: audio.data, format: audioFormat(audio.mimeType) } }];
2998
3133
  }
2999
3134
  if (item.type === "fileRef") {
3000
3135
  const ref = item;
@@ -3641,7 +3776,7 @@ function mapStopReason(reason) {
3641
3776
  }
3642
3777
  }
3643
3778
  function convertContentBlocks(content) {
3644
- const supportedBlocks = content.filter((block) => block.type === "text" || block.type === "image");
3779
+ const supportedBlocks = content.map((block) => block.type === "text" || block.type === "image" ? block : { type: "text", text: `[${block.type} attachment omitted: unsupported by this provider. Re-read with a compatible model.]` });
3645
3780
  const hasImages = supportedBlocks.some((c) => c.type === "image");
3646
3781
  if (!hasImages) {
3647
3782
  const text = supportedBlocks.filter((c) => c.type === "text").map((c) => c.text).join("\n");
@@ -3,7 +3,7 @@ import {
3
3
  EventStream,
4
4
  streamSimple,
5
5
  validateToolArguments
6
- } from "./chunk-UD7KYQ6J.js";
6
+ } from "./chunk-O2DKMLNX.js";
7
7
 
8
8
  // ../../packages/agent-core/src/agent-loop.ts
9
9
  function createLoopErrorMessage(error, config, signal) {
@@ -409,6 +409,19 @@ function skipToolCall(toolCall, stream) {
409
409
  return toolResultMessage;
410
410
  }
411
411
 
412
+ // ../../packages/agent-core/src/tool-caller-identity.ts
413
+ var kToolCallerIdentity = /* @__PURE__ */ Symbol("pie.toolCallerIdentity");
414
+ function createToolCallerIdentity() {
415
+ return { kind: "pie.toolCallerIdentity" };
416
+ }
417
+ function bindToolCallerIdentity(signal, identity) {
418
+ signal[kToolCallerIdentity] = identity;
419
+ }
420
+ function getToolCallerIdentity(signal) {
421
+ if (!signal) return void 0;
422
+ return signal[kToolCallerIdentity];
423
+ }
424
+
412
425
  // ../../packages/agent-core/src/agent.ts
413
426
  function defaultConvertToLlm(messages) {
414
427
  return messages.filter((m) => m.role === "user" || m.role === "assistant" || m.role === "toolResult");
@@ -443,11 +456,16 @@ var Agent = class {
443
456
  _thinkingBudgets;
444
457
  _maxRetryDelayMs;
445
458
  hooks;
459
+ /** Stable identity for this agent instance, bound onto every run signal
460
+ * handed to tools (signals themselves are per-run; see tool-caller-identity.ts). */
461
+ toolCallerIdentity = createToolCallerIdentity();
446
462
  statusSnapshot = {
447
463
  phase: "idle",
448
464
  turnState: "completed",
449
465
  hasPendingToolContinuation: false
450
466
  };
467
+ /** Assistant message already reported as turn_failed during this run. */
468
+ reportedFailureMessage;
451
469
  constructor(opts = {}) {
452
470
  this._state = {
453
471
  systemPrompt: "",
@@ -729,6 +747,7 @@ var Agent = class {
729
747
  const model = this._state.model;
730
748
  if (!model) throw new Error("No model configured");
731
749
  this.abortController = new AbortController();
750
+ bindToolCallerIdentity(this.abortController.signal, this.toolCallerIdentity);
732
751
  this._state.isStreaming = true;
733
752
  this._state.streamMessage = null;
734
753
  this._state.error = void 0;
@@ -954,6 +973,7 @@ var Agent = class {
954
973
  const stopReason = event.message.role === "assistant" ? event.message.stopReason : void 0;
955
974
  const hasToolCalls = event.message.role === "assistant" && Array.isArray(event.message.content) && event.message.content.some((block) => block.type === "toolCall");
956
975
  if (stopReason === "error" || stopReason === "aborted") {
976
+ this.reportedFailureMessage = event.message;
957
977
  this.updateStatusSnapshot({
958
978
  phase: "failed",
959
979
  turnState: "failed",
@@ -997,7 +1017,9 @@ var Agent = class {
997
1017
  }
998
1018
  case "agent_end": {
999
1019
  const lastMessage = event.messages[event.messages.length - 1];
1000
- if (lastMessage?.role === "assistant" && (lastMessage.stopReason === "error" || lastMessage.stopReason === "aborted")) {
1020
+ const alreadyReported = lastMessage !== void 0 && lastMessage === this.reportedFailureMessage;
1021
+ this.reportedFailureMessage = void 0;
1022
+ if (!alreadyReported && lastMessage?.role === "assistant" && (lastMessage.stopReason === "error" || lastMessage.stopReason === "aborted")) {
1001
1023
  this.updateStatusSnapshot({
1002
1024
  phase: "failed",
1003
1025
  turnState: "failed",
@@ -1025,5 +1047,8 @@ var Agent = class {
1025
1047
  export {
1026
1048
  agentLoop,
1027
1049
  agentLoopContinue,
1050
+ createToolCallerIdentity,
1051
+ bindToolCallerIdentity,
1052
+ getToolCallerIdentity,
1028
1053
  Agent
1029
1054
  };
@@ -0,0 +1,20 @@
1
+ import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
+ import {
3
+ Agent,
4
+ agentLoop,
5
+ agentLoopContinue,
6
+ bindToolCallerIdentity,
7
+ createToolCallerIdentity,
8
+ getToolCallerIdentity
9
+ } from "./chunk-Y4CYXJR7.js";
10
+ import "./chunk-O2DKMLNX.js";
11
+ import "./chunk-XXGYUYXI.js";
12
+ import "./chunk-LZQXQOPJ.js";
13
+ export {
14
+ Agent,
15
+ agentLoop,
16
+ agentLoopContinue,
17
+ bindToolCallerIdentity,
18
+ createToolCallerIdentity,
19
+ getToolCallerIdentity
20
+ };
@@ -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-UD7KYQ6J.js";
4
+ } from "./chunk-O2DKMLNX.js";
5
5
  import "./chunk-XXGYUYXI.js";
6
6
  import "./chunk-LZQXQOPJ.js";
7
7
 
package/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  createCliWebResearchHealthStore,
8
8
  formatSize,
9
9
  truncateHeadTail
10
- } from "./chunks/chunk-M4OJARWJ.js";
10
+ } from "./chunks/chunk-3F5ZP2CV.js";
11
11
  import {
12
12
  AGENTS_CONTEXT_FILE_NAME,
13
13
  AgentSessionController,
@@ -60,8 +60,8 @@ import {
60
60
  setExtensionEnabledInSettings,
61
61
  shouldPreserveExecutionStateForUserText,
62
62
  supersedeExecutionState
63
- } from "./chunks/chunk-LO2V5DZZ.js";
64
- import "./chunks/chunk-RTTGO2A6.js";
63
+ } from "./chunks/chunk-IKLQHWY2.js";
64
+ import "./chunks/chunk-Y4CYXJR7.js";
65
65
  import {
66
66
  Deref,
67
67
  EMPTY_ASSISTANT_CONTENT_ERROR,
@@ -85,7 +85,7 @@ import {
85
85
  setLogger,
86
86
  sortToolModelCandidatesByCapability,
87
87
  type_exports
88
- } from "./chunks/chunk-UD7KYQ6J.js";
88
+ } from "./chunks/chunk-O2DKMLNX.js";
89
89
  import {
90
90
  VERSION,
91
91
  getAgentDir,
@@ -52476,8 +52476,9 @@ function validateFileCapabilities(value, label) {
52476
52476
  if (!["image", "video", "audio", "document"].includes(kind)) throw new Error(`${label}.${kind} is unsupported`);
52477
52477
  if (typeof capability === "boolean") continue;
52478
52478
  if (!isPlainRecord(capability)) throw new Error(`${label}.${kind} is invalid`);
52479
- assertOnlyKeys(capability, ["supported", "formats", "maxFileSizeMb", "maxDurationSeconds"], `${label}.${kind}`);
52479
+ assertOnlyKeys(capability, ["supported", "formats", "maxFileSizeMb", "maxDurationSeconds", "nativeInline"], `${label}.${kind}`);
52480
52480
  assertOptionalBoolean(capability.supported, `${label}.${kind}.supported`);
52481
+ assertOptionalBoolean(capability.nativeInline, `${label}.${kind}.nativeInline`);
52481
52482
  if (capability.formats !== void 0 && (!Array.isArray(capability.formats) || capability.formats.some((item) => typeof item !== "string" || !item))) {
52482
52483
  throw new Error(`${label}.${kind}.formats is invalid`);
52483
52484
  }
@@ -53689,6 +53690,13 @@ var SettingsManager = class {
53689
53690
  this.settings.calmMode = enabled;
53690
53691
  this.writeSettings();
53691
53692
  }
53693
+ getToolOutputExpanded() {
53694
+ return this.settings.toolOutputExpanded === true;
53695
+ }
53696
+ setToolOutputExpanded(expanded) {
53697
+ this.settings.toolOutputExpanded = expanded;
53698
+ this.writeSettings();
53699
+ }
53692
53700
  // ==========================================================================
53693
53701
  // Extension enablement (user ~/.pie/settings.json + project ./.pie/settings.json)
53694
53702
  // ==========================================================================
@@ -70165,7 +70173,7 @@ function deriveSessionTitle(options) {
70165
70173
  }
70166
70174
  if (activeSession.metadata.nameSource === "manual") {
70167
70175
  const manual = normalizeSessionTitle(activeSession.metadata.name);
70168
- if (manual) return manual;
70176
+ return manual || activeSession.metadata.name.trim() || `S:${activeSession.id.slice(-6)}`;
70169
70177
  }
70170
70178
  if (persistedNameIsAuthoritative(activeSession.metadata)) {
70171
70179
  const persisted = normalizeSessionTitle(activeSession.metadata.name);
@@ -72843,12 +72851,6 @@ async function loadSession(host, sessionId) {
72843
72851
  host.agentSessionController?.drainQueuedInputsForEditor();
72844
72852
  host.updatePendingMessagesDisplay();
72845
72853
  renderChatHistory(host, messages);
72846
- if (messages.length > 50) {
72847
- host.chatContainer.addChild(new Spacer(1));
72848
- host.chatContainer.addChild(
72849
- new Text(theme.fg("dim", `... (${messages.length - 50} earlier messages hidden)`), 1, 0)
72850
- );
72851
- }
72852
72854
  host.chatContainer.addChild(new Spacer(1));
72853
72855
  host.chatContainer.addChild(
72854
72856
  new Text(theme.fg("accent", `\u2713 Loaded session: ${sessionId.slice(0, 8)}...`), 1, 0)
@@ -73072,7 +73074,7 @@ async function navigateToEntry(host, entryId) {
73072
73074
  }
73073
73075
  }
73074
73076
  function renderChatHistory(host, messages) {
73075
- const messagesToShow = messages.slice(-50);
73077
+ const messagesToShow = messages;
73076
73078
  const toolResultMap = /* @__PURE__ */ new Map();
73077
73079
  for (const msg of messages) {
73078
73080
  if (msg.role === "toolResult") {
@@ -77641,9 +77643,10 @@ function stripStaleUsageBeforeCompaction(messages, latestCompactionTimestamp) {
77641
77643
 
77642
77644
  // src/runtime/retry-policy.ts
77643
77645
  var TRANSIENT_NETWORK_ERROR_PATTERN = /sse stream aborted|sse stream closed before end|sse stream ended before response completed|(?:read\s+)?ECONNRESET|ETIMEDOUT|EAI_AGAIN|ENOTFOUND|ECONNREFUSED|(?:read\s+|write\s+)?EPIPE|socket hang up|request timeout|client network socket disconnected before secure TLS connection was established|certificate (?:has )?expired|unable to verify (?:the first certificate|certificate)|self[- ]signed cert|connection.?error|connection.?refused|other side closed|fetch failed|upstream.?connect|reset before headers|terminated/i;
77644
- var PROVIDER_TRANSIENT_ERROR_PATTERN = /overloaded|rate.?limit|too many requests|\b429\b|\b500\b|\b502\b|\b503\b|\b504\b|service.?unavailable|server error|internal error|retry delay/i;
77646
+ var PROVIDER_TRANSIENT_ERROR_PATTERN = /overloaded|rate.?limit|too many requests|\b429\b|\b500\b|\b502\b|\b503\b|\b504\b|service.?unavailable|server error|internal error|retry delay|quota (?:has been |is )?exhausted/i;
77645
77647
  var USER_ABORT_PATTERN = /request was aborted|local abort signal|user abort|user_interrupt|interrupted by user|esc pressed|ctrl\+c/i;
77646
77648
  var AUTH_CONFIG_PATTERN = /missing api key|invalid api key|api key.*invalid|unauthorized|\b401\b|\b403\b|forbidden|authentication failed|no configured model|no models? are configured/i;
77649
+ var QUOTA_EXHAUSTED_PATTERN = /insufficient[_ ]quota|exceeded[_ ]current[_ ]quota|exceeded your current quota|billing[_ ]hard[_ ]limit|insufficient[_ ]balance|credit balance is too low|\barrearage\b|余额不足|\b(?:account|monthly|billing) quota (?:has been |is )?exhausted/i;
77647
77650
  var INVALID_FILE_REFERENCE_PATTERN = /not the owner of this file|owner of this file|invalid_authentication_error/i;
77648
77651
  var INVALID_REQUEST_PATTERN = /bad request|\b400\b|invalid request|invalid schema|schema validation|invalid parameter|unsupported parameter|malformed/i;
77649
77652
  var CLI_RETRY_MAX_RETRIES = 3;
@@ -77683,7 +77686,7 @@ function classifyCliFailure(context) {
77683
77686
  if (INVALID_FILE_REFERENCE_PATTERN.test(errorMessage4)) {
77684
77687
  return createClassification("invalid_file_reference", errorMessage4);
77685
77688
  }
77686
- if (AUTH_CONFIG_PATTERN.test(errorMessage4)) {
77689
+ if (AUTH_CONFIG_PATTERN.test(errorMessage4) || QUOTA_EXHAUSTED_PATTERN.test(errorMessage4)) {
77687
77690
  return createClassification("auth_config", errorMessage4);
77688
77691
  }
77689
77692
  if (TRANSIENT_NETWORK_ERROR_PATTERN.test(errorMessage4)) {
@@ -79837,6 +79840,7 @@ var InteractiveMode = class {
79837
79840
  this.skillsSection = formatSkillsForPrompt(options.skills);
79838
79841
  this.knowledgeSection = buildCliProjectContextSection(options.cwd);
79839
79842
  this.calmMode = options.settingsManager.getCalmModeEnabled();
79843
+ this.toolOutputExpanded = options.settingsManager.getToolOutputExpanded();
79840
79844
  }
79841
79845
  options;
79842
79846
  get runtimeEventHost() {
@@ -80034,7 +80038,7 @@ var InteractiveMode = class {
80034
80038
  async init() {
80035
80039
  const activeSession = this.sessionManager.getActiveSession();
80036
80040
  this.thinkingLevel = resolveInitialThinkingLevel({ session: activeSession, settingsManager: this.options.settingsManager });
80037
- const { Agent } = await import("./chunks/src-33WRCQWX.js");
80041
+ const { Agent } = await import("./chunks/src-VCWCE7YV.js");
80038
80042
  this.agent = new Agent({
80039
80043
  initialState: {
80040
80044
  systemPrompt: this.buildSystemPrompt(),
@@ -80389,7 +80393,8 @@ var InteractiveMode = class {
80389
80393
  return interactiveCommands.some((cmd) => commandPath.startsWith(cmd));
80390
80394
  }
80391
80395
  toggleToolsExpansion() {
80392
- return toggleToolsExpansion(this.uiHelperHost);
80396
+ toggleToolsExpansion(this.uiHelperHost);
80397
+ this.options.settingsManager.setToolOutputExpanded(this.toolOutputExpanded);
80393
80398
  }
80394
80399
  showSelector(create) {
80395
80400
  return showSelector(this.uiHelperHost, create);
@@ -80868,7 +80873,7 @@ async function runPrintMode(params) {
80868
80873
  `);
80869
80874
  console.log("Assistant: ");
80870
80875
  }
80871
- const { Agent: AgentClass } = await import("./chunks/src-33WRCQWX.js");
80876
+ const { Agent: AgentClass } = await import("./chunks/src-VCWCE7YV.js");
80872
80877
  let agent;
80873
80878
  const printModeExtensions = await loadPrintModeExtensions({
80874
80879
  cwd: runtime.cwd,
@@ -81729,7 +81734,7 @@ async function runJsonEventsMode(params) {
81729
81734
  return;
81730
81735
  }
81731
81736
  const parent = agent;
81732
- const { Agent: AgentClass } = await import("./chunks/src-33WRCQWX.js");
81737
+ const { Agent: AgentClass } = await import("./chunks/src-VCWCE7YV.js");
81733
81738
  const sideAgent = new AgentClass({
81734
81739
  initialState: {
81735
81740
  systemPrompt: parent.state.systemPrompt,
@@ -82073,7 +82078,7 @@ async function runJsonEventsMode(params) {
82073
82078
  if (runtime.initialModel.unconfigured || controller) {
82074
82079
  return;
82075
82080
  }
82076
- const { Agent: AgentClass } = await import("./chunks/src-33WRCQWX.js");
82081
+ const { Agent: AgentClass } = await import("./chunks/src-VCWCE7YV.js");
82077
82082
  const jsonModeExtensions = await loadJsonModeExtensions({ runtime, getAgent: () => agent });
82078
82083
  extensionRunner = jsonModeExtensions.runner;
82079
82084
  const tools = [...runtime.tools, ...jsonModeExtensions.extensionTools];
@@ -82662,7 +82667,7 @@ async function runWithJsonEventsConsoleIsolation(fn) {
82662
82667
  }
82663
82668
  async function createCliTestStreamFnFromEnv() {
82664
82669
  if (!process.env.PIE_TEST_MOCK_STREAM_SEQUENCE) return void 0;
82665
- return (await import("./chunks/test-stream-LFR6GSKQ.js")).createTestStreamFnFromSequenceEnv();
82670
+ return (await import("./chunks/test-stream-GOSEWMJ3.js")).createTestStreamFnFromSequenceEnv();
82666
82671
  }
82667
82672
  function resolveJsonEventsDetailFlag() {
82668
82673
  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.5.2",
3
+ "version": "2.6.1",
4
4
  "description": "Pie AI Agent CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -17,7 +17,7 @@
17
17
  "validate:models": "tsx scripts/validate-models-config.ts",
18
18
  "test": "npm run test:offline",
19
19
  "pretest:offline": "npm run build --workspace @pie/agent-framework && npm run build --workspace @pie/shared-headless-capabilities && npm run build && npm run test:skill-regressions",
20
- "test:skill-regressions": "node --test --import tsx test/bash-lifecycle.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/computer-evidence.test.ts test/interactive-lifecycle.test.ts",
20
+ "test:skill-regressions": "node --test --import tsx test/bash-lifecycle.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-evidence.test.ts test/interactive-lifecycle.test.ts",
21
21
  "posttest:offline": "node --test --import tsx test/remote-model-catalog.test.ts",
22
22
  "test:offline": "node --test --test-concurrency=4 --import tsx 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/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/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/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/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/code-intel-typescript-provider.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/session-control.test.ts test/terminal-title.test.ts test/interactive-controller-title.test.ts test/todo-title.terminal.test.ts test/plan-mode-extension.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-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/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/mention-picker-navigation.test.ts test/pie-unity-rpc-skill.test.ts test/skill-creator-scripts.test.ts",
23
23
  "test:all": "npm run test:offline && npm run test:terminal:vitest",
@@ -1,14 +0,0 @@
1
- import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
- import {
3
- Agent,
4
- agentLoop,
5
- agentLoopContinue
6
- } from "./chunk-RTTGO2A6.js";
7
- import "./chunk-UD7KYQ6J.js";
8
- import "./chunk-XXGYUYXI.js";
9
- import "./chunk-LZQXQOPJ.js";
10
- export {
11
- Agent,
12
- agentLoop,
13
- agentLoopContinue
14
- };