omnius 1.0.573 → 1.0.574

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1257,8 +1257,8 @@ var init_model_broker = __esm({
1257
1257
  }
1258
1258
  /** Restore a set of previously evicted Ollama models, oldest first. */
1259
1259
  async restoreOllamaModels(models, options2 = {}) {
1260
- const unique3 = dedupeLoadedModels(models.filter((m2) => m2.host === "ollama")).sort((a2, b) => a2.lastUsedAt - b.lastUsedAt);
1261
- for (const model of unique3) {
1260
+ const unique4 = dedupeLoadedModels(models.filter((m2) => m2.host === "ollama")).sort((a2, b) => a2.lastUsedAt - b.lastUsedAt);
1261
+ for (const model of unique4) {
1262
1262
  await this.warmOllamaModel(model.name, options2.keepAlive ?? "30m").catch(() => false);
1263
1263
  }
1264
1264
  }
@@ -17409,8 +17409,8 @@ var init_unifiedMemoryStore = __esm({
17409
17409
  return matches.filter((match) => match.score >= (options2.minScore ?? 0)).sort((a2, b) => b.score - a2.score).slice(0, limit).map((match, index) => ({ ...match, rank: index + 1 }));
17410
17410
  }
17411
17411
  recordAccess(itemIds) {
17412
- const unique3 = [...new Set(itemIds)].filter(Boolean);
17413
- if (unique3.length === 0)
17412
+ const unique4 = [...new Set(itemIds)].filter(Boolean);
17413
+ if (unique4.length === 0)
17414
17414
  return;
17415
17415
  const update2 = this.db.prepare(`
17416
17416
  UPDATE memory_item
@@ -17420,7 +17420,7 @@ var init_unifiedMemoryStore = __esm({
17420
17420
  `);
17421
17421
  const now2 = this.nowIso();
17422
17422
  const txn = this.db.transaction(() => {
17423
- for (const id2 of unique3)
17423
+ for (const id2 of unique4)
17424
17424
  update2.run(now2, id2);
17425
17425
  });
17426
17426
  txn();
@@ -26246,9 +26246,9 @@ function loadEpisodeCandidates(db, limit) {
26246
26246
  }
26247
26247
  }
26248
26248
  function deleteEpisodes(db, ids, dryRun) {
26249
- const unique3 = [...new Set(ids)].filter(Boolean);
26250
- if (dryRun || unique3.length === 0)
26251
- return unique3.length;
26249
+ const unique4 = [...new Set(ids)].filter(Boolean);
26250
+ if (dryRun || unique4.length === 0)
26251
+ return unique4.length;
26252
26252
  let deleted = 0;
26253
26253
  const stmt = db.prepare(`DELETE FROM episodes WHERE id = ?`);
26254
26254
  const tx = db.transaction((rows) => {
@@ -26257,7 +26257,7 @@ function deleteEpisodes(db, ids, dryRun) {
26257
26257
  deleted += Number(result.changes ?? 0);
26258
26258
  }
26259
26259
  });
26260
- tx(unique3);
26260
+ tx(unique4);
26261
26261
  return deleted;
26262
26262
  }
26263
26263
  function maintainGraph(dbPath, options2, shouldStop) {
@@ -26358,7 +26358,7 @@ function vectorDuplicateNodePairs(rows, threshold) {
26358
26358
  }
26359
26359
  function mergeGraphNodes(db, pairs, dryRun) {
26360
26360
  const seen = /* @__PURE__ */ new Set();
26361
- const unique3 = pairs.filter((pair) => {
26361
+ const unique4 = pairs.filter((pair) => {
26362
26362
  if (!pair.keepId || !pair.dropId || pair.keepId === pair.dropId)
26363
26363
  return false;
26364
26364
  if (seen.has(pair.dropId))
@@ -26366,8 +26366,8 @@ function mergeGraphNodes(db, pairs, dryRun) {
26366
26366
  seen.add(pair.dropId);
26367
26367
  return true;
26368
26368
  });
26369
- if (dryRun || unique3.length === 0)
26370
- return unique3.length;
26369
+ if (dryRun || unique4.length === 0)
26370
+ return unique4.length;
26371
26371
  let merged = 0;
26372
26372
  const tx = db.transaction((rows) => {
26373
26373
  const src2 = db.prepare(`UPDATE kg_edges SET src_id = ? WHERE src_id = ?`);
@@ -26385,7 +26385,7 @@ function mergeGraphNodes(db, pairs, dryRun) {
26385
26385
  merged += Number(deleted.changes ?? 0);
26386
26386
  }
26387
26387
  });
26388
- tx(unique3);
26388
+ tx(unique4);
26389
26389
  return merged;
26390
26390
  }
26391
26391
  function dedupeGraphEdges(db, limit, dryRun) {
@@ -504294,11 +504294,11 @@ ${options2.prefix}` : "\n" : options2.prefix
504294
504294
  return true;
504295
504295
  }
504296
504296
  const set = /* @__PURE__ */ new Map();
504297
- let unique3 = 0;
504297
+ let unique4 = 0;
504298
504298
  for (const v of arr1) {
504299
504299
  if (set.get(v) !== true) {
504300
504300
  set.set(v, true);
504301
- unique3++;
504301
+ unique4++;
504302
504302
  }
504303
504303
  }
504304
504304
  for (const v of arr2) {
@@ -504308,10 +504308,10 @@ ${options2.prefix}` : "\n" : options2.prefix
504308
504308
  }
504309
504309
  if (isSet === true) {
504310
504310
  set.set(v, false);
504311
- unique3--;
504311
+ unique4--;
504312
504312
  }
504313
504313
  }
504314
- return unique3 === 0;
504314
+ return unique4 === 0;
504315
504315
  }
504316
504316
  function typeAcquisitionChanged(opt1, opt2) {
504317
504317
  return opt1.enable !== opt2.enable || !setIsEqualTo(opt1.include, opt2.include) || !setIsEqualTo(opt1.exclude, opt2.exclude);
@@ -554372,12 +554372,12 @@ function normalizeWorkItem(value2) {
554372
554372
  const title = sanitizeDelegationText(value2.title, 240);
554373
554373
  if (!cardId || !title)
554374
554374
  return void 0;
554375
- const unique3 = (items, limit) => [...new Set((items ?? []).map((item) => sanitizeDelegationText(item, 220)).filter(Boolean))].slice(0, limit);
554375
+ const unique4 = (items, limit) => [...new Set((items ?? []).map((item) => sanitizeDelegationText(item, 220)).filter(Boolean))].slice(0, limit);
554376
554376
  const epoch = typeof value2.taskEpoch === "number" && Number.isFinite(value2.taskEpoch) ? Math.max(0, Math.floor(value2.taskEpoch)) : void 0;
554377
- const todoIds = unique3(value2.todoIds, 8);
554378
- const ownedFiles = unique3(value2.ownedFiles, 8);
554379
- const evidenceRequirements = unique3(value2.evidenceRequirements, 6);
554380
- const expectedArtifacts = unique3(value2.expectedArtifacts, 8);
554377
+ const todoIds = unique4(value2.todoIds, 8);
554378
+ const ownedFiles = unique4(value2.ownedFiles, 8);
554379
+ const evidenceRequirements = unique4(value2.evidenceRequirements, 6);
554380
+ const expectedArtifacts = unique4(value2.expectedArtifacts, 8);
554381
554381
  const verifierCommand = sanitizeDelegationText(value2.verifierCommand, 360);
554382
554382
  return {
554383
554383
  cardId,
@@ -597450,9 +597450,9 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
597450
597450
  return updated.claimDiscovery;
597451
597451
  }
597452
597452
  _completionArtifactHashes(paths) {
597453
- const unique3 = [...new Set(paths.map((path16) => this._normalizeEvidencePath(path16)).filter(Boolean))].slice(0, 20);
597453
+ const unique4 = [...new Set(paths.map((path16) => this._normalizeEvidencePath(path16)).filter(Boolean))].slice(0, 20);
597454
597454
  const out = [];
597455
- for (const path16 of unique3) {
597455
+ for (const path16 of unique4) {
597456
597456
  try {
597457
597457
  const absolute = _pathResolve(this.authoritativeWorkingDirectory(), path16);
597458
597458
  if (!_fsExistsSync(absolute))
@@ -600248,21 +600248,21 @@ ${sections.join("\n")}` : sections.join("\n");
600248
600248
  sections.push(`Compacted historical entries: ${compactedCount}. They show what was observed earlier, not what is currently on disk. Re-run the narrow read or verifier when freshness matters.`);
600249
600249
  }
600250
600250
  if (filesRead.length > 0) {
600251
- const unique3 = [...new Set(filesRead)].slice(0, 30);
600252
- sections.push(`Files already read (${unique3.length}): ${unique3.join(", ")}`);
600251
+ const unique4 = [...new Set(filesRead)].slice(0, 30);
600252
+ sections.push(`Files already read (${unique4.length}): ${unique4.join(", ")}`);
600253
600253
  }
600254
600254
  if (dirsListed.length > 0) {
600255
- const unique3 = [...new Set(dirsListed)].slice(0, 15);
600256
- sections.push(`Directories already listed (${unique3.length}): ${unique3.join(", ")}`);
600255
+ const unique4 = [...new Set(dirsListed)].slice(0, 15);
600256
+ sections.push(`Directories already listed (${unique4.length}): ${unique4.join(", ")}`);
600257
600257
  sections.push(`Do not call list_directory again on these exact directories unless you changed their contents. Use the listed child paths directly with file_read/edit/delegation.`);
600258
600258
  }
600259
600259
  if (searches.length > 0) {
600260
- const unique3 = [...new Set(searches)].slice(0, 15);
600261
- sections.push(`Searches already run (${unique3.length}): ${unique3.join(", ")}`);
600260
+ const unique4 = [...new Set(searches)].slice(0, 15);
600261
+ sections.push(`Searches already run (${unique4.length}): ${unique4.join(", ")}`);
600262
600262
  }
600263
600263
  if (shells.length > 0) {
600264
- const unique3 = [...new Set(shells)].slice(0, 15);
600265
- sections.push(`Shell commands already executed (${unique3.length}): ${unique3.join(", ")}`);
600264
+ const unique4 = [...new Set(shells)].slice(0, 15);
600265
+ sections.push(`Shell commands already executed (${unique4.length}): ${unique4.join(", ")}`);
600266
600266
  }
600267
600267
  if (sections.length <= 1)
600268
600268
  return null;
@@ -603917,7 +603917,49 @@ ${rawTask}`;
603917
603917
  return null;
603918
603918
  }
603919
603919
  }
603920
+ /**
603921
+ * UI/observability fallback pairing for legacy controller-generated tool
603922
+ * events. Normal execution carries the backend tool-call id directly; this
603923
+ * queue keeps rejected/synthetic call-result pairs truthful too, without a
603924
+ * renderer guessing by adjacent text or command names.
603925
+ */
603926
+ _observabilityActionSequence = 0;
603927
+ _observabilityPendingActions = /* @__PURE__ */ new Map();
603920
603928
  emit(event) {
603929
+ if (event.type === "tool_call" || event.type === "tool_result") {
603930
+ event.workingDirectory ??= this.authoritativeWorkingDirectory();
603931
+ const key = `${event.turn ?? 0}:${event.toolName ?? "tool"}`;
603932
+ if (event.type === "tool_call") {
603933
+ const hadActionId = Boolean(event.actionId);
603934
+ if (!event.actionId) {
603935
+ this._observabilityActionSequence++;
603936
+ event.actionId = `runtime:${key}:${this._observabilityActionSequence}`;
603937
+ event.synthetic = true;
603938
+ }
603939
+ if (!hadActionId) {
603940
+ const pending2 = this._observabilityPendingActions.get(key) ?? [];
603941
+ pending2.push(event.actionId);
603942
+ this._observabilityPendingActions.set(key, pending2);
603943
+ }
603944
+ } else if (!event.actionId) {
603945
+ const pending2 = this._observabilityPendingActions.get(key) ?? [];
603946
+ event.actionId = pending2.shift();
603947
+ if (pending2.length > 0)
603948
+ this._observabilityPendingActions.set(key, pending2);
603949
+ else
603950
+ this._observabilityPendingActions.delete(key);
603951
+ if (!event.actionId) {
603952
+ this._observabilityActionSequence++;
603953
+ event.actionId = `runtime:${key}:${this._observabilityActionSequence}`;
603954
+ event.synthetic = true;
603955
+ }
603956
+ if (event.actionId.startsWith("runtime:")) {
603957
+ event.synthetic = true;
603958
+ if (event.success === false)
603959
+ event.blocked ??= true;
603960
+ }
603961
+ }
603962
+ }
603921
603963
  this._observeTrajectoryEvent(event);
603922
603964
  for (const handler of this.handlers) {
603923
603965
  try {
@@ -608188,8 +608230,11 @@ ${cachedResult}`,
608188
608230
  }
608189
608231
  this.emit({
608190
608232
  type: "tool_call",
608233
+ actionId: tc.id,
608191
608234
  toolName: tc.name,
608192
608235
  toolArgs: tc.arguments,
608236
+ workingDirectory: this.authoritativeWorkingDirectory(),
608237
+ targetPaths: this._extractToolTargetPaths(tc.name, tc.arguments ?? {}),
608193
608238
  turn,
608194
608239
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
608195
608240
  });
@@ -609687,9 +609732,16 @@ Evidence: ${evidencePreview}`.slice(0, 500);
609687
609732
  }
609688
609733
  this.emit({
609689
609734
  type: "tool_result",
609735
+ actionId: tc.id,
609690
609736
  toolName: tc.name,
609691
609737
  content: this.toolResultEventContent(tc.name, output || result.output || result.error || ""),
609692
609738
  success: result.success,
609739
+ workingDirectory: result.executionReceipt?.cwd ?? this.authoritativeWorkingDirectory(),
609740
+ targetPaths: toolTargetPaths,
609741
+ mutatedFiles: realMutationPaths,
609742
+ executionReceipt: result.executionReceipt,
609743
+ synthetic: result.runtimeAuthored === true,
609744
+ blocked: result.runtimeAuthored === true && result.success === false,
609693
609745
  turn,
609694
609746
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
609695
609747
  });
@@ -627476,8 +627528,8 @@ function isLowInformationAsciiPreview(ascii2) {
627476
627528
  if (!plain) return true;
627477
627529
  const visible = plain.replace(/\s/g, "");
627478
627530
  if (visible.length < 12) return true;
627479
- const unique3 = new Set(Array.from(visible));
627480
- if (unique3.size <= 2 && /[█▓▒░#@]/u.test(visible)) return true;
627531
+ const unique4 = new Set(Array.from(visible));
627532
+ if (unique4.size <= 2 && /[█▓▒░#@]/u.test(visible)) return true;
627481
627533
  return false;
627482
627534
  }
627483
627535
  function previewFailure(message2, width) {
@@ -638963,6 +639015,8 @@ var init_command_registry = __esm({
638963
639015
  ],
638964
639016
  ["/think", "Toggle thinking/reasoning mode (Qwen3, DeepSeek-R1, etc.)"],
638965
639017
  ["/stream", "Toggle real-time token streaming (pastel syntax highlighting)"],
639018
+ ["/tree", "Switch between the action waterfall and an explorable action tree"],
639019
+ ["/tree on|off|status", "Show, hide, or inspect the action-tree presentation"],
638966
639020
  ["/realtime", "Toggle short spoken-dialogue mode for ASR/TTS-backed chat"],
638967
639021
  ["/realtime on|off|status", "Set or inspect realtime conversation mode"],
638968
639022
  ["/mouse", "Toggle terminal mouse tracking"],
@@ -654936,14 +654990,14 @@ function loadFailurePatterns(store2) {
654936
654990
  const unresolved = store2.listUnresolved();
654937
654991
  if (unresolved.length === 0) return "";
654938
654992
  const seen = /* @__PURE__ */ new Set();
654939
- const unique3 = unresolved.filter((f2) => {
654993
+ const unique4 = unresolved.filter((f2) => {
654940
654994
  if (seen.has(f2.fingerprint)) return false;
654941
654995
  seen.add(f2.fingerprint);
654942
654996
  return true;
654943
654997
  });
654944
- if (unique3.length === 0) return "";
654998
+ if (unique4.length === 0) return "";
654945
654999
  const lines = ["Known failure patterns (avoid repeating these):"];
654946
- for (const f2 of unique3.slice(0, 8)) {
655000
+ for (const f2 of unique4.slice(0, 8)) {
654947
655001
  const file = f2.filePath ? ` in ${f2.filePath}` : "";
654948
655002
  lines.push(`- [${f2.failureType}]${file}: ${f2.errorMessage.slice(0, 150)}`);
654949
655003
  }
@@ -656288,6 +656342,13 @@ var init_status_bar = __esm({
656288
656342
  _lastBufferedAt = 0;
656289
656343
  _contentScrollOffset = 0;
656290
656344
  // 0 = live (bottom), >0 = scrolled back
656345
+ /** Stack is the normal waterfall; tree is a separate, read-only provenance surface. */
656346
+ _contentPresentation = "stack";
656347
+ _treeContentLines = [];
656348
+ _treeScrollOffset = 0;
656349
+ _treeAutoScroll = true;
656350
+ _treePresentationActive = false;
656351
+ _actionTreeBlockId = "observability-action-tree";
656291
656352
  _contentMaxLines = 1e4;
656292
656353
  _contentRevision = 0;
656293
656354
  // Trailing blank content lines are DEFERRED, not buffered immediately. A blank
@@ -656436,7 +656497,7 @@ var init_status_bar = __esm({
656436
656497
  _countdown = 0;
656437
656498
  _recBlink = true;
656438
656499
  _recBlinkTimer = null;
656439
- /** Current focus zone for Ctrl+Tab cycling */
656500
+ /** Current focus zone for the optional keyboard-navigation fallback. */
656440
656501
  _focusedZone = "footer";
656441
656502
  /** Callback to notify header (banner) of focus changes */
656442
656503
  _headerFocusHandler = null;
@@ -656500,6 +656561,83 @@ var init_status_bar = __esm({
656500
656561
  registerDynamicBlockClickHandler(id2, handler) {
656501
656562
  this._dynamicBlockClickHandlers.set(id2, handler);
656502
656563
  }
656564
+ /**
656565
+ * Install the separate action-tree presentation. Its sentinel never enters
656566
+ * the normal waterfall, so switching views cannot pollute agent/sub-agent
656567
+ * scrollback or cause live tool output to disappear from the stack.
656568
+ */
656569
+ setActionTreeRenderer(render2, onClick) {
656570
+ this.registerDynamicBlock(this._actionTreeBlockId, render2);
656571
+ this._treeContentLines = [
656572
+ `${this.DYNAMIC_BLOCK_MARK_PREFIX}${this._actionTreeBlockId}${this.DYNAMIC_BLOCK_MARK_SUFFIX}`
656573
+ ];
656574
+ if (onClick) {
656575
+ this.registerDynamicBlockClickHandler(
656576
+ this._actionTreeBlockId,
656577
+ (event) => onClick(event.offset)
656578
+ );
656579
+ } else {
656580
+ this._dynamicBlockClickHandlers.delete(this._actionTreeBlockId);
656581
+ }
656582
+ this._treeScrollOffset = 0;
656583
+ this._treeAutoScroll = true;
656584
+ this.markContentMutated();
656585
+ if (this.active && this._contentPresentation === "tree") this.repaintContent();
656586
+ }
656587
+ get contentPresentation() {
656588
+ return this._contentPresentation;
656589
+ }
656590
+ setContentPresentation(mode) {
656591
+ if (mode === "tree" && this._treeContentLines.length === 0) return this._contentPresentation;
656592
+ if (this._contentPresentation === mode) return mode;
656593
+ this._contentPresentation = mode;
656594
+ this._lastPaintReflow = null;
656595
+ this._lastPaintStartIdx = 0;
656596
+ this.invalidateRowCountCache();
656597
+ if (this.active) {
656598
+ this.fillContentArea();
656599
+ this.repaintContent();
656600
+ }
656601
+ return mode;
656602
+ }
656603
+ toggleActionTree() {
656604
+ return this.setContentPresentation(
656605
+ this._contentPresentation === "tree" ? "stack" : "tree"
656606
+ );
656607
+ }
656608
+ /** Repaint changed action-tree data immediately without touching stack scrollback. */
656609
+ refreshActionTree() {
656610
+ this.invalidateRowCountCache();
656611
+ if (this.active && this._contentPresentation === "tree") this.repaintContent();
656612
+ }
656613
+ /**
656614
+ * Reuse the mature virtual-scroll implementation while temporarily pointing
656615
+ * it at the tree's own source/offset. Normal content writers always see the
656616
+ * stack buffer outside this scope, even while the tree is visible.
656617
+ */
656618
+ withTreePresentation(fn) {
656619
+ if (this._contentPresentation !== "tree" || this._treePresentationActive) {
656620
+ return fn();
656621
+ }
656622
+ const stackLines = this._contentLines;
656623
+ const stackOffset = this._contentScrollOffset;
656624
+ const stackAutoScroll = this._autoScroll;
656625
+ this._contentLines = this._treeContentLines;
656626
+ this._contentScrollOffset = this._treeScrollOffset;
656627
+ this._autoScroll = this._treeAutoScroll;
656628
+ this._treePresentationActive = true;
656629
+ try {
656630
+ return fn();
656631
+ } finally {
656632
+ this._treeContentLines = this._contentLines;
656633
+ this._treeScrollOffset = this._contentScrollOffset;
656634
+ this._treeAutoScroll = this._autoScroll;
656635
+ this._contentLines = stackLines;
656636
+ this._contentScrollOffset = stackOffset;
656637
+ this._autoScroll = stackAutoScroll;
656638
+ this._treePresentationActive = false;
656639
+ }
656640
+ }
656503
656641
  /** Unregister a dynamic block. Existing sentinels in scrollback become inert (rendered as empty). */
656504
656642
  unregisterDynamicBlock(id2) {
656505
656643
  this._dynamicBlocks.delete(id2);
@@ -658477,6 +658615,11 @@ var init_status_bar = __esm({
658477
658615
  * when the click was consumed.
658478
658616
  */
658479
658617
  handleContentBlockClick(screenRow, col) {
658618
+ if (this._contentPresentation === "tree" && !this._treePresentationActive) {
658619
+ return this.withTreePresentation(
658620
+ () => this.handleContentBlockClick(screenRow, col)
658621
+ );
658622
+ }
658480
658623
  const hit = this.hitTestContentBlock(screenRow);
658481
658624
  if (!hit) return false;
658482
658625
  const handler = this._dynamicBlockClickHandlers.get(hit.id);
@@ -659391,6 +659534,8 @@ ${CONTENT_BG_SEQ}`);
659391
659534
  this._streamingRepaintTimer.unref?.();
659392
659535
  }
659393
659536
  getLiveBufferedLine() {
659537
+ if (this._contentPresentation === "tree" && this._treePresentationActive)
659538
+ return null;
659394
659539
  if (this.writeDepth === 0 || this._contentScrollOffset > 0) return null;
659395
659540
  if (this._inProgressLine.length === 0) return null;
659396
659541
  const sanitized = this.sanitizeBufferedContentLine(this._inProgressLine);
@@ -659791,6 +659936,10 @@ ${CONTENT_BG_SEQ}`);
659791
659936
  }
659792
659937
  /** Scroll up through content history */
659793
659938
  scrollContentUp(lines = 1) {
659939
+ if (this._contentPresentation === "tree" && !this._treePresentationActive) {
659940
+ this.withTreePresentation(() => this.scrollContentUp(lines));
659941
+ return;
659942
+ }
659794
659943
  if (!this.active) return;
659795
659944
  this.cancelMouseIdle();
659796
659945
  this.restoreMouseTracking();
@@ -659805,6 +659954,10 @@ ${CONTENT_BG_SEQ}`);
659805
659954
  }
659806
659955
  /** Scroll down through content history */
659807
659956
  scrollContentDown(lines = 1) {
659957
+ if (this._contentPresentation === "tree" && !this._treePresentationActive) {
659958
+ this.withTreePresentation(() => this.scrollContentDown(lines));
659959
+ return;
659960
+ }
659808
659961
  if (!this.active) return;
659809
659962
  this.cancelMouseIdle();
659810
659963
  this.restoreMouseTracking();
@@ -659826,6 +659979,10 @@ ${CONTENT_BG_SEQ}`);
659826
659979
  }
659827
659980
  /** Jump to live (End key) */
659828
659981
  jumpToLive() {
659982
+ if (this._contentPresentation === "tree" && !this._treePresentationActive) {
659983
+ this.withTreePresentation(() => this.jumpToLive());
659984
+ return;
659985
+ }
659829
659986
  this._contentScrollOffset = 0;
659830
659987
  this._autoScroll = true;
659831
659988
  this._syncPagerScope();
@@ -659903,6 +660060,10 @@ ${CONTENT_BG_SEQ}`);
659903
660060
  * Reference: btop_draw.cpp lines 2080-2102 — process list rendering.
659904
660061
  */
659905
660062
  repaintContent() {
660063
+ if (this._contentPresentation === "tree" && !this._treePresentationActive) {
660064
+ this.withTreePresentation(() => this.repaintContent());
660065
+ return;
660066
+ }
659906
660067
  const h = this.contentHeight;
659907
660068
  const livePartialLine = this.getLiveBufferedLine();
659908
660069
  const w = termCols();
@@ -661122,13 +661283,6 @@ ${CONTENT_BG_SEQ}`);
661122
661283
  onCtrlO();
661123
661284
  return;
661124
661285
  }
661125
- if (key?.name === "tab" && self2.inputStateProvider) {
661126
- const { line = "" } = self2.inputStateProvider() ?? {};
661127
- if (line.length === 0) {
661128
- self2.cycleFocus();
661129
- return;
661130
- }
661131
- }
661132
661286
  if (s2 === "") {
661133
661287
  self2.cycleFocus();
661134
661288
  return;
@@ -661263,13 +661417,13 @@ ${CONTENT_BG_SEQ}`);
661263
661417
  if (onCtrlO) di.on("ctrl-o", () => onCtrlO());
661264
661418
  if (onCtrlL) di.on("ctrl-l", () => onCtrlL());
661265
661419
  di.on("ctrl-i", () => self2.toggleFooterMetrics());
661420
+ di.on("ctrl-tab", () => self2.toggleActionTree());
661266
661421
  di.on("ctrl-left", () => self2.cycleAgentView("prev"));
661267
661422
  di.on("ctrl-right", () => self2.cycleAgentView("next"));
661268
661423
  di.on("pageup", () => self2.pageUpContent());
661269
661424
  di.on("pagedown", () => self2.pageDownContent());
661270
661425
  di.on("shiftup", () => self2.scrollContentUp(3));
661271
661426
  di.on("shiftdown", () => self2.scrollContentDown(3));
661272
- di.on("tab-empty", () => self2.cycleFocus());
661273
661427
  di.on("ctrl-backslash", () => self2.cycleFocus());
661274
661428
  di.on("ctrl-shift-c", () => void self2.copySelection());
661275
661429
  di.on("ctrl-shift-b", () => self2.armBlockSelection());
@@ -665831,9 +665985,9 @@ function formatExpandedContextDiagnostic(specs, math) {
665831
665985
  memBits.push(`RAM ${fmtGB(specs.availableRamGB)}/${fmtGB(specs.totalRamGB)}${specs.unifiedMemory ? " unified" : ""}`);
665832
665986
  const mem = memBits.join(", ");
665833
665987
  const kv = `KV ${fmtKB(math.kvBytesPerToken)}/tok (${math.kvSource})`;
665834
- const fit5 = `fit ${fmtK(math.memoryFit)}, arch ${math.archCtx !== null ? fmtK(math.archCtx) : "n/a"}, floor ${fmtK(math.floor)}`;
665988
+ const fit6 = `fit ${fmtK(math.memoryFit)}, arch ${math.archCtx !== null ? fmtK(math.archCtx) : "n/a"}, floor ${fmtK(math.floor)}`;
665835
665989
  const limit = `→ ${fmtK(math.numCtx)} (${math.limitedBy === "floor" ? "min floor" : math.limitedBy === "arch" ? "arch-capped" : "memory-fit"})`;
665836
- return `[${mem} | model ${fmtGB(math.modelSizeGB)} | ${kv} | ${fit5} ${limit}]`;
665990
+ return `[${mem} | model ${fmtGB(math.modelSizeGB)} | ${kv} | ${fit6} ${limit}]`;
665837
665991
  }
665838
665992
  async function ensureExpandedContext(modelName, backendUrl2) {
665839
665993
  if (modelName.includes("cloud") || modelName.includes(":cloud")) {
@@ -682846,6 +683000,33 @@ Clone a new voice: /voice clone <wav-file> [name]`);
682846
683000
  );
682847
683001
  return "handled";
682848
683002
  }
683003
+ case "tree": {
683004
+ const mode = arg.trim().toLowerCase();
683005
+ if (!ctx3.toggleActionTree || !ctx3.setActionTreeMode || !ctx3.getActionTreeMode) {
683006
+ renderWarning("Action-tree presentation is unavailable in this surface.");
683007
+ return "handled";
683008
+ }
683009
+ if (mode === "status" || mode === "?") {
683010
+ renderInfo(
683011
+ `Action tree: ${ctx3.getActionTreeMode() === "tree" ? "shown" : "hidden"}. Ctrl+Tab switches it when your terminal reports that key distinctly.`
683012
+ );
683013
+ return "handled";
683014
+ }
683015
+ if (mode === "on" || mode === "show") {
683016
+ ctx3.setActionTreeMode("tree");
683017
+ return "handled";
683018
+ }
683019
+ if (mode === "off" || mode === "hide") {
683020
+ ctx3.setActionTreeMode("stack");
683021
+ return "handled";
683022
+ }
683023
+ if (mode) {
683024
+ renderWarning("Usage: /tree [on|off|status]");
683025
+ return "handled";
683026
+ }
683027
+ ctx3.toggleActionTree();
683028
+ return "handled";
683029
+ }
682849
683030
  case "realtime": {
682850
683031
  const save3 = hasLocal ? ctx3.saveLocalSettings.bind(ctx3) : ctx3.saveSettings.bind(ctx3);
682851
683032
  const value2 = arg.trim().toLowerCase();
@@ -687334,12 +687515,12 @@ function cad3dFitIcon(score) {
687334
687515
  if (score >= 40) return c3.yellow("△");
687335
687516
  return c3.red("✖");
687336
687517
  }
687337
- function cad3dModelDetail(spec, fit5) {
687518
+ function cad3dModelDetail(spec, fit6) {
687338
687519
  const download = spec.resources.approxDownloadGB ? `~${spec.resources.approxDownloadGB}GB` : "size unknown";
687339
687520
  const vram = spec.resources.recommendedVramGB ? `${spec.resources.recommendedVramGB}GB VRAM rec` : "VRAM varies";
687340
687521
  const license = spec.hf.license ? `license ${spec.hf.license}` : "license unknown";
687341
687522
  const token = spec.deployment.requiresToken ? "requires HF token" : "no token gate";
687342
- return `${fit5.label} · ${spec.backend} · ${download} · ${vram} · ${license} · ${token}`;
687523
+ return `${fit6.label} · ${spec.backend} · ${download} · ${vram} · ${license} · ${token}`;
687343
687524
  }
687344
687525
  async function startCad3dViewerFromCommand(rawPath) {
687345
687526
  const viewer = await startCadModelViewer(
@@ -687355,11 +687536,11 @@ async function showCad3dModelsMenu(ctx3, hasLocal, mode) {
687355
687536
  const active = mode === "cad" ? settings.cadModel : settings.model3dModel;
687356
687537
  const currentViewer2 = getCurrentCadModelViewer();
687357
687538
  const buildItem = (entry) => {
687358
- const fit5 = rateCad3dModelForHardware(entry.spec, specs);
687539
+ const fit6 = rateCad3dModelForHardware(entry.spec, specs);
687359
687540
  return {
687360
687541
  key: `model:${entry.spec.id}`,
687361
- label: `${cad3dFitIcon(fit5.score)} ${String(fit5.score).padStart(3)}/100 ${entry.spec.label}`,
687362
- detail: cad3dModelDetail(entry.spec, fit5)
687542
+ label: `${cad3dFitIcon(fit6.score)} ${String(fit6.score).padStart(3)}/100 ${entry.spec.label}`,
687543
+ detail: cad3dModelDetail(entry.spec, fit6)
687363
687544
  };
687364
687545
  };
687365
687546
  const items = [
@@ -687394,11 +687575,11 @@ async function showCad3dModelsMenu(ctx3, hasLocal, mode) {
687394
687575
  const patch = mode === "cad" ? { cadModel: id2, cadBackend: entry.spec.backend } : { model3dModel: id2, model3dBackend: entry.spec.backend };
687395
687576
  const save3 = hasLocal ? ctx3.saveLocalSettings : ctx3.saveSettings;
687396
687577
  save3(patch);
687397
- const fit5 = rateCad3dModelForHardware(entry.spec, specs);
687578
+ const fit6 = rateCad3dModelForHardware(entry.spec, specs);
687398
687579
  renderInfo(
687399
687580
  `${mode === "cad" ? "CAD" : "3D"} model: ${id2} (${entry.spec.backend})${hasLocal ? " (project-local)" : ""}`
687400
687581
  );
687401
- renderInfo(`Hardware fit: ${fit5.score}/100 ${fit5.label} - ${fit5.note}`);
687582
+ renderInfo(`Hardware fit: ${fit6.score}/100 ${fit6.label} - ${fit6.note}`);
687402
687583
  if (entry.spec.resources.approxDownloadGB) {
687403
687584
  renderInfo(
687404
687585
  `Download estimate: ~${entry.spec.resources.approxDownloadGB}GB in ${unifiedModelStoreDir()}`
@@ -687549,19 +687730,19 @@ async function renderImageModelList(ctx3) {
687549
687730
  renderInfo("");
687550
687731
  renderInfo(c3.bold(category));
687551
687732
  for (const preset of presets) {
687552
- const fit5 = rateImagePresetForHardware(preset, specs);
687733
+ const fit6 = rateImagePresetForHardware(preset, specs);
687553
687734
  const primary = category === "Primary hyper-realistic baseline" ? c3.cyan(" ★") : "";
687554
687735
  const disk = ctx3 ? imageModelDiskStats(ctx3, preset, ollamaSizes) : { downloaded: false, bytes: 0, paths: [] };
687555
687736
  const diskInfo = disk.downloaded ? ` ${c3.green("✓")} ${formatFileSize(disk.bytes)}` : "";
687556
687737
  renderInfo(
687557
- `${imageFitIcon(fit5.score)} ${String(fit5.score).padStart(3)}/100 ${c3.bold(preset.label)}${primary}${diskInfo}`
687738
+ `${imageFitIcon(fit6.score)} ${String(fit6.score).padStart(3)}/100 ${c3.bold(preset.label)}${primary}${diskInfo}`
687558
687739
  );
687559
687740
  renderInfo(` id: ${preset.id}`);
687560
687741
  renderInfo(
687561
- ` type: ${preset.backend} · ${preset.sizeClass ?? "unknown size"} · ${fit5.label}`
687742
+ ` type: ${preset.backend} · ${preset.sizeClass ?? "unknown size"} · ${fit6.label}`
687562
687743
  );
687563
687744
  renderImagePresetDetail(" quality: ", preset.quality ?? preset.note);
687564
- renderImagePresetDetail(" fit: ", fit5.note);
687745
+ renderImagePresetDetail(" fit: ", fit6.note);
687565
687746
  if (preset.deployment)
687566
687747
  renderImagePresetDetail(" deploy: ", preset.deployment);
687567
687748
  }
@@ -687704,13 +687885,13 @@ async function showImageModelsMenu(ctx3, hasLocal) {
687704
687885
  () => /* @__PURE__ */ new Map()
687705
687886
  );
687706
687887
  const buildModelItem = (preset) => {
687707
- const fit5 = rateImagePresetForHardware(preset, specs);
687888
+ const fit6 = rateImagePresetForHardware(preset, specs);
687708
687889
  const disk = imageModelDiskStats(ctx3, preset, ollamaSizes);
687709
687890
  const downloaded = disk.downloaded ? `${c3.green("✓")} ` : "";
687710
687891
  return {
687711
687892
  key: `model:${preset.id}`,
687712
- label: `${downloaded}${imageFitIcon(fit5.score)} ${String(fit5.score).padStart(3)}/100 ${preset.label}`,
687713
- detail: `${fit5.score}/100 ${fit5.label} · ${preset.category ?? preset.backend} · ${preset.sizeClass ?? preset.id}${downloadedModelSuffix(disk)}`
687893
+ label: `${downloaded}${imageFitIcon(fit6.score)} ${String(fit6.score).padStart(3)}/100 ${preset.label}`,
687894
+ detail: `${fit6.score}/100 ${fit6.label} · ${preset.category ?? preset.backend} · ${preset.sizeClass ?? preset.id}${downloadedModelSuffix(disk)}`
687714
687895
  };
687715
687896
  };
687716
687897
  const items = [
@@ -687795,9 +687976,9 @@ async function showImageModelsMenu(ctx3, hasLocal) {
687795
687976
  renderInfo(
687796
687977
  `Image model: ${model} (${backend})${hasLocal ? " (project-local)" : ""}`
687797
687978
  );
687798
- const fit5 = preset ? rateImagePresetForHardware(preset, specs) : void 0;
687799
- if (fit5)
687800
- renderInfo(`Hardware fit: ${fit5.score}/100 ${fit5.label} — ${fit5.note}`);
687979
+ const fit6 = preset ? rateImagePresetForHardware(preset, specs) : void 0;
687980
+ if (fit6)
687981
+ renderInfo(`Hardware fit: ${fit6.score}/100 ${fit6.label} — ${fit6.note}`);
687801
687982
  if (preset?.install) renderInfo(`Prewarm command: ${preset.install}`);
687802
687983
  await prewarmImageModel(ctx3, model, backend);
687803
687984
  }
@@ -688113,19 +688294,19 @@ async function renderVideoModelList(ctx3) {
688113
688294
  renderInfo("");
688114
688295
  renderInfo(c3.bold(category));
688115
688296
  for (const preset of presets) {
688116
- const fit5 = rateVideoPresetForHardware(preset, specs);
688297
+ const fit6 = rateVideoPresetForHardware(preset, specs);
688117
688298
  const disk = videoModelDiskStats(ctx3, preset);
688118
688299
  const diskInfo = disk.downloaded ? ` ${c3.green("✓")} ${formatFileSize(disk.bytes)}` : "";
688119
688300
  renderInfo(
688120
- `${imageFitIcon(fit5.score)} ${String(fit5.score).padStart(3)}/100 ${c3.bold(preset.label)}${diskInfo}`
688301
+ `${imageFitIcon(fit6.score)} ${String(fit6.score).padStart(3)}/100 ${c3.bold(preset.label)}${diskInfo}`
688121
688302
  );
688122
688303
  renderInfo(` id: ${preset.id}`);
688123
688304
  renderInfo(
688124
- ` type: ${preset.backend} · ${preset.sizeClass} · ${preset.kinds.join("/")} · ${fit5.label}`
688305
+ ` type: ${preset.backend} · ${preset.sizeClass} · ${preset.kinds.join("/")} · ${fit6.label}`
688125
688306
  );
688126
688307
  renderImagePresetDetail(" quality: ", preset.quality);
688127
688308
  renderImagePresetDetail(" output: ", preset.output);
688128
- renderImagePresetDetail(" fit: ", fit5.note);
688309
+ renderImagePresetDetail(" fit: ", fit6.note);
688129
688310
  renderImagePresetDetail(" deploy: ", preset.deployment);
688130
688311
  if (preset.licenseNote)
688131
688312
  renderImagePresetDetail(" license: ", preset.licenseNote);
@@ -688136,13 +688317,13 @@ async function showVideoModelsMenu(ctx3, hasLocal) {
688136
688317
  const settings = resolveSettings(ctx3.repoRoot);
688137
688318
  const specs = await detectSystemSpecsAsync();
688138
688319
  const buildModelItem = (preset) => {
688139
- const fit5 = rateVideoPresetForHardware(preset, specs);
688320
+ const fit6 = rateVideoPresetForHardware(preset, specs);
688140
688321
  const disk = videoModelDiskStats(ctx3, preset);
688141
688322
  const downloaded = disk.downloaded ? `${c3.green("✓")} ` : "";
688142
688323
  return {
688143
688324
  key: `model:${preset.id}`,
688144
- label: `${downloaded}${imageFitIcon(fit5.score)} ${String(fit5.score).padStart(3)}/100 ${preset.label}`,
688145
- detail: `${fit5.label} · ${preset.category} · ${preset.kinds.join("/")}${downloadedModelSuffix(disk)}`
688325
+ label: `${downloaded}${imageFitIcon(fit6.score)} ${String(fit6.score).padStart(3)}/100 ${preset.label}`,
688326
+ detail: `${fit6.label} · ${preset.category} · ${preset.kinds.join("/")}${downloadedModelSuffix(disk)}`
688146
688327
  };
688147
688328
  };
688148
688329
  const items = [
@@ -688221,8 +688402,8 @@ async function showVideoModelsMenu(ctx3, hasLocal) {
688221
688402
  `Video model: ${model} (${backend})${hasLocal ? " (project-local)" : ""}`
688222
688403
  );
688223
688404
  if (preset) {
688224
- const fit5 = rateVideoPresetForHardware(preset, specs);
688225
- renderInfo(`Hardware fit: ${fit5.score}/100 ${fit5.label} — ${fit5.note}`);
688405
+ const fit6 = rateVideoPresetForHardware(preset, specs);
688406
+ renderInfo(`Hardware fit: ${fit6.score}/100 ${fit6.label} — ${fit6.note}`);
688226
688407
  if (preset.licenseNote) renderInfo(`License: ${preset.licenseNote}`);
688227
688408
  if (preset.install) renderInfo(`Prewarm command: ${preset.install}`);
688228
688409
  }
@@ -688484,19 +688665,19 @@ async function renderAudioModelList(ctx3, kind) {
688484
688665
  renderInfo("");
688485
688666
  renderInfo(c3.bold(category));
688486
688667
  for (const preset of presets) {
688487
- const fit5 = rateAudioPresetForHardware(preset, specs);
688668
+ const fit6 = rateAudioPresetForHardware(preset, specs);
688488
688669
  const disk = audioModelDiskStats(ctx3, preset);
688489
688670
  const diskInfo = disk.downloaded ? ` ${c3.green("✓")} ${formatFileSize(disk.bytes)}` : "";
688490
688671
  renderInfo(
688491
- `${audioFitIcon(fit5.score)} ${String(fit5.score).padStart(3)}/100 ${c3.bold(preset.label)}${diskInfo}`
688672
+ `${audioFitIcon(fit6.score)} ${String(fit6.score).padStart(3)}/100 ${c3.bold(preset.label)}${diskInfo}`
688492
688673
  );
688493
688674
  renderInfo(` id: ${preset.id}`);
688494
688675
  renderInfo(
688495
- ` type: ${preset.backend} · ${preset.sizeClass} · ${fit5.label}`
688676
+ ` type: ${preset.backend} · ${preset.sizeClass} · ${fit6.label}`
688496
688677
  );
688497
688678
  renderImagePresetDetail(" quality: ", preset.quality);
688498
688679
  renderImagePresetDetail(" output: ", preset.output);
688499
- renderImagePresetDetail(" fit: ", fit5.note);
688680
+ renderImagePresetDetail(" fit: ", fit6.note);
688500
688681
  renderImagePresetDetail(" deploy: ", preset.deployment);
688501
688682
  }
688502
688683
  }
@@ -688521,13 +688702,13 @@ async function showAudioGenerationMenu(ctx3, hasLocal, kind) {
688521
688702
  const activeModel = activeAudioModel(settings, kind);
688522
688703
  const title = kind === "music" ? "Music Generation" : "Sound Generation";
688523
688704
  const buildModelItem = (preset) => {
688524
- const fit5 = rateAudioPresetForHardware(preset, specs);
688705
+ const fit6 = rateAudioPresetForHardware(preset, specs);
688525
688706
  const disk = audioModelDiskStats(ctx3, preset);
688526
688707
  const downloaded = disk.downloaded ? `${c3.green("✓")} ` : "";
688527
688708
  return {
688528
688709
  key: `model:${preset.id}`,
688529
- label: `${downloaded}${audioFitIcon(fit5.score)} ${String(fit5.score).padStart(3)}/100 ${preset.label}`,
688530
- detail: `${fit5.label} · ${preset.category} · ${preset.sizeClass}${downloadedModelSuffix(disk)}`
688710
+ label: `${downloaded}${audioFitIcon(fit6.score)} ${String(fit6.score).padStart(3)}/100 ${preset.label}`,
688711
+ detail: `${fit6.label} · ${preset.category} · ${preset.sizeClass}${downloadedModelSuffix(disk)}`
688531
688712
  };
688532
688713
  };
688533
688714
  const setupItems = kind === "music" ? [
@@ -688648,8 +688829,8 @@ async function showAudioGenerationMenu(ctx3, hasLocal, kind) {
688648
688829
  `${kind === "music" ? "Music" : "Sound"} model: ${model} (${backend})${hasLocal ? " (project-local)" : ""}`
688649
688830
  );
688650
688831
  if (preset) {
688651
- const fit5 = rateAudioPresetForHardware(preset, specs);
688652
- renderInfo(`Hardware fit: ${fit5.score}/100 ${fit5.label} - ${fit5.note}`);
688832
+ const fit6 = rateAudioPresetForHardware(preset, specs);
688833
+ renderInfo(`Hardware fit: ${fit6.score}/100 ${fit6.label} - ${fit6.note}`);
688653
688834
  renderInfo(`Prewarm command: ${preset.install}`);
688654
688835
  }
688655
688836
  await prewarmAudioModel(ctx3, kind, model, backend);
@@ -698727,8 +698908,8 @@ function generateDescriptors(repoRoot) {
698727
698908
  if (repoName2 && !tags.includes(repoName2)) {
698728
698909
  tags.push(repoName2);
698729
698910
  }
698730
- const unique3 = [...new Set(tags.map((t2) => t2.toLowerCase().trim()).filter((t2) => t2.length > 1 && t2.length < 60))];
698731
- const phrases = unique3.map((text2) => ({
698911
+ const unique4 = [...new Set(tags.map((t2) => t2.toLowerCase().trim()).filter((t2) => t2.length > 1 && t2.length < 60))];
698912
+ const phrases = unique4.map((text2) => ({
698732
698913
  text: text2,
698733
698914
  color: weightedColor(profile)
698734
698915
  }));
@@ -698749,7 +698930,7 @@ function generateDescriptors(repoRoot) {
698749
698930
  ];
698750
698931
  for (const fb of fallbacks) {
698751
698932
  if (phrases.length >= 20) break;
698752
- if (!unique3.includes(fb)) {
698933
+ if (!unique4.includes(fb)) {
698753
698934
  phrases.push({ text: fb, color: weightedColor(profile) });
698754
698935
  }
698755
698936
  }
@@ -699842,6 +700023,370 @@ var init_stream_renderer = __esm({
699842
700023
  }
699843
700024
  });
699844
700025
 
700026
+ // packages/cli/src/tui/action-tree.ts
700027
+ function receiptDetails(receipt) {
700028
+ const details = [
700029
+ `command: ${compactText3(receipt.canonicalCommand || receipt.command, 220)}`,
700030
+ `receipt cwd: ${receipt.cwd}`,
700031
+ `exit: ${receipt.exitCode ?? "unknown"}${receipt.timedOut ? " · timed out" : ""}${receipt.pipefail ? " · pipefail" : ""}`,
700032
+ `finished: ${formatTime4(receipt.finishedAtIso)}`
700033
+ ];
700034
+ for (const artifact of receipt.artifactHashes ?? []) {
700035
+ details.push(`artifact: ${artifact.path} #${artifact.sha256.slice(0, 12)}`);
700036
+ }
700037
+ return details;
700038
+ }
700039
+ function stateMark(state) {
700040
+ switch (state) {
700041
+ case "passed":
700042
+ return ui.ok("●");
700043
+ case "failed":
700044
+ return ui.error("●");
700045
+ case "blocked":
700046
+ return ui.warn("●");
700047
+ case "running":
700048
+ return ui.accent("●");
700049
+ default:
700050
+ return ui.sub("●");
700051
+ }
700052
+ }
700053
+ function colorForState(state, text2) {
700054
+ switch (state) {
700055
+ case "passed":
700056
+ return ui.ok(text2);
700057
+ case "failed":
700058
+ return ui.error(text2);
700059
+ case "blocked":
700060
+ return ui.warn(text2);
700061
+ case "running":
700062
+ return ui.accent(text2);
700063
+ default:
700064
+ return ui.primary(text2);
700065
+ }
700066
+ }
700067
+ function redactJson(value2) {
700068
+ if (!value2) return "";
700069
+ try {
700070
+ return getSecretRedactor().redactText(JSON.stringify(value2));
700071
+ } catch {
700072
+ return "";
700073
+ }
700074
+ }
700075
+ function compactText3(value2, max) {
700076
+ const redacted = getSecretRedactor().redactText(String(value2 || ""));
700077
+ const single = redacted.replace(/\s+/g, " ").trim();
700078
+ return single.length > max ? `${single.slice(0, Math.max(1, max - 1))}…` : single;
700079
+ }
700080
+ function unique3(values) {
700081
+ return [...new Set(values.filter(Boolean))];
700082
+ }
700083
+ function fit4(line, width) {
700084
+ const visible = stripAnsi(line);
700085
+ if (displayWidth2(visible) <= width) return line;
700086
+ const target = Math.max(1, width - 1);
700087
+ let raw = "";
700088
+ let seen = 0;
700089
+ for (let i2 = 0; i2 < line.length && seen < target; ) {
700090
+ if (line[i2] === "\x1B") {
700091
+ const match = line.slice(i2).match(/^\x1B\[[0-?]*[ -/]*[@-~]/);
700092
+ if (match) {
700093
+ raw += match[0];
700094
+ i2 += match[0].length;
700095
+ continue;
700096
+ }
700097
+ }
700098
+ const codePoint = line.codePointAt(i2);
700099
+ const char = String.fromCodePoint(codePoint);
700100
+ const cells = displayWidth2(char);
700101
+ if (seen + cells > target) break;
700102
+ raw += char;
700103
+ seen += cells;
700104
+ i2 += char.length;
700105
+ }
700106
+ return `${raw}…\x1B[0m`;
700107
+ }
700108
+ function displayWidth2(value2) {
700109
+ let width = 0;
700110
+ for (const char of value2) {
700111
+ const point = char.codePointAt(0);
700112
+ if (new RegExp("\\p{Mark}", "u").test(char)) continue;
700113
+ width += point >= 4352 && (point <= 4447 || point === 9001 || point === 9002 || point >= 11904 && point <= 42191 || point >= 44032 && point <= 55203 || point >= 63744 && point <= 64255 || point >= 65040 && point <= 65049 || point >= 65072 && point <= 65135 || point >= 65280 && point <= 65376 || point >= 65504 && point <= 65510 || point >= 127744) ? 2 : 1;
700114
+ }
700115
+ return width;
700116
+ }
700117
+ function formatTime4(value2) {
700118
+ const date = new Date(value2);
700119
+ if (Number.isNaN(date.getTime())) return value2;
700120
+ return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" });
700121
+ }
700122
+ var ActionTreeStore;
700123
+ var init_action_tree = __esm({
700124
+ "packages/cli/src/tui/action-tree.ts"() {
700125
+ init_secret_redactor();
700126
+ init_render();
700127
+ init_text_selection();
700128
+ ActionTreeStore = class {
700129
+ root = null;
700130
+ actionNodes = /* @__PURE__ */ new Map();
700131
+ turnNodes = /* @__PURE__ */ new Map();
700132
+ lastRenderedNodeByRow = /* @__PURE__ */ new Map();
700133
+ nodeById = /* @__PURE__ */ new Map();
700134
+ sequence = 0;
700135
+ maxTopLevelNodes = 180;
700136
+ startRun(run2) {
700137
+ this.actionNodes.clear();
700138
+ this.turnNodes.clear();
700139
+ this.lastRenderedNodeByRow.clear();
700140
+ this.nodeById.clear();
700141
+ this.sequence = 0;
700142
+ const id2 = run2.id || `run-${Date.now()}`;
700143
+ const root = {
700144
+ id: id2,
700145
+ kind: "run",
700146
+ label: compactText3(run2.task, 150) || "Untitled task",
700147
+ state: "running",
700148
+ at: run2.startedAt || (/* @__PURE__ */ new Date()).toISOString(),
700149
+ expanded: true,
700150
+ details: [],
700151
+ children: []
700152
+ };
700153
+ const workspace = {
700154
+ id: `${id2}:workspace`,
700155
+ kind: "workspace",
700156
+ label: "current working dir",
700157
+ state: "info",
700158
+ at: root.at,
700159
+ expanded: true,
700160
+ details: [run2.cwd || "(not supplied)"],
700161
+ children: []
700162
+ };
700163
+ root.children.push(workspace);
700164
+ this.root = root;
700165
+ this.nodeById.set(root.id, root);
700166
+ this.nodeById.set(workspace.id, workspace);
700167
+ }
700168
+ recordEvent(event, options2 = {}) {
700169
+ if (!this.root) {
700170
+ this.startRun({
700171
+ task: "Run activity",
700172
+ cwd: options2.cwd || event.workingDirectory || process.cwd(),
700173
+ startedAt: event.timestamp
700174
+ });
700175
+ }
700176
+ const root = this.root;
700177
+ const at = event.timestamp || (/* @__PURE__ */ new Date()).toISOString();
700178
+ switch (event.type) {
700179
+ case "tool_call": {
700180
+ const actionId = this.actionIdFor(event, options2.agentId);
700181
+ const action = this.addActionNode(root, actionId, event, options2, at);
700182
+ this.actionNodes.set(actionId, action);
700183
+ break;
700184
+ }
700185
+ case "tool_result": {
700186
+ const actionId = this.actionIdFor(event, options2.agentId);
700187
+ const action = this.actionNodes.get(actionId) ?? this.addActionNode(root, actionId, event, options2, at);
700188
+ this.actionNodes.set(actionId, action);
700189
+ action.state = event.synthetic || event.blocked ? "blocked" : event.success === false ? "failed" : "passed";
700190
+ action.at = at;
700191
+ action.details = this.resultDetails(event, options2);
700192
+ break;
700193
+ }
700194
+ case "model_response":
700195
+ case "assistant_text": {
700196
+ const text2 = compactText3(event.content || "", 220);
700197
+ if (!text2) break;
700198
+ this.addNode(this.parentForTurn(root, event, options2.agentId, at), {
700199
+ id: this.nextId("reasoning"),
700200
+ kind: "reasoning",
700201
+ label: "reasoning / response",
700202
+ state: "info",
700203
+ at,
700204
+ // The tree makes the fact that thought text exists observable, but
700205
+ // keeps it collapsed until explicitly opened.
700206
+ expanded: false,
700207
+ details: [text2],
700208
+ children: []
700209
+ });
700210
+ break;
700211
+ }
700212
+ case "trajectory_checkpoint": {
700213
+ const checkpoint = event.trajectory;
700214
+ const summary = compactText3(
700215
+ [checkpoint?.assessment, checkpoint?.nextAction, event.content].filter(Boolean).join(" · "),
700216
+ 220
700217
+ );
700218
+ this.addNode(this.parentForTurn(root, event, options2.agentId, at), {
700219
+ id: this.nextId("checkpoint"),
700220
+ kind: "checkpoint",
700221
+ label: "trajectory checkpoint",
700222
+ state: checkpoint?.assessment === "blocked" ? "blocked" : "info",
700223
+ at,
700224
+ expanded: false,
700225
+ details: summary ? [summary] : [],
700226
+ children: []
700227
+ });
700228
+ break;
700229
+ }
700230
+ case "complete":
700231
+ case "error": {
700232
+ root.state = event.type === "complete" ? "passed" : "failed";
700233
+ this.addNode(root, {
700234
+ id: this.nextId("outcome"),
700235
+ kind: "outcome",
700236
+ label: event.type === "complete" ? "run completed" : "run error",
700237
+ state: event.type === "complete" ? "passed" : "failed",
700238
+ at,
700239
+ expanded: true,
700240
+ details: compactText3(event.content || "", 240) ? [compactText3(event.content || "", 240)] : [],
700241
+ children: []
700242
+ });
700243
+ break;
700244
+ }
700245
+ }
700246
+ this.trim();
700247
+ }
700248
+ /** Render a non-wrapping Unicode tree. Row-to-node links are refreshed here. */
700249
+ render(width) {
700250
+ const maxWidth = Math.max(12, width - 4);
700251
+ this.lastRenderedNodeByRow.clear();
700252
+ if (!this.root) {
700253
+ return [ui.hint("No run recorded yet. Start a task; /tree and Ctrl+Tab will return here.")];
700254
+ }
700255
+ const lines = [];
700256
+ const root = this.root;
700257
+ const rootState = stateMark(root.state);
700258
+ lines.push(
700259
+ fit4(
700260
+ `${ui.accent("╭─ action tree ───────────────────────────────────────────────╮")}`,
700261
+ maxWidth
700262
+ )
700263
+ );
700264
+ const rootRow = lines.length;
700265
+ lines.push(fit4(`${rootState} ${c3.bold(root.expanded ? "[▼] run" : "[▶] run")} ${root.label}`, maxWidth));
700266
+ this.lastRenderedNodeByRow.set(rootRow, root.id);
700267
+ lines.push(fit4(` ${ui.hint(`started ${formatTime4(root.at)} · click a labeled box to expand`)}`, maxWidth));
700268
+ if (root.expanded) this.renderChildren(root.children, "", lines, maxWidth);
700269
+ lines.push(fit4(ui.accent("╰─ Ctrl+Tab or /tree returns to the action stack ──────────────╯"), maxWidth));
700270
+ return lines;
700271
+ }
700272
+ /** Returns true when a clicked rendered row toggled an explorable node. */
700273
+ toggleAtRow(row2) {
700274
+ const id2 = this.lastRenderedNodeByRow.get(row2);
700275
+ const node = id2 ? this.nodeById.get(id2) : void 0;
700276
+ if (!node || node.children.length === 0 && node.details.length === 0) return false;
700277
+ node.expanded = !node.expanded;
700278
+ return true;
700279
+ }
700280
+ addActionNode(root, actionId, event, options2, at) {
700281
+ const parent = this.parentForTurn(root, event, options2.agentId, at);
700282
+ const action = {
700283
+ id: actionId,
700284
+ kind: "action",
700285
+ label: `${event.toolName || "tool"}${event.synthetic || event.blocked ? " (blocked)" : ""}`,
700286
+ state: event.synthetic || event.blocked ? "blocked" : "running",
700287
+ at,
700288
+ expanded: true,
700289
+ details: this.callDetails(event, options2),
700290
+ children: []
700291
+ };
700292
+ this.addNode(parent, action);
700293
+ return action;
700294
+ }
700295
+ parentForTurn(root, event, agentId, at) {
700296
+ const agent = agentId && agentId !== "main" ? `agent:${agentId}` : "main";
700297
+ const turn = event.turn ?? 0;
700298
+ const key = `${agent}:turn:${turn}`;
700299
+ const existing = this.turnNodes.get(key);
700300
+ if (existing) return existing;
700301
+ const node = {
700302
+ id: key,
700303
+ kind: "turn",
700304
+ label: agent === "main" ? `turn ${turn || "activity"}` : `${agent} · turn ${turn || "activity"}`,
700305
+ state: "info",
700306
+ at,
700307
+ expanded: true,
700308
+ details: [],
700309
+ children: []
700310
+ };
700311
+ this.turnNodes.set(key, node);
700312
+ this.addNode(root, node);
700313
+ return node;
700314
+ }
700315
+ callDetails(event, options2) {
700316
+ const details = [];
700317
+ const cwd4 = event.workingDirectory || options2.cwd;
700318
+ if (cwd4) details.push(`cwd: ${cwd4}`);
700319
+ const args = redactJson(event.toolArgs);
700320
+ if (args && args !== "{}") details.push(`args: ${compactText3(args, 220)}`);
700321
+ for (const path16 of event.targetPaths ?? []) details.push(`target: ${path16}`);
700322
+ return unique3(details);
700323
+ }
700324
+ resultDetails(event, options2) {
700325
+ const details = this.callDetails(event, options2);
700326
+ for (const path16 of event.mutatedFiles ?? []) details.push(`changed: ${path16}`);
700327
+ const receipt = event.executionReceipt;
700328
+ if (receipt) details.push(...receiptDetails(receipt));
700329
+ const output = compactText3(event.content || "", 280);
700330
+ if (output) details.push(`result: ${output}`);
700331
+ return unique3(details);
700332
+ }
700333
+ renderChildren(nodes, prefix, lines, maxWidth) {
700334
+ for (let i2 = 0; i2 < nodes.length; i2++) {
700335
+ const node = nodes[i2];
700336
+ const last2 = i2 === nodes.length - 1;
700337
+ const branch = last2 ? "└─" : "├─";
700338
+ const continuation = prefix + (last2 ? " " : "│ ");
700339
+ const expandable = node.children.length > 0 || node.details.length > 0;
700340
+ const toggle = expandable ? node.expanded ? "▼" : "▶" : "•";
700341
+ const title = `${prefix}${branch}┬─╭─ ${toggle} ${node.label} ─╮`;
700342
+ const row2 = lines.length;
700343
+ lines.push(fit4(colorForState(node.state, title), maxWidth));
700344
+ if (expandable) this.lastRenderedNodeByRow.set(row2, node.id);
700345
+ if (!node.expanded) continue;
700346
+ const details = node.details.slice(0, 8);
700347
+ for (const detail of details) {
700348
+ lines.push(fit4(`${continuation}├─│ ${ui.sub(detail)}`, maxWidth));
700349
+ }
700350
+ if (node.details.length > details.length) {
700351
+ lines.push(fit4(`${continuation}├─│ ${ui.hint(`… ${node.details.length - details.length} more details`)}`, maxWidth));
700352
+ }
700353
+ if (node.children.length > 0) {
700354
+ this.renderChildren(node.children, `${continuation}│ `, lines, maxWidth);
700355
+ }
700356
+ lines.push(fit4(`${continuation}└─╰────────────────────────────────────╯`, maxWidth));
700357
+ }
700358
+ }
700359
+ addNode(parent, node) {
700360
+ parent.children.push(node);
700361
+ this.nodeById.set(node.id, node);
700362
+ }
700363
+ actionIdFor(event, agentId) {
700364
+ if (event.actionId) return event.actionId;
700365
+ this.sequence += 1;
700366
+ return `${agentId || "main"}:${event.turn ?? 0}:${event.toolName || "event"}:${this.sequence}`;
700367
+ }
700368
+ nextId(kind) {
700369
+ this.sequence += 1;
700370
+ return `${kind}:${this.sequence}`;
700371
+ }
700372
+ trim() {
700373
+ if (!this.root) return;
700374
+ const children2 = this.root.children;
700375
+ while (children2.length > this.maxTopLevelNodes) {
700376
+ const idx = children2.findIndex((node) => node.kind !== "workspace");
700377
+ if (idx < 0) break;
700378
+ this.dropNode(children2.splice(idx, 1)[0]);
700379
+ }
700380
+ }
700381
+ dropNode(node) {
700382
+ this.nodeById.delete(node.id);
700383
+ this.actionNodes.delete(node.id);
700384
+ for (const child of node.children) this.dropNode(child);
700385
+ }
700386
+ };
700387
+ }
700388
+ });
700389
+
699845
700390
  // packages/cli/src/tui/edit-history.ts
699846
700391
  import { appendFileSync as appendFileSync18, mkdirSync as mkdirSync93 } from "node:fs";
699847
700392
  import { join as join164 } from "node:path";
@@ -704791,13 +705336,13 @@ function buildScopedToolList(scope) {
704791
705336
  const commandSigs = commands.flatMap((cmd) => cmd.signatures);
704792
705337
  const allSigs = [...syntheticSigs, ...commandSigs];
704793
705338
  const seen = /* @__PURE__ */ new Set();
704794
- const unique3 = allSigs.filter((sig) => {
705339
+ const unique4 = allSigs.filter((sig) => {
704795
705340
  if (seen.has(sig.signature)) return false;
704796
705341
  seen.add(sig.signature);
704797
705342
  return true;
704798
705343
  });
704799
705344
  const entries = [];
704800
- for (const sig of unique3) {
705345
+ for (const sig of unique4) {
704801
705346
  const matchingCmd = commands.find(
704802
705347
  (cmd) => cmd.signatures.some((s2) => s2.signature === sig.signature)
704803
705348
  );
@@ -709903,14 +710448,14 @@ function parseTelegramReplyPreferenceUpdate(parsed) {
709903
710448
  }
709904
710449
  function uniqueTelegramJsonCandidates(candidates) {
709905
710450
  const seen = /* @__PURE__ */ new Set();
709906
- const unique3 = [];
710451
+ const unique4 = [];
709907
710452
  for (const candidate of candidates) {
709908
710453
  const clean6 = candidate.trim();
709909
710454
  if (!clean6 || seen.has(clean6)) continue;
709910
710455
  seen.add(clean6);
709911
- unique3.push(clean6);
710456
+ unique4.push(clean6);
709912
710457
  }
709913
- return unique3;
710458
+ return unique4;
709914
710459
  }
709915
710460
  function extractBalancedTelegramJsonObjects(text2) {
709916
710461
  const objects = [];
@@ -710903,10 +711448,10 @@ function telegramHistoryTime(entry) {
710903
711448
  });
710904
711449
  }
710905
711450
  function formatTelegramIdentitySignals(signals) {
710906
- const unique3 = [
711451
+ const unique4 = [
710907
711452
  ...new Set(signals.map((signal) => signal.trim()).filter(Boolean))
710908
711453
  ];
710909
- return unique3.length > 0 ? unique3.join(", ") : "none";
711454
+ return unique4.length > 0 ? unique4.join(", ") : "none";
710910
711455
  }
710911
711456
  function summarizeTelegramMessageAttachments(msg) {
710912
711457
  const parts = [];
@@ -711394,12 +711939,12 @@ function buildTelegramHelpHTML(scope, maxPublicCommands = 24) {
711394
711939
  ...commands.flatMap((cmd) => cmd.signatures)
711395
711940
  ];
711396
711941
  const seen = /* @__PURE__ */ new Set();
711397
- const unique3 = signatures.filter((sig) => {
711942
+ const unique4 = signatures.filter((sig) => {
711398
711943
  if (seen.has(sig.signature)) return false;
711399
711944
  seen.add(sig.signature);
711400
711945
  return true;
711401
711946
  });
711402
- const visible = scope === "public" ? unique3.slice(0, maxPublicCommands) : unique3;
711947
+ const visible = scope === "public" ? unique4.slice(0, maxPublicCommands) : unique4;
711403
711948
  const lines = [
711404
711949
  `<b>Commands (${scope === "admin" ? "admin full scope" : "public secure scope"})</b>`,
711405
711950
  "",
@@ -711407,7 +711952,7 @@ function buildTelegramHelpHTML(scope, maxPublicCommands = 24) {
711407
711952
  (sig) => `<code>${escapeTelegramHTML(sig.signature)}</code> - ${escapeTelegramHTML(sig.description)}`
711408
711953
  )
711409
711954
  ];
711410
- if (scope === "public" && unique3.length > visible.length) {
711955
+ if (scope === "public" && unique4.length > visible.length) {
711411
711956
  lines.push("");
711412
711957
  lines.push(
711413
711958
  `Public scope truncated to ${visible.length} safe commands. Authenticate as admin for full command help.`
@@ -714499,10 +715044,10 @@ ${message2}`)
714499
715044
  telegramModelMenuItems(generation) {
714500
715045
  return this.telegramGenerationModelDescriptors(generation).map((model) => {
714501
715046
  const cached2 = model.cachedBytes > 0 ? `cached ${formatModelBytes(model.cachedBytes)}` : "not downloaded";
714502
- const fit5 = model.recommendedVramGB ? `${model.recommendedVramGB}GB VRAM rec` : model.minVramGB ? `${model.minVramGB}GB VRAM min` : "VRAM n/a";
715047
+ const fit6 = model.recommendedVramGB ? `${model.recommendedVramGB}GB VRAM rec` : model.minVramGB ? `${model.minVramGB}GB VRAM min` : "VRAM n/a";
714503
715048
  return {
714504
715049
  label: model.label,
714505
- description: `${model.backend} - ${model.category} - ${fit5} - ${cached2}`,
715050
+ description: `${model.backend} - ${model.category} - ${fit6} - ${cached2}`,
714506
715051
  action: {
714507
715052
  type: "model_detail",
714508
715053
  generation,
@@ -725877,20 +726422,20 @@ Scoped workspace: ${scopedRoot}`,
725877
726422
  };
725878
726423
  }
725879
726424
  async deleteTelegramMessages(chatId, messageIds, currentMsg) {
725880
- const unique3 = [...new Set(messageIds)].filter((id2) => Number.isFinite(id2));
725881
- if (unique3.length === 0)
726425
+ const unique4 = [...new Set(messageIds)].filter((id2) => Number.isFinite(id2));
726426
+ if (unique4.length === 0)
725882
726427
  throw new Error(
725883
726428
  "deleteTelegramMessages requires at least one message id."
725884
726429
  );
725885
726430
  await this.assertTelegramBotRightsForAction(
725886
726431
  "delete_messages",
725887
726432
  chatId,
725888
- unique3,
726433
+ unique4,
725889
726434
  currentMsg
725890
726435
  );
725891
726436
  const chunks = [];
725892
- for (let idx = 0; idx < unique3.length; idx += 100)
725893
- chunks.push(unique3.slice(idx, idx + 100));
726437
+ for (let idx = 0; idx < unique4.length; idx += 100)
726438
+ chunks.push(unique4.slice(idx, idx + 100));
725894
726439
  const results = [];
725895
726440
  for (const chunk of chunks) {
725896
726441
  const result = await this.apiCall("deleteMessages", {
@@ -725908,9 +726453,9 @@ Scoped workspace: ${scopedRoot}`,
725908
726453
  telegram_method: "deleteMessages",
725909
726454
  ok: true,
725910
726455
  chat_id: chatId,
725911
- message_ids: unique3,
726456
+ message_ids: unique4,
725912
726457
  batches: results,
725913
- bot_rights_checked: !this.telegramTargetLooksPrivate(chatId, currentMsg) && !unique3.every((id2) => this.isKnownAssistantTelegramMessage(chatId, id2)),
726458
+ bot_rights_checked: !this.telegramTargetLooksPrivate(chatId, currentMsg) && !unique4.every((id2) => this.isKnownAssistantTelegramMessage(chatId, id2)),
725914
726459
  policy_scope: this.telegramToolPolicy.chatOverrides?.[String(chatId)] ? "chat" : "global/default"
725915
726460
  };
725916
726461
  }
@@ -728784,9 +729329,9 @@ function pushShellLiveLine(state, line) {
728784
729329
  }
728785
729330
  }
728786
729331
  function contentRow2(value2, inner) {
728787
- return `│ ${fit4(value2, inner)} │`;
729332
+ return `│ ${fit5(value2, inner)} │`;
728788
729333
  }
728789
- function fit4(value2, width) {
729334
+ function fit5(value2, width) {
728790
729335
  const plain = value2.replace(ANSI_OR_OSC_RE, "").replace(/\s+$/g, "");
728791
729336
  const chars = Array.from(plain);
728792
729337
  if (chars.length > width) {
@@ -728859,8 +729404,8 @@ function gibberishTokenPenalty(s2) {
728859
729404
  const tokens = s2.trim().split(/\s+/).filter(Boolean);
728860
729405
  if (tokens.length < 2) return 0;
728861
729406
  let penalty = 0;
728862
- const unique3 = new Set(tokens.map((t2) => t2.toLowerCase()));
728863
- const uniqueRatio = unique3.size / tokens.length;
729407
+ const unique4 = new Set(tokens.map((t2) => t2.toLowerCase()));
729408
+ const uniqueRatio = unique4.size / tokens.length;
728864
729409
  if (tokens.length >= 4 && uniqueRatio <= 0.5) {
728865
729410
  penalty += Math.min(1, (0.5 - uniqueRatio) * 2 + 0.5);
728866
729411
  }
@@ -731026,6 +731571,10 @@ var init_direct_input = __esm({
731026
731571
  this._insertText("\n");
731027
731572
  return;
731028
731573
  }
731574
+ if (params === "27;5;9") {
731575
+ this.emit("ctrl-tab");
731576
+ return;
731577
+ }
731029
731578
  if (params === "3") {
731030
731579
  if (this.cursor < this.line.length) {
731031
731580
  this.line = this.line.slice(0, this.cursor) + this.line.slice(this.cursor + 1);
@@ -731069,6 +731618,10 @@ var init_direct_input = __esm({
731069
731618
  this.emit("ctrl-i");
731070
731619
  return;
731071
731620
  }
731621
+ if (hasCtrl && !hasShift && codepoint === 9) {
731622
+ this.emit("ctrl-tab");
731623
+ return;
731624
+ }
731072
731625
  return;
731073
731626
  }
731074
731627
  }
@@ -731183,10 +731736,6 @@ var init_direct_input = __esm({
731183
731736
  }
731184
731737
  /** Handle Tab completion */
731185
731738
  _handleTab() {
731186
- if (this.line.length === 0) {
731187
- this.emit("ctrl-i");
731188
- return;
731189
- }
731190
731739
  if (!this._completer) return;
731191
731740
  this._completer(this.line, (err, result) => {
731192
731741
  if (err || !result) return;
@@ -763953,6 +764502,20 @@ function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce
763953
764502
  }
763954
764503
  const modelTier2 = getModelTier(config.model);
763955
764504
  const sessionId = typeof restoredRunSessionId === "string" && restoredRunSessionId.trim() ? restoredRunSessionId.trim() : `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
764505
+ const actionTree = statusBar ? new ActionTreeStore() : null;
764506
+ actionTree?.startRun({
764507
+ id: sessionId,
764508
+ task: actualUserGoal ?? task,
764509
+ cwd: repoRoot
764510
+ });
764511
+ statusBar?.setActionTreeRenderer(
764512
+ (width) => actionTree?.render(width) ?? [],
764513
+ (row2) => {
764514
+ const toggled = actionTree?.toggleAtRow(row2) ?? false;
764515
+ if (toggled) statusBar.refreshActionTree();
764516
+ return toggled;
764517
+ }
764518
+ );
763956
764519
  const taskMetricDescription = cleanForStorage(task).replace(/\s+/g, " ").slice(0, 160) || "task";
763957
764520
  costTracker?.startTask(taskMetricDescription);
763958
764521
  sessionMetrics?.startTask(taskMetricDescription);
@@ -764525,7 +765088,11 @@ ${content}
764525
765088
  statusBar.ensureMonitorTimer();
764526
765089
  },
764527
765090
  onViewWrite: (id2, text2) => statusBar.recordAgentOutput(id2, text2),
764528
- onViewEvent: (id2, event) => writeSubAgentEventForView(statusBar, id2, event, config.verbose),
765091
+ onViewEvent: (id2, event) => {
765092
+ actionTree?.recordEvent(event, { agentId: id2, cwd: repoRoot });
765093
+ if (statusBar.contentPresentation === "tree") statusBar.refreshActionTree();
765094
+ return writeSubAgentEventForView(statusBar, id2, event, config.verbose);
765095
+ },
764529
765096
  onViewStatus: (id2, status) => {
764530
765097
  statusBar.updateAgentViewStatus(id2, status);
764531
765098
  const agent = registry2.subAgents.get(id2);
@@ -765103,6 +765670,8 @@ ${entry.fullContent}`
765103
765670
  }
765104
765671
  };
765105
765672
  runner.onEvent((event) => {
765673
+ actionTree?.recordEvent(event, { agentId: "main", cwd: repoRoot });
765674
+ if (statusBar?.contentPresentation === "tree") statusBar.refreshActionTree();
765106
765675
  emotionEngine?.appraise(event);
765107
765676
  const stageTransition = stageForAgentEvent(event);
765108
765677
  if (stageTransition) {
@@ -766509,6 +767078,15 @@ async function startInteractive(config, repoPath2) {
766509
767078
  }
766510
767079
  const statusBar = new StatusBar();
766511
767080
  statusBar.setVersion(version5);
767081
+ const idleActionTree = new ActionTreeStore();
767082
+ statusBar.setActionTreeRenderer(
767083
+ (width) => idleActionTree.render(width),
767084
+ (row2) => {
767085
+ const toggled = idleActionTree.toggleAtRow(row2);
767086
+ if (toggled) statusBar.refreshActionTree();
767087
+ return toggled;
767088
+ }
767089
+ );
766512
767090
  _liveMediaStatusSink = (status) => statusBar.setLiveMediaStatus(status);
766513
767091
  setBannerWriter((data) => statusBar.writeChrome(data));
766514
767092
  setCarouselWriter((data) => statusBar.writeChrome(data));
@@ -768723,6 +769301,15 @@ This is an independent background session started from /background.`
768723
769301
  refreshDisplay() {
768724
769302
  statusBar.refreshDisplay();
768725
769303
  },
769304
+ toggleActionTree() {
769305
+ return statusBar.toggleActionTree();
769306
+ },
769307
+ setActionTreeMode(mode) {
769308
+ return statusBar.setContentPresentation(mode);
769309
+ },
769310
+ getActionTreeMode() {
769311
+ return statusBar.contentPresentation;
769312
+ },
768726
769313
  exit() {
768727
769314
  if (reminderDispatchTimer) {
768728
769315
  clearInterval(reminderDispatchTimer);
@@ -772859,6 +773446,7 @@ var init_interactive = __esm({
772859
773446
  init_carousel_descriptors();
772860
773447
  init_voice();
772861
773448
  init_stream_renderer();
773449
+ init_action_tree();
772862
773450
  init_tui_select();
772863
773451
  init_edit_history();
772864
773452
  init_theme();