topchester-ai 0.22.0 → 0.23.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
@@ -98,7 +98,7 @@ async function enqueueFileMutation(path, mutate) {
98
98
  }
99
99
  //#endregion
100
100
  //#region src/agent/instructions.ts
101
- const PROJECT_INSTRUCTION_FILENAMES = ["AGENTS.override.md", "AGENTS.md"];
101
+ const PROJECT_INSTRUCTION_FILENAMES = ["AGENTS.md", "AGENTS.override.md"];
102
102
  async function resolveProjectInstructions(workspaceRoot, options = {}) {
103
103
  const filenames = getProjectInstructionFilenames(options);
104
104
  if (filenames.length === 0) return {
@@ -114,21 +114,23 @@ async function resolveProjectInstructions(workspaceRoot, options = {}) {
114
114
  const sources = [];
115
115
  let remainingBytes = Math.max(0, maxTotalBytes);
116
116
  for (const directory of directories) {
117
- const candidate = await readFirstInstructionCandidate(resolvedWorkspace, directory, filenames, options.logger);
118
- if (!candidate) continue;
119
- const scopedContentLimit = Math.min(Math.max(0, maxBytesPerFile), remainingBytes);
120
- const content = truncateUtf8(candidate.content, scopedContentLimit);
121
- const truncated = content !== candidate.content;
122
- remainingBytes -= Buffer.byteLength(content, "utf8");
123
- sources.push({
124
- path: candidate.absolutePath,
125
- relativePath: candidate.relativePath,
126
- scopePath: formatScopePath(relative(resolvedWorkspace, directory)),
127
- depth: getScopeDepth(relative(resolvedWorkspace, directory)),
128
- bytes: candidate.bytes,
129
- truncated,
130
- content
131
- });
117
+ const candidates = await readInstructionCandidates(resolvedWorkspace, directory, filenames, options.logger);
118
+ if (candidates.length === 0) continue;
119
+ for (const candidate of candidates) {
120
+ const scopedContentLimit = Math.min(Math.max(0, maxBytesPerFile), remainingBytes);
121
+ const content = truncateUtf8(candidate.content, scopedContentLimit);
122
+ const truncated = content !== candidate.content;
123
+ remainingBytes -= Buffer.byteLength(content, "utf8");
124
+ sources.push({
125
+ path: candidate.absolutePath,
126
+ relativePath: candidate.relativePath,
127
+ scopePath: formatScopePath(relative(resolvedWorkspace, directory)),
128
+ depth: getScopeDepth(relative(resolvedWorkspace, directory)),
129
+ bytes: candidate.bytes,
130
+ truncated,
131
+ content
132
+ });
133
+ }
132
134
  }
133
135
  options.logger?.debug({
134
136
  event: "project_instructions_resolved",
@@ -212,7 +214,8 @@ function getInstructionDirectories(resolvedWorkspace, targetDirectory) {
212
214
  }
213
215
  return directories;
214
216
  }
215
- async function readFirstInstructionCandidate(resolvedWorkspace, directory, filenames, logger) {
217
+ async function readInstructionCandidates(resolvedWorkspace, directory, filenames, logger) {
218
+ const candidates = [];
216
219
  for (const filename of filenames) {
217
220
  const absolutePath = resolve(directory, filename);
218
221
  const relativePath = formatRelativePath(relative(resolvedWorkspace, absolutePath));
@@ -235,12 +238,12 @@ async function readFirstInstructionCandidate(resolvedWorkspace, directory, filen
235
238
  }, "project instruction skipped");
236
239
  continue;
237
240
  }
238
- return {
241
+ candidates.push({
239
242
  absolutePath,
240
243
  relativePath,
241
244
  content,
242
245
  bytes: bytes.byteLength
243
- };
246
+ });
244
247
  } catch (error) {
245
248
  const code = typeof error === "object" && error && "code" in error ? String(error.code) : void 0;
246
249
  if (code === "ENOENT" || code === "ENOTDIR") continue;
@@ -252,6 +255,7 @@ async function readFirstInstructionCandidate(resolvedWorkspace, directory, filen
252
255
  }, "project instruction skipped");
253
256
  }
254
257
  }
258
+ return candidates;
255
259
  }
256
260
  function truncateUtf8(content, maxBytes) {
257
261
  if (maxBytes <= 0) return "";
@@ -8783,6 +8787,7 @@ var PromptHistory = class {
8783
8787
  };
8784
8788
  //#endregion
8785
8789
  //#region src/tui/status.ts
8790
+ const STARTUP_PROMPT_HINT = "Prompt hint: Enter sends, Shift+Enter adds a line, / opens commands, ↑↓ browse history.";
8786
8791
  function getStartupThreadMessages(context) {
8787
8792
  const assignments = context.config.models?.assignments ?? {};
8788
8793
  const providers = context.config.models?.providers ?? {};
@@ -8932,6 +8937,7 @@ var ChatLayout = class {
8932
8937
  promptCursor = 0;
8933
8938
  status = "ready";
8934
8939
  knowledgeStatus;
8940
+ startupHintLine;
8935
8941
  ephemeralLine;
8936
8942
  taskPlanNoticeLine;
8937
8943
  noticeLine;
@@ -8993,6 +8999,9 @@ var ChatLayout = class {
8993
8999
  isReady() {
8994
9000
  return this.status === "ready";
8995
9001
  }
9002
+ setStartupHintLine(line) {
9003
+ this.startupHintLine = line;
9004
+ }
8996
9005
  setEphemeralLine(line) {
8997
9006
  this.ephemeralLine = line;
8998
9007
  }
@@ -9026,6 +9035,7 @@ var ChatLayout = class {
9026
9035
  this.promptCursor = 0;
9027
9036
  this.status = "ready";
9028
9037
  this.knowledgeStatus = void 0;
9038
+ this.startupHintLine = void 0;
9029
9039
  this.ephemeralLine = void 0;
9030
9040
  this.taskPlanNoticeLine = void 0;
9031
9041
  this.noticeLine = void 0;
@@ -9110,6 +9120,7 @@ var ChatLayout = class {
9110
9120
  const spacer = index === this.messages.length - 1 ? [] : [padThreadLine("", width)];
9111
9121
  return [...this.renderThreadMessageLines(messageLines, innerWidth, width, message.kind === "user"), ...spacer];
9112
9122
  });
9123
+ if (this.startupHintLine) lines.push(...this.renderThreadMessageLines([` ${ui.muted(this.startupHintLine)}`], innerWidth, width, false));
9113
9124
  if (this.ephemeralLine) lines.push(...this.renderThreadMessageLines([` ${this.ephemeralLine}`], innerWidth, width, false));
9114
9125
  if (this.taskPlanNoticeLine) lines.push(...this.renderThreadMessageLines([` ${this.taskPlanNoticeLine}`], innerWidth, width, false));
9115
9126
  if (this.noticeLine) lines.push(...this.renderThreadMessageLines([` ${this.noticeLine}`], innerWidth, width, false));
@@ -9123,6 +9134,7 @@ var ChatLayout = class {
9123
9134
  });
9124
9135
  }
9125
9136
  renderPrompt(width) {
9137
+ const slashSuggestions = this.getSlashSuggestions();
9126
9138
  const top = `┌${"─".repeat(Math.max(0, width - 2))}┐`;
9127
9139
  const bottom = `└${"─".repeat(Math.max(0, width - 2))}┘`;
9128
9140
  const prefix = "> ";
@@ -9131,7 +9143,7 @@ var ChatLayout = class {
9131
9143
  const statusInnerWidth = Math.max(1, width - 2);
9132
9144
  const status = truncateToWidth(` ${formatStatusLine(this.folderName, this.modelLabel, this.status, this.knowledgeStatus, statusInnerWidth)} `, width, "…", true);
9133
9145
  return [
9134
- ...this.renderSlashSuggestions(width),
9146
+ ...this.renderSlashSuggestions(width, slashSuggestions),
9135
9147
  ...this.renderTaskPlan(width),
9136
9148
  top,
9137
9149
  ...inputLines.map((line, index) => `│ ${index === 0 ? prefix : " "}${padPromptInputLine(line, innerWidth)} │`),
@@ -9190,8 +9202,7 @@ var ChatLayout = class {
9190
9202
  if (!this.taskPlan) return [];
9191
9203
  return formatTaskPlanForTui(this.taskPlan, Math.max(1, width));
9192
9204
  }
9193
- renderSlashSuggestions(width) {
9194
- const suggestions = this.getSlashSuggestions();
9205
+ renderSlashSuggestions(width, suggestions = this.getSlashSuggestions()) {
9195
9206
  if (suggestions.length === 0 || this.promptHint) return [];
9196
9207
  this.activeSlashSuggestionIndex = Math.min(this.activeSlashSuggestionIndex, suggestions.length - 1);
9197
9208
  const innerWidth = Math.max(1, width - 4);
@@ -9542,6 +9553,8 @@ var ChatLayout = class {
9542
9553
  }
9543
9554
  submitUserInput(message) {
9544
9555
  this.setTaskPlanNotice(void 0);
9556
+ this.setStartupHintLine(void 0);
9557
+ this.setEphemeralLine(void 0);
9545
9558
  this.promptHistory.add(message);
9546
9559
  if (message.startsWith("/")) this.submitCommand?.(message);
9547
9560
  else this.submitMessage?.(message);
@@ -11969,6 +11982,7 @@ var TopchesterTuiShell = class {
11969
11982
  }
11970
11983
  });
11971
11984
  app.setTaskPlan(this.options.initialTaskPlan);
11985
+ if (!isResumed) app.setStartupHintLine(STARTUP_PROMPT_HINT);
11972
11986
  app.setSubmitMessage((message) => {
11973
11987
  this.startBackgroundTask(app, tui, "Chat", () => this.submitChatMessage(app, tui, message));
11974
11988
  });
@@ -12580,6 +12594,7 @@ var TopchesterTuiShell = class {
12580
12594
  await this.appendStartupRuntimeEvents(session, messages, await this.runtime.runSessionStartHooks?.(session, { isResumed: false }) ?? []);
12581
12595
  await this.appendStartupRuntimeEvents(session, messages, await this.runtime.checkProjectInstructions?.() ?? []);
12582
12596
  app.resetForNewSession(messages);
12597
+ app.setStartupHintLine(STARTUP_PROMPT_HINT);
12583
12598
  tui.requestRender();
12584
12599
  await this.checkAgent(app, tui);
12585
12600
  }