topchester-ai 0.4.0 → 0.5.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
@@ -1843,19 +1843,26 @@ function formatKnowledgeStatus(status) {
1843
1843
  const lines = [
1844
1844
  "KB status",
1845
1845
  `workspace: ${status.workspaceRoot}`,
1846
- `knowledge folder: ${formatPathStatus$2(status.kbPath, status.kbExists, status.kbIsDirectory)} (${status.kbPathSource})`,
1847
- `local cache folder: ${formatPathStatus$2(status.cachePath, status.cacheExists, status.cacheIsDirectory)} (${status.cachePathSource})`
1846
+ `knowledge folder: ${formatKnowledgePathStatus$2(status)} (${status.kbPathSource})`,
1847
+ `local cache folder: ${formatPathStatus$1(status.cachePath, status.cacheExists, status.cacheIsDirectory)} (${status.cachePathSource})`
1848
1848
  ];
1849
1849
  if (!status.kbExists) lines.push("state: no knowledge base found yet");
1850
1850
  else if (!status.kbIsDirectory) lines.push("state: knowledge base path is not a folder");
1851
+ else if (status.kbContentState !== "ready") lines.push("state: knowledge base folder is empty");
1851
1852
  else lines.push("state: knowledge base found");
1852
1853
  return lines;
1853
1854
  }
1854
- function formatPathStatus$2(path, exists, isDirectory) {
1855
+ function formatPathStatus$1(path, exists, isDirectory) {
1855
1856
  if (!exists) return `${path} [missing]`;
1856
1857
  if (!isDirectory) return `${path} [not a folder]`;
1857
1858
  return `${path} [ok]`;
1858
1859
  }
1860
+ function formatKnowledgePathStatus$2(status) {
1861
+ if (!status.kbExists) return `${status.kbPath} [missing]`;
1862
+ if (!status.kbIsDirectory) return `${status.kbPath} [not a folder]`;
1863
+ if (status.kbContentState !== "ready") return `${status.kbPath} [empty]`;
1864
+ return `${status.kbPath} [ok]`;
1865
+ }
1859
1866
  //#endregion
1860
1867
  //#region src/tui/markdown.ts
1861
1868
  const codeFenceSentinel = "topchester-code-fence";
@@ -2058,6 +2065,48 @@ function escapeRegex(value) {
2058
2065
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2059
2066
  }
2060
2067
  //#endregion
2068
+ //#region src/tui/prompt-history.ts
2069
+ const DEFAULT_MAX_PROMPTS = 100;
2070
+ var PromptHistory = class {
2071
+ maxPrompts;
2072
+ prompts = [];
2073
+ historyIndex = -1;
2074
+ draft = "";
2075
+ constructor(maxPrompts = DEFAULT_MAX_PROMPTS) {
2076
+ this.maxPrompts = Math.max(1, maxPrompts);
2077
+ }
2078
+ add(value) {
2079
+ const prompt = value.trim();
2080
+ this.resetBrowsing();
2081
+ if (prompt.length === 0 || prompt === this.prompts[0]) return;
2082
+ this.prompts.unshift(prompt);
2083
+ this.prompts = this.prompts.slice(0, this.maxPrompts);
2084
+ }
2085
+ previous(currentDraft) {
2086
+ if (this.prompts.length === 0) return;
2087
+ if (this.historyIndex === -1) {
2088
+ this.draft = currentDraft;
2089
+ this.historyIndex = 0;
2090
+ return this.prompts[this.historyIndex];
2091
+ }
2092
+ this.historyIndex = Math.min(this.historyIndex + 1, this.prompts.length - 1);
2093
+ return this.prompts[this.historyIndex];
2094
+ }
2095
+ next() {
2096
+ if (this.historyIndex === -1) return;
2097
+ if (this.historyIndex === 0) {
2098
+ this.historyIndex = -1;
2099
+ return this.draft;
2100
+ }
2101
+ this.historyIndex -= 1;
2102
+ return this.prompts[this.historyIndex];
2103
+ }
2104
+ resetBrowsing() {
2105
+ this.historyIndex = -1;
2106
+ this.draft = "";
2107
+ }
2108
+ };
2109
+ //#endregion
2061
2110
  //#region src/tui/status.ts
2062
2111
  function getStartupThreadMessages(context) {
2063
2112
  const assignments = context.config.models?.assignments ?? {};
@@ -2136,10 +2185,17 @@ function formatKnowledgeFooterStatus(status) {
2136
2185
  if (status.kbContentState !== "ready") return `${ui.label("○")} kb: ${ui.label("empty")}`;
2137
2186
  return `${ui.ok("✅")} kb: ${ui.ok("ready")}`;
2138
2187
  }
2139
- function formatPathStatus$1(path, exists, isDirectory) {
2140
- if (!exists) return `${path} ${ui.warn("[missing]")}`;
2141
- if (!isDirectory) return `${path} ${ui.error("[not a folder]")}`;
2142
- return `${path} ${ui.ok("[ok]")}`;
2188
+ function formatKnowledgePathStatus$1(status) {
2189
+ const pathLabel = `${ui.label("")} ${formatWorkspaceRelativePath(status.kbPath, status.workspaceRoot)}`;
2190
+ if (!status.kbExists) return `${pathLabel} ${ui.warn("[missing]")}`;
2191
+ if (!status.kbIsDirectory) return `${pathLabel} ${ui.error("[not a folder]")}`;
2192
+ if (status.kbContentState !== "ready") return `${pathLabel} ${ui.label("[empty]")}`;
2193
+ return `${pathLabel} ${ui.ok("[ok]")}`;
2194
+ }
2195
+ function formatWorkspaceRelativePath(path, workspaceRoot) {
2196
+ const relativePath = relative(workspaceRoot, path);
2197
+ if (relativePath && !relativePath.startsWith("..") && !isAbsolute(relativePath)) return relativePath;
2198
+ return path;
2143
2199
  }
2144
2200
  function getModelLabel(context) {
2145
2201
  const purpose = context.config.models?.defaultPurpose ?? "agent.primary";
@@ -2188,6 +2244,7 @@ var ChatLayout = class {
2188
2244
  activeModalActionIndex = 0;
2189
2245
  activeSlashSuggestionIndex = 0;
2190
2246
  threadScrollOffset = 0;
2247
+ promptHistory = new PromptHistory();
2191
2248
  constructor(terminal, messages, folderName, modelLabel, exitAgent = () => {}) {
2192
2249
  this.terminal = terminal;
2193
2250
  this.messages = messages;
@@ -2264,8 +2321,11 @@ var ChatLayout = class {
2264
2321
  }
2265
2322
  if (this.handleModalInput(data)) return;
2266
2323
  if (this.handleSlashSuggestionInput(data)) return;
2324
+ if (this.handlePromptHistoryInput(data)) return;
2267
2325
  if (this.handleThreadScrollInput(data)) return;
2326
+ const previousInput = this.input.getValue();
2268
2327
  this.input.handleInput(data);
2328
+ if (this.input.getValue() !== previousInput) this.promptHistory.resetBrowsing();
2269
2329
  }
2270
2330
  invalidate() {
2271
2331
  this.input.invalidate();
@@ -2377,14 +2437,6 @@ var ChatLayout = class {
2377
2437
  handleThreadScrollInput(data) {
2378
2438
  const pageSize = Math.max(1, Math.floor(this.terminal.rows / 2));
2379
2439
  const wheel = parseMouseWheel(data);
2380
- if (isUpKey(data)) {
2381
- this.threadScrollOffset += 3;
2382
- return true;
2383
- }
2384
- if (isDownKey(data)) {
2385
- this.threadScrollOffset = Math.max(0, this.threadScrollOffset - 3);
2386
- return true;
2387
- }
2388
2440
  if (wheel === "up") {
2389
2441
  this.threadScrollOffset += 3;
2390
2442
  return true;
@@ -2411,6 +2463,20 @@ var ChatLayout = class {
2411
2463
  }
2412
2464
  return false;
2413
2465
  }
2466
+ handlePromptHistoryInput(data) {
2467
+ if (this.promptHint) return false;
2468
+ if (isUpKey(data)) {
2469
+ const prompt = this.promptHistory.previous(this.input.getValue());
2470
+ if (prompt !== void 0) this.input.setValue(prompt);
2471
+ return true;
2472
+ }
2473
+ if (isDownKey(data)) {
2474
+ const prompt = this.promptHistory.next();
2475
+ if (prompt !== void 0) this.input.setValue(prompt);
2476
+ return true;
2477
+ }
2478
+ return false;
2479
+ }
2414
2480
  handleSlashSuggestionInput(data) {
2415
2481
  const suggestions = this.getSlashSuggestions();
2416
2482
  if (suggestions.length === 0) {
@@ -2438,6 +2504,7 @@ var ChatLayout = class {
2438
2504
  completeSlashSuggestion(suggestions) {
2439
2505
  this.input.setValue(suggestions[this.activeSlashSuggestionIndex]?.value ?? this.input.getValue());
2440
2506
  this.input.handleInput("\x1B[F");
2507
+ this.promptHistory.resetBrowsing();
2441
2508
  }
2442
2509
  getSlashSuggestions() {
2443
2510
  return getSlashCommandSuggestions(this.input.getValue());
@@ -2453,6 +2520,7 @@ var ChatLayout = class {
2453
2520
  this.submitUserInput(message);
2454
2521
  }
2455
2522
  submitUserInput(message) {
2523
+ this.promptHistory.add(message);
2456
2524
  if (message.startsWith("/")) this.submitCommand?.(message);
2457
2525
  else this.submitMessage?.(message);
2458
2526
  }
@@ -3739,7 +3807,7 @@ function renderRuntimeEvent(event) {
3739
3807
  switch (event.type) {
3740
3808
  case "message": return [event.role === "assistant" ? agentMessage(event.text, event.meta) : systemMessage(event.text)];
3741
3809
  case "tool_call": return [systemMessage(event.label)];
3742
- case "knowledge_status": return [systemMessage(`KB status: ${formatPathStatus$1(event.status.kbPath, event.status.kbExists, event.status.kbIsDirectory)} (${event.status.kbPathSource})`)];
3810
+ case "knowledge_status": return [systemMessage(`KB status: ${formatKnowledgePathStatus$1(event.status)}${formatKbPathSource(event.status)}`)];
3743
3811
  case "choice": return [modalMessage({
3744
3812
  tone: event.tone,
3745
3813
  title: event.title,
@@ -3749,6 +3817,9 @@ function renderRuntimeEvent(event) {
3749
3817
  case "status": return [];
3750
3818
  }
3751
3819
  }
3820
+ function formatKbPathSource(status) {
3821
+ return status.kbPathSource === "env" ? " (custom)" : "";
3822
+ }
3752
3823
  //#endregion
3753
3824
  //#region src/tui/terminal.ts
3754
3825
  function enterAlternateScreen(terminal) {
@@ -4135,10 +4206,11 @@ kbCommand.command("status").description("show project knowledge base status").ac
4135
4206
  const status = await ui.spinner("Checking knowledge base...", () => getKnowledgeStatus(context.workspaceRoot));
4136
4207
  console.log(ui.heading("KB status"));
4137
4208
  console.log(`${ui.label("workspace")}: ${status.workspaceRoot}`);
4138
- console.log(`${ui.label("knowledge folder")}: ${formatPathStatus(status.kbPath, status.kbExists, status.kbIsDirectory)} ${ui.label(`(${status.kbPathSource})`)}`);
4209
+ console.log(`${ui.label("knowledge folder")}: ${formatKnowledgePathStatus(status)} ${ui.label(`(${status.kbPathSource})`)}`);
4139
4210
  console.log(`${ui.label("local cache folder")}: ${formatPathStatus(status.cachePath, status.cacheExists, status.cacheIsDirectory)} ${ui.label(`(${status.cachePathSource})`)}`);
4140
4211
  if (!status.kbExists) console.log(`${ui.label("state")}: ${ui.warn("no knowledge base found yet")}`);
4141
4212
  else if (!status.kbIsDirectory) console.log(`${ui.label("state")}: ${ui.error("knowledge base path is not a folder")}`);
4213
+ else if (status.kbContentState !== "ready") console.log(`${ui.label("state")}: ${ui.label("knowledge base folder is empty")}`);
4142
4214
  else console.log(`${ui.label("state")}: ${ui.ok("knowledge base found")}`);
4143
4215
  });
4144
4216
  await program.parseAsync();
@@ -4190,6 +4262,12 @@ function formatPathStatus(path, exists, isDirectory) {
4190
4262
  if (!isDirectory) return `${path} ${ui.error("[not a folder]")}`;
4191
4263
  return `${path} ${ui.ok("[ok]")}`;
4192
4264
  }
4265
+ function formatKnowledgePathStatus(status) {
4266
+ if (!status.kbExists) return `${status.kbPath} ${ui.warn("[missing]")}`;
4267
+ if (!status.kbIsDirectory) return `${status.kbPath} ${ui.error("[not a folder]")}`;
4268
+ if (status.kbContentState !== "ready") return `${status.kbPath} ${ui.label("[empty]")}`;
4269
+ return `${status.kbPath} ${ui.ok("[ok]")}`;
4270
+ }
4193
4271
  //#endregion
4194
4272
  export {};
4195
4273