omnius 1.0.572 → 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) {
@@ -468840,7 +468840,7 @@ ${newComment.split("\n").map((c9) => ` * ${c9}`).join("\n")}
468840
468840
  }
468841
468841
  }
468842
468842
  return result;
468843
- function escapeRegExp3(str) {
468843
+ function escapeRegExp4(str) {
468844
468844
  return str.replace(/[-[\]/{}()*+?.\\^$|]/g, "\\$&");
468845
468845
  }
468846
468846
  function getTodoCommentsRegExp() {
@@ -468848,7 +468848,7 @@ ${newComment.split("\n").map((c9) => ` * ${c9}`).join("\n")}
468848
468848
  const multiLineCommentStart = /(?:\/\*+\s*)/.source;
468849
468849
  const anyNumberOfSpacesAndAsterisksAtStartOfLine = /(?:^(?:\s|\*)*)/.source;
468850
468850
  const preamble = "(" + anyNumberOfSpacesAndAsterisksAtStartOfLine + "|" + singleLineCommentStart + "|" + multiLineCommentStart + ")";
468851
- const literals = "(?:" + map2(descriptors, (d2) => "(" + escapeRegExp3(d2.text) + ")").join("|") + ")";
468851
+ const literals = "(?:" + map2(descriptors, (d2) => "(" + escapeRegExp4(d2.text) + ")").join("|") + ")";
468852
468852
  const endOfLineOrEndOfComment = /(?:$|\*\/)/.source;
468853
468853
  const messageRemainder = /(?:.*?)/.source;
468854
468854
  const messagePortion = "(" + literals + messageRemainder + ")";
@@ -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,
@@ -568001,6 +568001,9 @@ function setClaimDiscoveryState(ledger, state) {
568001
568001
  function claimDiscoveryStateFromSurvey(input) {
568002
568002
  const normalizedInventory = input.boundedInventory;
568003
568003
  const paths = [...new Set((Array.isArray(input.candidatePaths) ? input.candidatePaths : []).map((value2) => normalizeEvidencePath(value2)).filter(Boolean).slice(0, 16))];
568004
+ const requestedRequiredPaths = input.requiredArtifactPaths === void 0 ? paths : input.requiredArtifactPaths;
568005
+ const requiredPathSet = new Set((Array.isArray(requestedRequiredPaths) ? requestedRequiredPaths : []).map((value2) => normalizeEvidencePath(value2)).filter((path16) => paths.includes(path16)));
568006
+ const requiredArtifactPaths = paths.filter((path16) => requiredPathSet.has(path16));
568004
568007
  const reasons = /* @__PURE__ */ Object.create(null);
568005
568008
  for (const [rawPath, rawReason] of Object.entries(input.pathReasons ?? {})) {
568006
568009
  const path16 = normalizeEvidencePath(rawPath);
@@ -568008,7 +568011,7 @@ function claimDiscoveryStateFromSurvey(input) {
568008
568011
  if (path16)
568009
568012
  reasons[path16] = reason || "candidate selected from bounded workspace inventory";
568010
568013
  }
568011
- const openDeltas = paths.map((path16) => ({
568014
+ const openDeltas = requiredArtifactPaths.map((path16) => ({
568012
568015
  path: path16,
568013
568016
  reason: reasons[path16] || "candidate selected from bounded workspace inventory"
568014
568017
  }));
@@ -568016,7 +568019,7 @@ function claimDiscoveryStateFromSurvey(input) {
568016
568019
  const blockers = Array.isArray(input.survivingBlockers) ? input.survivingBlockers.map((item) => cleanText(item, 220)).filter(Boolean) : [];
568017
568020
  const hasBlockers = blockers.length > 0;
568018
568021
  const hasQuestions = unresolved.length > 0;
568019
- const resolvedStatus = paths.length === 0 ? hasBlockers || hasQuestions ? "blocked" : "skipped" : hasBlockers || hasQuestions ? "blocked" : "active";
568022
+ const resolvedStatus = requiredArtifactPaths.length === 0 ? hasBlockers || hasQuestions ? "blocked" : "skipped" : hasBlockers || hasQuestions ? "blocked" : "active";
568020
568023
  return {
568021
568024
  status: resolvedStatus,
568022
568025
  generatedAtIso: nowIso3(),
@@ -568024,13 +568027,14 @@ function claimDiscoveryStateFromSurvey(input) {
568024
568027
  context: cleanText(input.context, 480),
568025
568028
  boundedInventory: normalizedInventory,
568026
568029
  candidatePaths: paths,
568030
+ requiredArtifactPaths,
568027
568031
  pathReasons: reasons,
568028
568032
  unresolvedQuestions: unresolved.slice(0, 10),
568029
568033
  openDeltas,
568030
568034
  survivingBlockers: blockers.slice(0, 8),
568031
- evidenceHandles: [...new Set(paths.map((path16) => `workspace:${path16}`))],
568035
+ evidenceHandles: [...new Set(requiredArtifactPaths.map((path16) => `workspace:${path16}`))],
568032
568036
  resolvedEvidenceHandles: [],
568033
- requiresEvidence: typeof input.requiresEvidence === "boolean" ? input.requiresEvidence : true
568037
+ requiresEvidence: typeof input.requiresEvidence === "boolean" ? input.requiresEvidence : requiredArtifactPaths.length > 0
568034
568038
  };
568035
568039
  }
568036
568040
  function nowIso3(now2 = /* @__PURE__ */ new Date()) {
@@ -568240,6 +568244,9 @@ function claimDiscoveryControllerSignals(stage2) {
568240
568244
  const unresolvedQuestions = stage2.unresolvedQuestions ?? [];
568241
568245
  const boundedInventory = stage2.boundedInventory;
568242
568246
  const boundedDirs = boundedInventory?.dirs ?? [];
568247
+ const requiredArtifactPaths = stage2.requiredArtifactPaths ?? stage2.candidatePaths ?? [];
568248
+ const requiredSet = new Set(requiredArtifactPaths);
568249
+ const exploratoryPaths = (stage2.candidatePaths ?? []).filter((path16) => !requiredSet.has(path16));
568243
568250
  const resolvedCount = Math.min(evidenceHandles.length, new Set(resolvedEvidenceHandles).size);
568244
568251
  const unresolvedEvidenceCount = Math.max(evidenceHandles.length - resolvedCount, 0);
568245
568252
  return [
@@ -568247,7 +568254,8 @@ function claimDiscoveryControllerSignals(stage2) {
568247
568254
  `status=${stage2.status ?? "skipped"} generated_at=${stage2.generatedAtIso ?? ""}`,
568248
568255
  `requires_evidence=${stage2.requiresEvidence ? "true" : "false"}`,
568249
568256
  `bounded_inventory=${boundedInventory ? `${boundedInventory.root}|files=${boundedInventory.files.length}|dirs=${boundedDirs.length}|truncated=${Boolean(boundedInventory.truncated)}` : "none"}`,
568250
- `candidate_paths=${(stage2.candidatePaths ?? []).join(",") || "none"}`,
568257
+ `required_artifact_paths=${requiredArtifactPaths.join(",") || "none"}`,
568258
+ `exploratory_paths=${exploratoryPaths.join(",") || "none"}`,
568251
568259
  `open_deltas=${openDeltas.map((delta) => `${delta.path} :: ${delta.reason}`.replace(/\s+/g, " ")).join(" | ") || "none"}`,
568252
568260
  `open_delta_count=${openDeltas.length} unresolved_evidence_count=${unresolvedEvidenceCount}`,
568253
568261
  `surviving_blockers=${survivingBlockers.join(" | ") || "none"}`,
@@ -568438,7 +568446,10 @@ function buildCriticPacketFromLedger(ledger) {
568438
568446
  lines.push("Claim Discovery:");
568439
568447
  lines.push(` status=${ledger.claimDiscovery.status}`);
568440
568448
  lines.push(` generated_at=${ledger.claimDiscovery.generatedAtIso}`);
568441
- lines.push(` candidate_paths=${ledger.claimDiscovery.candidatePaths.join(",") || "none"}`);
568449
+ const requiredArtifactPaths = ledger.claimDiscovery.requiredArtifactPaths ?? ledger.claimDiscovery.candidatePaths;
568450
+ const exploratoryPaths = ledger.claimDiscovery.candidatePaths.filter((path16) => !requiredArtifactPaths.includes(path16));
568451
+ lines.push(` exploratory_paths=${exploratoryPaths.join(",") || "none"}`);
568452
+ lines.push(` required_artifact_paths=${requiredArtifactPaths.join(",") || "none"}`);
568442
568453
  lines.push(` open_deltas=${ledger.claimDiscovery.openDeltas.map((delta) => `${delta.path} :: ${delta.reason}`).slice(0, 10).join(" | ") || "none"}`);
568443
568454
  lines.push(` surviving_blockers=${ledger.claimDiscovery.survivingBlockers.join(" | ") || "none"}`);
568444
568455
  lines.push(` unresolved_questions=${ledger.claimDiscovery.unresolvedQuestions.join(" | ") || "none"}`);
@@ -568558,7 +568569,7 @@ function claimDiscoveryResolvedHandles(ledger, state) {
568558
568569
  if (!state)
568559
568570
  return [];
568560
568571
  const inspected = /* @__PURE__ */ new Set();
568561
- const candidatePaths = [...state.candidatePaths].map((value2) => normalizeEvidencePath(value2)).filter(Boolean).map((path16) => path16.replace(/^\/+/, ""));
568572
+ const candidatePaths = [...state.requiredArtifactPaths ?? state.candidatePaths].map((value2) => normalizeEvidencePath(value2)).filter(Boolean).map((path16) => path16.replace(/^\/+/, ""));
568562
568573
  for (const entry of ledger.evidence) {
568563
568574
  if (entry.success !== true)
568564
568575
  continue;
@@ -569145,6 +569156,10 @@ import { createHash as createHash28 } from "node:crypto";
569145
569156
  function clean3(value2, max) {
569146
569157
  return String(value2 ?? "").replace(/\s+/g, " ").trim().slice(0, max);
569147
569158
  }
569159
+ function isValidObservationReceipt(entry) {
569160
+ const receipt = entry.receipt;
569161
+ return entry.success === true && entry.role === "observation" && receipt?.schema === "omnius.command-evidence-receipt.v1" && Boolean(receipt.canonicalCommand.trim()) && Boolean(receipt.cwd.trim()) && receipt.exitCode === 0 && receipt.timedOut === false;
569162
+ }
569148
569163
  function selectedEvidence(ledger) {
569149
569164
  if (!ledger) {
569150
569165
  return {
@@ -569153,7 +569168,7 @@ function selectedEvidence(ledger) {
569153
569168
  artifactHashes: []
569154
569169
  };
569155
569170
  }
569156
- const candidates = ledger.evidence.filter((entry) => entry.success === true && (entry.role === "verification" || entry.role === "mutation")).slice(-16);
569171
+ const candidates = ledger.evidence.filter((entry) => entry.success === true && (entry.role === "verification" || entry.role === "mutation" || isValidObservationReceipt(entry))).slice(-16);
569157
569172
  const artifacts = /* @__PURE__ */ new Map();
569158
569173
  const commandReceipts = [];
569159
569174
  for (const entry of candidates) {
@@ -569174,6 +569189,7 @@ function selectedEvidence(ledger) {
569174
569189
  timedOut: Boolean(receipt.timedOut),
569175
569190
  startedAtIso: receipt.startedAtIso ?? "",
569176
569191
  finishedAtIso: receipt.finishedAtIso ?? "",
569192
+ observedPaths: receipt.observedPaths ?? [],
569177
569193
  artifactHashes: entry.receipt.artifactHashes?.length ? entry.receipt.artifactHashes : []
569178
569194
  });
569179
569195
  }
@@ -590943,6 +590959,25 @@ function chunkHasSymbolMatch(token, text2) {
590943
590959
  const tokens = haystack.split(" ").filter(Boolean);
590944
590960
  return tokens.includes(token);
590945
590961
  }
590962
+ function escapeRegExp3(value2) {
590963
+ return value2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
590964
+ }
590965
+ function shellCommandLooksLikeInspection(command) {
590966
+ const outsideQuotes = stripShellQuotedSegments(command);
590967
+ return /\b(?:cat|sed|head|tail|less|more|awk|grep|rg|file|stat|wc|sha(?:1|224|256|384|512)sum|md5sum|git\s+(?:show|diff))\b/i.test(outsideQuotes);
590968
+ }
590969
+ function shellCommandReferencesExactPath(command, path16, workspaceRoot) {
590970
+ const normalized = path16.replace(/\\/g, "/").replace(/^\.\//, "").trim();
590971
+ if (!normalized || normalized.includes(".."))
590972
+ return false;
590973
+ const absolute = _pathResolve(workspaceRoot, normalized).replace(/\\/g, "/");
590974
+ const candidates = [normalized, `./${normalized}`, absolute];
590975
+ return candidates.some((candidate) => {
590976
+ const escaped = escapeRegExp3(candidate);
590977
+ const matcher = new RegExp(`(?:^|[\\s"'\`=:(])${escaped}(?=$|[\\s"'\`;|)&,])`);
590978
+ return matcher.test(command);
590979
+ });
590980
+ }
590946
590981
  function isCompilerLikeVerifierCommand(command) {
590947
590982
  const normalized = command.toLowerCase();
590948
590983
  return /\b(?:pio|platformio|tsc|gcc|g\+\+|clang\+\+?|clang|cargo\s+(?:build|check)|go\s+(?:build|test)|javac|gradle|mvn|msbuild|dotnet\s+build|python(?:3)?\s+-m\s+(?:py_compile|compileall)|mypy|pyright)\b/.test(normalized);
@@ -597291,11 +597326,17 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
597291
597326
  return;
597292
597327
  const realFileMutation = input.realFileMutation ?? this._isRealProjectMutation(input.toolName, input.result);
597293
597328
  const attemptedTargetPaths = this._extractToolTargetPaths(input.toolName, input.args, input.result);
597329
+ const explicitInspectionPaths = this._successfulShellInspectionAnchorPaths(input.toolName, input.result);
597330
+ const evidenceTargetPaths2 = [
597331
+ .../* @__PURE__ */ new Set([...attemptedTargetPaths, ...explicitInspectionPaths])
597332
+ ];
597294
597333
  const realMutationPaths = input.realMutationPaths ?? (realFileMutation ? attemptedTargetPaths : []);
597295
597334
  const receipt = input.result.executionReceipt ? {
597296
597335
  ...input.result.executionReceipt,
597336
+ ...explicitInspectionPaths.length > 0 ? { observedPaths: explicitInspectionPaths } : {},
597297
597337
  artifactHashes: this._completionArtifactHashes([
597298
597338
  ...attemptedTargetPaths,
597339
+ ...explicitInspectionPaths,
597299
597340
  ...realMutationPaths
597300
597341
  ])
597301
597342
  } : void 0;
@@ -597312,8 +597353,8 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
597312
597353
  success: input.result.success,
597313
597354
  outputPreview: (input.outputPreview ?? this._toolEvidencePreview(input.result, void 0, 1200, input.toolName)).toString().slice(0, input.toolName === "audio_analyze" || input.toolName === "video_understand" ? 1200 : 500),
597314
597355
  argsKey: input.argsKey.slice(0, 300),
597315
- targetPaths: attemptedTargetPaths,
597316
- role: input.result.completionEvidenceRole ?? (input.result.alreadyApplied === true ? "mutation" : realFileMutation ? "mutation" : input.result.runtimeAuthored === true && !shellVerification ? "blocker" : shellVerification ? "verification" : void 0),
597356
+ targetPaths: evidenceTargetPaths2,
597357
+ role: input.result.completionEvidenceRole ?? (input.result.alreadyApplied === true ? "mutation" : realFileMutation ? "mutation" : input.result.runtimeAuthored === true && !shellVerification ? "blocker" : shellVerification ? "verification" : input.result.success === true ? "observation" : void 0),
597317
597358
  family: input.result.completionEvidenceFamily ?? (input.result.runtimeAuthored === true && !shellVerification ? "runtime_control" : shellVerification ? shellVerificationFamily : void 0),
597318
597359
  verificationImpact: input.result.completionVerificationImpact ?? (input.result.alreadyApplied === true ? "neutral" : realFileMutation ? "invalidates" : void 0),
597319
597360
  metrics: input.result.completionEvidenceMetrics,
@@ -597338,14 +597379,38 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
597338
597379
  }
597339
597380
  this._saveCompletionLedgerSafe();
597340
597381
  }
597382
+ /**
597383
+ * Credit a shell read only when it has a trusted successful local receipt
597384
+ * and mentions one of the user's explicit, inventory-resolved artifact
597385
+ * anchors. This prevents filename/token guesses, echoed path strings, and
597386
+ * arbitrary shell output from becoming discovery evidence.
597387
+ */
597388
+ _successfulShellInspectionAnchorPaths(toolName, result) {
597389
+ if (toolName !== "shell" || result.success !== true)
597390
+ return [];
597391
+ const receipt = result.executionReceipt;
597392
+ if (!receipt || receipt.schema !== "omnius.command-evidence-receipt.v1" || receipt.exitCode !== 0 || receipt.timedOut || !receipt.command.trim() || !receipt.canonicalCommand.trim() || !receipt.cwd.trim()) {
597393
+ return [];
597394
+ }
597395
+ const command = receipt.command;
597396
+ if (!shellCommandLooksLikeInspection(command))
597397
+ return [];
597398
+ const anchors = this._completionLedger?.claimDiscovery?.requiredArtifactPaths ?? [];
597399
+ if (anchors.length === 0)
597400
+ return [];
597401
+ const root = this.authoritativeWorkingDirectory();
597402
+ return anchors.filter((path16) => shellCommandReferencesExactPath(command, path16, root)).slice(0, 16);
597403
+ }
597341
597404
  _refreshClaimDiscoveryStateFromEvidence() {
597342
597405
  if (!this._completionLedger?.claimDiscovery)
597343
597406
  return;
597344
597407
  const state = this._completionLedger.claimDiscovery;
597345
- const evidenceHandles = state.evidenceHandles ?? [];
597408
+ const legacyUnclassifiedCandidates = !Array.isArray(state.requiredArtifactPaths);
597409
+ const requiredArtifactPaths = legacyUnclassifiedCandidates ? [] : state.requiredArtifactPaths;
597410
+ const evidenceHandles = legacyUnclassifiedCandidates ? [] : state.evidenceHandles ?? [];
597346
597411
  const survivingBlockers = state.survivingBlockers ?? [];
597347
597412
  const unresolvedQuestions = state.unresolvedQuestions ?? [];
597348
- const openDeltas = state.openDeltas ?? [];
597413
+ const openDeltas = legacyUnclassifiedCandidates ? [] : state.openDeltas ?? [];
597349
597414
  const resolved = claimDiscoveryResolvedHandles(this._completionLedger, state);
597350
597415
  const unresolvedEvidence = evidenceHandles.filter((handle2) => !resolved.includes(handle2));
597351
597416
  const unresolvedHandleSet = new Set(unresolvedEvidence);
@@ -597355,11 +597420,11 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
597355
597420
  return unresolvedHandleSet.has(handle2);
597356
597421
  });
597357
597422
  const hasBlockers = survivingBlockers.length > 0;
597358
- const hasCandidates = state.candidatePaths.length > 0;
597423
+ const hasRequiredAnchors = evidenceHandles.length > 0;
597359
597424
  const hasOpenQuestions = unresolvedQuestions.length > 0;
597360
597425
  const hasOpenEvidence = unresolvedEvidence.length > 0;
597361
597426
  let status;
597362
- if (!hasCandidates) {
597427
+ if (!hasRequiredAnchors) {
597363
597428
  status = hasBlockers || hasOpenQuestions ? "blocked" : "skipped";
597364
597429
  } else if (hasOpenEvidence || hasOpenQuestions || hasBlockers) {
597365
597430
  status = hasOpenQuestions || hasBlockers ? "blocked" : "active";
@@ -597370,12 +597435,14 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
597370
597435
  ...this._completionLedger,
597371
597436
  claimDiscovery: {
597372
597437
  ...state,
597438
+ requiredArtifactPaths,
597373
597439
  openDeltas: unresolvedOpenDeltas,
597374
597440
  resolvedEvidenceHandles: resolved,
597375
597441
  evidenceHandles,
597376
597442
  survivingBlockers,
597377
597443
  unresolvedQuestions,
597378
- status
597444
+ status,
597445
+ requiresEvidence: legacyUnclassifiedCandidates ? false : state.requiresEvidence
597379
597446
  }
597380
597447
  };
597381
597448
  this._completionLedger = updated;
@@ -597383,9 +597450,9 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
597383
597450
  return updated.claimDiscovery;
597384
597451
  }
597385
597452
  _completionArtifactHashes(paths) {
597386
- 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);
597387
597454
  const out = [];
597388
- for (const path16 of unique3) {
597455
+ for (const path16 of unique4) {
597389
597456
  try {
597390
597457
  const absolute = _pathResolve(this.authoritativeWorkingDirectory(), path16);
597391
597458
  if (!_fsExistsSync(absolute))
@@ -600181,21 +600248,21 @@ ${sections.join("\n")}` : sections.join("\n");
600181
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.`);
600182
600249
  }
600183
600250
  if (filesRead.length > 0) {
600184
- const unique3 = [...new Set(filesRead)].slice(0, 30);
600185
- 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(", ")}`);
600186
600253
  }
600187
600254
  if (dirsListed.length > 0) {
600188
- const unique3 = [...new Set(dirsListed)].slice(0, 15);
600189
- 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(", ")}`);
600190
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.`);
600191
600258
  }
600192
600259
  if (searches.length > 0) {
600193
- const unique3 = [...new Set(searches)].slice(0, 15);
600194
- 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(", ")}`);
600195
600262
  }
600196
600263
  if (shells.length > 0) {
600197
- const unique3 = [...new Set(shells)].slice(0, 15);
600198
- 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(", ")}`);
600199
600266
  }
600200
600267
  if (sections.length <= 1)
600201
600268
  return null;
@@ -603687,11 +603754,13 @@ ${rawTask}`;
603687
603754
  const survivingBlockers = unmatchedHints.size > 0 ? [
603688
603755
  `Unmatched explicit task hints: ${[...unmatchedHints].slice(0, 3).join(", ")}`
603689
603756
  ] : [];
603690
- const shouldRequireEvidence = finalCandidatePaths.length > 0 && (explicitPathHints.length > 0 || rankedCandidates.length > 0);
603757
+ const requiredArtifactPaths = [...new Set(explicitCandidates)].slice(0, 8);
603758
+ const shouldRequireEvidence = requiredArtifactPaths.length > 0 || unmatchedHints.size > 0;
603691
603759
  return claimDiscoveryStateFromSurvey({
603692
603760
  request: task,
603693
603761
  boundedInventory,
603694
603762
  candidatePaths: finalCandidatePaths,
603763
+ requiredArtifactPaths,
603695
603764
  pathReasons,
603696
603765
  unresolvedQuestions,
603697
603766
  survivingBlockers,
@@ -603848,7 +603917,49 @@ ${rawTask}`;
603848
603917
  return null;
603849
603918
  }
603850
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();
603851
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
+ }
603852
603963
  this._observeTrajectoryEvent(event);
603853
603964
  for (const handler of this.handlers) {
603854
603965
  try {
@@ -608119,8 +608230,11 @@ ${cachedResult}`,
608119
608230
  }
608120
608231
  this.emit({
608121
608232
  type: "tool_call",
608233
+ actionId: tc.id,
608122
608234
  toolName: tc.name,
608123
608235
  toolArgs: tc.arguments,
608236
+ workingDirectory: this.authoritativeWorkingDirectory(),
608237
+ targetPaths: this._extractToolTargetPaths(tc.name, tc.arguments ?? {}),
608124
608238
  turn,
608125
608239
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
608126
608240
  });
@@ -609618,9 +609732,16 @@ Evidence: ${evidencePreview}`.slice(0, 500);
609618
609732
  }
609619
609733
  this.emit({
609620
609734
  type: "tool_result",
609735
+ actionId: tc.id,
609621
609736
  toolName: tc.name,
609622
609737
  content: this.toolResultEventContent(tc.name, output || result.output || result.error || ""),
609623
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,
609624
609745
  turn,
609625
609746
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
609626
609747
  });
@@ -627407,8 +627528,8 @@ function isLowInformationAsciiPreview(ascii2) {
627407
627528
  if (!plain) return true;
627408
627529
  const visible = plain.replace(/\s/g, "");
627409
627530
  if (visible.length < 12) return true;
627410
- const unique3 = new Set(Array.from(visible));
627411
- 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;
627412
627533
  return false;
627413
627534
  }
627414
627535
  function previewFailure(message2, width) {
@@ -634466,7 +634587,11 @@ function mapExecutionToolResult(result) {
634466
634587
  partial: result.partial,
634467
634588
  beforeHash: result.beforeHash,
634468
634589
  afterHash: result.afterHash,
634469
- evidenceEvents: result.evidenceEvents
634590
+ evidenceEvents: result.evidenceEvents,
634591
+ // Preserve process facts separately from display text. The orchestrator
634592
+ // uses this receipt for completion evidence; reconstructing it from a
634593
+ // truncated/streamed transcript would be unsound.
634594
+ executionReceipt: result.executionReceipt
634470
634595
  };
634471
634596
  }
634472
634597
  function adaptExecutionTool(tool, options2 = {}) {
@@ -638890,6 +639015,8 @@ var init_command_registry = __esm({
638890
639015
  ],
638891
639016
  ["/think", "Toggle thinking/reasoning mode (Qwen3, DeepSeek-R1, etc.)"],
638892
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"],
638893
639020
  ["/realtime", "Toggle short spoken-dialogue mode for ASR/TTS-backed chat"],
638894
639021
  ["/realtime on|off|status", "Set or inspect realtime conversation mode"],
638895
639022
  ["/mouse", "Toggle terminal mouse tracking"],
@@ -654863,14 +654990,14 @@ function loadFailurePatterns(store2) {
654863
654990
  const unresolved = store2.listUnresolved();
654864
654991
  if (unresolved.length === 0) return "";
654865
654992
  const seen = /* @__PURE__ */ new Set();
654866
- const unique3 = unresolved.filter((f2) => {
654993
+ const unique4 = unresolved.filter((f2) => {
654867
654994
  if (seen.has(f2.fingerprint)) return false;
654868
654995
  seen.add(f2.fingerprint);
654869
654996
  return true;
654870
654997
  });
654871
- if (unique3.length === 0) return "";
654998
+ if (unique4.length === 0) return "";
654872
654999
  const lines = ["Known failure patterns (avoid repeating these):"];
654873
- for (const f2 of unique3.slice(0, 8)) {
655000
+ for (const f2 of unique4.slice(0, 8)) {
654874
655001
  const file = f2.filePath ? ` in ${f2.filePath}` : "";
654875
655002
  lines.push(`- [${f2.failureType}]${file}: ${f2.errorMessage.slice(0, 150)}`);
654876
655003
  }
@@ -656215,6 +656342,13 @@ var init_status_bar = __esm({
656215
656342
  _lastBufferedAt = 0;
656216
656343
  _contentScrollOffset = 0;
656217
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";
656218
656352
  _contentMaxLines = 1e4;
656219
656353
  _contentRevision = 0;
656220
656354
  // Trailing blank content lines are DEFERRED, not buffered immediately. A blank
@@ -656363,7 +656497,7 @@ var init_status_bar = __esm({
656363
656497
  _countdown = 0;
656364
656498
  _recBlink = true;
656365
656499
  _recBlinkTimer = null;
656366
- /** Current focus zone for Ctrl+Tab cycling */
656500
+ /** Current focus zone for the optional keyboard-navigation fallback. */
656367
656501
  _focusedZone = "footer";
656368
656502
  /** Callback to notify header (banner) of focus changes */
656369
656503
  _headerFocusHandler = null;
@@ -656427,6 +656561,83 @@ var init_status_bar = __esm({
656427
656561
  registerDynamicBlockClickHandler(id2, handler) {
656428
656562
  this._dynamicBlockClickHandlers.set(id2, handler);
656429
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
+ }
656430
656641
  /** Unregister a dynamic block. Existing sentinels in scrollback become inert (rendered as empty). */
656431
656642
  unregisterDynamicBlock(id2) {
656432
656643
  this._dynamicBlocks.delete(id2);
@@ -658404,6 +658615,11 @@ var init_status_bar = __esm({
658404
658615
  * when the click was consumed.
658405
658616
  */
658406
658617
  handleContentBlockClick(screenRow, col) {
658618
+ if (this._contentPresentation === "tree" && !this._treePresentationActive) {
658619
+ return this.withTreePresentation(
658620
+ () => this.handleContentBlockClick(screenRow, col)
658621
+ );
658622
+ }
658407
658623
  const hit = this.hitTestContentBlock(screenRow);
658408
658624
  if (!hit) return false;
658409
658625
  const handler = this._dynamicBlockClickHandlers.get(hit.id);
@@ -659318,6 +659534,8 @@ ${CONTENT_BG_SEQ}`);
659318
659534
  this._streamingRepaintTimer.unref?.();
659319
659535
  }
659320
659536
  getLiveBufferedLine() {
659537
+ if (this._contentPresentation === "tree" && this._treePresentationActive)
659538
+ return null;
659321
659539
  if (this.writeDepth === 0 || this._contentScrollOffset > 0) return null;
659322
659540
  if (this._inProgressLine.length === 0) return null;
659323
659541
  const sanitized = this.sanitizeBufferedContentLine(this._inProgressLine);
@@ -659718,6 +659936,10 @@ ${CONTENT_BG_SEQ}`);
659718
659936
  }
659719
659937
  /** Scroll up through content history */
659720
659938
  scrollContentUp(lines = 1) {
659939
+ if (this._contentPresentation === "tree" && !this._treePresentationActive) {
659940
+ this.withTreePresentation(() => this.scrollContentUp(lines));
659941
+ return;
659942
+ }
659721
659943
  if (!this.active) return;
659722
659944
  this.cancelMouseIdle();
659723
659945
  this.restoreMouseTracking();
@@ -659732,6 +659954,10 @@ ${CONTENT_BG_SEQ}`);
659732
659954
  }
659733
659955
  /** Scroll down through content history */
659734
659956
  scrollContentDown(lines = 1) {
659957
+ if (this._contentPresentation === "tree" && !this._treePresentationActive) {
659958
+ this.withTreePresentation(() => this.scrollContentDown(lines));
659959
+ return;
659960
+ }
659735
659961
  if (!this.active) return;
659736
659962
  this.cancelMouseIdle();
659737
659963
  this.restoreMouseTracking();
@@ -659753,6 +659979,10 @@ ${CONTENT_BG_SEQ}`);
659753
659979
  }
659754
659980
  /** Jump to live (End key) */
659755
659981
  jumpToLive() {
659982
+ if (this._contentPresentation === "tree" && !this._treePresentationActive) {
659983
+ this.withTreePresentation(() => this.jumpToLive());
659984
+ return;
659985
+ }
659756
659986
  this._contentScrollOffset = 0;
659757
659987
  this._autoScroll = true;
659758
659988
  this._syncPagerScope();
@@ -659830,6 +660060,10 @@ ${CONTENT_BG_SEQ}`);
659830
660060
  * Reference: btop_draw.cpp lines 2080-2102 — process list rendering.
659831
660061
  */
659832
660062
  repaintContent() {
660063
+ if (this._contentPresentation === "tree" && !this._treePresentationActive) {
660064
+ this.withTreePresentation(() => this.repaintContent());
660065
+ return;
660066
+ }
659833
660067
  const h = this.contentHeight;
659834
660068
  const livePartialLine = this.getLiveBufferedLine();
659835
660069
  const w = termCols();
@@ -661049,13 +661283,6 @@ ${CONTENT_BG_SEQ}`);
661049
661283
  onCtrlO();
661050
661284
  return;
661051
661285
  }
661052
- if (key?.name === "tab" && self2.inputStateProvider) {
661053
- const { line = "" } = self2.inputStateProvider() ?? {};
661054
- if (line.length === 0) {
661055
- self2.cycleFocus();
661056
- return;
661057
- }
661058
- }
661059
661286
  if (s2 === "") {
661060
661287
  self2.cycleFocus();
661061
661288
  return;
@@ -661190,13 +661417,13 @@ ${CONTENT_BG_SEQ}`);
661190
661417
  if (onCtrlO) di.on("ctrl-o", () => onCtrlO());
661191
661418
  if (onCtrlL) di.on("ctrl-l", () => onCtrlL());
661192
661419
  di.on("ctrl-i", () => self2.toggleFooterMetrics());
661420
+ di.on("ctrl-tab", () => self2.toggleActionTree());
661193
661421
  di.on("ctrl-left", () => self2.cycleAgentView("prev"));
661194
661422
  di.on("ctrl-right", () => self2.cycleAgentView("next"));
661195
661423
  di.on("pageup", () => self2.pageUpContent());
661196
661424
  di.on("pagedown", () => self2.pageDownContent());
661197
661425
  di.on("shiftup", () => self2.scrollContentUp(3));
661198
661426
  di.on("shiftdown", () => self2.scrollContentDown(3));
661199
- di.on("tab-empty", () => self2.cycleFocus());
661200
661427
  di.on("ctrl-backslash", () => self2.cycleFocus());
661201
661428
  di.on("ctrl-shift-c", () => void self2.copySelection());
661202
661429
  di.on("ctrl-shift-b", () => self2.armBlockSelection());
@@ -665758,9 +665985,9 @@ function formatExpandedContextDiagnostic(specs, math) {
665758
665985
  memBits.push(`RAM ${fmtGB(specs.availableRamGB)}/${fmtGB(specs.totalRamGB)}${specs.unifiedMemory ? " unified" : ""}`);
665759
665986
  const mem = memBits.join(", ");
665760
665987
  const kv = `KV ${fmtKB(math.kvBytesPerToken)}/tok (${math.kvSource})`;
665761
- 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)}`;
665762
665989
  const limit = `→ ${fmtK(math.numCtx)} (${math.limitedBy === "floor" ? "min floor" : math.limitedBy === "arch" ? "arch-capped" : "memory-fit"})`;
665763
- return `[${mem} | model ${fmtGB(math.modelSizeGB)} | ${kv} | ${fit5} ${limit}]`;
665990
+ return `[${mem} | model ${fmtGB(math.modelSizeGB)} | ${kv} | ${fit6} ${limit}]`;
665764
665991
  }
665765
665992
  async function ensureExpandedContext(modelName, backendUrl2) {
665766
665993
  if (modelName.includes("cloud") || modelName.includes(":cloud")) {
@@ -682773,6 +683000,33 @@ Clone a new voice: /voice clone <wav-file> [name]`);
682773
683000
  );
682774
683001
  return "handled";
682775
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
+ }
682776
683030
  case "realtime": {
682777
683031
  const save3 = hasLocal ? ctx3.saveLocalSettings.bind(ctx3) : ctx3.saveSettings.bind(ctx3);
682778
683032
  const value2 = arg.trim().toLowerCase();
@@ -687261,12 +687515,12 @@ function cad3dFitIcon(score) {
687261
687515
  if (score >= 40) return c3.yellow("△");
687262
687516
  return c3.red("✖");
687263
687517
  }
687264
- function cad3dModelDetail(spec, fit5) {
687518
+ function cad3dModelDetail(spec, fit6) {
687265
687519
  const download = spec.resources.approxDownloadGB ? `~${spec.resources.approxDownloadGB}GB` : "size unknown";
687266
687520
  const vram = spec.resources.recommendedVramGB ? `${spec.resources.recommendedVramGB}GB VRAM rec` : "VRAM varies";
687267
687521
  const license = spec.hf.license ? `license ${spec.hf.license}` : "license unknown";
687268
687522
  const token = spec.deployment.requiresToken ? "requires HF token" : "no token gate";
687269
- return `${fit5.label} · ${spec.backend} · ${download} · ${vram} · ${license} · ${token}`;
687523
+ return `${fit6.label} · ${spec.backend} · ${download} · ${vram} · ${license} · ${token}`;
687270
687524
  }
687271
687525
  async function startCad3dViewerFromCommand(rawPath) {
687272
687526
  const viewer = await startCadModelViewer(
@@ -687282,11 +687536,11 @@ async function showCad3dModelsMenu(ctx3, hasLocal, mode) {
687282
687536
  const active = mode === "cad" ? settings.cadModel : settings.model3dModel;
687283
687537
  const currentViewer2 = getCurrentCadModelViewer();
687284
687538
  const buildItem = (entry) => {
687285
- const fit5 = rateCad3dModelForHardware(entry.spec, specs);
687539
+ const fit6 = rateCad3dModelForHardware(entry.spec, specs);
687286
687540
  return {
687287
687541
  key: `model:${entry.spec.id}`,
687288
- label: `${cad3dFitIcon(fit5.score)} ${String(fit5.score).padStart(3)}/100 ${entry.spec.label}`,
687289
- 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)
687290
687544
  };
687291
687545
  };
687292
687546
  const items = [
@@ -687321,11 +687575,11 @@ async function showCad3dModelsMenu(ctx3, hasLocal, mode) {
687321
687575
  const patch = mode === "cad" ? { cadModel: id2, cadBackend: entry.spec.backend } : { model3dModel: id2, model3dBackend: entry.spec.backend };
687322
687576
  const save3 = hasLocal ? ctx3.saveLocalSettings : ctx3.saveSettings;
687323
687577
  save3(patch);
687324
- const fit5 = rateCad3dModelForHardware(entry.spec, specs);
687578
+ const fit6 = rateCad3dModelForHardware(entry.spec, specs);
687325
687579
  renderInfo(
687326
687580
  `${mode === "cad" ? "CAD" : "3D"} model: ${id2} (${entry.spec.backend})${hasLocal ? " (project-local)" : ""}`
687327
687581
  );
687328
- renderInfo(`Hardware fit: ${fit5.score}/100 ${fit5.label} - ${fit5.note}`);
687582
+ renderInfo(`Hardware fit: ${fit6.score}/100 ${fit6.label} - ${fit6.note}`);
687329
687583
  if (entry.spec.resources.approxDownloadGB) {
687330
687584
  renderInfo(
687331
687585
  `Download estimate: ~${entry.spec.resources.approxDownloadGB}GB in ${unifiedModelStoreDir()}`
@@ -687476,19 +687730,19 @@ async function renderImageModelList(ctx3) {
687476
687730
  renderInfo("");
687477
687731
  renderInfo(c3.bold(category));
687478
687732
  for (const preset of presets) {
687479
- const fit5 = rateImagePresetForHardware(preset, specs);
687733
+ const fit6 = rateImagePresetForHardware(preset, specs);
687480
687734
  const primary = category === "Primary hyper-realistic baseline" ? c3.cyan(" ★") : "";
687481
687735
  const disk = ctx3 ? imageModelDiskStats(ctx3, preset, ollamaSizes) : { downloaded: false, bytes: 0, paths: [] };
687482
687736
  const diskInfo = disk.downloaded ? ` ${c3.green("✓")} ${formatFileSize(disk.bytes)}` : "";
687483
687737
  renderInfo(
687484
- `${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}`
687485
687739
  );
687486
687740
  renderInfo(` id: ${preset.id}`);
687487
687741
  renderInfo(
687488
- ` type: ${preset.backend} · ${preset.sizeClass ?? "unknown size"} · ${fit5.label}`
687742
+ ` type: ${preset.backend} · ${preset.sizeClass ?? "unknown size"} · ${fit6.label}`
687489
687743
  );
687490
687744
  renderImagePresetDetail(" quality: ", preset.quality ?? preset.note);
687491
- renderImagePresetDetail(" fit: ", fit5.note);
687745
+ renderImagePresetDetail(" fit: ", fit6.note);
687492
687746
  if (preset.deployment)
687493
687747
  renderImagePresetDetail(" deploy: ", preset.deployment);
687494
687748
  }
@@ -687631,13 +687885,13 @@ async function showImageModelsMenu(ctx3, hasLocal) {
687631
687885
  () => /* @__PURE__ */ new Map()
687632
687886
  );
687633
687887
  const buildModelItem = (preset) => {
687634
- const fit5 = rateImagePresetForHardware(preset, specs);
687888
+ const fit6 = rateImagePresetForHardware(preset, specs);
687635
687889
  const disk = imageModelDiskStats(ctx3, preset, ollamaSizes);
687636
687890
  const downloaded = disk.downloaded ? `${c3.green("✓")} ` : "";
687637
687891
  return {
687638
687892
  key: `model:${preset.id}`,
687639
- label: `${downloaded}${imageFitIcon(fit5.score)} ${String(fit5.score).padStart(3)}/100 ${preset.label}`,
687640
- 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)}`
687641
687895
  };
687642
687896
  };
687643
687897
  const items = [
@@ -687722,9 +687976,9 @@ async function showImageModelsMenu(ctx3, hasLocal) {
687722
687976
  renderInfo(
687723
687977
  `Image model: ${model} (${backend})${hasLocal ? " (project-local)" : ""}`
687724
687978
  );
687725
- const fit5 = preset ? rateImagePresetForHardware(preset, specs) : void 0;
687726
- if (fit5)
687727
- 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}`);
687728
687982
  if (preset?.install) renderInfo(`Prewarm command: ${preset.install}`);
687729
687983
  await prewarmImageModel(ctx3, model, backend);
687730
687984
  }
@@ -688040,19 +688294,19 @@ async function renderVideoModelList(ctx3) {
688040
688294
  renderInfo("");
688041
688295
  renderInfo(c3.bold(category));
688042
688296
  for (const preset of presets) {
688043
- const fit5 = rateVideoPresetForHardware(preset, specs);
688297
+ const fit6 = rateVideoPresetForHardware(preset, specs);
688044
688298
  const disk = videoModelDiskStats(ctx3, preset);
688045
688299
  const diskInfo = disk.downloaded ? ` ${c3.green("✓")} ${formatFileSize(disk.bytes)}` : "";
688046
688300
  renderInfo(
688047
- `${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}`
688048
688302
  );
688049
688303
  renderInfo(` id: ${preset.id}`);
688050
688304
  renderInfo(
688051
- ` type: ${preset.backend} · ${preset.sizeClass} · ${preset.kinds.join("/")} · ${fit5.label}`
688305
+ ` type: ${preset.backend} · ${preset.sizeClass} · ${preset.kinds.join("/")} · ${fit6.label}`
688052
688306
  );
688053
688307
  renderImagePresetDetail(" quality: ", preset.quality);
688054
688308
  renderImagePresetDetail(" output: ", preset.output);
688055
- renderImagePresetDetail(" fit: ", fit5.note);
688309
+ renderImagePresetDetail(" fit: ", fit6.note);
688056
688310
  renderImagePresetDetail(" deploy: ", preset.deployment);
688057
688311
  if (preset.licenseNote)
688058
688312
  renderImagePresetDetail(" license: ", preset.licenseNote);
@@ -688063,13 +688317,13 @@ async function showVideoModelsMenu(ctx3, hasLocal) {
688063
688317
  const settings = resolveSettings(ctx3.repoRoot);
688064
688318
  const specs = await detectSystemSpecsAsync();
688065
688319
  const buildModelItem = (preset) => {
688066
- const fit5 = rateVideoPresetForHardware(preset, specs);
688320
+ const fit6 = rateVideoPresetForHardware(preset, specs);
688067
688321
  const disk = videoModelDiskStats(ctx3, preset);
688068
688322
  const downloaded = disk.downloaded ? `${c3.green("✓")} ` : "";
688069
688323
  return {
688070
688324
  key: `model:${preset.id}`,
688071
- label: `${downloaded}${imageFitIcon(fit5.score)} ${String(fit5.score).padStart(3)}/100 ${preset.label}`,
688072
- 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)}`
688073
688327
  };
688074
688328
  };
688075
688329
  const items = [
@@ -688148,8 +688402,8 @@ async function showVideoModelsMenu(ctx3, hasLocal) {
688148
688402
  `Video model: ${model} (${backend})${hasLocal ? " (project-local)" : ""}`
688149
688403
  );
688150
688404
  if (preset) {
688151
- const fit5 = rateVideoPresetForHardware(preset, specs);
688152
- 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}`);
688153
688407
  if (preset.licenseNote) renderInfo(`License: ${preset.licenseNote}`);
688154
688408
  if (preset.install) renderInfo(`Prewarm command: ${preset.install}`);
688155
688409
  }
@@ -688411,19 +688665,19 @@ async function renderAudioModelList(ctx3, kind) {
688411
688665
  renderInfo("");
688412
688666
  renderInfo(c3.bold(category));
688413
688667
  for (const preset of presets) {
688414
- const fit5 = rateAudioPresetForHardware(preset, specs);
688668
+ const fit6 = rateAudioPresetForHardware(preset, specs);
688415
688669
  const disk = audioModelDiskStats(ctx3, preset);
688416
688670
  const diskInfo = disk.downloaded ? ` ${c3.green("✓")} ${formatFileSize(disk.bytes)}` : "";
688417
688671
  renderInfo(
688418
- `${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}`
688419
688673
  );
688420
688674
  renderInfo(` id: ${preset.id}`);
688421
688675
  renderInfo(
688422
- ` type: ${preset.backend} · ${preset.sizeClass} · ${fit5.label}`
688676
+ ` type: ${preset.backend} · ${preset.sizeClass} · ${fit6.label}`
688423
688677
  );
688424
688678
  renderImagePresetDetail(" quality: ", preset.quality);
688425
688679
  renderImagePresetDetail(" output: ", preset.output);
688426
- renderImagePresetDetail(" fit: ", fit5.note);
688680
+ renderImagePresetDetail(" fit: ", fit6.note);
688427
688681
  renderImagePresetDetail(" deploy: ", preset.deployment);
688428
688682
  }
688429
688683
  }
@@ -688448,13 +688702,13 @@ async function showAudioGenerationMenu(ctx3, hasLocal, kind) {
688448
688702
  const activeModel = activeAudioModel(settings, kind);
688449
688703
  const title = kind === "music" ? "Music Generation" : "Sound Generation";
688450
688704
  const buildModelItem = (preset) => {
688451
- const fit5 = rateAudioPresetForHardware(preset, specs);
688705
+ const fit6 = rateAudioPresetForHardware(preset, specs);
688452
688706
  const disk = audioModelDiskStats(ctx3, preset);
688453
688707
  const downloaded = disk.downloaded ? `${c3.green("✓")} ` : "";
688454
688708
  return {
688455
688709
  key: `model:${preset.id}`,
688456
- label: `${downloaded}${audioFitIcon(fit5.score)} ${String(fit5.score).padStart(3)}/100 ${preset.label}`,
688457
- 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)}`
688458
688712
  };
688459
688713
  };
688460
688714
  const setupItems = kind === "music" ? [
@@ -688575,8 +688829,8 @@ async function showAudioGenerationMenu(ctx3, hasLocal, kind) {
688575
688829
  `${kind === "music" ? "Music" : "Sound"} model: ${model} (${backend})${hasLocal ? " (project-local)" : ""}`
688576
688830
  );
688577
688831
  if (preset) {
688578
- const fit5 = rateAudioPresetForHardware(preset, specs);
688579
- 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}`);
688580
688834
  renderInfo(`Prewarm command: ${preset.install}`);
688581
688835
  }
688582
688836
  await prewarmAudioModel(ctx3, kind, model, backend);
@@ -698654,8 +698908,8 @@ function generateDescriptors(repoRoot) {
698654
698908
  if (repoName2 && !tags.includes(repoName2)) {
698655
698909
  tags.push(repoName2);
698656
698910
  }
698657
- const unique3 = [...new Set(tags.map((t2) => t2.toLowerCase().trim()).filter((t2) => t2.length > 1 && t2.length < 60))];
698658
- 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) => ({
698659
698913
  text: text2,
698660
698914
  color: weightedColor(profile)
698661
698915
  }));
@@ -698676,7 +698930,7 @@ function generateDescriptors(repoRoot) {
698676
698930
  ];
698677
698931
  for (const fb of fallbacks) {
698678
698932
  if (phrases.length >= 20) break;
698679
- if (!unique3.includes(fb)) {
698933
+ if (!unique4.includes(fb)) {
698680
698934
  phrases.push({ text: fb, color: weightedColor(profile) });
698681
698935
  }
698682
698936
  }
@@ -699769,6 +700023,370 @@ var init_stream_renderer = __esm({
699769
700023
  }
699770
700024
  });
699771
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
+
699772
700390
  // packages/cli/src/tui/edit-history.ts
699773
700391
  import { appendFileSync as appendFileSync18, mkdirSync as mkdirSync93 } from "node:fs";
699774
700392
  import { join as join164 } from "node:path";
@@ -704718,13 +705336,13 @@ function buildScopedToolList(scope) {
704718
705336
  const commandSigs = commands.flatMap((cmd) => cmd.signatures);
704719
705337
  const allSigs = [...syntheticSigs, ...commandSigs];
704720
705338
  const seen = /* @__PURE__ */ new Set();
704721
- const unique3 = allSigs.filter((sig) => {
705339
+ const unique4 = allSigs.filter((sig) => {
704722
705340
  if (seen.has(sig.signature)) return false;
704723
705341
  seen.add(sig.signature);
704724
705342
  return true;
704725
705343
  });
704726
705344
  const entries = [];
704727
- for (const sig of unique3) {
705345
+ for (const sig of unique4) {
704728
705346
  const matchingCmd = commands.find(
704729
705347
  (cmd) => cmd.signatures.some((s2) => s2.signature === sig.signature)
704730
705348
  );
@@ -709830,14 +710448,14 @@ function parseTelegramReplyPreferenceUpdate(parsed) {
709830
710448
  }
709831
710449
  function uniqueTelegramJsonCandidates(candidates) {
709832
710450
  const seen = /* @__PURE__ */ new Set();
709833
- const unique3 = [];
710451
+ const unique4 = [];
709834
710452
  for (const candidate of candidates) {
709835
710453
  const clean6 = candidate.trim();
709836
710454
  if (!clean6 || seen.has(clean6)) continue;
709837
710455
  seen.add(clean6);
709838
- unique3.push(clean6);
710456
+ unique4.push(clean6);
709839
710457
  }
709840
- return unique3;
710458
+ return unique4;
709841
710459
  }
709842
710460
  function extractBalancedTelegramJsonObjects(text2) {
709843
710461
  const objects = [];
@@ -710830,10 +711448,10 @@ function telegramHistoryTime(entry) {
710830
711448
  });
710831
711449
  }
710832
711450
  function formatTelegramIdentitySignals(signals) {
710833
- const unique3 = [
711451
+ const unique4 = [
710834
711452
  ...new Set(signals.map((signal) => signal.trim()).filter(Boolean))
710835
711453
  ];
710836
- return unique3.length > 0 ? unique3.join(", ") : "none";
711454
+ return unique4.length > 0 ? unique4.join(", ") : "none";
710837
711455
  }
710838
711456
  function summarizeTelegramMessageAttachments(msg) {
710839
711457
  const parts = [];
@@ -711321,12 +711939,12 @@ function buildTelegramHelpHTML(scope, maxPublicCommands = 24) {
711321
711939
  ...commands.flatMap((cmd) => cmd.signatures)
711322
711940
  ];
711323
711941
  const seen = /* @__PURE__ */ new Set();
711324
- const unique3 = signatures.filter((sig) => {
711942
+ const unique4 = signatures.filter((sig) => {
711325
711943
  if (seen.has(sig.signature)) return false;
711326
711944
  seen.add(sig.signature);
711327
711945
  return true;
711328
711946
  });
711329
- const visible = scope === "public" ? unique3.slice(0, maxPublicCommands) : unique3;
711947
+ const visible = scope === "public" ? unique4.slice(0, maxPublicCommands) : unique4;
711330
711948
  const lines = [
711331
711949
  `<b>Commands (${scope === "admin" ? "admin full scope" : "public secure scope"})</b>`,
711332
711950
  "",
@@ -711334,7 +711952,7 @@ function buildTelegramHelpHTML(scope, maxPublicCommands = 24) {
711334
711952
  (sig) => `<code>${escapeTelegramHTML(sig.signature)}</code> - ${escapeTelegramHTML(sig.description)}`
711335
711953
  )
711336
711954
  ];
711337
- if (scope === "public" && unique3.length > visible.length) {
711955
+ if (scope === "public" && unique4.length > visible.length) {
711338
711956
  lines.push("");
711339
711957
  lines.push(
711340
711958
  `Public scope truncated to ${visible.length} safe commands. Authenticate as admin for full command help.`
@@ -714426,10 +715044,10 @@ ${message2}`)
714426
715044
  telegramModelMenuItems(generation) {
714427
715045
  return this.telegramGenerationModelDescriptors(generation).map((model) => {
714428
715046
  const cached2 = model.cachedBytes > 0 ? `cached ${formatModelBytes(model.cachedBytes)}` : "not downloaded";
714429
- 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";
714430
715048
  return {
714431
715049
  label: model.label,
714432
- description: `${model.backend} - ${model.category} - ${fit5} - ${cached2}`,
715050
+ description: `${model.backend} - ${model.category} - ${fit6} - ${cached2}`,
714433
715051
  action: {
714434
715052
  type: "model_detail",
714435
715053
  generation,
@@ -725804,20 +726422,20 @@ Scoped workspace: ${scopedRoot}`,
725804
726422
  };
725805
726423
  }
725806
726424
  async deleteTelegramMessages(chatId, messageIds, currentMsg) {
725807
- const unique3 = [...new Set(messageIds)].filter((id2) => Number.isFinite(id2));
725808
- if (unique3.length === 0)
726425
+ const unique4 = [...new Set(messageIds)].filter((id2) => Number.isFinite(id2));
726426
+ if (unique4.length === 0)
725809
726427
  throw new Error(
725810
726428
  "deleteTelegramMessages requires at least one message id."
725811
726429
  );
725812
726430
  await this.assertTelegramBotRightsForAction(
725813
726431
  "delete_messages",
725814
726432
  chatId,
725815
- unique3,
726433
+ unique4,
725816
726434
  currentMsg
725817
726435
  );
725818
726436
  const chunks = [];
725819
- for (let idx = 0; idx < unique3.length; idx += 100)
725820
- 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));
725821
726439
  const results = [];
725822
726440
  for (const chunk of chunks) {
725823
726441
  const result = await this.apiCall("deleteMessages", {
@@ -725835,9 +726453,9 @@ Scoped workspace: ${scopedRoot}`,
725835
726453
  telegram_method: "deleteMessages",
725836
726454
  ok: true,
725837
726455
  chat_id: chatId,
725838
- message_ids: unique3,
726456
+ message_ids: unique4,
725839
726457
  batches: results,
725840
- 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)),
725841
726459
  policy_scope: this.telegramToolPolicy.chatOverrides?.[String(chatId)] ? "chat" : "global/default"
725842
726460
  };
725843
726461
  }
@@ -728711,9 +729329,9 @@ function pushShellLiveLine(state, line) {
728711
729329
  }
728712
729330
  }
728713
729331
  function contentRow2(value2, inner) {
728714
- return `│ ${fit4(value2, inner)} │`;
729332
+ return `│ ${fit5(value2, inner)} │`;
728715
729333
  }
728716
- function fit4(value2, width) {
729334
+ function fit5(value2, width) {
728717
729335
  const plain = value2.replace(ANSI_OR_OSC_RE, "").replace(/\s+$/g, "");
728718
729336
  const chars = Array.from(plain);
728719
729337
  if (chars.length > width) {
@@ -728786,8 +729404,8 @@ function gibberishTokenPenalty(s2) {
728786
729404
  const tokens = s2.trim().split(/\s+/).filter(Boolean);
728787
729405
  if (tokens.length < 2) return 0;
728788
729406
  let penalty = 0;
728789
- const unique3 = new Set(tokens.map((t2) => t2.toLowerCase()));
728790
- const uniqueRatio = unique3.size / tokens.length;
729407
+ const unique4 = new Set(tokens.map((t2) => t2.toLowerCase()));
729408
+ const uniqueRatio = unique4.size / tokens.length;
728791
729409
  if (tokens.length >= 4 && uniqueRatio <= 0.5) {
728792
729410
  penalty += Math.min(1, (0.5 - uniqueRatio) * 2 + 0.5);
728793
729411
  }
@@ -730953,6 +731571,10 @@ var init_direct_input = __esm({
730953
731571
  this._insertText("\n");
730954
731572
  return;
730955
731573
  }
731574
+ if (params === "27;5;9") {
731575
+ this.emit("ctrl-tab");
731576
+ return;
731577
+ }
730956
731578
  if (params === "3") {
730957
731579
  if (this.cursor < this.line.length) {
730958
731580
  this.line = this.line.slice(0, this.cursor) + this.line.slice(this.cursor + 1);
@@ -730996,6 +731618,10 @@ var init_direct_input = __esm({
730996
731618
  this.emit("ctrl-i");
730997
731619
  return;
730998
731620
  }
731621
+ if (hasCtrl && !hasShift && codepoint === 9) {
731622
+ this.emit("ctrl-tab");
731623
+ return;
731624
+ }
730999
731625
  return;
731000
731626
  }
731001
731627
  }
@@ -731110,10 +731736,6 @@ var init_direct_input = __esm({
731110
731736
  }
731111
731737
  /** Handle Tab completion */
731112
731738
  _handleTab() {
731113
- if (this.line.length === 0) {
731114
- this.emit("ctrl-i");
731115
- return;
731116
- }
731117
731739
  if (!this._completer) return;
731118
731740
  this._completer(this.line, (err, result) => {
731119
731741
  if (err || !result) return;
@@ -763880,6 +764502,20 @@ function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce
763880
764502
  }
763881
764503
  const modelTier2 = getModelTier(config.model);
763882
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
+ );
763883
764519
  const taskMetricDescription = cleanForStorage(task).replace(/\s+/g, " ").slice(0, 160) || "task";
763884
764520
  costTracker?.startTask(taskMetricDescription);
763885
764521
  sessionMetrics?.startTask(taskMetricDescription);
@@ -764452,7 +765088,11 @@ ${content}
764452
765088
  statusBar.ensureMonitorTimer();
764453
765089
  },
764454
765090
  onViewWrite: (id2, text2) => statusBar.recordAgentOutput(id2, text2),
764455
- 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
+ },
764456
765096
  onViewStatus: (id2, status) => {
764457
765097
  statusBar.updateAgentViewStatus(id2, status);
764458
765098
  const agent = registry2.subAgents.get(id2);
@@ -765030,6 +765670,8 @@ ${entry.fullContent}`
765030
765670
  }
765031
765671
  };
765032
765672
  runner.onEvent((event) => {
765673
+ actionTree?.recordEvent(event, { agentId: "main", cwd: repoRoot });
765674
+ if (statusBar?.contentPresentation === "tree") statusBar.refreshActionTree();
765033
765675
  emotionEngine?.appraise(event);
765034
765676
  const stageTransition = stageForAgentEvent(event);
765035
765677
  if (stageTransition) {
@@ -766436,6 +767078,15 @@ async function startInteractive(config, repoPath2) {
766436
767078
  }
766437
767079
  const statusBar = new StatusBar();
766438
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
+ );
766439
767090
  _liveMediaStatusSink = (status) => statusBar.setLiveMediaStatus(status);
766440
767091
  setBannerWriter((data) => statusBar.writeChrome(data));
766441
767092
  setCarouselWriter((data) => statusBar.writeChrome(data));
@@ -768650,6 +769301,15 @@ This is an independent background session started from /background.`
768650
769301
  refreshDisplay() {
768651
769302
  statusBar.refreshDisplay();
768652
769303
  },
769304
+ toggleActionTree() {
769305
+ return statusBar.toggleActionTree();
769306
+ },
769307
+ setActionTreeMode(mode) {
769308
+ return statusBar.setContentPresentation(mode);
769309
+ },
769310
+ getActionTreeMode() {
769311
+ return statusBar.contentPresentation;
769312
+ },
768653
769313
  exit() {
768654
769314
  if (reminderDispatchTimer) {
768655
769315
  clearInterval(reminderDispatchTimer);
@@ -772786,6 +773446,7 @@ var init_interactive = __esm({
772786
773446
  init_carousel_descriptors();
772787
773447
  init_voice();
772788
773448
  init_stream_renderer();
773449
+ init_action_tree();
772789
773450
  init_tui_select();
772790
773451
  init_edit_history();
772791
773452
  init_theme();