topchester-ai 0.26.0 → 0.28.0

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/cli.mjs CHANGED
@@ -17,6 +17,7 @@ import pino from "pino";
17
17
  import picomatch from "picomatch";
18
18
  import { uuidv7 } from "uuidv7";
19
19
  import { CURSOR_MARKER, Markdown, ProcessTerminal, TUI, decodeKittyPrintable, isKeyRelease, isKeyRepeat, matchesKey, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
20
+ import { diffWords } from "diff";
20
21
  import { highlight, supportsLanguage } from "cli-highlight";
21
22
  //#region src/agent/tools/ai-sdk-tools.ts
22
23
  function toAiSdkToolSet(definitions) {
@@ -3088,6 +3089,10 @@ const ui = {
3088
3089
  error(text) {
3089
3090
  return color(text, "red");
3090
3091
  },
3092
+ inverse(text) {
3093
+ if (!shouldUseColor()) return text;
3094
+ return `\u001b[7m${text}\u001b[27m`;
3095
+ },
3091
3096
  softBackground(text) {
3092
3097
  return color(text, "bgSoftGray");
3093
3098
  },
@@ -3258,7 +3263,7 @@ function formatTaskPlanNotice(change, state) {
3258
3263
  }
3259
3264
  function formatTaskPlanForTui(state, width, visibleLimit = 6) {
3260
3265
  if (state.items.length === 0) return [];
3261
- const itemWidth = Math.max(1, Math.max(12, width) - 6);
3266
+ const itemWidth = Math.max(1, Math.max(12, width) - 4);
3262
3267
  const visibleItems = state.items.slice(0, visibleLimit);
3263
3268
  const lines = visibleItems.map((item) => formatTaskPlanTuiLine(item, truncateText(item.text, itemWidth)));
3264
3269
  const remaining = state.items.length - visibleItems.length;
@@ -3267,9 +3272,9 @@ function formatTaskPlanForTui(state, width, visibleLimit = 6) {
3267
3272
  }
3268
3273
  function formatTaskPlanTuiLine(item, text) {
3269
3274
  switch (item.status) {
3270
- case "completed": return ` ${ui.ok("[x]")} ${ui.muted(text)}`;
3271
- case "in_progress": return ` ${ui.ok("[>]")} ${ui.ok(text)}`;
3272
- case "pending": return ` ${ui.muted("[ ]")} ${text}`;
3275
+ case "completed": return ` ${ui.ok("")} ${ui.muted(text)}`;
3276
+ case "in_progress": return ` ${ui.ok("")} ${ui.ok(text)}`;
3277
+ case "pending": return ` ${ui.muted("")} ${text}`;
3273
3278
  }
3274
3279
  }
3275
3280
  function truncateText(text, width) {
@@ -7556,6 +7561,85 @@ const queryStopWords = new Set([
7556
7561
  "when"
7557
7562
  ]);
7558
7563
  //#endregion
7564
+ //#region src/tui/diff.ts
7565
+ function renderUnifiedDiff(diffText, options = {}) {
7566
+ const indent = options.indent ?? "";
7567
+ const wrapWidth = options.width === void 0 ? void 0 : Math.max(1, options.width - indent.length);
7568
+ const rawLines = diffText.split("\n");
7569
+ const rendered = [];
7570
+ let index = 0;
7571
+ while (index < rawLines.length) {
7572
+ const line = rawLines[index];
7573
+ if (isRemovedBodyLine(line)) {
7574
+ const removed = [];
7575
+ while (index < rawLines.length && isRemovedBodyLine(rawLines[index])) {
7576
+ removed.push({
7577
+ kind: "removed",
7578
+ content: rawLines[index].slice(1)
7579
+ });
7580
+ index += 1;
7581
+ }
7582
+ const added = [];
7583
+ while (index < rawLines.length && isAddedBodyLine(rawLines[index])) {
7584
+ added.push({
7585
+ kind: "added",
7586
+ content: rawLines[index].slice(1)
7587
+ });
7588
+ index += 1;
7589
+ }
7590
+ rendered.push(...renderChangedLines(removed, added, indent, wrapWidth));
7591
+ continue;
7592
+ }
7593
+ if (isAddedBodyLine(line)) rendered.push(...renderWrappedLine(ui.ok(`+${expandTabs$1(line.slice(1))}`), indent, wrapWidth));
7594
+ else if (line.startsWith("@@")) rendered.push(...renderWrappedLine(ui.model(line), indent, wrapWidth));
7595
+ else if (line.startsWith("diff --git ") || line.startsWith("--- ") || line.startsWith("+++ ")) rendered.push(...renderWrappedLine(ui.muted(line), indent, wrapWidth));
7596
+ else if (line.startsWith(" ")) rendered.push(...renderWrappedLine(ui.label(` ${expandTabs$1(line.slice(1))}`), indent, wrapWidth));
7597
+ else if (line.length > 0) rendered.push(...renderWrappedLine(ui.label(line), indent, wrapWidth));
7598
+ index += 1;
7599
+ }
7600
+ return rendered;
7601
+ }
7602
+ function renderChangedLines(removedLines, addedLines, indent, wrapWidth) {
7603
+ if (removedLines.length === 1 && addedLines.length === 1) {
7604
+ const { removed, added } = renderIntraLineDiff(expandTabs$1(removedLines[0].content), expandTabs$1(addedLines[0].content));
7605
+ return [...renderWrappedLine(ui.error(`-${removed}`), indent, wrapWidth), ...renderWrappedLine(ui.ok(`+${added}`), indent, wrapWidth)];
7606
+ }
7607
+ return [...removedLines.flatMap((line) => renderWrappedLine(ui.error(`-${expandTabs$1(line.content)}`), indent, wrapWidth)), ...addedLines.flatMap((line) => renderWrappedLine(ui.ok(`+${expandTabs$1(line.content)}`), indent, wrapWidth))];
7608
+ }
7609
+ function renderIntraLineDiff(oldContent, newContent) {
7610
+ const parts = diffWords(oldContent, newContent);
7611
+ let removed = "";
7612
+ let added = "";
7613
+ for (const part of parts) if (part.removed) removed += highlightChangedPart(part.value);
7614
+ else if (part.added) added += highlightChangedPart(part.value);
7615
+ else {
7616
+ removed += part.value;
7617
+ added += part.value;
7618
+ }
7619
+ return {
7620
+ removed,
7621
+ added
7622
+ };
7623
+ }
7624
+ function highlightChangedPart(value) {
7625
+ const leading = value.match(/^\s*/u)?.[0] ?? "";
7626
+ const trailing = value.match(/\s*$/u)?.[0] ?? "";
7627
+ const body = value.slice(leading.length, value.length - trailing.length);
7628
+ return body.length === 0 ? value : `${leading}${ui.inverse(body)}${trailing}`;
7629
+ }
7630
+ function renderWrappedLine(line, indent, width) {
7631
+ return (width === void 0 ? [line] : wrapTextWithAnsi(line, width)).map((part) => `${indent}${part}`);
7632
+ }
7633
+ function isRemovedBodyLine(line) {
7634
+ return line.startsWith("-") && !line.startsWith("--- ");
7635
+ }
7636
+ function isAddedBodyLine(line) {
7637
+ return line.startsWith("+") && !line.startsWith("+++ ");
7638
+ }
7639
+ function expandTabs$1(text) {
7640
+ return text.replace(/\t/gu, " ");
7641
+ }
7642
+ //#endregion
7559
7643
  //#region src/tui/markdown.ts
7560
7644
  const codeFenceSentinel = "topchester-code-fence";
7561
7645
  function renderMarkdown(text, width) {
@@ -7647,16 +7731,13 @@ function thinkingMessage(text) {
7647
7731
  text
7648
7732
  };
7649
7733
  }
7650
- function toolCallMessage(call, label, resultSummary) {
7651
- return resultSummary === void 0 ? {
7652
- kind: "tool_call",
7653
- call,
7654
- label
7655
- } : {
7734
+ function toolCallMessage(call, label, resultSummary, diff) {
7735
+ return {
7656
7736
  kind: "tool_call",
7657
7737
  call,
7658
7738
  label,
7659
- resultSummary
7739
+ ...resultSummary === void 0 ? {} : { resultSummary },
7740
+ ...diff === void 0 ? {} : { diff }
7660
7741
  };
7661
7742
  }
7662
7743
  function hookStatusMessage(label, eventName, statusMessage) {
@@ -7682,7 +7763,7 @@ function modalMessage(message) {
7682
7763
  const DEFAULT_MODAL_VISIBLE_ACTION_LIMIT = 16;
7683
7764
  function renderChatMessage(message, options = {}) {
7684
7765
  if (message.kind === "modal") return renderChatModal(message, options.selectedActionIndex, options.maxModalHeight, options.width);
7685
- if (message.kind === "tool_call") return renderToolCallMessage(message);
7766
+ if (message.kind === "tool_call") return renderToolCallMessage(message, options.width);
7686
7767
  if (message.kind === "hook_status") return renderHookStatusMessage(message);
7687
7768
  if (message.kind === "subagent") return renderSubagentMessage(message);
7688
7769
  if (message.kind === "thinking") return message.text.split("\n").map((line) => ui.muted(line));
@@ -7714,9 +7795,14 @@ function renderSystemMessage(lines) {
7714
7795
  function formatSystemBodyLine(line) {
7715
7796
  return expandTabs(line).replace(/\(changed \+\d+\/-\d+\)$/u, (summary) => ui.muted(summary)).replace(/\(created \+\d+\)$/u, (summary) => ui.muted(summary));
7716
7797
  }
7717
- function renderToolCallMessage(message) {
7798
+ function renderToolCallMessage(message, width) {
7718
7799
  const visibleLabel = message.resultSummary && !message.label.includes(message.resultSummary) ? `${message.label} ${message.resultSummary}` : message.label;
7719
- return [` ${ui.muted(expandTabs(visibleLabel))}`];
7800
+ const label = ` ${ui.muted(expandTabs(visibleLabel))}`;
7801
+ if (!message.diff) return [label];
7802
+ return [label, ...renderUnifiedDiff(message.diff, {
7803
+ indent: " ",
7804
+ width
7805
+ })];
7720
7806
  }
7721
7807
  function renderHookStatusMessage(message) {
7722
7808
  return [` ${ui.muted(expandTabs(message.label))}`];
@@ -7888,7 +7974,8 @@ const messagePayloadSchema = z.object({
7888
7974
  const toolCallPayloadSchema = z.object({
7889
7975
  kind: z.literal("tool_call"),
7890
7976
  label: z.string(),
7891
- call: z.record(z.string(), jsonValueSchema)
7977
+ call: z.record(z.string(), jsonValueSchema),
7978
+ diff: z.string().optional()
7892
7979
  });
7893
7980
  const hookStatusPayloadSchema = z.object({
7894
7981
  kind: z.literal("hook_status"),
@@ -8133,7 +8220,7 @@ function rehydrateSession(events) {
8133
8220
  if (event.role === "user") visibleOnlyActionValues = /* @__PURE__ */ new Set();
8134
8221
  break;
8135
8222
  case "tool_call":
8136
- messages.push(toolCallMessage(event.call, event.label));
8223
+ messages.push(toolCallMessage(event.call, event.label, void 0, event.diff));
8137
8224
  break;
8138
8225
  case "hook_status":
8139
8226
  messages.push(hookStatusMessage(event.label, event.eventName, event.statusMessage));
@@ -8757,11 +8844,16 @@ const agentEvent = {
8757
8844
  meta
8758
8845
  };
8759
8846
  },
8760
- toolCall(call, label) {
8761
- return {
8847
+ toolCall(call, label, diff) {
8848
+ return diff === void 0 ? {
8762
8849
  type: "tool_call",
8763
8850
  call,
8764
8851
  label
8852
+ } : {
8853
+ type: "tool_call",
8854
+ call,
8855
+ label,
8856
+ diff
8765
8857
  };
8766
8858
  },
8767
8859
  hookStatus(eventName, statusMessage) {
@@ -9060,6 +9152,7 @@ function stripAnsi(text) {
9060
9152
  //#endregion
9061
9153
  //#region src/tui/layout.ts
9062
9154
  const PROMPT_VISIBLE_CONTENT_LINES = 5;
9155
+ const SLASH_SUGGESTION_VISIBLE_ROWS = 6;
9063
9156
  const PASTE_PREVIEW_MIN_LINES = 6;
9064
9157
  const PASTE_PREVIEW_MIN_CHARS = 500;
9065
9158
  const BRACKETED_PASTE_START = "\x1B[200~";
@@ -9076,6 +9169,7 @@ var ChatLayout = class {
9076
9169
  knowledgeStatus;
9077
9170
  startupHintLine;
9078
9171
  ephemeralLine;
9172
+ temporaryLine;
9079
9173
  taskPlanNoticeLine;
9080
9174
  noticeLine;
9081
9175
  promptHint;
@@ -9092,13 +9186,16 @@ var ChatLayout = class {
9092
9186
  pastedContent = /* @__PURE__ */ new Map();
9093
9187
  promptHistory = new PromptHistory();
9094
9188
  exitAgent;
9189
+ requestRender;
9095
9190
  transcriptMode;
9191
+ temporaryLineExpireTimer;
9096
9192
  constructor(terminal, messages, folderName, modelLabel, options = {}) {
9097
9193
  this.terminal = terminal;
9098
9194
  this.messages = messages;
9099
9195
  this.folderName = folderName;
9100
9196
  this.modelLabel = modelLabel;
9101
9197
  this.exitAgent = typeof options === "function" ? options : options.exitAgent ?? (() => {});
9198
+ this.requestRender = typeof options === "function" ? () => {} : options.requestRender ?? (() => {});
9102
9199
  this.transcriptMode = typeof options === "function" ? "viewport" : options.transcriptMode ?? "viewport";
9103
9200
  }
9104
9201
  addMessage(message) {
@@ -9142,6 +9239,18 @@ var ChatLayout = class {
9142
9239
  setEphemeralLine(line) {
9143
9240
  this.ephemeralLine = line;
9144
9241
  }
9242
+ setTemporaryLine(line, options = {}) {
9243
+ this.clearTemporaryLineExpireTimer();
9244
+ this.temporaryLine = line;
9245
+ const expireAfterMs = options.expireAfterMs;
9246
+ if (line && expireAfterMs !== void 0 && expireAfterMs > 0) this.temporaryLineExpireTimer = setTimeout(() => {
9247
+ this.temporaryLineExpireTimer = void 0;
9248
+ if (this.temporaryLine === line) {
9249
+ this.temporaryLine = void 0;
9250
+ this.requestRender();
9251
+ }
9252
+ }, expireAfterMs);
9253
+ }
9145
9254
  setNoticeLine(line) {
9146
9255
  this.noticeLine = line;
9147
9256
  }
@@ -9173,7 +9282,9 @@ var ChatLayout = class {
9173
9282
  this.status = "ready";
9174
9283
  this.knowledgeStatus = void 0;
9175
9284
  this.startupHintLine = void 0;
9285
+ this.clearTemporaryLineExpireTimer();
9176
9286
  this.ephemeralLine = void 0;
9287
+ this.temporaryLine = void 0;
9177
9288
  this.taskPlanNoticeLine = void 0;
9178
9289
  this.noticeLine = void 0;
9179
9290
  this.promptHint = void 0;
@@ -9246,6 +9357,12 @@ var ChatLayout = class {
9246
9357
  const start = Math.max(0, end - threadHeight);
9247
9358
  return [...padLines(allThreadLines.slice(start, end), threadHeight, safeWidth), ...footerLines];
9248
9359
  }
9360
+ clearTemporaryLineExpireTimer() {
9361
+ if (this.temporaryLineExpireTimer) {
9362
+ clearTimeout(this.temporaryLineExpireTimer);
9363
+ this.temporaryLineExpireTimer = void 0;
9364
+ }
9365
+ }
9249
9366
  renderThread(width, threadHeight) {
9250
9367
  const innerWidth = Math.max(1, width);
9251
9368
  const activeModalIndex = this.getActiveModalIndex();
@@ -9260,6 +9377,7 @@ var ChatLayout = class {
9260
9377
  });
9261
9378
  if (this.startupHintLine) lines.push(...this.renderThreadMessageLines([` ${ui.muted(this.startupHintLine)}`], innerWidth, width, false));
9262
9379
  if (this.ephemeralLine) lines.push(...this.renderThreadMessageLines([` ${this.ephemeralLine}`], innerWidth, width, false));
9380
+ if (this.temporaryLine) lines.push(...this.renderThreadMessageLines([` ${ui.muted(this.temporaryLine)}`], innerWidth, width, false));
9263
9381
  if (this.taskPlanNoticeLine) lines.push(...this.renderThreadMessageLines([` ${this.taskPlanNoticeLine}`], innerWidth, width, false));
9264
9382
  if (this.noticeLine) lines.push(...this.renderThreadMessageLines([` ${this.noticeLine}`], innerWidth, width, false));
9265
9383
  return lines;
@@ -9344,11 +9462,12 @@ var ChatLayout = class {
9344
9462
  if (suggestions.length === 0 || this.promptHint) return [];
9345
9463
  this.activeSlashSuggestionIndex = Math.min(this.activeSlashSuggestionIndex, suggestions.length - 1);
9346
9464
  const innerWidth = Math.max(1, width - 4);
9347
- const visibleSuggestions = suggestions.slice(0, 6);
9465
+ const windowStart = getVisibleSuggestionWindowStart(suggestions.length, this.activeSlashSuggestionIndex, SLASH_SUGGESTION_VISIBLE_ROWS);
9466
+ const visibleSuggestions = suggestions.slice(windowStart, windowStart + SLASH_SUGGESTION_VISIBLE_ROWS);
9348
9467
  const lines = [
9349
9468
  ui.label("slash commands"),
9350
9469
  ...visibleSuggestions.map((suggestion, index) => {
9351
- return truncateToWidth(`${index === this.activeSlashSuggestionIndex ? ">" : " "} ${suggestion.value} — ${suggestion.description}`, innerWidth, "…", true);
9470
+ return truncateToWidth(`${windowStart + index === this.activeSlashSuggestionIndex ? ">" : " "} ${suggestion.value} — ${suggestion.description}`, innerWidth, "…", true);
9352
9471
  }),
9353
9472
  ui.label("Tab complete · ↑↓ choose")
9354
9473
  ];
@@ -9698,6 +9817,10 @@ var ChatLayout = class {
9698
9817
  else this.submitMessage?.(message);
9699
9818
  }
9700
9819
  };
9820
+ function getVisibleSuggestionWindowStart(total, activeIndex, visibleRows) {
9821
+ if (total <= visibleRows) return 0;
9822
+ return Math.max(0, Math.min(activeIndex - visibleRows + 1, total - visibleRows));
9823
+ }
9701
9824
  function colorUserMessageBorder(line) {
9702
9825
  return line.replace("▌", ui.modelInline("▌"));
9703
9826
  }
@@ -10456,7 +10579,8 @@ function runtimeEventToSessionPayload(event) {
10456
10579
  case "tool_call": return {
10457
10580
  kind: "tool_call",
10458
10581
  label: event.label,
10459
- call: event.call
10582
+ call: event.call,
10583
+ ...event.diff === void 0 ? {} : { diff: event.diff }
10460
10584
  };
10461
10585
  case "hook_status": return {
10462
10586
  kind: "hook_status",
@@ -11349,7 +11473,7 @@ var TopchesterAgentRuntime = class TopchesterAgentRuntime {
11349
11473
  const call = taskCalls[index];
11350
11474
  const toolResult = taskResults[index];
11351
11475
  for (const event of createInstructionContextEventsFromToolResult(toolResult, persistedProjectInstructionKeys)) yield event;
11352
- yield agentEvent.toolCall(call, formatToolCallMessage(call, toolResult));
11476
+ yield agentEvent.toolCall(call, formatToolCallMessage(call, toolResult), getToolCallDisplayDiff(toolResult));
11353
11477
  const postHookRun = this.startPostToolUseHook(call, modelToolCalls[index]?.id, toolResult, session, abortSignal);
11354
11478
  for await (const event of postHookRun.statusEvents) yield event;
11355
11479
  const postHook = await postHookRun.result;
@@ -11411,7 +11535,7 @@ var TopchesterAgentRuntime = class TopchesterAgentRuntime {
11411
11535
  const call = parallelCalls[index];
11412
11536
  const toolResult = parallelResults[index];
11413
11537
  for (const event of createInstructionContextEventsFromToolResult(toolResult, persistedProjectInstructionKeys)) yield event;
11414
- yield agentEvent.toolCall(call, formatToolCallMessage(call, toolResult));
11538
+ yield agentEvent.toolCall(call, formatToolCallMessage(call, toolResult), getToolCallDisplayDiff(toolResult));
11415
11539
  const postHookRun = this.startPostToolUseHook(call, modelToolCalls[index]?.id, toolResult, session, abortSignal);
11416
11540
  for await (const event of postHookRun.statusEvents) yield event;
11417
11541
  const postHook = await postHookRun.result;
@@ -11474,7 +11598,7 @@ var TopchesterAgentRuntime = class TopchesterAgentRuntime {
11474
11598
  }
11475
11599
  }
11476
11600
  for (const event of createInstructionContextEventsFromToolResult(toolResult, persistedProjectInstructionKeys)) yield event;
11477
- yield agentEvent.toolCall(executableToolCall, formatToolCallMessage(executableToolCall, toolResult));
11601
+ yield agentEvent.toolCall(executableToolCall, formatToolCallMessage(executableToolCall, toolResult), getToolCallDisplayDiff(toolResult));
11478
11602
  if (!isToolErrorResult(toolResult) && toolResult.tool === "plan_todo") yield agentEvent.taskPlan(toolResult.plan);
11479
11603
  const postHookRun = this.startPostToolUseHook(executableToolCall, toolCall.id, toolResult, session, abortSignal);
11480
11604
  for await (const event of postHookRun.statusEvents) yield event;
@@ -11780,6 +11904,9 @@ function createToolErrorResult(tool, message) {
11780
11904
  warning: message
11781
11905
  };
11782
11906
  }
11907
+ function getToolCallDisplayDiff(result) {
11908
+ if (result.tool === "edit_file" && !isToolErrorResult(result) && "diff" in result) return result.diff;
11909
+ }
11783
11910
  function isL1ContextDisabledByEnv() {
11784
11911
  const value = process.env.TOPCHESTER_DISABLE_L1_CONTEXT?.trim().toLowerCase();
11785
11912
  return value === "1" || value === "true" || value === "yes" || value === "on";
@@ -11820,7 +11947,7 @@ function createInstructionContextEvents(sources, persistedKeys) {
11820
11947
  function renderRuntimeEvent(event) {
11821
11948
  switch (event.type) {
11822
11949
  case "message": return [event.role === "assistant" ? agentMessage(event.text, event.meta) : systemMessage(event.text)];
11823
- case "tool_call": return [toolCallMessage(event.call, event.label)];
11950
+ case "tool_call": return [toolCallMessage(event.call, event.label, void 0, event.diff)];
11824
11951
  case "hook_status": return [hookStatusMessage(event.label, event.eventName, event.statusMessage)];
11825
11952
  case "knowledge_status": return [systemMessage([`KB status: ${formatKnowledgePathStatus(event.status)}${formatKbPathSource(event.status)}`, event.guidance].filter(Boolean).join("\n"))];
11826
11953
  case "choice": return [modalMessage({
@@ -12080,7 +12207,8 @@ function chatMessageToSessionPayload(message) {
12080
12207
  if (message.kind === "tool_call") return {
12081
12208
  kind: "tool_call",
12082
12209
  label: message.label,
12083
- call: message.call
12210
+ call: message.call,
12211
+ ...message.diff === void 0 ? {} : { diff: message.diff }
12084
12212
  };
12085
12213
  }
12086
12214
  function slashCommandToSessionPayload(command) {
@@ -12265,6 +12393,7 @@ function formatSkillSource(skill) {
12265
12393
  }
12266
12394
  //#endregion
12267
12395
  //#region src/tui/shell.ts
12396
+ const HOOK_STATUS_EXPIRE_AFTER_MS = 2e3;
12268
12397
  function formatBashApprovalBody(request) {
12269
12398
  const reason = request.reason.includes(request.command) ? "This bash command is not allowed yet." : request.reason;
12270
12399
  return [
@@ -12324,6 +12453,9 @@ var TopchesterTuiShell = class {
12324
12453
  };
12325
12454
  const app = new ChatLayout(terminal, messages, folderName, modelLabel, {
12326
12455
  transcriptMode: "inline",
12456
+ requestRender: () => {
12457
+ tui.requestRender();
12458
+ },
12327
12459
  exitAgent: () => {
12328
12460
  exit();
12329
12461
  process.exit(0);
@@ -12968,7 +13100,8 @@ var TopchesterTuiShell = class {
12968
13100
  app.setTaskPlanNotice(formatTaskPlanNotice(change, event.plan));
12969
13101
  this.scheduleTaskPlanNoticeClear(app, renderRequester);
12970
13102
  }
12971
- for (const message of renderRuntimeEvent(event)) app.addMessage(message);
13103
+ if (event.type === "hook_status") app.setTemporaryLine(event.label, { expireAfterMs: HOOK_STATUS_EXPIRE_AFTER_MS });
13104
+ else for (const message of renderRuntimeEvent(event)) app.addMessage(message);
12972
13105
  await this.persistPayloadWithWarning(app, runtimeEventToSessionPayload(event));
12973
13106
  }
12974
13107
  }