topchester-ai 0.27.0 → 0.29.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.d.mts +7 -1
- package/dist/cli.mjs +229 -124
- package/dist/cli.mjs.map +1 -1
- package/package.json +2 -1
package/dist/cli.d.mts
CHANGED
package/dist/cli.mjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { cwd, stderr, stdout } from "node:process";
|
|
4
4
|
import { basename, delimiter, dirname, extname, isAbsolute, join, parse, relative, resolve, sep, win32 } from "node:path";
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
6
|
import { Command } from "commander";
|
|
6
7
|
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
|
|
7
8
|
import { generateText, streamText, tool } from "ai";
|
|
@@ -11,12 +12,12 @@ import { execFile, spawn } from "node:child_process";
|
|
|
11
12
|
import { constants, existsSync, mkdirSync, readFileSync, statSync } from "node:fs";
|
|
12
13
|
import { createHash, randomUUID } from "node:crypto";
|
|
13
14
|
import { parse as parse$1, parseDocument } from "yaml";
|
|
14
|
-
import { fileURLToPath } from "node:url";
|
|
15
15
|
import { homedir } from "node:os";
|
|
16
16
|
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
|
},
|
|
@@ -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
|
|
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
|
-
|
|
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) {
|
|
@@ -10487,7 +10579,8 @@ function runtimeEventToSessionPayload(event) {
|
|
|
10487
10579
|
case "tool_call": return {
|
|
10488
10580
|
kind: "tool_call",
|
|
10489
10581
|
label: event.label,
|
|
10490
|
-
call: event.call
|
|
10582
|
+
call: event.call,
|
|
10583
|
+
...event.diff === void 0 ? {} : { diff: event.diff }
|
|
10491
10584
|
};
|
|
10492
10585
|
case "hook_status": return {
|
|
10493
10586
|
kind: "hook_status",
|
|
@@ -11380,7 +11473,7 @@ var TopchesterAgentRuntime = class TopchesterAgentRuntime {
|
|
|
11380
11473
|
const call = taskCalls[index];
|
|
11381
11474
|
const toolResult = taskResults[index];
|
|
11382
11475
|
for (const event of createInstructionContextEventsFromToolResult(toolResult, persistedProjectInstructionKeys)) yield event;
|
|
11383
|
-
yield agentEvent.toolCall(call, formatToolCallMessage(call, toolResult));
|
|
11476
|
+
yield agentEvent.toolCall(call, formatToolCallMessage(call, toolResult), getToolCallDisplayDiff(toolResult));
|
|
11384
11477
|
const postHookRun = this.startPostToolUseHook(call, modelToolCalls[index]?.id, toolResult, session, abortSignal);
|
|
11385
11478
|
for await (const event of postHookRun.statusEvents) yield event;
|
|
11386
11479
|
const postHook = await postHookRun.result;
|
|
@@ -11442,7 +11535,7 @@ var TopchesterAgentRuntime = class TopchesterAgentRuntime {
|
|
|
11442
11535
|
const call = parallelCalls[index];
|
|
11443
11536
|
const toolResult = parallelResults[index];
|
|
11444
11537
|
for (const event of createInstructionContextEventsFromToolResult(toolResult, persistedProjectInstructionKeys)) yield event;
|
|
11445
|
-
yield agentEvent.toolCall(call, formatToolCallMessage(call, toolResult));
|
|
11538
|
+
yield agentEvent.toolCall(call, formatToolCallMessage(call, toolResult), getToolCallDisplayDiff(toolResult));
|
|
11446
11539
|
const postHookRun = this.startPostToolUseHook(call, modelToolCalls[index]?.id, toolResult, session, abortSignal);
|
|
11447
11540
|
for await (const event of postHookRun.statusEvents) yield event;
|
|
11448
11541
|
const postHook = await postHookRun.result;
|
|
@@ -11505,7 +11598,7 @@ var TopchesterAgentRuntime = class TopchesterAgentRuntime {
|
|
|
11505
11598
|
}
|
|
11506
11599
|
}
|
|
11507
11600
|
for (const event of createInstructionContextEventsFromToolResult(toolResult, persistedProjectInstructionKeys)) yield event;
|
|
11508
|
-
yield agentEvent.toolCall(executableToolCall, formatToolCallMessage(executableToolCall, toolResult));
|
|
11601
|
+
yield agentEvent.toolCall(executableToolCall, formatToolCallMessage(executableToolCall, toolResult), getToolCallDisplayDiff(toolResult));
|
|
11509
11602
|
if (!isToolErrorResult(toolResult) && toolResult.tool === "plan_todo") yield agentEvent.taskPlan(toolResult.plan);
|
|
11510
11603
|
const postHookRun = this.startPostToolUseHook(executableToolCall, toolCall.id, toolResult, session, abortSignal);
|
|
11511
11604
|
for await (const event of postHookRun.statusEvents) yield event;
|
|
@@ -11811,6 +11904,9 @@ function createToolErrorResult(tool, message) {
|
|
|
11811
11904
|
warning: message
|
|
11812
11905
|
};
|
|
11813
11906
|
}
|
|
11907
|
+
function getToolCallDisplayDiff(result) {
|
|
11908
|
+
if (result.tool === "edit_file" && !isToolErrorResult(result) && "diff" in result) return result.diff;
|
|
11909
|
+
}
|
|
11814
11910
|
function isL1ContextDisabledByEnv() {
|
|
11815
11911
|
const value = process.env.TOPCHESTER_DISABLE_L1_CONTEXT?.trim().toLowerCase();
|
|
11816
11912
|
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
@@ -11851,7 +11947,7 @@ function createInstructionContextEvents(sources, persistedKeys) {
|
|
|
11851
11947
|
function renderRuntimeEvent(event) {
|
|
11852
11948
|
switch (event.type) {
|
|
11853
11949
|
case "message": return [event.role === "assistant" ? agentMessage(event.text, event.meta) : systemMessage(event.text)];
|
|
11854
|
-
case "tool_call": return [toolCallMessage(event.call, event.label)];
|
|
11950
|
+
case "tool_call": return [toolCallMessage(event.call, event.label, void 0, event.diff)];
|
|
11855
11951
|
case "hook_status": return [hookStatusMessage(event.label, event.eventName, event.statusMessage)];
|
|
11856
11952
|
case "knowledge_status": return [systemMessage([`KB status: ${formatKnowledgePathStatus(event.status)}${formatKbPathSource(event.status)}`, event.guidance].filter(Boolean).join("\n"))];
|
|
11857
11953
|
case "choice": return [modalMessage({
|
|
@@ -12111,7 +12207,8 @@ function chatMessageToSessionPayload(message) {
|
|
|
12111
12207
|
if (message.kind === "tool_call") return {
|
|
12112
12208
|
kind: "tool_call",
|
|
12113
12209
|
label: message.label,
|
|
12114
|
-
call: message.call
|
|
12210
|
+
call: message.call,
|
|
12211
|
+
...message.diff === void 0 ? {} : { diff: message.diff }
|
|
12115
12212
|
};
|
|
12116
12213
|
}
|
|
12117
12214
|
function slashCommandToSessionPayload(command) {
|
|
@@ -13316,104 +13413,112 @@ function defaultSelfUpdateRunner(command, args) {
|
|
|
13316
13413
|
}
|
|
13317
13414
|
//#endregion
|
|
13318
13415
|
//#region src/cli.ts
|
|
13319
|
-
|
|
13320
|
-
program
|
|
13321
|
-
|
|
13322
|
-
program.
|
|
13323
|
-
|
|
13324
|
-
|
|
13325
|
-
|
|
13326
|
-
|
|
13327
|
-
|
|
13328
|
-
|
|
13329
|
-
|
|
13330
|
-
|
|
13331
|
-
|
|
13332
|
-
|
|
13333
|
-
|
|
13334
|
-
|
|
13335
|
-
|
|
13416
|
+
async function runTopchesterCli(argv = process.argv, options = {}) {
|
|
13417
|
+
const program = createTopchesterProgram();
|
|
13418
|
+
if (options.exitOverride) program.exitOverride();
|
|
13419
|
+
await program.parseAsync(argv);
|
|
13420
|
+
}
|
|
13421
|
+
function createTopchesterProgram() {
|
|
13422
|
+
const program = new Command();
|
|
13423
|
+
program.name("topchester").description("KB-first terminal coding agent").version(getTopchesterVersion());
|
|
13424
|
+
program.option("-c, --config <path>", "explicit config file path").option("--workspace <path>", "workspace root", cwd()).option("--resume <session>", "resume a project session: latest or an exact session id").option("--dev <flag>", "enable a development flag", collectDevFlag, []);
|
|
13425
|
+
program.action(async () => {
|
|
13426
|
+
const context = createContextFromOptions(program);
|
|
13427
|
+
const options = program.opts();
|
|
13428
|
+
try {
|
|
13429
|
+
if (options.resume) {
|
|
13430
|
+
const loaded = await loadSession(context.workspaceRoot, options.resume);
|
|
13431
|
+
const session = await loadSessionForAppend(context.workspaceRoot, loaded.sessionId);
|
|
13432
|
+
const rehydrated = rehydrateSession(loaded.events);
|
|
13433
|
+
await new TopchesterTuiShell(context, void 0, {
|
|
13434
|
+
session,
|
|
13435
|
+
initialMessages: rehydrated.messages,
|
|
13436
|
+
initialTaskPlan: rehydrated.taskPlan
|
|
13437
|
+
}).render();
|
|
13438
|
+
return;
|
|
13439
|
+
}
|
|
13440
|
+
await new TopchesterTuiShell(context).render();
|
|
13441
|
+
} catch (error) {
|
|
13442
|
+
console.error(formatStartupError(error));
|
|
13443
|
+
process.exitCode = 1;
|
|
13336
13444
|
}
|
|
13337
|
-
|
|
13338
|
-
|
|
13339
|
-
|
|
13340
|
-
|
|
13341
|
-
|
|
13342
|
-
});
|
|
13343
|
-
program.command("
|
|
13344
|
-
|
|
13345
|
-
|
|
13346
|
-
|
|
13347
|
-
|
|
13348
|
-
|
|
13349
|
-
|
|
13350
|
-
|
|
13351
|
-
|
|
13352
|
-
|
|
13353
|
-
|
|
13354
|
-
|
|
13355
|
-
|
|
13356
|
-
|
|
13357
|
-
|
|
13358
|
-
|
|
13359
|
-
|
|
13360
|
-
|
|
13361
|
-
|
|
13362
|
-
|
|
13363
|
-
|
|
13364
|
-
|
|
13365
|
-
|
|
13366
|
-
|
|
13367
|
-
|
|
13368
|
-
|
|
13369
|
-
kbCommand.command("
|
|
13370
|
-
|
|
13371
|
-
|
|
13372
|
-
|
|
13373
|
-
});
|
|
13374
|
-
kbCommand.command("
|
|
13375
|
-
|
|
13376
|
-
|
|
13377
|
-
|
|
13378
|
-
|
|
13379
|
-
|
|
13380
|
-
|
|
13381
|
-
|
|
13382
|
-
|
|
13383
|
-
|
|
13384
|
-
|
|
13385
|
-
|
|
13386
|
-
|
|
13387
|
-
|
|
13388
|
-
|
|
13389
|
-
|
|
13390
|
-
|
|
13391
|
-
|
|
13392
|
-
|
|
13393
|
-
|
|
13394
|
-
|
|
13395
|
-
|
|
13396
|
-
});
|
|
13397
|
-
kbCommand.command("
|
|
13398
|
-
|
|
13399
|
-
|
|
13400
|
-
|
|
13401
|
-
});
|
|
13402
|
-
|
|
13403
|
-
|
|
13404
|
-
|
|
13405
|
-
|
|
13406
|
-
})
|
|
13407
|
-
|
|
13408
|
-
|
|
13409
|
-
|
|
13410
|
-
|
|
13411
|
-
|
|
13412
|
-
|
|
13413
|
-
|
|
13414
|
-
}
|
|
13415
|
-
});
|
|
13416
|
-
await program.parseAsync();
|
|
13445
|
+
});
|
|
13446
|
+
program.command("dev").description("start local development mode").action(() => {
|
|
13447
|
+
const context = createContextFromOptions(program);
|
|
13448
|
+
console.log("Topchester local dev mode");
|
|
13449
|
+
printStartupSummary(context);
|
|
13450
|
+
});
|
|
13451
|
+
program.command("run").description("run one prompt or slash command without opening the TUI").argument("<prompt...>", "prompt text or slash command").option("--model <model>", "override the agent.primary model for this run").option("--timeout <ms>", "timeout for the run in milliseconds", parsePositiveInteger).option("--json", "write JSONL run events to stdout").option("--output-json <path>", "write JSONL run events to a file").action(async (promptParts, options) => {
|
|
13452
|
+
const context = createContextFromOptions(program);
|
|
13453
|
+
const globalOptions = program.opts();
|
|
13454
|
+
try {
|
|
13455
|
+
await executeRunCommand(context, {
|
|
13456
|
+
prompt: promptParts.join(" "),
|
|
13457
|
+
model: options.model,
|
|
13458
|
+
timeoutMs: options.timeout,
|
|
13459
|
+
json: options.json,
|
|
13460
|
+
outputJson: options.outputJson,
|
|
13461
|
+
resume: globalOptions.resume
|
|
13462
|
+
});
|
|
13463
|
+
} catch (error) {
|
|
13464
|
+
console.error(formatStartupError(error));
|
|
13465
|
+
process.exitCode = 1;
|
|
13466
|
+
}
|
|
13467
|
+
});
|
|
13468
|
+
program.command("search").description("search compiled L1 knowledge entries").argument("<query...>", "search query").option("--limit <count>", "maximum number of matches", parsePositiveInteger).option("--json", "write full JSON search result to stdout").action(async (queryParts, options) => {
|
|
13469
|
+
await executeKbSearchCommand(program, queryParts, options);
|
|
13470
|
+
});
|
|
13471
|
+
const kbCommand = program.command("kb").description("knowledge base commands");
|
|
13472
|
+
kbCommand.command("init").description("initialize a project knowledge base").action(async () => {
|
|
13473
|
+
const context = createContextFromOptions(program);
|
|
13474
|
+
const result = await ui.progress("Preparing project knowledge folders...", (report) => initializeKnowledgeBase(context.workspaceRoot, { onProgress: (event) => report(event.message) }));
|
|
13475
|
+
console.log(formatKnowledgeInitResult(result).join("\n"));
|
|
13476
|
+
});
|
|
13477
|
+
kbCommand.command("dry-run").description("list project files that would be synced into the knowledge base").action(async () => {
|
|
13478
|
+
const context = createContextFromOptions(program);
|
|
13479
|
+
const result = await ui.spinner("Listing project files for KB sync...", () => dryRunKnowledgeCompile(context.workspaceRoot, { config: context.config }));
|
|
13480
|
+
console.log(formatKnowledgeCompileDryRunResult(result, { formatSyncStatus: formatDryRunSyncStatus }).join("\n"));
|
|
13481
|
+
});
|
|
13482
|
+
kbCommand.command("sync").description("sync project files into the knowledge base").option("--full", "sync all in-scope files and remove orphaned L1 entries").action(async (options) => {
|
|
13483
|
+
const context = createContextFromOptions(program);
|
|
13484
|
+
const result = await ui.progress(options.full ? "Syncing all L1 file entries..." : "Syncing non-clean L1 file entries...", (report) => syncKnowledgeBase(context.workspaceRoot, {
|
|
13485
|
+
model: context.modelGateway,
|
|
13486
|
+
requireModel: true,
|
|
13487
|
+
config: context.config,
|
|
13488
|
+
full: options.full,
|
|
13489
|
+
onProgress: (event) => report(event.message)
|
|
13490
|
+
}));
|
|
13491
|
+
console.log(formatKnowledgeSyncResult(result, { title: options.full ? "KB sync --full" : "KB sync" }).join("\n"));
|
|
13492
|
+
if (isPartialKnowledgeCompileResult(result)) process.exitCode = 2;
|
|
13493
|
+
});
|
|
13494
|
+
kbCommand.command("search").alias("query").description("search compiled L1 knowledge entries").argument("<query...>", "search query").option("--limit <count>", "maximum number of matches", parsePositiveInteger).option("--json", "write full JSON search result to stdout").action(async (queryParts, options) => {
|
|
13495
|
+
await executeKbSearchCommand(program, queryParts, options);
|
|
13496
|
+
});
|
|
13497
|
+
kbCommand.command("context").description("create an L1 context pack for a query").argument("<query...>", "context query").option("--limit <count>", "maximum number of relevant files", parsePositiveInteger).option("--min-score <score>", "minimum match score", parseNonNegativeNumber).option("--json", "write JSON context pack to stdout").option("--full-l1", "include full raw L1 entries in JSON output").action(async (queryParts, options) => {
|
|
13498
|
+
await executeKbContextCommand(program, queryParts, options);
|
|
13499
|
+
});
|
|
13500
|
+
kbCommand.command("reset").description("delete the local project knowledge base and cache").action(async () => {
|
|
13501
|
+
const context = createContextFromOptions(program);
|
|
13502
|
+
const result = await ui.progress("Resetting project knowledge base...", (report) => resetKnowledgeBase(context.workspaceRoot, { onProgress: (event) => report(event.message) }));
|
|
13503
|
+
console.log(formatKnowledgeResetResult(result).join("\n"));
|
|
13504
|
+
});
|
|
13505
|
+
kbCommand.command("status").description("show project files that are not current in the knowledge base").action(async () => {
|
|
13506
|
+
const context = createContextFromOptions(program);
|
|
13507
|
+
const result = await ui.spinner("Checking KB file status...", async () => filterNonCleanKnowledgeCompileResult(await dryRunKnowledgeCompile(context.workspaceRoot, { config: context.config })));
|
|
13508
|
+
console.log(formatKnowledgeCompileStatusResult(result, { formatSyncStatus: formatDryRunSyncStatus }).join("\n"));
|
|
13509
|
+
});
|
|
13510
|
+
program.command("update").alias("upgrade").description("update Topchester with the package manager that installed it").argument("[target]", "version or npm dist tag to install", "latest").action(async (target) => {
|
|
13511
|
+
try {
|
|
13512
|
+
const command = await runSelfUpdate({ target });
|
|
13513
|
+
console.log(formatSelfUpdateSuccess(command).join("\n"));
|
|
13514
|
+
} catch (error) {
|
|
13515
|
+
console.error(formatStartupError(error));
|
|
13516
|
+
process.exitCode = 1;
|
|
13517
|
+
}
|
|
13518
|
+
});
|
|
13519
|
+
return program;
|
|
13520
|
+
}
|
|
13521
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) await runTopchesterCli();
|
|
13417
13522
|
function printStartupSummary(context) {
|
|
13418
13523
|
const assignments = context.config.models?.assignments ?? {};
|
|
13419
13524
|
const providers = context.config.models?.providers ?? {};
|
|
@@ -13441,7 +13546,7 @@ function printStartupSummary(context) {
|
|
|
13441
13546
|
}
|
|
13442
13547
|
}
|
|
13443
13548
|
}
|
|
13444
|
-
function createContextFromOptions() {
|
|
13549
|
+
function createContextFromOptions(program) {
|
|
13445
13550
|
const options = program.opts();
|
|
13446
13551
|
return createAppContext({
|
|
13447
13552
|
workspaceRoot: options.workspace,
|
|
@@ -13449,8 +13554,8 @@ function createContextFromOptions() {
|
|
|
13449
13554
|
devFlags: options.dev
|
|
13450
13555
|
});
|
|
13451
13556
|
}
|
|
13452
|
-
async function executeKbSearchCommand(queryParts, options) {
|
|
13453
|
-
const context = createContextFromOptions();
|
|
13557
|
+
async function executeKbSearchCommand(program, queryParts, options) {
|
|
13558
|
+
const context = createContextFromOptions(program);
|
|
13454
13559
|
const query = queryParts.join(" ");
|
|
13455
13560
|
const result = options.json ? await searchL1Knowledge(context.workspaceRoot, query, { limit: options.limit }) : await ui.spinner("Searching L1 knowledge entries...", () => searchL1Knowledge(context.workspaceRoot, query, { limit: options.limit }));
|
|
13456
13561
|
if (options.json) {
|
|
@@ -13459,8 +13564,8 @@ async function executeKbSearchCommand(queryParts, options) {
|
|
|
13459
13564
|
}
|
|
13460
13565
|
console.log(formatL1KnowledgeSearchResult(result).join("\n"));
|
|
13461
13566
|
}
|
|
13462
|
-
async function executeKbContextCommand(queryParts, options) {
|
|
13463
|
-
const context = createContextFromOptions();
|
|
13567
|
+
async function executeKbContextCommand(program, queryParts, options) {
|
|
13568
|
+
const context = createContextFromOptions(program);
|
|
13464
13569
|
const query = queryParts.join(" ");
|
|
13465
13570
|
const contextPackOptions = {
|
|
13466
13571
|
limit: options.limit,
|
|
@@ -13498,6 +13603,6 @@ function formatDryRunSyncStatus(status) {
|
|
|
13498
13603
|
return ui.warn(status);
|
|
13499
13604
|
}
|
|
13500
13605
|
//#endregion
|
|
13501
|
-
export {};
|
|
13606
|
+
export { runTopchesterCli };
|
|
13502
13607
|
|
|
13503
13608
|
//# sourceMappingURL=cli.mjs.map
|