@cydm/pie 1.0.21 → 1.0.23

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.
@@ -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-NHR6EBM2.js";
5
- import "../../../chunks/chunk-L5BJNCNG.js";
6
- import "../../../chunks/chunk-VESPMEDG.js";
4
+ } from "../../../chunks/chunk-AFTBFF6J.js";
5
+ import "../../../chunks/chunk-PUZP2Q3F.js";
6
+ import "../../../chunks/chunk-7ABSJC2D.js";
7
7
  import "../../../chunks/chunk-TG2EQLX2.js";
8
8
 
9
9
  // builtin/extensions/ask-user/index.ts
@@ -7,9 +7,9 @@ import {
7
7
  isPlanModeSafeCommand,
8
8
  markCompletedPlanSteps,
9
9
  restoreExecutionState
10
- } from "../../../chunks/chunk-NHR6EBM2.js";
11
- import "../../../chunks/chunk-L5BJNCNG.js";
12
- import "../../../chunks/chunk-VESPMEDG.js";
10
+ } from "../../../chunks/chunk-AFTBFF6J.js";
11
+ import "../../../chunks/chunk-PUZP2Q3F.js";
12
+ import "../../../chunks/chunk-7ABSJC2D.js";
13
13
  import "../../../chunks/chunk-TG2EQLX2.js";
14
14
 
15
15
  // builtin/extensions/plan-mode/index.ts
@@ -1,13 +1,13 @@
1
1
  import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
2
  import {
3
3
  createCliHostCapabilities
4
- } from "../../../chunks/chunk-ZYOTRKU7.js";
4
+ } from "../../../chunks/chunk-4WU5VAX4.js";
5
5
  import {
6
6
  createSharedFileSystemTools,
7
7
  createSubagentCapability
8
- } from "../../../chunks/chunk-NHR6EBM2.js";
9
- import "../../../chunks/chunk-L5BJNCNG.js";
10
- import "../../../chunks/chunk-VESPMEDG.js";
8
+ } from "../../../chunks/chunk-AFTBFF6J.js";
9
+ import "../../../chunks/chunk-PUZP2Q3F.js";
10
+ import "../../../chunks/chunk-7ABSJC2D.js";
11
11
  import "../../../chunks/chunk-TG2EQLX2.js";
12
12
 
13
13
  // builtin/extensions/subagent/index.ts
@@ -7,9 +7,9 @@ import {
7
7
  executeManageTodoList,
8
8
  executionStateToTodos,
9
9
  restoreExecutionState
10
- } from "../../../chunks/chunk-NHR6EBM2.js";
11
- import "../../../chunks/chunk-L5BJNCNG.js";
12
- import "../../../chunks/chunk-VESPMEDG.js";
10
+ } from "../../../chunks/chunk-AFTBFF6J.js";
11
+ import "../../../chunks/chunk-PUZP2Q3F.js";
12
+ import "../../../chunks/chunk-7ABSJC2D.js";
13
13
  import "../../../chunks/chunk-TG2EQLX2.js";
14
14
 
15
15
  // builtin/extensions/todo/index.ts
@@ -8,10 +8,10 @@ import {
8
8
  createSharedWebSearchTool,
9
9
  interpretShellExit,
10
10
  requestInteraction
11
- } from "./chunk-NHR6EBM2.js";
11
+ } from "./chunk-AFTBFF6J.js";
12
12
  import {
13
13
  Type
14
- } from "./chunk-VESPMEDG.js";
14
+ } from "./chunk-7ABSJC2D.js";
15
15
 
16
16
  // src/config.ts
17
17
  import { existsSync, mkdirSync, readFileSync, renameSync } from "fs";
@@ -5791,6 +5791,31 @@ function convertTools2(tools) {
5791
5791
  };
5792
5792
  });
5793
5793
  }
5794
+ function applyCacheBreakpoints(params, retention) {
5795
+ if (retention === "none") return;
5796
+ const cacheControl = {
5797
+ type: "ephemeral",
5798
+ ...retention === "long" ? { ttl: "1h" } : {}
5799
+ };
5800
+ if (Array.isArray(params.system) && params.system.length > 0) {
5801
+ const last = params.system[params.system.length - 1];
5802
+ last.cache_control = { ...cacheControl };
5803
+ }
5804
+ if (Array.isArray(params.tools) && params.tools.length > 0) {
5805
+ const last = params.tools[params.tools.length - 1];
5806
+ last.cache_control = { ...cacheControl };
5807
+ }
5808
+ for (let i = params.messages.length - 1; i >= 0; i--) {
5809
+ const msg = params.messages[i];
5810
+ if (msg.role !== "user") continue;
5811
+ if (typeof msg.content === "string") {
5812
+ msg.content = [{ type: "text", text: msg.content, cache_control: { ...cacheControl } }];
5813
+ } else if (Array.isArray(msg.content) && msg.content.length > 0) {
5814
+ msg.content[msg.content.length - 1].cache_control = { ...cacheControl };
5815
+ }
5816
+ break;
5817
+ }
5818
+ }
5794
5819
  var streamAnthropic = (model, context, options) => {
5795
5820
  const stream = new AssistantMessageEventStream();
5796
5821
  (async () => {
@@ -5813,6 +5838,20 @@ var streamAnthropic = (model, context, options) => {
5813
5838
  };
5814
5839
  try {
5815
5840
  const apiKey = options?.apiKey ?? getEnvApiKey(model.provider, model.apiKeyEnv) ?? "";
5841
+ const modelHeaders = model.headers || {};
5842
+ const otherModelHeaders = {};
5843
+ let modelBetaValue;
5844
+ for (const [key, value] of Object.entries(modelHeaders)) {
5845
+ if (key.toLowerCase() === "anthropic-beta") {
5846
+ modelBetaValue = value;
5847
+ } else {
5848
+ otherModelHeaders[key] = value;
5849
+ }
5850
+ }
5851
+ const betaFlags = [
5852
+ ...options?.cacheRetention === "long" ? ["extended-cache-ttl-2025-04-11"] : [],
5853
+ ...modelBetaValue?.split(",") ?? []
5854
+ ].map((flag) => flag.trim()).filter(Boolean);
5816
5855
  const client = new Anthropic({
5817
5856
  apiKey,
5818
5857
  baseURL: model.baseUrl,
@@ -5821,7 +5860,8 @@ var streamAnthropic = (model, context, options) => {
5821
5860
  accept: "application/json",
5822
5861
  "anthropic-dangerous-direct-browser-access": "true",
5823
5862
  "anthropic-version": "2023-06-01",
5824
- ...model.headers || {}
5863
+ ...otherModelHeaders,
5864
+ ...betaFlags.length > 0 ? { "anthropic-beta": [...new Set(betaFlags)].join(",") } : {}
5825
5865
  }
5826
5866
  });
5827
5867
  const params = {
@@ -5834,12 +5874,6 @@ var streamAnthropic = (model, context, options) => {
5834
5874
  if (context.systemPrompt) {
5835
5875
  params.system = [{ type: "text", text: sanitizeSurrogates(context.systemPrompt) }];
5836
5876
  }
5837
- if (isPromptCacheCapability(cacheCapability) && options?.cacheRetention !== "none") {
5838
- params.cache_control = {
5839
- type: "ephemeral",
5840
- ...options?.cacheRetention === "long" ? { ttl: "1h" } : {}
5841
- };
5842
- }
5843
5877
  if (options?.temperature !== void 0) {
5844
5878
  params.temperature = options.temperature;
5845
5879
  }
@@ -5859,6 +5893,9 @@ var streamAnthropic = (model, context, options) => {
5859
5893
  params.tool_choice = options.toolChoice;
5860
5894
  }
5861
5895
  }
5896
+ if (isPromptCacheCapability(cacheCapability)) {
5897
+ applyCacheBreakpoints(params, options?.cacheRetention);
5898
+ }
5862
5899
  options?.onPayload?.(params);
5863
5900
  const anthropicStream = client.messages.stream({ ...params, stream: true }, { signal: options?.signal });
5864
5901
  stream.push({ type: "start", partial: output });
@@ -9462,6 +9499,7 @@ export {
9462
9499
  Type,
9463
9500
  EventStream,
9464
9501
  getModelCacheCapability,
9502
+ EMPTY_ASSISTANT_CONTENT_ERROR,
9465
9503
  streamSimple,
9466
9504
  completeSimple,
9467
9505
  MODEL_CLASS_FALLBACK_ORDER,
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
2
  import {
3
3
  Agent
4
- } from "./chunk-L5BJNCNG.js";
4
+ } from "./chunk-PUZP2Q3F.js";
5
5
  import {
6
6
  FileSystemGateway,
7
7
  Type,
@@ -11,7 +11,7 @@ import {
11
11
  getPlatformConfig,
12
12
  hashText,
13
13
  streamSimple
14
- } from "./chunk-VESPMEDG.js";
14
+ } from "./chunk-7ABSJC2D.js";
15
15
  import {
16
16
  __require
17
17
  } from "./chunk-TG2EQLX2.js";
@@ -3,7 +3,7 @@ import {
3
3
  EventStream,
4
4
  streamSimple,
5
5
  validateToolArguments
6
- } from "./chunk-VESPMEDG.js";
6
+ } from "./chunk-7ABSJC2D.js";
7
7
 
8
8
  // ../../packages/agent-core/src/agent-loop.ts
9
9
  function createLoopErrorMessage(error, config, signal) {
@@ -3,8 +3,8 @@ import {
3
3
  Agent,
4
4
  agentLoop,
5
5
  agentLoopContinue
6
- } from "./chunk-L5BJNCNG.js";
7
- import "./chunk-VESPMEDG.js";
6
+ } from "./chunk-PUZP2Q3F.js";
7
+ import "./chunk-7ABSJC2D.js";
8
8
  import "./chunk-TG2EQLX2.js";
9
9
  export {
10
10
  Agent,
@@ -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-VESPMEDG.js";
4
+ } from "./chunk-7ABSJC2D.js";
5
5
  import "./chunk-TG2EQLX2.js";
6
6
 
7
7
  // src/app/test-stream.ts
package/dist/cli.js CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  getSettingsPath,
16
16
  getThemesDir,
17
17
  migrateConfigFromAgentDir
18
- } from "./chunks/chunk-ZYOTRKU7.js";
18
+ } from "./chunks/chunk-4WU5VAX4.js";
19
19
  import {
20
20
  AGENTS_CONTEXT_FILE_NAME,
21
21
  AgentSessionController,
@@ -59,10 +59,11 @@ import {
59
59
  selectToolsForRuntimePolicy,
60
60
  shouldPreserveExecutionStateForUserText,
61
61
  supersedeExecutionState
62
- } from "./chunks/chunk-NHR6EBM2.js";
63
- import "./chunks/chunk-L5BJNCNG.js";
62
+ } from "./chunks/chunk-AFTBFF6J.js";
63
+ import "./chunks/chunk-PUZP2Q3F.js";
64
64
  import {
65
65
  Deref,
66
+ EMPTY_ASSISTANT_CONTENT_ERROR,
66
67
  Errors,
67
68
  ExtendsUndefinedCheck,
68
69
  HasTransform,
@@ -94,7 +95,7 @@ import {
94
95
  setLogger,
95
96
  sortToolModelCandidatesByCapability,
96
97
  type_exports
97
- } from "./chunks/chunk-VESPMEDG.js";
98
+ } from "./chunks/chunk-7ABSJC2D.js";
98
99
  import {
99
100
  resolveCliProjectRoot
100
101
  } from "./chunks/chunk-NTYHFBUA.js";
@@ -1905,7 +1906,7 @@ var require_core = __commonJS({
1905
1906
  return match && match.index === 0;
1906
1907
  }
1907
1908
  var BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;
1908
- function join19(regexps, separator = "|") {
1909
+ function join20(regexps, separator = "|") {
1909
1910
  let numCaptures = 0;
1910
1911
  return regexps.map((regex) => {
1911
1912
  numCaptures += 1;
@@ -2209,7 +2210,7 @@ var require_core = __commonJS({
2209
2210
  this.exec = () => null;
2210
2211
  }
2211
2212
  const terminators = this.regexes.map((el) => el[1]);
2212
- this.matcherRe = langRe(join19(terminators), true);
2213
+ this.matcherRe = langRe(join20(terminators), true);
2213
2214
  this.lastIndex = 0;
2214
2215
  }
2215
2216
  /** @param {string} s */
@@ -43946,7 +43947,7 @@ var require_dist = __commonJS({
43946
43947
  });
43947
43948
 
43948
43949
  // src/cli.ts
43949
- import * as fs26 from "fs";
43950
+ import * as fs27 from "fs";
43950
43951
  import * as path26 from "path";
43951
43952
 
43952
43953
  // src/cli-args.ts
@@ -45461,11 +45462,13 @@ async function probeModelsConfig(options) {
45461
45462
  };
45462
45463
  }
45463
45464
  function parseModelsCommandArgs(args) {
45464
- const parsed = { force: false, stdout: false };
45465
+ const parsed = { force: false, stdout: false, json: false };
45465
45466
  for (let i = 0; i < args.length; i += 1) {
45466
45467
  const arg = args[i];
45467
45468
  if (arg === "--force") {
45468
45469
  parsed.force = true;
45470
+ } else if (arg === "--json") {
45471
+ parsed.json = true;
45469
45472
  } else if (arg === "--stdout") {
45470
45473
  parsed.stdout = true;
45471
45474
  } else if (arg === "--probe" && args[i + 1]) {
@@ -58600,20 +58603,32 @@ var SessionSelectorComponent = class extends Container {
58600
58603
  selectList;
58601
58604
  sessions;
58602
58605
  callbacks;
58603
- constructor(sessions, callbacks) {
58606
+ options;
58607
+ items = [];
58608
+ baseDescriptions = /* @__PURE__ */ new Map();
58609
+ loadedPreviews = /* @__PURE__ */ new Map();
58610
+ inflightPreviews = /* @__PURE__ */ new Set();
58611
+ destroyed = false;
58612
+ constructor(sessions, callbacks, options = {}) {
58604
58613
  super();
58605
58614
  this.sessions = sessions;
58606
58615
  this.callbacks = callbacks;
58616
+ this.options = options;
58607
58617
  this.addChild(new Text(theme.bold(theme.fg("accent", "Resume Session")), 0, 0));
58608
58618
  this.addChild(new Spacer(1));
58609
- const items = sessions.map((session) => ({
58610
- value: session.id,
58611
- label: session.name || `Session ${session.id.slice(0, 8)}`,
58612
- description: `${session.messageCount} messages \xB7 ${formatDate(session.updatedAt)}`
58613
- }));
58619
+ this.items = sessions.map((session) => {
58620
+ const description = `${session.messageCount} messages \xB7 ${formatDate(session.updatedAt)}`;
58621
+ this.baseDescriptions.set(session.id, description);
58622
+ return {
58623
+ value: session.id,
58624
+ label: session.name || `Session ${session.id.slice(0, 8)}`,
58625
+ description
58626
+ };
58627
+ });
58628
+ const maxVisible = options.maxVisible ?? Math.min(this.items.length, 8);
58614
58629
  this.selectList = new SelectList(
58615
- items,
58616
- Math.min(items.length, 8),
58630
+ this.items,
58631
+ maxVisible,
58617
58632
  {
58618
58633
  selectedPrefix: (text) => theme.fg("accent", text),
58619
58634
  selectedText: (text) => theme.fg("accent", text),
@@ -58623,16 +58638,59 @@ var SessionSelectorComponent = class extends Container {
58623
58638
  }
58624
58639
  );
58625
58640
  this.selectList.onSelect = (item) => {
58641
+ this.destroyed = true;
58626
58642
  this.callbacks.onSelect(item.value);
58627
58643
  };
58628
58644
  this.selectList.onCancel = () => {
58645
+ this.destroyed = true;
58629
58646
  this.callbacks.onCancel();
58630
58647
  };
58648
+ this.selectList.onSelectionChange = (item) => {
58649
+ this.prefetchAroundValue(item.value);
58650
+ };
58631
58651
  this.addChild(this.selectList);
58632
58652
  this.addChild(new Spacer(1));
58633
58653
  this.addChild(
58634
58654
  new Text(theme.fg("dim", " \u2191\u2193 to navigate \xB7 \u2190\u2192 to page \xB7 Enter to select \xB7 Esc to cancel"), 0, 0)
58635
58655
  );
58656
+ this.prefetchWindow(0);
58657
+ }
58658
+ /** Prefetch previews for the window surrounding the given item value. */
58659
+ prefetchAroundValue(value) {
58660
+ const index = this.items.findIndex((item) => item.value === value);
58661
+ if (index >= 0) {
58662
+ this.prefetchWindow(index);
58663
+ }
58664
+ }
58665
+ prefetchWindow(centerIndex) {
58666
+ if (!this.options.loadPreview) return;
58667
+ const maxVisible = this.options.maxVisible ?? Math.min(this.items.length, 8);
58668
+ const start = Math.max(0, centerIndex - 2);
58669
+ const end = Math.min(this.items.length, centerIndex + maxVisible);
58670
+ for (let i = start; i < end; i++) {
58671
+ this.prefetchOne(this.items[i]);
58672
+ }
58673
+ }
58674
+ prefetchOne(item) {
58675
+ const loader = this.options.loadPreview;
58676
+ if (!item || !loader) return;
58677
+ const id = item.value;
58678
+ if (this.loadedPreviews.has(id) || this.inflightPreviews.has(id)) return;
58679
+ this.inflightPreviews.add(id);
58680
+ void loader(id).then((preview) => {
58681
+ this.loadedPreviews.set(id, preview);
58682
+ if (preview) {
58683
+ const base = this.baseDescriptions.get(id) ?? "";
58684
+ item.description = `\u276F ${preview} \xB7 ${base}`;
58685
+ if (!this.destroyed) {
58686
+ this.options.requestRender?.();
58687
+ }
58688
+ }
58689
+ }).catch(() => {
58690
+ this.loadedPreviews.set(id, null);
58691
+ }).finally(() => {
58692
+ this.inflightPreviews.delete(id);
58693
+ });
58636
58694
  }
58637
58695
  handleInput(data) {
58638
58696
  this.selectList.handleInput(data);
@@ -58642,6 +58700,123 @@ var SessionSelectorComponent = class extends Container {
58642
58700
  }
58643
58701
  };
58644
58702
 
58703
+ // src/session-preview.ts
58704
+ import { promises as fs21 } from "node:fs";
58705
+ import { join as join15 } from "node:path";
58706
+ var PREFIX_BYTES = 64 * 1024;
58707
+ var MAX_ENTRIES_SCANNED = 20;
58708
+ var MAX_PREVIEW_LENGTH = 120;
58709
+ var previewCache = /* @__PURE__ */ new Map();
58710
+ function getSessionFilePath(sessionId, sessionsDir) {
58711
+ const safeId = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
58712
+ return join15(sessionsDir ?? getSessionsDir(), `${safeId}.json`);
58713
+ }
58714
+ function extractTextFromContent(content) {
58715
+ if (typeof content === "string") return content;
58716
+ if (Array.isArray(content)) {
58717
+ const parts = [];
58718
+ for (const block of content) {
58719
+ if (block && typeof block === "object" && block.type === "text") {
58720
+ parts.push(block.text || "");
58721
+ }
58722
+ }
58723
+ return parts.join(" ");
58724
+ }
58725
+ return "";
58726
+ }
58727
+ function* scanJsonObjects(text, startIndex) {
58728
+ let depth = 0;
58729
+ let inString = false;
58730
+ let escaped = false;
58731
+ let objectStart = -1;
58732
+ for (let i = startIndex; i < text.length; i++) {
58733
+ const ch = text[i];
58734
+ if (inString) {
58735
+ if (escaped) {
58736
+ escaped = false;
58737
+ } else if (ch === "\\") {
58738
+ escaped = true;
58739
+ } else if (ch === '"') {
58740
+ inString = false;
58741
+ }
58742
+ continue;
58743
+ }
58744
+ if (ch === '"') {
58745
+ inString = true;
58746
+ continue;
58747
+ }
58748
+ if (ch === "{") {
58749
+ if (depth === 0) objectStart = i;
58750
+ depth++;
58751
+ } else if (ch === "}") {
58752
+ depth--;
58753
+ if (depth === 0 && objectStart >= 0) {
58754
+ yield text.slice(objectStart, i + 1);
58755
+ objectStart = -1;
58756
+ }
58757
+ if (depth < 0) return;
58758
+ } else if (ch === "]" && depth === 0) {
58759
+ return;
58760
+ }
58761
+ }
58762
+ }
58763
+ function normalizePreview(text) {
58764
+ const normalized = text.replace(/\s+/g, " ").trim();
58765
+ if (!normalized) return null;
58766
+ return normalized.length > MAX_PREVIEW_LENGTH ? `${normalized.slice(0, MAX_PREVIEW_LENGTH)}...` : normalized;
58767
+ }
58768
+ async function readSessionPromptPreview(sessionId, sessionsDir) {
58769
+ const filePath = getSessionFilePath(sessionId, sessionsDir);
58770
+ let handle;
58771
+ try {
58772
+ handle = await fs21.open(filePath, "r");
58773
+ const buffer = Buffer.alloc(PREFIX_BYTES);
58774
+ const { bytesRead } = await handle.read(buffer, 0, PREFIX_BYTES, 0);
58775
+ const text = buffer.toString("utf-8", 0, bytesRead);
58776
+ const entriesIndex = text.indexOf('"entries"');
58777
+ if (entriesIndex < 0) return null;
58778
+ const arrayStart = text.indexOf("[", entriesIndex);
58779
+ if (arrayStart < 0) return null;
58780
+ let scanned = 0;
58781
+ for (const objectText of scanJsonObjects(text, arrayStart + 1)) {
58782
+ if (++scanned > MAX_ENTRIES_SCANNED) break;
58783
+ let entry;
58784
+ try {
58785
+ entry = JSON.parse(objectText);
58786
+ } catch {
58787
+ break;
58788
+ }
58789
+ if (entry?.type === "message" && entry.message?.role === "user") {
58790
+ return normalizePreview(extractTextFromContent(entry.message.content));
58791
+ }
58792
+ }
58793
+ return null;
58794
+ } catch {
58795
+ return null;
58796
+ } finally {
58797
+ if (handle) {
58798
+ await handle.close().catch(() => {
58799
+ });
58800
+ }
58801
+ }
58802
+ }
58803
+ async function getSessionPromptPreview(sessionId, sessionsDir) {
58804
+ const filePath = getSessionFilePath(sessionId, sessionsDir);
58805
+ let mtimeMs;
58806
+ try {
58807
+ mtimeMs = (await fs21.stat(filePath)).mtimeMs;
58808
+ } catch {
58809
+ return null;
58810
+ }
58811
+ const cached = previewCache.get(filePath);
58812
+ if (cached && cached.mtimeMs === mtimeMs) {
58813
+ return cached.preview;
58814
+ }
58815
+ const preview = await readSessionPromptPreview(sessionId, sessionsDir);
58816
+ previewCache.set(filePath, { mtimeMs, preview });
58817
+ return preview;
58818
+ }
58819
+
58645
58820
  // src/components/tree-selector.ts
58646
58821
  var RESET = "\x1B[0m";
58647
58822
  var INVERSE = "\x1B[7m";
@@ -58670,7 +58845,7 @@ function extractContent(entry) {
58670
58845
  }
58671
58846
  if (!entry.message) return "";
58672
58847
  const msg = entry.message;
58673
- const extractTextFromContent = (content) => {
58848
+ const extractTextFromContent2 = (content) => {
58674
58849
  if (typeof content === "string") return content;
58675
58850
  if (Array.isArray(content)) {
58676
58851
  const parts = [];
@@ -58692,10 +58867,10 @@ function extractContent(entry) {
58692
58867
  return "";
58693
58868
  };
58694
58869
  if (msg.role === "user") {
58695
- return extractTextFromContent(msg.content) || "(empty)";
58870
+ return extractTextFromContent2(msg.content) || "(empty)";
58696
58871
  }
58697
58872
  if (msg.role === "assistant") {
58698
- const textContent = extractTextFromContent(msg.content);
58873
+ const textContent = extractTextFromContent2(msg.content);
58699
58874
  if (textContent) {
58700
58875
  return textContent;
58701
58876
  }
@@ -60193,15 +60368,22 @@ async function handleResumeCommand(host) {
60193
60368
  return;
60194
60369
  }
60195
60370
  host.showSelector((done) => {
60196
- const selector = new SessionSelectorComponent(sessions, {
60197
- onSelect: async (sessionId) => {
60198
- await host.loadSession(sessionId);
60199
- done();
60371
+ const selector = new SessionSelectorComponent(
60372
+ sessions,
60373
+ {
60374
+ onSelect: async (sessionId) => {
60375
+ await host.loadSession(sessionId);
60376
+ done();
60377
+ },
60378
+ onCancel: () => {
60379
+ done();
60380
+ }
60200
60381
  },
60201
- onCancel: () => {
60202
- done();
60382
+ {
60383
+ loadPreview: (sessionId) => getSessionPromptPreview(sessionId),
60384
+ requestRender: () => host.ui.requestRender()
60203
60385
  }
60204
- });
60386
+ );
60205
60387
  return { component: selector, focus: selector.getSelectList() };
60206
60388
  });
60207
60389
  }
@@ -60212,6 +60394,8 @@ async function loadSession(host, sessionId) {
60212
60394
  host.showError(`Session not found: ${sessionId}`);
60213
60395
  return;
60214
60396
  }
60397
+ setControllerBusy(host, false);
60398
+ setWaitingForUser(host, false);
60215
60399
  const activeSession = host.sessionManager.getActiveSession();
60216
60400
  if (activeSession) {
60217
60401
  host.agent.sessionId = activeSession.id;
@@ -60355,7 +60539,19 @@ async function loadSession(host, sessionId) {
60355
60539
  host.ui.requestRender();
60356
60540
  }
60357
60541
  }
60358
- function updateTerminalTitle(host) {
60542
+ var TITLE_SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
60543
+ var TITLE_SPINNER_INTERVAL_MS = 80;
60544
+ var TITLE_WAITING_PREFIX = "\u23F8";
60545
+ var titleSpinnerTimers = /* @__PURE__ */ new WeakMap();
60546
+ var controllerBusyHosts = /* @__PURE__ */ new WeakSet();
60547
+ var waitingForUserHosts = /* @__PURE__ */ new WeakSet();
60548
+ function isHostBusy(host) {
60549
+ return host.submitLock || controllerBusyHosts.has(host);
60550
+ }
60551
+ function isWaitingForUser(host) {
60552
+ return waitingForUserHosts.has(host);
60553
+ }
60554
+ function updateTerminalTitle(host, spinnerFrame) {
60359
60555
  const activeSession = host.sessionManager.getActiveSession();
60360
60556
  if (!activeSession) {
60361
60557
  host.ui.terminal.setTitle("Pie");
@@ -60365,15 +60561,79 @@ function updateTerminalTitle(host) {
60365
60561
  activeSession,
60366
60562
  messages: host.sessionManager.getMessages()
60367
60563
  });
60368
- const activityState = host.submitLock ? "busy" : "ready";
60369
- host.ui.terminal.setTitle(`Pie \xB7 ${sessionLabel} [ms:session=${activeSession.id};state=${activityState}]`);
60564
+ const waiting = isWaitingForUser(host);
60565
+ const busy = isHostBusy(host);
60566
+ const activityState = waiting ? "waiting" : busy ? "busy" : "ready";
60567
+ const prefix = spinnerFrame ? `${spinnerFrame} ` : waiting ? `${TITLE_WAITING_PREFIX} ` : "";
60568
+ host.ui.terminal.setTitle(`${prefix}Pie \xB7 ${sessionLabel} [ms:session=${activeSession.id};state=${activityState}]`);
60569
+ }
60570
+ function stopTitleSpinner(host) {
60571
+ const timer = titleSpinnerTimers.get(host);
60572
+ if (timer) {
60573
+ clearInterval(timer);
60574
+ titleSpinnerTimers.delete(host);
60575
+ }
60576
+ }
60577
+ function startTitleSpinner(host) {
60578
+ stopTitleSpinner(host);
60579
+ let frameIndex = 0;
60580
+ const timer = setInterval(() => {
60581
+ const frame = TITLE_SPINNER_FRAMES[frameIndex % TITLE_SPINNER_FRAMES.length];
60582
+ updateTerminalTitle(host, frame);
60583
+ frameIndex++;
60584
+ }, TITLE_SPINNER_INTERVAL_MS);
60585
+ if (typeof timer.unref === "function") {
60586
+ timer.unref();
60587
+ }
60588
+ titleSpinnerTimers.set(host, timer);
60589
+ updateTerminalTitle(host, TITLE_SPINNER_FRAMES[0]);
60590
+ }
60591
+ function syncTitleActivity(host) {
60592
+ if (isWaitingForUser(host)) {
60593
+ stopTitleSpinner(host);
60594
+ host.updateTerminalTitle();
60595
+ return;
60596
+ }
60597
+ if (isHostBusy(host)) {
60598
+ if (titleSpinnerTimers.has(host)) {
60599
+ return;
60600
+ }
60601
+ startTitleSpinner(host);
60602
+ return;
60603
+ }
60604
+ stopTitleSpinner(host);
60605
+ host.updateTerminalTitle();
60370
60606
  }
60371
60607
  function setSubmitLock(host, locked) {
60372
60608
  if (host.submitLock === locked) {
60373
60609
  return;
60374
60610
  }
60375
60611
  host.submitLock = locked;
60376
- host.updateTerminalTitle();
60612
+ syncTitleActivity(host);
60613
+ }
60614
+ function setControllerBusy(host, busy) {
60615
+ const wasBusy = controllerBusyHosts.has(host);
60616
+ if (wasBusy === busy) {
60617
+ return;
60618
+ }
60619
+ if (busy) {
60620
+ controllerBusyHosts.add(host);
60621
+ } else {
60622
+ controllerBusyHosts.delete(host);
60623
+ }
60624
+ syncTitleActivity(host);
60625
+ }
60626
+ function setWaitingForUser(host, waiting) {
60627
+ const wasWaiting = waitingForUserHosts.has(host);
60628
+ if (wasWaiting === waiting) {
60629
+ return;
60630
+ }
60631
+ if (waiting) {
60632
+ waitingForUserHosts.add(host);
60633
+ } else {
60634
+ waitingForUserHosts.delete(host);
60635
+ }
60636
+ syncTitleActivity(host);
60377
60637
  }
60378
60638
  async function handleTreeCommand(host) {
60379
60639
  const entries = host.sessionManager.getEntries();
@@ -60510,7 +60770,7 @@ async function handleForkCommand(host) {
60510
60770
  }
60511
60771
 
60512
60772
  // src/commands/interactive-skill-commands.ts
60513
- import * as fs21 from "fs";
60773
+ import * as fs22 from "fs";
60514
60774
  import * as os4 from "os";
60515
60775
  import * as path20 from "path";
60516
60776
 
@@ -60854,7 +61114,7 @@ function expandSkillCommand(host, text) {
60854
61114
  const skill = host.skills.find((s) => s.name === skillName);
60855
61115
  if (!skill) return text;
60856
61116
  try {
60857
- const content = fs21.readFileSync(skill.filePath, "utf-8");
61117
+ const content = fs22.readFileSync(skill.filePath, "utf-8");
60858
61118
  const body = host.stripFrontmatter(content).trim();
60859
61119
  const skillBlock = `<skill name="${skill.name}" location="${skill.filePath}">
60860
61120
  References are relative to ${skill.baseDir}.
@@ -60924,13 +61184,13 @@ async function handleSkillsCreate(host, args) {
60924
61184
  const skillDir = path20.join(skillsDir, name);
60925
61185
  const skillFile = path20.join(skillDir, "SKILL.md");
60926
61186
  console.error(`[SkillsCreate] Creating at: ${skillFile}`);
60927
- if (fs21.existsSync(skillDir)) {
61187
+ if (fs22.existsSync(skillDir)) {
60928
61188
  host.showError(`Skill "${name}" already exists at ${skillDir}`);
60929
61189
  return;
60930
61190
  }
60931
- fs21.mkdirSync(skillDir, { recursive: true });
61191
+ fs22.mkdirSync(skillDir, { recursive: true });
60932
61192
  const template = createSkillTemplate(name, description);
60933
- fs21.writeFileSync(skillFile, template, "utf-8");
61193
+ fs22.writeFileSync(skillFile, template, "utf-8");
60934
61194
  console.error(`[SkillsCreate] Successfully created skill`);
60935
61195
  host.chatContainer.addChild(new Spacer(1));
60936
61196
  host.chatContainer.addChild(new Text(theme.fg("accent", `\u2713 Created skill: ${name}`), 1, 0));
@@ -61355,6 +61615,8 @@ function showThinkingLevelSelector(host) {
61355
61615
  });
61356
61616
  }
61357
61617
  async function handleClearCommand(host) {
61618
+ host.setControllerBusy(false);
61619
+ host.setWaitingForUser(false);
61358
61620
  host.executionState.clear();
61359
61621
  host.executionReminder = null;
61360
61622
  host.agent.reset();
@@ -62401,7 +62663,7 @@ function setupInteractiveEditorSubmitHandler(host) {
62401
62663
  }
62402
62664
 
62403
62665
  // src/input/interactive-file-pipeline.ts
62404
- import * as fs24 from "fs";
62666
+ import * as fs25 from "fs";
62405
62667
  import * as path23 from "path";
62406
62668
 
62407
62669
  // src/components/file-picker.ts
@@ -62623,7 +62885,7 @@ var FilePickerComponent = class extends Container {
62623
62885
  };
62624
62886
 
62625
62887
  // src/files/commands/file-commands.ts
62626
- import * as fs22 from "node:fs";
62888
+ import * as fs23 from "node:fs";
62627
62889
  import * as path21 from "node:path";
62628
62890
  var FileCommands = class {
62629
62891
  context;
@@ -62640,7 +62902,7 @@ var FileCommands = class {
62640
62902
  return;
62641
62903
  }
62642
62904
  const filePath = resolvePath(parsed.path);
62643
- if (!fs22.existsSync(filePath)) {
62905
+ if (!fs23.existsSync(filePath)) {
62644
62906
  this.context.showError(`File not found: ${parsed.path}`);
62645
62907
  return;
62646
62908
  }
@@ -62679,7 +62941,7 @@ var FileCommands = class {
62679
62941
  return;
62680
62942
  }
62681
62943
  const resolvedPath = resolvePath(filePath);
62682
- if (!fs22.existsSync(resolvedPath)) {
62944
+ if (!fs23.existsSync(resolvedPath)) {
62683
62945
  this.context.showError(`File not found: ${filePath}`);
62684
62946
  return;
62685
62947
  }
@@ -62710,7 +62972,7 @@ var FileCommands = class {
62710
62972
  return;
62711
62973
  }
62712
62974
  const resolvedPath = resolvePath(parsed.path);
62713
- if (!fs22.existsSync(resolvedPath)) {
62975
+ if (!fs23.existsSync(resolvedPath)) {
62714
62976
  this.context.showError(`File not found: ${parsed.path}`);
62715
62977
  return;
62716
62978
  }
@@ -63188,7 +63450,7 @@ var FileStatusMonitor = class {
63188
63450
  };
63189
63451
 
63190
63452
  // src/files/mention/mention-handler.ts
63191
- import * as fs23 from "node:fs";
63453
+ import * as fs24 from "node:fs";
63192
63454
  import * as path22 from "node:path";
63193
63455
  var MentionHandler = class {
63194
63456
  fileManager;
@@ -63558,8 +63820,8 @@ var MentionHandler = class {
63558
63820
  }
63559
63821
  if (this.isPath(query)) {
63560
63822
  const resolvedPath = resolvePath(query);
63561
- if (fs23.existsSync(resolvedPath)) {
63562
- const stats = fs23.statSync(resolvedPath);
63823
+ if (fs24.existsSync(resolvedPath)) {
63824
+ const stats = fs24.statSync(resolvedPath);
63563
63825
  if (stats.isFile()) {
63564
63826
  const type = FileCache.getFileTypeFromName(resolvedPath);
63565
63827
  const name = path22.basename(resolvedPath);
@@ -63583,7 +63845,7 @@ var MentionHandler = class {
63583
63845
  return void 0;
63584
63846
  }
63585
63847
  const queryPath = this.isPath(query) ? resolvePath(query) : void 0;
63586
- const filter = queryPath ? fs23.existsSync(queryPath) && fs23.statSync(queryPath).isDirectory() ? "" : path22.basename(queryPath) : query;
63848
+ const filter = queryPath ? fs24.existsSync(queryPath) && fs24.statSync(queryPath).isDirectory() ? "" : path22.basename(queryPath) : query;
63587
63849
  const entries = this.fileManager.listPathEntries(currentDir, filter);
63588
63850
  const options = [];
63589
63851
  const homeDir = process.env.HOME || "";
@@ -63624,7 +63886,7 @@ var MentionHandler = class {
63624
63886
  getBrowserDirectory(query = this.currentQuery) {
63625
63887
  if (this.isPath(query)) {
63626
63888
  const resolvedPath = resolvePath(query);
63627
- if (fs23.existsSync(resolvedPath) && fs23.statSync(resolvedPath).isDirectory()) {
63889
+ if (fs24.existsSync(resolvedPath) && fs24.statSync(resolvedPath).isDirectory()) {
63628
63890
  return resolvedPath;
63629
63891
  }
63630
63892
  return path22.dirname(resolvedPath);
@@ -63988,13 +64250,13 @@ function convertPreparedAttachmentItems(items) {
63988
64250
  break;
63989
64251
  case "image": {
63990
64252
  if (!item.data && !item.path) return void 0;
63991
- const data = item.data ?? fs24.readFileSync(item.path, "base64");
64253
+ const data = item.data ?? fs25.readFileSync(item.path, "base64");
63992
64254
  converted.push({ type: "image", data, mimeType: item.mimeType });
63993
64255
  break;
63994
64256
  }
63995
64257
  case "video": {
63996
64258
  if (!item.data && !item.path) return void 0;
63997
- const data = item.data ?? fs24.readFileSync(item.path, "base64");
64259
+ const data = item.data ?? fs25.readFileSync(item.path, "base64");
63998
64260
  converted.push({ type: "video", data, mimeType: item.mimeType });
63999
64261
  break;
64000
64262
  }
@@ -64631,6 +64893,12 @@ function classifyCliFailure(context) {
64631
64893
  terminal: false
64632
64894
  });
64633
64895
  }
64896
+ if (errorMessage3.includes(EMPTY_ASSISTANT_CONTENT_ERROR)) {
64897
+ return createClassification("provider_transient", errorMessage3, {
64898
+ retryable: true,
64899
+ terminal: false
64900
+ });
64901
+ }
64634
64902
  if (PROVIDER_TRANSIENT_ERROR_PATTERN.test(errorMessage3)) {
64635
64903
  return createClassification("provider_transient", errorMessage3, {
64636
64904
  retryable: true,
@@ -65320,6 +65588,7 @@ function createInteractiveAgentSessionController(host) {
65320
65588
  host.updatePendingMessagesDisplay();
65321
65589
  host.safeRequestRender();
65322
65590
  } else if (event.type === "queued_turn_dispatched") {
65591
+ host.setControllerBusy(true);
65323
65592
  if (event.queuedInput.visibility === "user") {
65324
65593
  host.chatContainer.addChild(new UserMessageComponent(event.queuedInput.displayText));
65325
65594
  host.sessionTrace.noteDispatchStart({
@@ -65411,6 +65680,7 @@ function createInteractiveAgentSessionController(host) {
65411
65680
  host.showStatus("Todo list preserved. Send 'continue' when you want to resume it.");
65412
65681
  }
65413
65682
  host.showError(event.failure.message);
65683
+ host.setControllerBusy(false);
65414
65684
  } else if (event.type === "turn_cancelled") {
65415
65685
  const outcome = host.executionState.abort();
65416
65686
  host.logDebug("execution:turn_cancelled", {
@@ -65426,6 +65696,7 @@ function createInteractiveAgentSessionController(host) {
65426
65696
  if (outcome.terminalSummary) {
65427
65697
  host.appendWarningSummary(outcome.terminalSummary);
65428
65698
  }
65699
+ host.setControllerBusy(false);
65429
65700
  } else if (event.type === "runtime_guard_triggered") {
65430
65701
  host.sessionTrace.noteStalled("runtime_guard_triggered", {
65431
65702
  toolName: event.toolName,
@@ -65447,6 +65718,7 @@ function createInteractiveAgentSessionController(host) {
65447
65718
  const prefix = event.reason === "overflow" ? "Context overflow recovery failed" : "Auto-compaction failed";
65448
65719
  host.showError(`${prefix}: ${event.errorMessage}`);
65449
65720
  host.footer.setState({ status: "ready" });
65721
+ host.setControllerBusy(false);
65450
65722
  return;
65451
65723
  }
65452
65724
  host.resetFileObservationState();
@@ -65468,8 +65740,15 @@ function createInteractiveAgentSessionController(host) {
65468
65740
  if (!event.willRetry && !event.result?.aborted) {
65469
65741
  host.showStatus("Context auto-compacted");
65470
65742
  }
65471
- } else if (event.type === "auto_continue_scheduled" && event.reason === "todo_closure") {
65472
- host.showStatus("Continuing active todo list");
65743
+ } else if (event.type === "auto_continue_scheduled") {
65744
+ host.setControllerBusy(true);
65745
+ if (event.reason === "todo_closure") {
65746
+ host.showStatus("Continuing active todo list");
65747
+ }
65748
+ } else if (event.type === "auto_continue_skipped") {
65749
+ if (event.reason !== "queued_messages" && event.reason !== "runtime_busy" && !host.isWaitingForUserInteraction()) {
65750
+ host.setControllerBusy(false);
65751
+ }
65473
65752
  }
65474
65753
  }
65475
65754
  });
@@ -65750,11 +66029,15 @@ function installInteractiveInteractionHandler(host) {
65750
66029
  registerInteractionHandler(async (request) => {
65751
66030
  const beginWaitingForUser = () => {
65752
66031
  host.activeInteractionCount++;
66032
+ host.setWaitingForUser(true);
65753
66033
  host.footer.setState({ lifecycleEvent: "waiting_for_user_input" });
65754
66034
  host.safeRequestRender();
65755
66035
  };
65756
66036
  const endWaitingForUser = () => {
65757
66037
  host.activeInteractionCount = Math.max(0, host.activeInteractionCount - 1);
66038
+ if (host.activeInteractionCount === 0) {
66039
+ host.setWaitingForUser(false);
66040
+ }
65758
66041
  host.footer.setState({ lifecycleEvent: "tool_execution_start" });
65759
66042
  host.safeRequestRender();
65760
66043
  };
@@ -66059,7 +66342,7 @@ var AttachmentResolver = class {
66059
66342
  };
66060
66343
 
66061
66344
  // src/extensions/loader.ts
66062
- import * as fs25 from "node:fs";
66345
+ import * as fs26 from "node:fs";
66063
66346
  import * as os5 from "os";
66064
66347
  import * as path24 from "path";
66065
66348
  import { pathToFileURL } from "node:url";
@@ -66243,7 +66526,7 @@ function normalizeExtensionImportPath(extensionPath) {
66243
66526
  }
66244
66527
  async function loadExtension(extensionPath, cwd, uiContext, abortFn, isIdleFn, hasUI, actions) {
66245
66528
  const resolvedPath = resolvePath2(extensionPath, cwd);
66246
- if (!fs25.existsSync(resolvedPath)) {
66529
+ if (!fs26.existsSync(resolvedPath)) {
66247
66530
  return { extension: null, error: `Extension not found: ${extensionPath}` };
66248
66531
  }
66249
66532
  try {
@@ -66264,12 +66547,12 @@ async function loadExtension(extensionPath, cwd, uiContext, abortFn, isIdleFn, h
66264
66547
  }
66265
66548
  }
66266
66549
  function discoverExtensionsInDir(dir) {
66267
- if (!fs25.existsSync(dir)) {
66550
+ if (!fs26.existsSync(dir)) {
66268
66551
  return [];
66269
66552
  }
66270
66553
  const discovered = [];
66271
66554
  try {
66272
- const entries = fs25.readdirSync(dir, { withFileTypes: true });
66555
+ const entries = fs26.readdirSync(dir, { withFileTypes: true });
66273
66556
  for (const entry of entries) {
66274
66557
  const entryPath = path24.join(dir, entry.name);
66275
66558
  if (entry.isFile() && (entry.name.endsWith(".cjs") || entry.name.endsWith(".js") || entry.name.endsWith(".ts"))) {
@@ -66278,13 +66561,13 @@ function discoverExtensionsInDir(dir) {
66278
66561
  }
66279
66562
  if (entry.isDirectory()) {
66280
66563
  const packageJsonPath = path24.join(entryPath, "package.json");
66281
- if (fs25.existsSync(packageJsonPath)) {
66564
+ if (fs26.existsSync(packageJsonPath)) {
66282
66565
  try {
66283
- const pkg = JSON.parse(fs25.readFileSync(packageJsonPath, "utf-8"));
66566
+ const pkg = JSON.parse(fs26.readFileSync(packageJsonPath, "utf-8"));
66284
66567
  const manifest = pkg.pie;
66285
66568
  if (manifest?.main) {
66286
66569
  const mainPath = path24.resolve(entryPath, manifest.main);
66287
- if (fs25.existsSync(mainPath)) {
66570
+ if (fs26.existsSync(mainPath)) {
66288
66571
  discovered.push({
66289
66572
  entryPath: mainPath,
66290
66573
  manifestName: manifest.name || pkg.name
@@ -66296,17 +66579,17 @@ function discoverExtensionsInDir(dir) {
66296
66579
  }
66297
66580
  }
66298
66581
  const indexCjs = path24.join(entryPath, "index.cjs");
66299
- if (fs25.existsSync(indexCjs)) {
66582
+ if (fs26.existsSync(indexCjs)) {
66300
66583
  discovered.push({ entryPath: indexCjs });
66301
66584
  continue;
66302
66585
  }
66303
66586
  const indexJs = path24.join(entryPath, "index.js");
66304
- if (fs25.existsSync(indexJs)) {
66587
+ if (fs26.existsSync(indexJs)) {
66305
66588
  discovered.push({ entryPath: indexJs });
66306
66589
  continue;
66307
66590
  }
66308
66591
  const indexTs = path24.join(entryPath, "index.ts");
66309
- if (fs25.existsSync(indexTs)) {
66592
+ if (fs26.existsSync(indexTs)) {
66310
66593
  discovered.push({ entryPath: indexTs });
66311
66594
  continue;
66312
66595
  }
@@ -66355,11 +66638,11 @@ async function loadExtensions(configuredPaths, cwd, uiContext, abortFn, isIdleFn
66355
66638
  }
66356
66639
  for (const p of configuredPaths) {
66357
66640
  const resolved = resolvePath2(p, cwd);
66358
- if (!fs25.existsSync(resolved)) {
66641
+ if (!fs26.existsSync(resolved)) {
66359
66642
  errors.push({ path: p, error: `Extension path not found: ${p}` });
66360
66643
  continue;
66361
66644
  }
66362
- if (!fs25.statSync(resolved).isDirectory()) {
66645
+ if (!fs26.statSync(resolved).isDirectory()) {
66363
66646
  errors.push({ path: p, error: `Extension path must be a directory: ${p}` });
66364
66647
  continue;
66365
66648
  }
@@ -67343,7 +67626,7 @@ var InteractiveMode = class {
67343
67626
  if (savedLevel) {
67344
67627
  this.thinkingLevel = savedLevel;
67345
67628
  }
67346
- const { Agent } = await import("./chunks/src-2FHZO63Y.js");
67629
+ const { Agent } = await import("./chunks/src-UCXJ4C6P.js");
67347
67630
  const activeSession = this.sessionManager.getActiveSession();
67348
67631
  this.agent = new Agent({
67349
67632
  initialState: {
@@ -67557,6 +67840,12 @@ var InteractiveMode = class {
67557
67840
  setSubmitLock(locked) {
67558
67841
  return setSubmitLock(this, locked);
67559
67842
  }
67843
+ setControllerBusy(busy) {
67844
+ return setControllerBusy(this, busy);
67845
+ }
67846
+ setWaitingForUser(waiting) {
67847
+ return setWaitingForUser(this, waiting);
67848
+ }
67560
67849
  async handleTreeCommand() {
67561
67850
  return handleTreeCommand(this);
67562
67851
  }
@@ -68021,7 +68310,7 @@ async function runPrintMode(params) {
68021
68310
  `);
68022
68311
  console.log("Assistant: ");
68023
68312
  }
68024
- const { Agent: AgentClass } = await import("./chunks/src-2FHZO63Y.js");
68313
+ const { Agent: AgentClass } = await import("./chunks/src-UCXJ4C6P.js");
68025
68314
  let agent;
68026
68315
  const printModeExtensions = await loadPrintModeExtensions({
68027
68316
  cwd: runtime.cwd,
@@ -68407,6 +68696,9 @@ async function runJsonEventsMode(params) {
68407
68696
  let trace;
68408
68697
  let lastRetryEvent;
68409
68698
  let mockActiveEntryId;
68699
+ let thinkingLevel = "off";
68700
+ let defaultRuntime;
68701
+ let defaultModelState;
68410
68702
  const noProgressTimeoutMs = Number(process.env.PIE_JSON_EVENTS_NO_PROGRESS_MS || 6e5);
68411
68703
  const mockResponseDelayMs = Number(process.env.PIE_TEST_MOCK_RESPONSE_DELAY_MS || 0);
68412
68704
  writeEvent({ type: "agent.ready", sessionId });
@@ -68752,10 +69044,14 @@ async function runJsonEventsMode(params) {
68752
69044
  if (!runtime) {
68753
69045
  throw new Error("JSON events mode requires a CLI runtime");
68754
69046
  }
69047
+ if (defaultRuntime !== runtime) {
69048
+ defaultRuntime = runtime;
69049
+ defaultModelState = configuredDefaultModelState(runtime);
69050
+ }
68755
69051
  if (runtime.initialModel.unconfigured || controller) {
68756
69052
  return;
68757
69053
  }
68758
- const { Agent: AgentClass } = await import("./chunks/src-2FHZO63Y.js");
69054
+ const { Agent: AgentClass } = await import("./chunks/src-UCXJ4C6P.js");
68759
69055
  const jsonModeExtensions = await loadJsonModeExtensions({ runtime, getAgent: () => agent });
68760
69056
  const tools = [...runtime.tools, ...jsonModeExtensions.extensionTools];
68761
69057
  recordCliCompositionStep(runtime.compositionTrace, {
@@ -68780,7 +69076,7 @@ async function runJsonEventsMode(params) {
68780
69076
  systemPrompt: baseSystemPrompt,
68781
69077
  model: runtime.model,
68782
69078
  tools,
68783
- thinkingLevel: "off"
69079
+ thinkingLevel
68784
69080
  },
68785
69081
  apiKey: runtime.apiKey,
68786
69082
  streamFn: params.streamFn
@@ -68833,6 +69129,77 @@ async function runJsonEventsMode(params) {
68833
69129
  controller.updateRuntimeContext({ tools: agent.state.tools });
68834
69130
  disposeSemanticSubscription = agent.subscribeSemantic(handleSemanticEvent);
68835
69131
  }
69132
+ function metadataSelection(metadata, key) {
69133
+ if (!metadata || !(key in metadata)) return void 0;
69134
+ const value = metadata[key];
69135
+ if (value === null) return null;
69136
+ if (typeof value !== "string") throw new Error(`${key} must be a string or null`);
69137
+ const normalized = value.trim();
69138
+ return normalized && normalized !== "default" ? normalized : null;
69139
+ }
69140
+ function configuredDefaultModelState(runtime2) {
69141
+ const model = runtime2.initialModel.model ?? runtime2.model;
69142
+ const apiKey = runtime2.initialModel.apiKey || runtime2.modelRegistry.getApiKey(model) || runtime2.apiKey;
69143
+ return {
69144
+ provider: runtime2.initialModel.provider || model.provider || runtime2.provider,
69145
+ modelId: runtime2.initialModel.modelId || model.id || runtime2.modelId,
69146
+ model,
69147
+ apiKey
69148
+ };
69149
+ }
69150
+ function parseRequestedModel(value) {
69151
+ const separator = value.indexOf("/");
69152
+ if (separator <= 0 || separator === value.length - 1) return void 0;
69153
+ return {
69154
+ provider: value.slice(0, separator),
69155
+ modelId: value.slice(separator + 1)
69156
+ };
69157
+ }
69158
+ function applyRuntimeSelection(message) {
69159
+ if (!runtime || !agent) return;
69160
+ const requestedModel = metadataSelection(message.metadata, "model");
69161
+ const requestedThinkingLevel = metadataSelection(message.metadata, "thinkingLevel");
69162
+ if (requestedModel !== void 0) {
69163
+ if (requestedModel === null) {
69164
+ const defaults = defaultModelState;
69165
+ if (defaults) {
69166
+ agent.setModel(defaults.model);
69167
+ agent.apiKey = defaults.apiKey;
69168
+ runtime.model = defaults.model;
69169
+ runtime.provider = defaults.provider;
69170
+ runtime.modelId = defaults.modelId;
69171
+ runtime.apiKey = defaults.apiKey;
69172
+ }
69173
+ } else {
69174
+ const parsed = parseRequestedModel(requestedModel);
69175
+ if (!parsed) throw new Error(`model must use profile/modelId format: ${requestedModel}`);
69176
+ const { provider, modelId } = parsed;
69177
+ const model = runtime.modelRegistry.find(provider, modelId);
69178
+ if (!model) throw new Error(`Model "${requestedModel}" not found`);
69179
+ const apiKey = runtime.modelRegistry.getApiKey(model);
69180
+ agent.setModel(model);
69181
+ agent.apiKey = apiKey;
69182
+ runtime.model = model;
69183
+ runtime.provider = provider;
69184
+ runtime.modelId = modelId;
69185
+ runtime.apiKey = apiKey;
69186
+ }
69187
+ }
69188
+ if (requestedThinkingLevel !== void 0) {
69189
+ const nextLevel = requestedThinkingLevel === null ? "off" : requestedThinkingLevel;
69190
+ if (!isThinkingLevel(nextLevel)) throw new Error(`Unsupported thinkingLevel: ${nextLevel}`);
69191
+ thinkingLevel = nextLevel;
69192
+ applyThinkingLevel({
69193
+ level: thinkingLevel,
69194
+ agent,
69195
+ settingsManager: runtime.settingsManager,
69196
+ sessionManager: runtime.sessionManager,
69197
+ model: runtime.model
69198
+ });
69199
+ } else {
69200
+ syncSessionModelMetadata(runtime.sessionManager, runtime.model, thinkingLevel);
69201
+ }
69202
+ }
68836
69203
  async function runTurn(message) {
68837
69204
  if (isSessionMismatch(message)) {
68838
69205
  writeEvent({
@@ -68915,6 +69282,14 @@ async function runJsonEventsMode(params) {
68915
69282
  if (activeTurn === turn) activeTurn = null;
68916
69283
  return;
68917
69284
  }
69285
+ try {
69286
+ applyRuntimeSelection(message);
69287
+ } catch (error) {
69288
+ finalize("failed", error instanceof Error ? error.message : String(error));
69289
+ if (activeTurn === turn) emitSettled(turn);
69290
+ if (activeTurn === turn) activeTurn = null;
69291
+ return;
69292
+ }
68918
69293
  const progressTimer = setInterval(() => {
68919
69294
  const turn2 = activeTurn;
68920
69295
  if (!turn2 || turn2.finalized) return;
@@ -69062,8 +69437,8 @@ var logError = (msg, err) => {
69062
69437
  const logPath = getRuntimeLogPath();
69063
69438
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
69064
69439
  const stack = err instanceof Error ? err.stack || "" : "";
69065
- fs26.mkdirSync(path26.dirname(logPath), { recursive: true });
69066
- fs26.appendFileSync(logPath, `[${timestamp}] ${msg}
69440
+ fs27.mkdirSync(path26.dirname(logPath), { recursive: true });
69441
+ fs27.appendFileSync(logPath, `[${timestamp}] ${msg}
69067
69442
  ${stack}
69068
69443
 
69069
69444
  `);
@@ -69135,6 +69510,12 @@ async function runModelsCommand(args) {
69135
69510
  }
69136
69511
  if (subcommand === "validate") {
69137
69512
  const result = validateModelsConfig({ path: parsed.path });
69513
+ if (parsed.json) {
69514
+ const probe = result.ok && parsed.probe ? await probeModelsConfig({ path: parsed.path, probe: parsed.probe }) : void 0;
69515
+ console.log(JSON.stringify({ ...result, ...probe ? { probe } : {} }, null, 2));
69516
+ if (!result.ok || probe?.status === "failed") process.exitCode = 1;
69517
+ return;
69518
+ }
69138
69519
  if (!result.ok) {
69139
69520
  console.error(result.message);
69140
69521
  process.exitCode = 1;
@@ -69175,7 +69556,7 @@ async function runModelsCommand(args) {
69175
69556
  }
69176
69557
  console.log(`Usage:
69177
69558
  pie models init [--path <path>] [--force] [--stdout]
69178
- pie models validate [--path <path>] [--probe web_search]`);
69559
+ pie models validate [--path <path>] [--probe web_search] [--json]`);
69179
69560
  }
69180
69561
  function parseRepeatedFlag(args, flag) {
69181
69562
  const values = [];
@@ -69207,7 +69588,7 @@ async function createCliTestStreamFnFromEnv() {
69207
69588
  if (!process.env.PIE_TEST_MOCK_STREAM_SEQUENCE) {
69208
69589
  return void 0;
69209
69590
  }
69210
- const { createTestStreamFnFromSequenceEnv } = await import("./chunks/test-stream-UW74PA6T.js");
69591
+ const { createTestStreamFnFromSequenceEnv } = await import("./chunks/test-stream-UKULOPZB.js");
69211
69592
  return createTestStreamFnFromSequenceEnv();
69212
69593
  }
69213
69594
  async function startChat(initialPrompt, testCommand) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cydm/pie",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
4
4
  "description": "Pie AI Agent CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,7 +16,7 @@
16
16
  "validate:models": "tsx scripts/validate-models-config.ts",
17
17
  "test": "npm run test:offline",
18
18
  "pretest:offline": "npm run build --workspace @pie/agent-framework && npm run build --workspace @pie/shared-headless-capabilities && npm run build",
19
- "test:offline": "node --test --import tsx 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-extension.test.ts test/document-attachment-extension.test.ts test/auto-compact-overflow.test.ts test/hierarchical-command-system.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/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/code-intel-typescript-provider.test.ts test/init-extension-contract.test.ts test/skills-runtime.test.ts test/cross-host-parity.test.ts test/tool-name-rendering.test.ts test/tools-registry.test.ts test/system-prompt-contract.test.ts test/daily-agent-smoke.terminal.test.ts",
19
+ "test:offline": "node --test --import tsx 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-extension.test.ts test/document-attachment-extension.test.ts test/auto-compact-overflow.test.ts test/hierarchical-command-system.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/session-preview.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/code-intel-typescript-provider.test.ts test/init-extension-contract.test.ts test/skills-runtime.test.ts test/cross-host-parity.test.ts test/tool-name-rendering.test.ts test/tools-registry.test.ts test/system-prompt-contract.test.ts test/daily-agent-smoke.terminal.test.ts",
20
20
  "test:all": "npm run test:offline && npm run test:terminal:vitest",
21
21
  "test:terminal:vitest": "vitest run test/mention-file-select.terminal.test.ts test/tool-partial-display.terminal.test.ts test/viewport-position-final.test.ts",
22
22
  "test:todo-tui": "PIE_REAL_TODO_TUI=1 node --test --import tsx test/todo-closure.terminal.test.ts",