topchester-ai 0.26.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 +160 -27
- 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
|
},
|
|
@@ -3258,7 +3263,7 @@ function formatTaskPlanNotice(change, state) {
|
|
|
3258
3263
|
}
|
|
3259
3264
|
function formatTaskPlanForTui(state, width, visibleLimit = 6) {
|
|
3260
3265
|
if (state.items.length === 0) return [];
|
|
3261
|
-
const itemWidth = Math.max(1, Math.max(12, width) -
|
|
3266
|
+
const itemWidth = Math.max(1, Math.max(12, width) - 4);
|
|
3262
3267
|
const visibleItems = state.items.slice(0, visibleLimit);
|
|
3263
3268
|
const lines = visibleItems.map((item) => formatTaskPlanTuiLine(item, truncateText(item.text, itemWidth)));
|
|
3264
3269
|
const remaining = state.items.length - visibleItems.length;
|
|
@@ -3267,9 +3272,9 @@ function formatTaskPlanForTui(state, width, visibleLimit = 6) {
|
|
|
3267
3272
|
}
|
|
3268
3273
|
function formatTaskPlanTuiLine(item, text) {
|
|
3269
3274
|
switch (item.status) {
|
|
3270
|
-
case "completed": return ` ${ui.ok("
|
|
3271
|
-
case "in_progress": return ` ${ui.ok("
|
|
3272
|
-
case "pending": return ` ${ui.muted("
|
|
3275
|
+
case "completed": return ` ${ui.ok("●")} ${ui.muted(text)}`;
|
|
3276
|
+
case "in_progress": return ` ${ui.ok("◐")} ${ui.ok(text)}`;
|
|
3277
|
+
case "pending": return ` ${ui.muted("○")} ${text}`;
|
|
3273
3278
|
}
|
|
3274
3279
|
}
|
|
3275
3280
|
function truncateText(text, width) {
|
|
@@ -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) {
|
|
@@ -9060,6 +9152,7 @@ function stripAnsi(text) {
|
|
|
9060
9152
|
//#endregion
|
|
9061
9153
|
//#region src/tui/layout.ts
|
|
9062
9154
|
const PROMPT_VISIBLE_CONTENT_LINES = 5;
|
|
9155
|
+
const SLASH_SUGGESTION_VISIBLE_ROWS = 6;
|
|
9063
9156
|
const PASTE_PREVIEW_MIN_LINES = 6;
|
|
9064
9157
|
const PASTE_PREVIEW_MIN_CHARS = 500;
|
|
9065
9158
|
const BRACKETED_PASTE_START = "\x1B[200~";
|
|
@@ -9076,6 +9169,7 @@ var ChatLayout = class {
|
|
|
9076
9169
|
knowledgeStatus;
|
|
9077
9170
|
startupHintLine;
|
|
9078
9171
|
ephemeralLine;
|
|
9172
|
+
temporaryLine;
|
|
9079
9173
|
taskPlanNoticeLine;
|
|
9080
9174
|
noticeLine;
|
|
9081
9175
|
promptHint;
|
|
@@ -9092,13 +9186,16 @@ var ChatLayout = class {
|
|
|
9092
9186
|
pastedContent = /* @__PURE__ */ new Map();
|
|
9093
9187
|
promptHistory = new PromptHistory();
|
|
9094
9188
|
exitAgent;
|
|
9189
|
+
requestRender;
|
|
9095
9190
|
transcriptMode;
|
|
9191
|
+
temporaryLineExpireTimer;
|
|
9096
9192
|
constructor(terminal, messages, folderName, modelLabel, options = {}) {
|
|
9097
9193
|
this.terminal = terminal;
|
|
9098
9194
|
this.messages = messages;
|
|
9099
9195
|
this.folderName = folderName;
|
|
9100
9196
|
this.modelLabel = modelLabel;
|
|
9101
9197
|
this.exitAgent = typeof options === "function" ? options : options.exitAgent ?? (() => {});
|
|
9198
|
+
this.requestRender = typeof options === "function" ? () => {} : options.requestRender ?? (() => {});
|
|
9102
9199
|
this.transcriptMode = typeof options === "function" ? "viewport" : options.transcriptMode ?? "viewport";
|
|
9103
9200
|
}
|
|
9104
9201
|
addMessage(message) {
|
|
@@ -9142,6 +9239,18 @@ var ChatLayout = class {
|
|
|
9142
9239
|
setEphemeralLine(line) {
|
|
9143
9240
|
this.ephemeralLine = line;
|
|
9144
9241
|
}
|
|
9242
|
+
setTemporaryLine(line, options = {}) {
|
|
9243
|
+
this.clearTemporaryLineExpireTimer();
|
|
9244
|
+
this.temporaryLine = line;
|
|
9245
|
+
const expireAfterMs = options.expireAfterMs;
|
|
9246
|
+
if (line && expireAfterMs !== void 0 && expireAfterMs > 0) this.temporaryLineExpireTimer = setTimeout(() => {
|
|
9247
|
+
this.temporaryLineExpireTimer = void 0;
|
|
9248
|
+
if (this.temporaryLine === line) {
|
|
9249
|
+
this.temporaryLine = void 0;
|
|
9250
|
+
this.requestRender();
|
|
9251
|
+
}
|
|
9252
|
+
}, expireAfterMs);
|
|
9253
|
+
}
|
|
9145
9254
|
setNoticeLine(line) {
|
|
9146
9255
|
this.noticeLine = line;
|
|
9147
9256
|
}
|
|
@@ -9173,7 +9282,9 @@ var ChatLayout = class {
|
|
|
9173
9282
|
this.status = "ready";
|
|
9174
9283
|
this.knowledgeStatus = void 0;
|
|
9175
9284
|
this.startupHintLine = void 0;
|
|
9285
|
+
this.clearTemporaryLineExpireTimer();
|
|
9176
9286
|
this.ephemeralLine = void 0;
|
|
9287
|
+
this.temporaryLine = void 0;
|
|
9177
9288
|
this.taskPlanNoticeLine = void 0;
|
|
9178
9289
|
this.noticeLine = void 0;
|
|
9179
9290
|
this.promptHint = void 0;
|
|
@@ -9246,6 +9357,12 @@ var ChatLayout = class {
|
|
|
9246
9357
|
const start = Math.max(0, end - threadHeight);
|
|
9247
9358
|
return [...padLines(allThreadLines.slice(start, end), threadHeight, safeWidth), ...footerLines];
|
|
9248
9359
|
}
|
|
9360
|
+
clearTemporaryLineExpireTimer() {
|
|
9361
|
+
if (this.temporaryLineExpireTimer) {
|
|
9362
|
+
clearTimeout(this.temporaryLineExpireTimer);
|
|
9363
|
+
this.temporaryLineExpireTimer = void 0;
|
|
9364
|
+
}
|
|
9365
|
+
}
|
|
9249
9366
|
renderThread(width, threadHeight) {
|
|
9250
9367
|
const innerWidth = Math.max(1, width);
|
|
9251
9368
|
const activeModalIndex = this.getActiveModalIndex();
|
|
@@ -9260,6 +9377,7 @@ var ChatLayout = class {
|
|
|
9260
9377
|
});
|
|
9261
9378
|
if (this.startupHintLine) lines.push(...this.renderThreadMessageLines([` ${ui.muted(this.startupHintLine)}`], innerWidth, width, false));
|
|
9262
9379
|
if (this.ephemeralLine) lines.push(...this.renderThreadMessageLines([` ${this.ephemeralLine}`], innerWidth, width, false));
|
|
9380
|
+
if (this.temporaryLine) lines.push(...this.renderThreadMessageLines([` ${ui.muted(this.temporaryLine)}`], innerWidth, width, false));
|
|
9263
9381
|
if (this.taskPlanNoticeLine) lines.push(...this.renderThreadMessageLines([` ${this.taskPlanNoticeLine}`], innerWidth, width, false));
|
|
9264
9382
|
if (this.noticeLine) lines.push(...this.renderThreadMessageLines([` ${this.noticeLine}`], innerWidth, width, false));
|
|
9265
9383
|
return lines;
|
|
@@ -9344,11 +9462,12 @@ var ChatLayout = class {
|
|
|
9344
9462
|
if (suggestions.length === 0 || this.promptHint) return [];
|
|
9345
9463
|
this.activeSlashSuggestionIndex = Math.min(this.activeSlashSuggestionIndex, suggestions.length - 1);
|
|
9346
9464
|
const innerWidth = Math.max(1, width - 4);
|
|
9347
|
-
const
|
|
9465
|
+
const windowStart = getVisibleSuggestionWindowStart(suggestions.length, this.activeSlashSuggestionIndex, SLASH_SUGGESTION_VISIBLE_ROWS);
|
|
9466
|
+
const visibleSuggestions = suggestions.slice(windowStart, windowStart + SLASH_SUGGESTION_VISIBLE_ROWS);
|
|
9348
9467
|
const lines = [
|
|
9349
9468
|
ui.label("slash commands"),
|
|
9350
9469
|
...visibleSuggestions.map((suggestion, index) => {
|
|
9351
|
-
return truncateToWidth(`${index === this.activeSlashSuggestionIndex ? ">" : " "} ${suggestion.value} — ${suggestion.description}`, innerWidth, "…", true);
|
|
9470
|
+
return truncateToWidth(`${windowStart + index === this.activeSlashSuggestionIndex ? ">" : " "} ${suggestion.value} — ${suggestion.description}`, innerWidth, "…", true);
|
|
9352
9471
|
}),
|
|
9353
9472
|
ui.label("Tab complete · ↑↓ choose")
|
|
9354
9473
|
];
|
|
@@ -9698,6 +9817,10 @@ var ChatLayout = class {
|
|
|
9698
9817
|
else this.submitMessage?.(message);
|
|
9699
9818
|
}
|
|
9700
9819
|
};
|
|
9820
|
+
function getVisibleSuggestionWindowStart(total, activeIndex, visibleRows) {
|
|
9821
|
+
if (total <= visibleRows) return 0;
|
|
9822
|
+
return Math.max(0, Math.min(activeIndex - visibleRows + 1, total - visibleRows));
|
|
9823
|
+
}
|
|
9701
9824
|
function colorUserMessageBorder(line) {
|
|
9702
9825
|
return line.replace("▌", ui.modelInline("▌"));
|
|
9703
9826
|
}
|
|
@@ -10456,7 +10579,8 @@ function runtimeEventToSessionPayload(event) {
|
|
|
10456
10579
|
case "tool_call": return {
|
|
10457
10580
|
kind: "tool_call",
|
|
10458
10581
|
label: event.label,
|
|
10459
|
-
call: event.call
|
|
10582
|
+
call: event.call,
|
|
10583
|
+
...event.diff === void 0 ? {} : { diff: event.diff }
|
|
10460
10584
|
};
|
|
10461
10585
|
case "hook_status": return {
|
|
10462
10586
|
kind: "hook_status",
|
|
@@ -11349,7 +11473,7 @@ var TopchesterAgentRuntime = class TopchesterAgentRuntime {
|
|
|
11349
11473
|
const call = taskCalls[index];
|
|
11350
11474
|
const toolResult = taskResults[index];
|
|
11351
11475
|
for (const event of createInstructionContextEventsFromToolResult(toolResult, persistedProjectInstructionKeys)) yield event;
|
|
11352
|
-
yield agentEvent.toolCall(call, formatToolCallMessage(call, toolResult));
|
|
11476
|
+
yield agentEvent.toolCall(call, formatToolCallMessage(call, toolResult), getToolCallDisplayDiff(toolResult));
|
|
11353
11477
|
const postHookRun = this.startPostToolUseHook(call, modelToolCalls[index]?.id, toolResult, session, abortSignal);
|
|
11354
11478
|
for await (const event of postHookRun.statusEvents) yield event;
|
|
11355
11479
|
const postHook = await postHookRun.result;
|
|
@@ -11411,7 +11535,7 @@ var TopchesterAgentRuntime = class TopchesterAgentRuntime {
|
|
|
11411
11535
|
const call = parallelCalls[index];
|
|
11412
11536
|
const toolResult = parallelResults[index];
|
|
11413
11537
|
for (const event of createInstructionContextEventsFromToolResult(toolResult, persistedProjectInstructionKeys)) yield event;
|
|
11414
|
-
yield agentEvent.toolCall(call, formatToolCallMessage(call, toolResult));
|
|
11538
|
+
yield agentEvent.toolCall(call, formatToolCallMessage(call, toolResult), getToolCallDisplayDiff(toolResult));
|
|
11415
11539
|
const postHookRun = this.startPostToolUseHook(call, modelToolCalls[index]?.id, toolResult, session, abortSignal);
|
|
11416
11540
|
for await (const event of postHookRun.statusEvents) yield event;
|
|
11417
11541
|
const postHook = await postHookRun.result;
|
|
@@ -11474,7 +11598,7 @@ var TopchesterAgentRuntime = class TopchesterAgentRuntime {
|
|
|
11474
11598
|
}
|
|
11475
11599
|
}
|
|
11476
11600
|
for (const event of createInstructionContextEventsFromToolResult(toolResult, persistedProjectInstructionKeys)) yield event;
|
|
11477
|
-
yield agentEvent.toolCall(executableToolCall, formatToolCallMessage(executableToolCall, toolResult));
|
|
11601
|
+
yield agentEvent.toolCall(executableToolCall, formatToolCallMessage(executableToolCall, toolResult), getToolCallDisplayDiff(toolResult));
|
|
11478
11602
|
if (!isToolErrorResult(toolResult) && toolResult.tool === "plan_todo") yield agentEvent.taskPlan(toolResult.plan);
|
|
11479
11603
|
const postHookRun = this.startPostToolUseHook(executableToolCall, toolCall.id, toolResult, session, abortSignal);
|
|
11480
11604
|
for await (const event of postHookRun.statusEvents) yield event;
|
|
@@ -11780,6 +11904,9 @@ function createToolErrorResult(tool, message) {
|
|
|
11780
11904
|
warning: message
|
|
11781
11905
|
};
|
|
11782
11906
|
}
|
|
11907
|
+
function getToolCallDisplayDiff(result) {
|
|
11908
|
+
if (result.tool === "edit_file" && !isToolErrorResult(result) && "diff" in result) return result.diff;
|
|
11909
|
+
}
|
|
11783
11910
|
function isL1ContextDisabledByEnv() {
|
|
11784
11911
|
const value = process.env.TOPCHESTER_DISABLE_L1_CONTEXT?.trim().toLowerCase();
|
|
11785
11912
|
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
@@ -11820,7 +11947,7 @@ function createInstructionContextEvents(sources, persistedKeys) {
|
|
|
11820
11947
|
function renderRuntimeEvent(event) {
|
|
11821
11948
|
switch (event.type) {
|
|
11822
11949
|
case "message": return [event.role === "assistant" ? agentMessage(event.text, event.meta) : systemMessage(event.text)];
|
|
11823
|
-
case "tool_call": return [toolCallMessage(event.call, event.label)];
|
|
11950
|
+
case "tool_call": return [toolCallMessage(event.call, event.label, void 0, event.diff)];
|
|
11824
11951
|
case "hook_status": return [hookStatusMessage(event.label, event.eventName, event.statusMessage)];
|
|
11825
11952
|
case "knowledge_status": return [systemMessage([`KB status: ${formatKnowledgePathStatus(event.status)}${formatKbPathSource(event.status)}`, event.guidance].filter(Boolean).join("\n"))];
|
|
11826
11953
|
case "choice": return [modalMessage({
|
|
@@ -12080,7 +12207,8 @@ function chatMessageToSessionPayload(message) {
|
|
|
12080
12207
|
if (message.kind === "tool_call") return {
|
|
12081
12208
|
kind: "tool_call",
|
|
12082
12209
|
label: message.label,
|
|
12083
|
-
call: message.call
|
|
12210
|
+
call: message.call,
|
|
12211
|
+
...message.diff === void 0 ? {} : { diff: message.diff }
|
|
12084
12212
|
};
|
|
12085
12213
|
}
|
|
12086
12214
|
function slashCommandToSessionPayload(command) {
|
|
@@ -12265,6 +12393,7 @@ function formatSkillSource(skill) {
|
|
|
12265
12393
|
}
|
|
12266
12394
|
//#endregion
|
|
12267
12395
|
//#region src/tui/shell.ts
|
|
12396
|
+
const HOOK_STATUS_EXPIRE_AFTER_MS = 2e3;
|
|
12268
12397
|
function formatBashApprovalBody(request) {
|
|
12269
12398
|
const reason = request.reason.includes(request.command) ? "This bash command is not allowed yet." : request.reason;
|
|
12270
12399
|
return [
|
|
@@ -12324,6 +12453,9 @@ var TopchesterTuiShell = class {
|
|
|
12324
12453
|
};
|
|
12325
12454
|
const app = new ChatLayout(terminal, messages, folderName, modelLabel, {
|
|
12326
12455
|
transcriptMode: "inline",
|
|
12456
|
+
requestRender: () => {
|
|
12457
|
+
tui.requestRender();
|
|
12458
|
+
},
|
|
12327
12459
|
exitAgent: () => {
|
|
12328
12460
|
exit();
|
|
12329
12461
|
process.exit(0);
|
|
@@ -12968,7 +13100,8 @@ var TopchesterTuiShell = class {
|
|
|
12968
13100
|
app.setTaskPlanNotice(formatTaskPlanNotice(change, event.plan));
|
|
12969
13101
|
this.scheduleTaskPlanNoticeClear(app, renderRequester);
|
|
12970
13102
|
}
|
|
12971
|
-
|
|
13103
|
+
if (event.type === "hook_status") app.setTemporaryLine(event.label, { expireAfterMs: HOOK_STATUS_EXPIRE_AFTER_MS });
|
|
13104
|
+
else for (const message of renderRuntimeEvent(event)) app.addMessage(message);
|
|
12972
13105
|
await this.persistPayloadWithWarning(app, runtimeEventToSessionPayload(event));
|
|
12973
13106
|
}
|
|
12974
13107
|
}
|