@cydm/pie 2.6.5 → 2.6.6

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.
@@ -3,7 +3,7 @@ import {
3
3
  EventStream,
4
4
  streamSimple,
5
5
  validateToolArguments
6
- } from "./chunk-5OXH6NUH.js";
6
+ } from "./chunk-G5B6D35K.js";
7
7
 
8
8
  // ../../packages/agent-core/src/agent-loop.ts
9
9
  function createLoopErrorMessage(error, config, signal) {
@@ -8,7 +8,7 @@ import {
8
8
  createSharedWebSearchTool,
9
9
  interpretShellExit,
10
10
  requestInteraction
11
- } from "./chunk-QKSK5K5N.js";
11
+ } from "./chunk-H6BAM2N4.js";
12
12
  import {
13
13
  getBuiltinDir,
14
14
  getConfigDir
@@ -6,8 +6,8 @@ import {
6
6
  bindToolCallerIdentity,
7
7
  createToolCallerIdentity,
8
8
  getToolCallerIdentity
9
- } from "./chunk-AETQBDEG.js";
10
- import "./chunk-5OXH6NUH.js";
9
+ } from "./chunk-KEARZX6F.js";
10
+ import "./chunk-G5B6D35K.js";
11
11
  import "./chunk-XXGYUYXI.js";
12
12
  import "./chunk-LZQXQOPJ.js";
13
13
  export {
@@ -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-5OXH6NUH.js";
4
+ } from "./chunk-G5B6D35K.js";
5
5
  import "./chunk-XXGYUYXI.js";
6
6
  import "./chunk-LZQXQOPJ.js";
7
7
 
package/dist/cli.js CHANGED
@@ -7,10 +7,11 @@ import {
7
7
  createCliWebResearchHealthStore,
8
8
  formatSize,
9
9
  truncateHeadTail
10
- } from "./chunks/chunk-TFRQE7UQ.js";
10
+ } from "./chunks/chunk-OWSXALCG.js";
11
11
  import {
12
12
  AGENTS_CONTEXT_FILE_NAME,
13
13
  AgentSessionController,
14
+ AttentionCoordinator,
14
15
  BUILTIN_TOOL_CAPABILITY_METADATA,
15
16
  ExtensionResourceScope,
16
17
  FileSessionStore,
@@ -46,6 +47,8 @@ import {
46
47
  getAutoCompactTokenLimit,
47
48
  getExtensionEnablementEntry,
48
49
  hasInteractionHandler,
50
+ interactionAttentionReason,
51
+ interactionAttentionResolution,
49
52
  isCompactSummaryMessage,
50
53
  isExtensionEnabled,
51
54
  maybeAdvanceTodoExecutionState,
@@ -60,8 +63,8 @@ import {
60
63
  setExtensionEnabledInSettings,
61
64
  shouldPreserveExecutionStateForUserText,
62
65
  supersedeExecutionState
63
- } from "./chunks/chunk-QKSK5K5N.js";
64
- import "./chunks/chunk-AETQBDEG.js";
66
+ } from "./chunks/chunk-H6BAM2N4.js";
67
+ import "./chunks/chunk-KEARZX6F.js";
65
68
  import {
66
69
  Deref,
67
70
  EMPTY_ASSISTANT_CONTENT_ERROR,
@@ -85,7 +88,7 @@ import {
85
88
  setLogger,
86
89
  sortToolModelCandidatesByCapability,
87
90
  type_exports
88
- } from "./chunks/chunk-5OXH6NUH.js";
91
+ } from "./chunks/chunk-G5B6D35K.js";
89
92
  import {
90
93
  VERSION,
91
94
  getAgentDir,
@@ -53606,8 +53609,7 @@ function mergeDeltaNode(load, cur, disk) {
53606
53609
  const diskValue = own(merged, key);
53607
53610
  if (after === void 0) {
53608
53611
  if (isPlainObject(before) && isPlainObject(diskValue)) {
53609
- const pruned = { ...diskValue };
53610
- for (const nestedKey of Object.keys(before)) delete pruned[nestedKey];
53612
+ const pruned = applyNodeDeletion(before, diskValue);
53611
53613
  if (Object.keys(pruned).length === 0) delete merged[key];
53612
53614
  else setOwnDataProperty(merged, key, pruned);
53613
53615
  } else {
@@ -53626,6 +53628,22 @@ function mergeDeltaNode(load, cur, disk) {
53626
53628
  function setOwnDataProperty(target, key, value) {
53627
53629
  Object.defineProperty(target, key, { value, writable: true, enumerable: true, configurable: true });
53628
53630
  }
53631
+ function applyNodeDeletion(before, diskNode) {
53632
+ const pruned = { ...diskNode };
53633
+ for (const key of Object.keys(before)) {
53634
+ if (!Object.hasOwn(pruned, key)) continue;
53635
+ const beforeChild = before[key];
53636
+ const diskChild = pruned[key];
53637
+ if (isPlainObject(beforeChild) && isPlainObject(diskChild)) {
53638
+ const nested = applyNodeDeletion(beforeChild, diskChild);
53639
+ if (Object.keys(nested).length === 0) delete pruned[key];
53640
+ else setOwnDataProperty(pruned, key, nested);
53641
+ } else {
53642
+ delete pruned[key];
53643
+ }
53644
+ }
53645
+ return pruned;
53646
+ }
53629
53647
  function cloneJsonDocument(value) {
53630
53648
  return JSON.parse(JSON.stringify(value));
53631
53649
  }
@@ -55292,7 +55310,7 @@ function runCapabilitiesCommand(args) {
55292
55310
  import fs8 from "node:fs";
55293
55311
 
55294
55312
  // src/session-control.ts
55295
- import * as fs7 from "node:fs";
55313
+ import fs7 from "fs";
55296
55314
  import * as path7 from "node:path";
55297
55315
  var SessionControlError = class extends Error {
55298
55316
  constructor(code, message, recoverable = sessionControlErrorRecoverable(code)) {
@@ -55700,11 +55718,12 @@ function recoverOnePublishJournal(params) {
55700
55718
  warn(message);
55701
55719
  return { action: "unreadable-journal", journal: journalName, message };
55702
55720
  }
55703
- const dirExists = (id) => {
55721
+ const entryKind = (id) => {
55704
55722
  try {
55705
- return fs7.lstatSync(path7.join(params.sessionsDir, id)).isDirectory();
55706
- } catch {
55707
- return false;
55723
+ return fs7.lstatSync(path7.join(params.sessionsDir, id)).isDirectory() ? "directory" : "aliased";
55724
+ } catch (error) {
55725
+ const code = error?.code;
55726
+ return code === "ENOENT" ? "absent" : "unknown";
55708
55727
  }
55709
55728
  };
55710
55729
  const removeSessionDir = (id) => {
@@ -55713,9 +55732,23 @@ function recoverOnePublishJournal(params) {
55713
55732
  const removeJournal = () => {
55714
55733
  fs7.rmSync(params.journalPath, { force: true });
55715
55734
  };
55716
- const targetExists = dirExists(record.targetId);
55717
- const backupExists = record.backupDir ? dirExists(record.backupDir) : false;
55718
- const stagingExists = dirExists(record.stagingId);
55735
+ const targetKind = entryKind(record.targetId);
55736
+ const backupKind = record.backupDir ? entryKind(record.backupDir) : "absent";
55737
+ const stagingKind = entryKind(record.stagingId);
55738
+ const targetExists = targetKind === "directory";
55739
+ const backupExists = backupKind === "directory";
55740
+ const stagingExists = stagingKind === "directory";
55741
+ const ambiguous = (kind) => kind === "aliased" || kind === "unknown" ? kind : null;
55742
+ const ambiguousKinds = [
55743
+ ambiguous(targetKind) ? `target(${ambiguous(targetKind)})` : null,
55744
+ ambiguous(backupKind) ? `backup(${ambiguous(backupKind)})` : null,
55745
+ ambiguous(stagingKind) ? `staging(${ambiguous(stagingKind)})` : null
55746
+ ].filter(Boolean).join("+");
55747
+ if (ambiguousKinds !== "") {
55748
+ const message = `[session-control] Interrupted publish journal ${journalName} references an ambiguous ${ambiguousKinds} entry (target=${record.targetId}, backup=${record.backupDir ?? "none"}, staging=${record.stagingId}); nothing was deleted \u2014 inspect ${params.sessionsDir} manually`;
55749
+ warn(message);
55750
+ return { action: "ambiguous-preserved", targetId: record.targetId, message };
55751
+ }
55719
55752
  try {
55720
55753
  if (targetExists && !stagingExists && record.failedAt === void 0) {
55721
55754
  if (backupExists && record.backupDir) removeSessionDir(record.backupDir);
@@ -64756,7 +64789,7 @@ function restoreInteractiveSessionState(options) {
64756
64789
  }
64757
64790
 
64758
64791
  // src/keybindings.ts
64759
- import { existsSync as existsSync9, readFileSync as readFileSync8 } from "fs";
64792
+ import { existsSync as existsSync8, readFileSync as readFileSync7 } from "fs";
64760
64793
  import { join as join8 } from "path";
64761
64794
  var DEFAULT_APP_KEYBINDINGS = {
64762
64795
  interrupt: "escape",
@@ -64840,9 +64873,9 @@ var KeybindingsManager = class _KeybindingsManager {
64840
64873
  return new _KeybindingsManager(config);
64841
64874
  }
64842
64875
  static loadFromFile(path34) {
64843
- if (!existsSync9(path34)) return {};
64876
+ if (!existsSync8(path34)) return {};
64844
64877
  try {
64845
- return JSON.parse(readFileSync8(path34, "utf-8"));
64878
+ return JSON.parse(readFileSync7(path34, "utf-8"));
64846
64879
  } catch {
64847
64880
  return {};
64848
64881
  }
@@ -71994,60 +72027,46 @@ function formatFooterLifecycleEvent(event) {
71994
72027
  }
71995
72028
  }
71996
72029
 
71997
- // src/runtime/terminal-bell.ts
71998
- var BEL = "\x07";
71999
- var DEFAULT_MIN_INTERVAL_MS = 500;
72000
- var lastRingAtMs = 0;
72001
- function ringTerminalBell(options = {}) {
72002
- const {
72003
- enabled = true,
72004
- stdout = process.stdout,
72005
- now = Date.now,
72006
- minIntervalMs = DEFAULT_MIN_INTERVAL_MS
72007
- } = options;
72008
- if (!enabled) return false;
72009
- if (!stdout.isTTY) return false;
72010
- const atMs = now();
72011
- if (atMs - lastRingAtMs < minIntervalMs) return false;
72012
- lastRingAtMs = atMs;
72013
- stdout.write(BEL);
72014
- return true;
72015
- }
72016
- function ringTurnSettledBell(host) {
72017
- if ((host.agentSessionController?.pendingMessageCount ?? 0) > 0) return;
72018
- if (host.executionState.read().awaitingContinuation) return;
72019
- if (host.peekTodoAutoContinuePrompt?.()) return;
72020
- host.ringAttentionBell?.("turn-settled");
72021
- }
72022
- function attentionMessage(reason) {
72023
- switch (reason) {
72024
- case "interaction":
72025
- return { title: "Pie", body: "Waiting for your input" };
72026
- case "turn-settled":
72027
- return { title: "Pie", body: "Response ready" };
72028
- case "turn-failed":
72029
- return { title: "Pie", body: "Turn failed" };
72030
- case "stall-recovery":
72031
- return { title: "Pie", body: "Recovered from a stalled turn" };
72030
+ // src/runtime/cli-attention.ts
72031
+ var CliAttentionAdapter = class {
72032
+ constructor(host) {
72033
+ this.host = host;
72034
+ this.coordinator.handle({ type: "session_work_started", ...this.identity });
72035
+ this.coordinator.subscribe((event) => {
72036
+ if (event.type !== "attention_requested") return;
72037
+ host.updateTerminalTitle?.();
72038
+ host.ringAttentionBell?.(event.reason === "failed" ? "turn-failed" : event.reason === "blocked" ? "stall-recovery" : "interaction");
72039
+ });
72032
72040
  }
72033
- }
72034
- var DEFAULT_NOTIFICATION_MIN_INTERVAL_MS = 1e3;
72035
- var lastNotificationAtMs = 0;
72036
- function sendDesktopNotification(reason, options = {}) {
72037
- const {
72038
- enabled = true,
72039
- terminal,
72040
- now = Date.now,
72041
- minIntervalMs = DEFAULT_NOTIFICATION_MIN_INTERVAL_MS
72042
- } = options;
72043
- if (!enabled) return false;
72044
- if (!terminal || typeof terminal.notify !== "function") return false;
72045
- const atMs = now();
72046
- if (atMs - lastNotificationAtMs < minIntervalMs) return false;
72047
- lastNotificationAtMs = atMs;
72048
- const { title, body } = attentionMessage(reason);
72049
- terminal.notify(title, body);
72050
- return true;
72041
+ host;
72042
+ coordinator = new AttentionCoordinator({ completion: "off" });
72043
+ identity = { sessionId: void 0, generation: 0 };
72044
+ hasWorkEvent = false;
72045
+ handle(event) {
72046
+ this.hasWorkEvent = true;
72047
+ this.identity = { sessionId: event.sessionId, generation: event.generation };
72048
+ if (event.type === "session_invalidated" && event.reason === "dispose") this.coordinator.dispose();
72049
+ else this.coordinator.handle(event);
72050
+ }
72051
+ request(reason, id) {
72052
+ const identity = this.host.agentSessionController?.workIdentity ?? this.identity;
72053
+ if (!this.hasWorkEvent) {
72054
+ this.handle({ type: "session_work_started", ...identity });
72055
+ }
72056
+ return this.coordinator.request(identity, reason, id);
72057
+ }
72058
+ resolve(request, resolution) {
72059
+ if (request) this.coordinator.resolve(request.id, request, resolution);
72060
+ }
72061
+ };
72062
+ var adapters = /* @__PURE__ */ new WeakMap();
72063
+ function cliAttention(host) {
72064
+ let adapter = adapters.get(host);
72065
+ if (!adapter) {
72066
+ adapter = new CliAttentionAdapter(host);
72067
+ adapters.set(host, adapter);
72068
+ }
72069
+ return adapter;
72051
72070
  }
72052
72071
 
72053
72072
  // src/runtime/interactive-runtime-events.ts
@@ -72069,6 +72088,15 @@ function requestStreamingRender(host) {
72069
72088
  }, STREAM_RENDER_MIN_INTERVAL_MS - (now - lastStreamRenderAt));
72070
72089
  }
72071
72090
  }
72091
+ var pendingAttentionRings = /* @__PURE__ */ new WeakMap();
72092
+ function queueFailedRing(host) {
72093
+ pendingAttentionRings.set(host, "failed");
72094
+ }
72095
+ function takeAttentionRing(host) {
72096
+ const attention = pendingAttentionRings.get(host);
72097
+ pendingAttentionRings.delete(host);
72098
+ return attention;
72099
+ }
72072
72100
  function bindInteractiveRuntimeEvents(host) {
72073
72101
  host.agent.subscribe((event) => {
72074
72102
  switch (event.type) {
@@ -72172,8 +72200,15 @@ function bindInteractiveRuntimeEvents(host) {
72172
72200
  host.streamingComponent = void 0;
72173
72201
  removeCalmToolLines(host.chatContainer, host.pendingTools);
72174
72202
  host.pendingTools.clear();
72175
- host.emitExtensionEvent({ type: "agent:end", messages: host.agent.state.messages });
72203
+ if (!hasControllerTurnAuthority(host)) {
72204
+ host.emitExtensionEvent({ type: "agent:end", messages: host.agent.state.messages });
72205
+ }
72176
72206
  host.footer.setState({ status: "ready" });
72207
+ host.updateTerminalTitle?.();
72208
+ const attention = takeAttentionRing(host);
72209
+ if (attention === "failed" && !hasControllerTurnAuthority(host)) {
72210
+ cliAttention(host).request("failed");
72211
+ }
72177
72212
  host.safeRequestRender();
72178
72213
  break;
72179
72214
  }
@@ -72240,7 +72275,6 @@ function handleSemanticAgentEvent(host, event) {
72240
72275
  host.appendWarningSummary(outcome.terminalSummary);
72241
72276
  }
72242
72277
  host.sessionTrace.completeTurn(event.message, false);
72243
- ringTurnSettledBell(host);
72244
72278
  host._semanticTurnIndex++;
72245
72279
  break;
72246
72280
  }
@@ -72252,6 +72286,7 @@ function handleSemanticAgentEvent(host, event) {
72252
72286
  });
72253
72287
  break;
72254
72288
  }
72289
+ queueFailedRing(host);
72255
72290
  host.clearContinuationTimeout("turn_failed");
72256
72291
  host.emitExtensionEvent({
72257
72292
  type: "turn:failed",
@@ -72275,7 +72310,6 @@ function handleSemanticAgentEvent(host, event) {
72275
72310
  host.appendWarningSummary(outcome.terminalSummary);
72276
72311
  }
72277
72312
  host.sessionTrace.completeTurn(event.message, true);
72278
- host.ringAttentionBell?.("turn-failed");
72279
72313
  host._semanticTurnIndex++;
72280
72314
  break;
72281
72315
  }
@@ -72288,6 +72322,7 @@ function handleSemanticAgentEvent(host, event) {
72288
72322
  host.clearContinuationTimeout("status_idle");
72289
72323
  const outcome = host.executionState.markAwaitingContinuationStalled();
72290
72324
  if (outcome.changed) {
72325
+ cliAttention(host).request("blocked", "continuation-stalled");
72291
72326
  host.logDebug("execution:continuation_stalled", {
72292
72327
  turnIndex: host._semanticTurnIndex,
72293
72328
  currentStepId: host.executionState.read().currentStepId,
@@ -78732,7 +78767,7 @@ async function recoverHardStalledTurn(host, stalledMs) {
78732
78767
  void host.refreshTodoWidget();
78733
78768
  host.footer.setState({ status: "ready" });
78734
78769
  host.safeRequestRender();
78735
- host.ringAttentionBell?.("stall-recovery");
78770
+ cliAttention(host).request("blocked", "hard-stall-recovery");
78736
78771
  appendWarningSummary(host, "Recovered from a stalled turn (no progress for " + Math.round(stalledMs / 1e3) + "s). The previous turn was interrupted; review its partial output before continuing.");
78737
78772
  if (abortOutcome.terminalSummary) {
78738
78773
  appendWarningSummary(host, abortOutcome.terminalSummary);
@@ -78786,6 +78821,7 @@ function scheduleContinuationTimeout(host) {
78786
78821
  terminalStatus: outcome.terminalStatus
78787
78822
  });
78788
78823
  if (outcome.changed) {
78824
+ cliAttention(host).request("blocked", "continuation-stalled");
78789
78825
  host.persistExecutionState();
78790
78826
  void host.refreshTodoWidget();
78791
78827
  if (outcome.terminalSummary) {
@@ -78832,7 +78868,7 @@ function createInteractiveAgentSessionController(host) {
78832
78868
  }
78833
78869
  let retryElapsedTicker;
78834
78870
  let retryElapsedStartedAt = 0;
78835
- let pendingSettleKind;
78871
+ const attention = cliAttention(host);
78836
78872
  const stopRetryElapsedTicker = () => {
78837
78873
  if (retryElapsedTicker !== void 0) {
78838
78874
  clearInterval(retryElapsedTicker);
@@ -78845,6 +78881,9 @@ function createInteractiveAgentSessionController(host) {
78845
78881
  cwd: host.options.cwd,
78846
78882
  baseSystemPrompt: host.agent.state.systemPrompt,
78847
78883
  prepareTurn: (context) => prepareAgentTurn(host, context),
78884
+ onExecutionEnd: async ({ messages }) => {
78885
+ await host.emitExtensionEvent({ type: "agent:end", messages });
78886
+ },
78848
78887
  canDispatchQueuedTurn: () => {
78849
78888
  if (host.isWaitingForUserInteraction()) {
78850
78889
  return { allowed: false, reason: "waiting_for_user_interaction", retryAfterMs: 100 };
@@ -78905,7 +78944,10 @@ function createInteractiveAgentSessionController(host) {
78905
78944
  onEvent: (event) => {
78906
78945
  stopRetryElapsedTicker();
78907
78946
  host.sessionTrace.noteRuntimeEvent(event.type, event);
78908
- if (event.type === "session_synced") {
78947
+ if (event.type === "session_work_started" || event.type === "session_invalidated" || event.type === "session_quiescent") {
78948
+ if (event.type === "session_quiescent") host.setControllerBusy(false);
78949
+ attention.handle(event);
78950
+ } else if (event.type === "session_synced") {
78909
78951
  host.lastSyncedMessageCount = event.totalMessages;
78910
78952
  } else if (event.type === "queue_changed") {
78911
78953
  host.updatePendingMessagesDisplay();
@@ -78976,14 +79018,9 @@ function createInteractiveAgentSessionController(host) {
78976
79018
  host.appendWarningSummary(outcome.terminalSummary);
78977
79019
  }
78978
79020
  host.sessionTrace.completeTurn(event.message, false);
78979
- pendingSettleKind = "completed";
78980
79021
  host._semanticTurnIndex++;
78981
79022
  } else if (event.type === "turn_settled") {
78982
79023
  host.setControllerBusy(false);
78983
- if (pendingSettleKind === "completed") {
78984
- ringTurnSettledBell(host);
78985
- }
78986
- pendingSettleKind = void 0;
78987
79024
  } else if (event.type === "turn_failed_terminal") {
78988
79025
  host.clearContinuationTimeout("turn_failed_terminal");
78989
79026
  if (event.message) {
@@ -79018,8 +79055,6 @@ function createInteractiveAgentSessionController(host) {
79018
79055
  host.showStatus("Todo list preserved. Send 'continue' when you want to resume it.");
79019
79056
  }
79020
79057
  host.showError(event.failure.message);
79021
- host.ringAttentionBell?.("turn-failed");
79022
- pendingSettleKind = "failed";
79023
79058
  host.setControllerBusy(false);
79024
79059
  } else if (event.type === "turn_cancelled") {
79025
79060
  const outcome = host.executionState.abort();
@@ -79036,7 +79071,6 @@ function createInteractiveAgentSessionController(host) {
79036
79071
  if (outcome.terminalSummary) {
79037
79072
  host.appendWarningSummary(outcome.terminalSummary);
79038
79073
  }
79039
- pendingSettleKind = "cancelled";
79040
79074
  host.setControllerBusy(false);
79041
79075
  } else if (event.type === "runtime_guard_advisory") {
79042
79076
  host.noteRuntimeGuardAdvisory(event);
@@ -79295,6 +79329,56 @@ function selectToolsForRuntimeMode(tools, mode) {
79295
79329
  return selectToolsForRuntimePolicy(tools, mode);
79296
79330
  }
79297
79331
 
79332
+ // src/runtime/terminal-bell.ts
79333
+ var BEL = "\x07";
79334
+ var DEFAULT_MIN_INTERVAL_MS = 500;
79335
+ var lastRingAtMs = 0;
79336
+ function ringTerminalBell(options = {}) {
79337
+ const {
79338
+ enabled = true,
79339
+ stdout = process.stdout,
79340
+ now = Date.now,
79341
+ minIntervalMs = DEFAULT_MIN_INTERVAL_MS
79342
+ } = options;
79343
+ if (!enabled) return false;
79344
+ if (!stdout.isTTY) return false;
79345
+ const atMs = now();
79346
+ if (atMs - lastRingAtMs < minIntervalMs) return false;
79347
+ lastRingAtMs = atMs;
79348
+ stdout.write(BEL);
79349
+ return true;
79350
+ }
79351
+ function attentionMessage(reason) {
79352
+ switch (reason) {
79353
+ case "interaction":
79354
+ return { title: "Pie", body: "Waiting for your input" };
79355
+ case "turn-settled":
79356
+ return { title: "Pie", body: "Response ready" };
79357
+ case "turn-failed":
79358
+ return { title: "Pie", body: "Turn failed" };
79359
+ case "stall-recovery":
79360
+ return { title: "Pie", body: "Recovered from a stalled turn" };
79361
+ }
79362
+ }
79363
+ var DEFAULT_NOTIFICATION_MIN_INTERVAL_MS = 1e3;
79364
+ var lastNotificationAtMs = 0;
79365
+ function sendDesktopNotification(reason, options = {}) {
79366
+ const {
79367
+ enabled = true,
79368
+ terminal,
79369
+ now = Date.now,
79370
+ minIntervalMs = DEFAULT_NOTIFICATION_MIN_INTERVAL_MS
79371
+ } = options;
79372
+ if (!enabled) return false;
79373
+ if (!terminal || typeof terminal.notify !== "function") return false;
79374
+ const atMs = now();
79375
+ if (atMs - lastNotificationAtMs < minIntervalMs) return false;
79376
+ lastNotificationAtMs = atMs;
79377
+ const { title, body } = attentionMessage(reason);
79378
+ terminal.notify(title, body);
79379
+ return true;
79380
+ }
79381
+
79298
79382
  // src/input/direct-bash.ts
79299
79383
  function buildDirectShellCommand(command) {
79300
79384
  if (process.platform === "win32") {
@@ -79428,13 +79512,25 @@ async function handleDirectBash(host, command) {
79428
79512
 
79429
79513
  // src/extensions/interactive-extension-ui.ts
79430
79514
  function createInteractiveExtensionUIContext(host) {
79515
+ const interact = async (run) => {
79516
+ const attention = cliAttention(host);
79517
+ const request = attention.request("input-required");
79518
+ let resolution = "cancelled";
79519
+ try {
79520
+ const value = await run();
79521
+ resolution = interactionAttentionResolution({ value });
79522
+ return value;
79523
+ } finally {
79524
+ attention.resolve(request, resolution);
79525
+ }
79526
+ };
79431
79527
  return {
79432
79528
  notify: (message, type = "info") => showExtensionNotification(host, message, type),
79433
- select: (title, options, opts) => showExtensionSelector2(host, title, options, opts),
79434
- confirm: (title, message, opts) => showExtensionConfirm(host, title, message, opts),
79435
- input: (title, placeholder, opts) => showExtensionInput(host, title, placeholder, opts),
79436
- editor: (title, prefill) => showExtensionEditor(host, title, prefill),
79437
- custom: (factory, options) => showExtensionCustom(host, factory, options),
79529
+ select: (title, options, opts) => interact(() => showExtensionSelector2(host, title, options, opts)),
79530
+ confirm: async (title, message, opts) => await interact(() => showExtensionConfirm(host, title, message, opts)) === true,
79531
+ input: (title, placeholder, opts) => interact(() => showExtensionInput(host, title, placeholder, opts)),
79532
+ editor: (title, prefill) => interact(() => showExtensionEditor(host, title, prefill)),
79533
+ custom: (factory, options) => interact(() => showExtensionCustom(host, factory, options)),
79438
79534
  setStatus: (key, text) => {
79439
79535
  host.footer.extensionStatuses.set(key, text);
79440
79536
  host.ui.requestRender();
@@ -79447,11 +79543,14 @@ function createInteractiveExtensionUIContext(host) {
79447
79543
  }
79448
79544
  function installInteractiveInteractionHandler(host) {
79449
79545
  registerInteractionHandler(async (request) => {
79546
+ const attention = cliAttention(host);
79547
+ let attentionRequest;
79450
79548
  const beginWaitingForUser = () => {
79451
79549
  host.activeInteractionCount++;
79452
79550
  host.setWaitingForUser(true);
79453
79551
  host.footer.setState({ lifecycleEvent: "waiting_for_user_input" });
79454
- host.ringAttentionBell?.("interaction");
79552
+ const reason = interactionAttentionReason(request);
79553
+ if (reason) attentionRequest = attention.request(reason, "id" in request ? request.id : void 0);
79455
79554
  host.safeRequestRender();
79456
79555
  };
79457
79556
  const endWaitingForUser = () => {
@@ -79479,9 +79578,13 @@ function installInteractiveInteractionHandler(host) {
79479
79578
  };
79480
79579
  const waitForUser = async (createPromise) => {
79481
79580
  beginWaitingForUser();
79581
+ let resolution = "cancelled";
79482
79582
  try {
79483
- return await withTimeout2(createPromise());
79583
+ const result = await withTimeout2(createPromise());
79584
+ resolution = interactionAttentionResolution(result);
79585
+ return result;
79484
79586
  } finally {
79587
+ attention.resolve(attentionRequest, resolution);
79485
79588
  endWaitingForUser();
79486
79589
  }
79487
79590
  };
@@ -79526,7 +79629,7 @@ function installInteractiveInteractionHandler(host) {
79526
79629
  confirmed,
79527
79630
  timedOut
79528
79631
  });
79529
- return { type: "confirm", id: request.id, confirmed: confirmed === true, timedOut, skipped: timedOut };
79632
+ return { type: "confirm", id: request.id, confirmed: confirmed === true, timedOut, skipped: timedOut || confirmed === void 0 };
79530
79633
  }
79531
79634
  case "text_input": {
79532
79635
  host.logDebug("interaction:text_input:start", {
@@ -79608,7 +79711,7 @@ function showExtensionSelector2(host, title, options, opts) {
79608
79711
  async function showExtensionConfirm(host, title, message, opts) {
79609
79712
  const result = await showExtensionSelector2(host, `${title}
79610
79713
  ${message}`, ["Yes", "No"], opts);
79611
- return result === "Yes";
79714
+ return result === void 0 ? void 0 : result === "Yes";
79612
79715
  }
79613
79716
  function showExtensionInput(host, title, placeholder, opts) {
79614
79717
  return new Promise((resolve7) => {
@@ -80436,7 +80539,7 @@ var InteractiveMode = class {
80436
80539
  async init() {
80437
80540
  const activeSession = this.sessionManager.getActiveSession();
80438
80541
  this.thinkingLevel = resolveInitialThinkingLevel({ session: activeSession, settingsManager: this.options.settingsManager });
80439
- const { Agent } = await import("./chunks/src-Z4KWMX6E.js");
80542
+ const { Agent } = await import("./chunks/src-ZJXBS2DB.js");
80440
80543
  this.agent = new Agent({
80441
80544
  initialState: {
80442
80545
  systemPrompt: this.buildSystemPrompt(),
@@ -80852,7 +80955,7 @@ var InteractiveMode = class {
80852
80955
  };
80853
80956
 
80854
80957
  // src/app/runtime-composition.ts
80855
- import { existsSync as existsSync19, mkdirSync as mkdirSync14 } from "fs";
80958
+ import { existsSync as existsSync18, mkdirSync as mkdirSync13 } from "fs";
80856
80959
  import * as path31 from "path";
80857
80960
  var CliMissingApiKeyError = class extends Error {
80858
80961
  constructor(message) {
@@ -80879,8 +80982,8 @@ function getCliRuntimePaths() {
80879
80982
  return { configDir, sessionsDir, skillsDir, builtinSkillsDir };
80880
80983
  }
80881
80984
  function ensureCliRuntimePaths(paths = getCliRuntimePaths()) {
80882
- if (!existsSync19(paths.skillsDir)) {
80883
- mkdirSync14(paths.skillsDir, { recursive: true });
80985
+ if (!existsSync18(paths.skillsDir)) {
80986
+ mkdirSync13(paths.skillsDir, { recursive: true });
80884
80987
  }
80885
80988
  return paths;
80886
80989
  }
@@ -81268,7 +81371,7 @@ async function runPrintMode(params) {
81268
81371
  `);
81269
81372
  console.log("Assistant: ");
81270
81373
  }
81271
- const { Agent: AgentClass } = await import("./chunks/src-Z4KWMX6E.js");
81374
+ const { Agent: AgentClass } = await import("./chunks/src-ZJXBS2DB.js");
81272
81375
  let agent;
81273
81376
  const printModeExtensions = await loadPrintModeExtensions({
81274
81377
  cwd: runtime.cwd,
@@ -82129,7 +82232,7 @@ async function runJsonEventsMode(params) {
82129
82232
  return;
82130
82233
  }
82131
82234
  const parent = agent;
82132
- const { Agent: AgentClass } = await import("./chunks/src-Z4KWMX6E.js");
82235
+ const { Agent: AgentClass } = await import("./chunks/src-ZJXBS2DB.js");
82133
82236
  const sideAgent = new AgentClass({
82134
82237
  initialState: {
82135
82238
  systemPrompt: parent.state.systemPrompt,
@@ -82473,7 +82576,7 @@ async function runJsonEventsMode(params) {
82473
82576
  if (runtime.initialModel.unconfigured || controller) {
82474
82577
  return;
82475
82578
  }
82476
- const { Agent: AgentClass } = await import("./chunks/src-Z4KWMX6E.js");
82579
+ const { Agent: AgentClass } = await import("./chunks/src-ZJXBS2DB.js");
82477
82580
  const jsonModeExtensions = await loadJsonModeExtensions({ runtime, getAgent: () => agent });
82478
82581
  extensionRunner = jsonModeExtensions.runner;
82479
82582
  const tools = [...runtime.tools, ...jsonModeExtensions.extensionTools];
@@ -83067,7 +83170,7 @@ async function runWithJsonEventsConsoleIsolation(fn) {
83067
83170
  }
83068
83171
  async function createCliTestStreamFnFromEnv() {
83069
83172
  if (!process.env.PIE_TEST_MOCK_STREAM_SEQUENCE) return void 0;
83070
- return (await import("./chunks/test-stream-3FG7FHHU.js")).createTestStreamFnFromSequenceEnv();
83173
+ return (await import("./chunks/test-stream-TI2S25NY.js")).createTestStreamFnFromSequenceEnv();
83071
83174
  }
83072
83175
  function resolveJsonEventsDetailFlag() {
83073
83176
  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.6.5",
3
+ "version": "2.6.6",
4
4
  "description": "Pie AI Agent CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,7 +19,7 @@
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
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
- "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/stream-render-throttle.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",
22
+ "test:offline": "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/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/stream-render-throttle.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",
24
24
  "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",
25
25
  "test:todo-tui": "node ../../scripts/run-with-env.mjs PIE_REAL_TODO_TUI=1 -- --test --import tsx test/todo-closure.terminal.test.ts",