topchester-ai 0.26.0 → 0.27.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
@@ -3258,7 +3258,7 @@ function formatTaskPlanNotice(change, state) {
3258
3258
  }
3259
3259
  function formatTaskPlanForTui(state, width, visibleLimit = 6) {
3260
3260
  if (state.items.length === 0) return [];
3261
- const itemWidth = Math.max(1, Math.max(12, width) - 6);
3261
+ const itemWidth = Math.max(1, Math.max(12, width) - 4);
3262
3262
  const visibleItems = state.items.slice(0, visibleLimit);
3263
3263
  const lines = visibleItems.map((item) => formatTaskPlanTuiLine(item, truncateText(item.text, itemWidth)));
3264
3264
  const remaining = state.items.length - visibleItems.length;
@@ -3267,9 +3267,9 @@ function formatTaskPlanForTui(state, width, visibleLimit = 6) {
3267
3267
  }
3268
3268
  function formatTaskPlanTuiLine(item, text) {
3269
3269
  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}`;
3270
+ case "completed": return ` ${ui.ok("")} ${ui.muted(text)}`;
3271
+ case "in_progress": return ` ${ui.ok("")} ${ui.ok(text)}`;
3272
+ case "pending": return ` ${ui.muted("")} ${text}`;
3273
3273
  }
3274
3274
  }
3275
3275
  function truncateText(text, width) {
@@ -9060,6 +9060,7 @@ function stripAnsi(text) {
9060
9060
  //#endregion
9061
9061
  //#region src/tui/layout.ts
9062
9062
  const PROMPT_VISIBLE_CONTENT_LINES = 5;
9063
+ const SLASH_SUGGESTION_VISIBLE_ROWS = 6;
9063
9064
  const PASTE_PREVIEW_MIN_LINES = 6;
9064
9065
  const PASTE_PREVIEW_MIN_CHARS = 500;
9065
9066
  const BRACKETED_PASTE_START = "\x1B[200~";
@@ -9076,6 +9077,7 @@ var ChatLayout = class {
9076
9077
  knowledgeStatus;
9077
9078
  startupHintLine;
9078
9079
  ephemeralLine;
9080
+ temporaryLine;
9079
9081
  taskPlanNoticeLine;
9080
9082
  noticeLine;
9081
9083
  promptHint;
@@ -9092,13 +9094,16 @@ var ChatLayout = class {
9092
9094
  pastedContent = /* @__PURE__ */ new Map();
9093
9095
  promptHistory = new PromptHistory();
9094
9096
  exitAgent;
9097
+ requestRender;
9095
9098
  transcriptMode;
9099
+ temporaryLineExpireTimer;
9096
9100
  constructor(terminal, messages, folderName, modelLabel, options = {}) {
9097
9101
  this.terminal = terminal;
9098
9102
  this.messages = messages;
9099
9103
  this.folderName = folderName;
9100
9104
  this.modelLabel = modelLabel;
9101
9105
  this.exitAgent = typeof options === "function" ? options : options.exitAgent ?? (() => {});
9106
+ this.requestRender = typeof options === "function" ? () => {} : options.requestRender ?? (() => {});
9102
9107
  this.transcriptMode = typeof options === "function" ? "viewport" : options.transcriptMode ?? "viewport";
9103
9108
  }
9104
9109
  addMessage(message) {
@@ -9142,6 +9147,18 @@ var ChatLayout = class {
9142
9147
  setEphemeralLine(line) {
9143
9148
  this.ephemeralLine = line;
9144
9149
  }
9150
+ setTemporaryLine(line, options = {}) {
9151
+ this.clearTemporaryLineExpireTimer();
9152
+ this.temporaryLine = line;
9153
+ const expireAfterMs = options.expireAfterMs;
9154
+ if (line && expireAfterMs !== void 0 && expireAfterMs > 0) this.temporaryLineExpireTimer = setTimeout(() => {
9155
+ this.temporaryLineExpireTimer = void 0;
9156
+ if (this.temporaryLine === line) {
9157
+ this.temporaryLine = void 0;
9158
+ this.requestRender();
9159
+ }
9160
+ }, expireAfterMs);
9161
+ }
9145
9162
  setNoticeLine(line) {
9146
9163
  this.noticeLine = line;
9147
9164
  }
@@ -9173,7 +9190,9 @@ var ChatLayout = class {
9173
9190
  this.status = "ready";
9174
9191
  this.knowledgeStatus = void 0;
9175
9192
  this.startupHintLine = void 0;
9193
+ this.clearTemporaryLineExpireTimer();
9176
9194
  this.ephemeralLine = void 0;
9195
+ this.temporaryLine = void 0;
9177
9196
  this.taskPlanNoticeLine = void 0;
9178
9197
  this.noticeLine = void 0;
9179
9198
  this.promptHint = void 0;
@@ -9246,6 +9265,12 @@ var ChatLayout = class {
9246
9265
  const start = Math.max(0, end - threadHeight);
9247
9266
  return [...padLines(allThreadLines.slice(start, end), threadHeight, safeWidth), ...footerLines];
9248
9267
  }
9268
+ clearTemporaryLineExpireTimer() {
9269
+ if (this.temporaryLineExpireTimer) {
9270
+ clearTimeout(this.temporaryLineExpireTimer);
9271
+ this.temporaryLineExpireTimer = void 0;
9272
+ }
9273
+ }
9249
9274
  renderThread(width, threadHeight) {
9250
9275
  const innerWidth = Math.max(1, width);
9251
9276
  const activeModalIndex = this.getActiveModalIndex();
@@ -9260,6 +9285,7 @@ var ChatLayout = class {
9260
9285
  });
9261
9286
  if (this.startupHintLine) lines.push(...this.renderThreadMessageLines([` ${ui.muted(this.startupHintLine)}`], innerWidth, width, false));
9262
9287
  if (this.ephemeralLine) lines.push(...this.renderThreadMessageLines([` ${this.ephemeralLine}`], innerWidth, width, false));
9288
+ if (this.temporaryLine) lines.push(...this.renderThreadMessageLines([` ${ui.muted(this.temporaryLine)}`], innerWidth, width, false));
9263
9289
  if (this.taskPlanNoticeLine) lines.push(...this.renderThreadMessageLines([` ${this.taskPlanNoticeLine}`], innerWidth, width, false));
9264
9290
  if (this.noticeLine) lines.push(...this.renderThreadMessageLines([` ${this.noticeLine}`], innerWidth, width, false));
9265
9291
  return lines;
@@ -9344,11 +9370,12 @@ var ChatLayout = class {
9344
9370
  if (suggestions.length === 0 || this.promptHint) return [];
9345
9371
  this.activeSlashSuggestionIndex = Math.min(this.activeSlashSuggestionIndex, suggestions.length - 1);
9346
9372
  const innerWidth = Math.max(1, width - 4);
9347
- const visibleSuggestions = suggestions.slice(0, 6);
9373
+ const windowStart = getVisibleSuggestionWindowStart(suggestions.length, this.activeSlashSuggestionIndex, SLASH_SUGGESTION_VISIBLE_ROWS);
9374
+ const visibleSuggestions = suggestions.slice(windowStart, windowStart + SLASH_SUGGESTION_VISIBLE_ROWS);
9348
9375
  const lines = [
9349
9376
  ui.label("slash commands"),
9350
9377
  ...visibleSuggestions.map((suggestion, index) => {
9351
- return truncateToWidth(`${index === this.activeSlashSuggestionIndex ? ">" : " "} ${suggestion.value} — ${suggestion.description}`, innerWidth, "…", true);
9378
+ return truncateToWidth(`${windowStart + index === this.activeSlashSuggestionIndex ? ">" : " "} ${suggestion.value} — ${suggestion.description}`, innerWidth, "…", true);
9352
9379
  }),
9353
9380
  ui.label("Tab complete · ↑↓ choose")
9354
9381
  ];
@@ -9698,6 +9725,10 @@ var ChatLayout = class {
9698
9725
  else this.submitMessage?.(message);
9699
9726
  }
9700
9727
  };
9728
+ function getVisibleSuggestionWindowStart(total, activeIndex, visibleRows) {
9729
+ if (total <= visibleRows) return 0;
9730
+ return Math.max(0, Math.min(activeIndex - visibleRows + 1, total - visibleRows));
9731
+ }
9701
9732
  function colorUserMessageBorder(line) {
9702
9733
  return line.replace("▌", ui.modelInline("▌"));
9703
9734
  }
@@ -12265,6 +12296,7 @@ function formatSkillSource(skill) {
12265
12296
  }
12266
12297
  //#endregion
12267
12298
  //#region src/tui/shell.ts
12299
+ const HOOK_STATUS_EXPIRE_AFTER_MS = 2e3;
12268
12300
  function formatBashApprovalBody(request) {
12269
12301
  const reason = request.reason.includes(request.command) ? "This bash command is not allowed yet." : request.reason;
12270
12302
  return [
@@ -12324,6 +12356,9 @@ var TopchesterTuiShell = class {
12324
12356
  };
12325
12357
  const app = new ChatLayout(terminal, messages, folderName, modelLabel, {
12326
12358
  transcriptMode: "inline",
12359
+ requestRender: () => {
12360
+ tui.requestRender();
12361
+ },
12327
12362
  exitAgent: () => {
12328
12363
  exit();
12329
12364
  process.exit(0);
@@ -12968,7 +13003,8 @@ var TopchesterTuiShell = class {
12968
13003
  app.setTaskPlanNotice(formatTaskPlanNotice(change, event.plan));
12969
13004
  this.scheduleTaskPlanNoticeClear(app, renderRequester);
12970
13005
  }
12971
- for (const message of renderRuntimeEvent(event)) app.addMessage(message);
13006
+ if (event.type === "hook_status") app.setTemporaryLine(event.label, { expireAfterMs: HOOK_STATUS_EXPIRE_AFTER_MS });
13007
+ else for (const message of renderRuntimeEvent(event)) app.addMessage(message);
12972
13008
  await this.persistPayloadWithWarning(app, runtimeEventToSessionPayload(event));
12973
13009
  }
12974
13010
  }