topchester-ai 0.27.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 +117 -20
- package/dist/cli.mjs.map +1 -1
- package/package.json +2 -1
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
|
},
|
|
@@ -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) {
|