kfc-code-cli 0.0.1-alpha.21 → 0.0.1-alpha.22
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/main.mjs +707 -156
- package/package.json +1 -1
package/dist/main.mjs
CHANGED
|
@@ -77020,6 +77020,44 @@ function extractMatcherValue(input) {
|
|
|
77020
77020
|
return input;
|
|
77021
77021
|
}
|
|
77022
77022
|
/**
|
|
77023
|
+
* OAuth error classes.
|
|
77024
|
+
*
|
|
77025
|
+
* All errors derive from {@link OAuthError}. Distinguishing subclasses let
|
|
77026
|
+
* callers react appropriately:
|
|
77027
|
+
* - `OAuthUnauthorizedError`: 401/403 from token endpoint → refresh_token
|
|
77028
|
+
* or credentials are bad; drive user through `/login` again.
|
|
77029
|
+
* - `DeviceCodeExpiredError`: device_code TTL ran out before user approved;
|
|
77030
|
+
* restart the device flow.
|
|
77031
|
+
* - `DeviceCodeTimeoutError`: local 15 min wall-clock budget exhausted
|
|
77032
|
+
* (D2 from Slice 5.0 brief).
|
|
77033
|
+
* - `RetryableRefreshError`: 429 / 5xx from token endpoint; the refresh
|
|
77034
|
+
* helper retries with exponential backoff before surfacing this.
|
|
77035
|
+
*/
|
|
77036
|
+
var OAuthError = class extends Error {
|
|
77037
|
+
constructor(message) {
|
|
77038
|
+
super(message);
|
|
77039
|
+
this.name = "OAuthError";
|
|
77040
|
+
}
|
|
77041
|
+
};
|
|
77042
|
+
var OAuthUnauthorizedError = class extends OAuthError {
|
|
77043
|
+
constructor(message) {
|
|
77044
|
+
super(message);
|
|
77045
|
+
this.name = "OAuthUnauthorizedError";
|
|
77046
|
+
}
|
|
77047
|
+
};
|
|
77048
|
+
var DeviceCodeTimeoutError = class extends OAuthError {
|
|
77049
|
+
constructor(message = "Device authorization timed out locally.") {
|
|
77050
|
+
super(message);
|
|
77051
|
+
this.name = "DeviceCodeTimeoutError";
|
|
77052
|
+
}
|
|
77053
|
+
};
|
|
77054
|
+
var RetryableRefreshError = class extends OAuthError {
|
|
77055
|
+
constructor(message) {
|
|
77056
|
+
super(message);
|
|
77057
|
+
this.name = "RetryableRefreshError";
|
|
77058
|
+
}
|
|
77059
|
+
};
|
|
77060
|
+
/**
|
|
77023
77061
|
* Business-error sentinel classes — Phase 18 A.11 / A.12 / A.13
|
|
77024
77062
|
* (v2 §3.1 wire error code table).
|
|
77025
77063
|
*
|
|
@@ -77132,6 +77170,50 @@ function classifyBusinessError(error) {
|
|
|
77132
77170
|
};
|
|
77133
77171
|
return null;
|
|
77134
77172
|
}
|
|
77173
|
+
function classifySessionErrorType(error) {
|
|
77174
|
+
if (error instanceof ContextOverflowError) return "context_overflow";
|
|
77175
|
+
if (isRateLimitLikeError(error)) return "rate_limit";
|
|
77176
|
+
if (isAuthLikeError(error)) return "auth_error";
|
|
77177
|
+
if (error instanceof LLMNotSetError) return "auth_error";
|
|
77178
|
+
if (error instanceof LLMCapabilityMismatchError || error instanceof ProviderError) return "api_error";
|
|
77179
|
+
if (error instanceof Error && /provider|backend|upstream/i.test(error.message)) return "api_error";
|
|
77180
|
+
return "internal";
|
|
77181
|
+
}
|
|
77182
|
+
function isAuthLikeError(error) {
|
|
77183
|
+
for (const item of errorChain(error)) {
|
|
77184
|
+
if (item instanceof OAuthError) return true;
|
|
77185
|
+
const rec = item;
|
|
77186
|
+
if (rec["status"] === 401 || rec["status"] === 403) return true;
|
|
77187
|
+
if (rec["statusCode"] === 401 || rec["statusCode"] === 403) return true;
|
|
77188
|
+
const code = rec["code"];
|
|
77189
|
+
if (typeof code === "string" && /^(unauthorized|authentication_error|auth_error|invalid_api_key|invalid_grant|permission_denied)$/i.test(code)) return true;
|
|
77190
|
+
if (item instanceof ProviderError || item instanceof Error) {
|
|
77191
|
+
const message = item.message;
|
|
77192
|
+
if (/(api key|authenticat|unauthori[sz]ed|forbidden|credentials|run \/login)/i.test(message)) return true;
|
|
77193
|
+
}
|
|
77194
|
+
}
|
|
77195
|
+
return false;
|
|
77196
|
+
}
|
|
77197
|
+
function isRateLimitLikeError(error) {
|
|
77198
|
+
for (const item of errorChain(error)) {
|
|
77199
|
+
if (item instanceof RetryableRefreshError) return true;
|
|
77200
|
+
const rec = item;
|
|
77201
|
+
if (rec["status"] === 429 || rec["statusCode"] === 429) return true;
|
|
77202
|
+
const code = rec["code"];
|
|
77203
|
+
if (typeof code === "string" && /^(rate_limit|rate_limit_exceeded|too_many_requests)$/i.test(code)) return true;
|
|
77204
|
+
}
|
|
77205
|
+
return false;
|
|
77206
|
+
}
|
|
77207
|
+
function errorChain(error) {
|
|
77208
|
+
const out = [];
|
|
77209
|
+
let current = error;
|
|
77210
|
+
for (let depth = 0; depth < 8 && current !== void 0 && current !== null; depth += 1) {
|
|
77211
|
+
out.push(current);
|
|
77212
|
+
if (typeof current !== "object") break;
|
|
77213
|
+
current = current.cause;
|
|
77214
|
+
}
|
|
77215
|
+
return out;
|
|
77216
|
+
}
|
|
77135
77217
|
/**
|
|
77136
77218
|
* SoulRegistry — per-session `Map<SoulKey, SoulHandle>` (v2 §5.2.3).
|
|
77137
77219
|
*
|
|
@@ -82003,7 +82085,7 @@ var TurnManager = class {
|
|
|
82003
82085
|
this.deps.sink.emit({
|
|
82004
82086
|
type: "session.error",
|
|
82005
82087
|
error: message,
|
|
82006
|
-
error_type:
|
|
82088
|
+
error_type: classifySessionErrorType(error),
|
|
82007
82089
|
details: {
|
|
82008
82090
|
name,
|
|
82009
82091
|
stack
|
|
@@ -82126,7 +82208,9 @@ var TurnManager = class {
|
|
|
82126
82208
|
runtime,
|
|
82127
82209
|
context: this.deps.contextState,
|
|
82128
82210
|
sink: this.deps.sink,
|
|
82129
|
-
emitStatusUpdate: () =>
|
|
82211
|
+
emitStatusUpdate: () => {
|
|
82212
|
+
this.emitStatusUpdate();
|
|
82213
|
+
}
|
|
82130
82214
|
});
|
|
82131
82215
|
}
|
|
82132
82216
|
};
|
|
@@ -92758,44 +92842,6 @@ var LocalFetchURLProvider = class {
|
|
|
92758
92842
|
return titleText.length > 0 ? `# ${titleText}\n\n${fallbackText}` : fallbackText;
|
|
92759
92843
|
}
|
|
92760
92844
|
};
|
|
92761
|
-
/**
|
|
92762
|
-
* OAuth error classes.
|
|
92763
|
-
*
|
|
92764
|
-
* All errors derive from {@link OAuthError}. Distinguishing subclasses let
|
|
92765
|
-
* callers react appropriately:
|
|
92766
|
-
* - `OAuthUnauthorizedError`: 401/403 from token endpoint → refresh_token
|
|
92767
|
-
* or credentials are bad; drive user through `/login` again.
|
|
92768
|
-
* - `DeviceCodeExpiredError`: device_code TTL ran out before user approved;
|
|
92769
|
-
* restart the device flow.
|
|
92770
|
-
* - `DeviceCodeTimeoutError`: local 15 min wall-clock budget exhausted
|
|
92771
|
-
* (D2 from Slice 5.0 brief).
|
|
92772
|
-
* - `RetryableRefreshError`: 429 / 5xx from token endpoint; the refresh
|
|
92773
|
-
* helper retries with exponential backoff before surfacing this.
|
|
92774
|
-
*/
|
|
92775
|
-
var OAuthError = class extends Error {
|
|
92776
|
-
constructor(message) {
|
|
92777
|
-
super(message);
|
|
92778
|
-
this.name = "OAuthError";
|
|
92779
|
-
}
|
|
92780
|
-
};
|
|
92781
|
-
var OAuthUnauthorizedError = class extends OAuthError {
|
|
92782
|
-
constructor(message) {
|
|
92783
|
-
super(message);
|
|
92784
|
-
this.name = "OAuthUnauthorizedError";
|
|
92785
|
-
}
|
|
92786
|
-
};
|
|
92787
|
-
var DeviceCodeTimeoutError = class extends OAuthError {
|
|
92788
|
-
constructor(message = "Device authorization timed out locally.") {
|
|
92789
|
-
super(message);
|
|
92790
|
-
this.name = "DeviceCodeTimeoutError";
|
|
92791
|
-
}
|
|
92792
|
-
};
|
|
92793
|
-
var RetryableRefreshError = class extends OAuthError {
|
|
92794
|
-
constructor(message) {
|
|
92795
|
-
super(message);
|
|
92796
|
-
this.name = "RetryableRefreshError";
|
|
92797
|
-
}
|
|
92798
|
-
};
|
|
92799
92845
|
function tokenToWire(token) {
|
|
92800
92846
|
return {
|
|
92801
92847
|
access_token: token.accessToken,
|
|
@@ -94403,8 +94449,11 @@ var KimiWireClient = class {
|
|
|
94403
94449
|
authStatus(providerName) {
|
|
94404
94450
|
return this.request("auth.status", providerName !== void 0 ? { provider_name: providerName } : {});
|
|
94405
94451
|
}
|
|
94406
|
-
authLogin(providerName) {
|
|
94407
|
-
return this.request("auth.login", providerName !== void 0 ? { provider_name: providerName } : {}, {
|
|
94452
|
+
authLogin(providerName, options) {
|
|
94453
|
+
return this.request("auth.login", providerName !== void 0 ? { provider_name: providerName } : {}, {
|
|
94454
|
+
timeoutMs: 1200 * 1e3,
|
|
94455
|
+
...options?.signal !== void 0 ? { signal: options.signal } : {}
|
|
94456
|
+
});
|
|
94408
94457
|
}
|
|
94409
94458
|
authLogout(providerName) {
|
|
94410
94459
|
return this.request("auth.logout", providerName !== void 0 ? { provider_name: providerName } : {});
|
|
@@ -95430,6 +95479,123 @@ function pathTextForVideo(att) {
|
|
|
95430
95479
|
return att.sourcePath;
|
|
95431
95480
|
}
|
|
95432
95481
|
//#endregion
|
|
95482
|
+
//#region src/tui/components/chrome/device-code-box.ts
|
|
95483
|
+
var DeviceCodeBoxComponent = class {
|
|
95484
|
+
params;
|
|
95485
|
+
constructor(params) {
|
|
95486
|
+
this.params = params;
|
|
95487
|
+
}
|
|
95488
|
+
invalidate() {}
|
|
95489
|
+
render(width) {
|
|
95490
|
+
const { title, url, code, hint, colors } = this.params;
|
|
95491
|
+
const border = (s) => chalk.hex(colors.primary)(s);
|
|
95492
|
+
const safeWidth = Math.max(28, width);
|
|
95493
|
+
const innerWidth = Math.max(10, safeWidth - 4);
|
|
95494
|
+
const pad = " ";
|
|
95495
|
+
const contentLines = [
|
|
95496
|
+
truncateToWidth(chalk.bold.hex(colors.textStrong)(title), innerWidth, "…"),
|
|
95497
|
+
"",
|
|
95498
|
+
truncateToWidth(chalk.hex(colors.textDim)("Visit the URL below in your browser to authorize:"), innerWidth, "…"),
|
|
95499
|
+
truncateToWidth(chalk.hex(colors.primary)(url), innerWidth, "…"),
|
|
95500
|
+
"",
|
|
95501
|
+
truncateToWidth(`${chalk.bold.hex(colors.textDim)("Verification code: ")}${chalk.bold.hex(colors.accent)(code)}`, innerWidth, "…")
|
|
95502
|
+
];
|
|
95503
|
+
if (hint !== void 0 && hint.length > 0) {
|
|
95504
|
+
contentLines.push("");
|
|
95505
|
+
contentLines.push(truncateToWidth(chalk.hex(colors.textDim)(hint), innerWidth, "…"));
|
|
95506
|
+
}
|
|
95507
|
+
const lines = [
|
|
95508
|
+
"",
|
|
95509
|
+
border("╭" + "─".repeat(safeWidth - 2) + "╮"),
|
|
95510
|
+
border("│") + " ".repeat(safeWidth - 2) + border("│")
|
|
95511
|
+
];
|
|
95512
|
+
for (const content of contentLines) {
|
|
95513
|
+
const truncated = content;
|
|
95514
|
+
const vis = visibleWidth(truncated);
|
|
95515
|
+
const rightPad = Math.max(0, innerWidth - vis);
|
|
95516
|
+
lines.push(border("│") + pad + truncated + " ".repeat(rightPad) + border("│"));
|
|
95517
|
+
}
|
|
95518
|
+
lines.push(border("│") + " ".repeat(safeWidth - 2) + border("│"));
|
|
95519
|
+
lines.push(border("╰" + "─".repeat(safeWidth - 2) + "╯"));
|
|
95520
|
+
lines.push("");
|
|
95521
|
+
return lines;
|
|
95522
|
+
}
|
|
95523
|
+
};
|
|
95524
|
+
//#endregion
|
|
95525
|
+
//#region src/tui/components/chrome/moon-loader.ts
|
|
95526
|
+
const MOON_PHASES = [
|
|
95527
|
+
"🌑",
|
|
95528
|
+
"🌒",
|
|
95529
|
+
"🌓",
|
|
95530
|
+
"🌔",
|
|
95531
|
+
"🌕",
|
|
95532
|
+
"🌖",
|
|
95533
|
+
"🌗",
|
|
95534
|
+
"🌘"
|
|
95535
|
+
];
|
|
95536
|
+
const MOON_INTERVAL = 120;
|
|
95537
|
+
const BRAILLE_FRAMES = [
|
|
95538
|
+
"⠋",
|
|
95539
|
+
"⠙",
|
|
95540
|
+
"⠹",
|
|
95541
|
+
"⠸",
|
|
95542
|
+
"⠼",
|
|
95543
|
+
"⠴",
|
|
95544
|
+
"⠦",
|
|
95545
|
+
"⠧",
|
|
95546
|
+
"⠇",
|
|
95547
|
+
"⠏"
|
|
95548
|
+
];
|
|
95549
|
+
const BRAILLE_INTERVAL = 80;
|
|
95550
|
+
var MoonLoader = class extends Text {
|
|
95551
|
+
currentFrame = 0;
|
|
95552
|
+
intervalId = null;
|
|
95553
|
+
ui;
|
|
95554
|
+
frames;
|
|
95555
|
+
interval;
|
|
95556
|
+
colorFn;
|
|
95557
|
+
label;
|
|
95558
|
+
constructor(ui, style = "moon", colorFn, label = "") {
|
|
95559
|
+
super("", 1, 0);
|
|
95560
|
+
this.ui = ui;
|
|
95561
|
+
this.frames = style === "moon" ? MOON_PHASES : BRAILLE_FRAMES;
|
|
95562
|
+
this.interval = style === "moon" ? MOON_INTERVAL : BRAILLE_INTERVAL;
|
|
95563
|
+
this.colorFn = colorFn;
|
|
95564
|
+
this.label = label;
|
|
95565
|
+
this.start();
|
|
95566
|
+
}
|
|
95567
|
+
render(width) {
|
|
95568
|
+
return ["", ...super.render(width)];
|
|
95569
|
+
}
|
|
95570
|
+
start() {
|
|
95571
|
+
this.updateDisplay();
|
|
95572
|
+
this.intervalId = setInterval(() => {
|
|
95573
|
+
this.currentFrame = (this.currentFrame + 1) % this.frames.length;
|
|
95574
|
+
this.updateDisplay();
|
|
95575
|
+
}, this.interval);
|
|
95576
|
+
}
|
|
95577
|
+
stop() {
|
|
95578
|
+
if (this.intervalId) {
|
|
95579
|
+
clearInterval(this.intervalId);
|
|
95580
|
+
this.intervalId = null;
|
|
95581
|
+
}
|
|
95582
|
+
}
|
|
95583
|
+
setLabel(label) {
|
|
95584
|
+
this.label = label;
|
|
95585
|
+
this.updateDisplay();
|
|
95586
|
+
}
|
|
95587
|
+
setColorFn(colorFn) {
|
|
95588
|
+
this.colorFn = colorFn;
|
|
95589
|
+
this.updateDisplay();
|
|
95590
|
+
}
|
|
95591
|
+
updateDisplay() {
|
|
95592
|
+
const frame = this.frames[this.currentFrame];
|
|
95593
|
+
const coloredFrame = this.colorFn ? this.colorFn(frame) : frame;
|
|
95594
|
+
this.setText(this.label ? `${coloredFrame} ${this.label}` : coloredFrame);
|
|
95595
|
+
this.ui.requestRender();
|
|
95596
|
+
}
|
|
95597
|
+
};
|
|
95598
|
+
//#endregion
|
|
95433
95599
|
//#region src/tui/components/chrome/welcome.ts
|
|
95434
95600
|
var WelcomeComponent = class {
|
|
95435
95601
|
state;
|
|
@@ -96250,7 +96416,10 @@ function pickResultRenderer(toolName) {
|
|
|
96250
96416
|
const MAX_ARG_LENGTH = 60;
|
|
96251
96417
|
const CALL_PREVIEW_LINES = 10;
|
|
96252
96418
|
const MAX_SUB_TOOL_CALLS_SHOWN = 4;
|
|
96419
|
+
const MAX_SINGLE_SUBAGENT_TOOL_ROWS = 4;
|
|
96253
96420
|
const APPROVED_PLAN_MARKER = "## Approved Plan:";
|
|
96421
|
+
const STREAMING_PROGRESS_INTERVAL_MS = 1e3;
|
|
96422
|
+
const SUBAGENT_ELAPSED_INTERVAL_MS = 1e3;
|
|
96254
96423
|
function str(v) {
|
|
96255
96424
|
return typeof v === "string" ? v : "";
|
|
96256
96425
|
}
|
|
@@ -96260,6 +96429,17 @@ function formatSubagentTokens(usage) {
|
|
|
96260
96429
|
if (total <= 0) return void 0;
|
|
96261
96430
|
return `${total >= 1e3 ? `${(total / 1e3).toFixed(1)}k` : String(total)} tok`;
|
|
96262
96431
|
}
|
|
96432
|
+
function formatByteSize(bytes) {
|
|
96433
|
+
if (bytes < 1024) return `${String(bytes)} B`;
|
|
96434
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
96435
|
+
return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
96436
|
+
}
|
|
96437
|
+
function formatElapsed(seconds) {
|
|
96438
|
+
if (seconds < 60) return `${String(seconds)}s`;
|
|
96439
|
+
const minutes = Math.floor(seconds / 60);
|
|
96440
|
+
const remainder = seconds % 60;
|
|
96441
|
+
return `${String(minutes)}m ${String(remainder)}s`;
|
|
96442
|
+
}
|
|
96263
96443
|
function extractApprovedPlan(output) {
|
|
96264
96444
|
const markerIndex = output.indexOf(APPROVED_PLAN_MARKER);
|
|
96265
96445
|
if (markerIndex < 0) return "";
|
|
@@ -96419,6 +96599,30 @@ function extractKeyArgument(toolName, args) {
|
|
|
96419
96599
|
}
|
|
96420
96600
|
return null;
|
|
96421
96601
|
}
|
|
96602
|
+
function formatSubagentLabel(agentName) {
|
|
96603
|
+
const raw = agentName?.trim();
|
|
96604
|
+
if (raw === void 0 || raw.length === 0) return "SubAgent";
|
|
96605
|
+
const label = raw.split(/[-_\s]+/).filter((part) => part.length > 0).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
96606
|
+
if (/\bagent$/i.test(label)) return label;
|
|
96607
|
+
return `${label} Agent`;
|
|
96608
|
+
}
|
|
96609
|
+
function tailNonEmptyLines(text, maxLines) {
|
|
96610
|
+
if (text.length === 0) return [];
|
|
96611
|
+
return text.split("\n").map((line) => line.trimEnd()).filter((line) => line.trim().length > 0).slice(-maxLines);
|
|
96612
|
+
}
|
|
96613
|
+
var PrefixedWrappedLine = class {
|
|
96614
|
+
constructor(firstPrefix, continuationPrefix, text) {
|
|
96615
|
+
this.firstPrefix = firstPrefix;
|
|
96616
|
+
this.continuationPrefix = continuationPrefix;
|
|
96617
|
+
this.text = text;
|
|
96618
|
+
}
|
|
96619
|
+
invalidate() {}
|
|
96620
|
+
render(width) {
|
|
96621
|
+
const prefixWidth = Math.max(visibleWidth(this.firstPrefix), visibleWidth(this.continuationPrefix));
|
|
96622
|
+
const contentWidth = Math.max(1, width - prefixWidth);
|
|
96623
|
+
return new Text(this.text, 0, 0).render(contentWidth).map((line, index) => index === 0 ? `${this.firstPrefix}${line}` : `${this.continuationPrefix}${line}`);
|
|
96624
|
+
}
|
|
96625
|
+
};
|
|
96422
96626
|
var ToolCallComponent = class extends Container {
|
|
96423
96627
|
expanded = false;
|
|
96424
96628
|
toolCall;
|
|
@@ -96440,16 +96644,22 @@ var ToolCallComponent = class extends Container {
|
|
|
96440
96644
|
subagentAgentName;
|
|
96441
96645
|
ongoingSubCalls = /* @__PURE__ */ new Map();
|
|
96442
96646
|
finishedSubCalls = [];
|
|
96647
|
+
subToolActivities = /* @__PURE__ */ new Map();
|
|
96648
|
+
subToolOrderSeq = 0;
|
|
96443
96649
|
hiddenSubCallCount = 0;
|
|
96444
96650
|
/**
|
|
96445
|
-
* 子 agent
|
|
96446
|
-
* 最后几行,避免占用过多屏幕。
|
|
96651
|
+
* 子 agent 最近的若干行正式输出。历史 replay 只有混合 text 时也落在这里。
|
|
96447
96652
|
*/
|
|
96448
96653
|
subagentText = "";
|
|
96654
|
+
subagentThinkingText = "";
|
|
96449
96655
|
subagentPhase;
|
|
96450
96656
|
subagentUsage;
|
|
96451
96657
|
subagentResultSummary;
|
|
96452
96658
|
subagentError;
|
|
96659
|
+
streamingProgressTimer;
|
|
96660
|
+
subagentElapsedTimer;
|
|
96661
|
+
subagentStartedAtMs;
|
|
96662
|
+
subagentEndedAtMs;
|
|
96453
96663
|
/**
|
|
96454
96664
|
* 当 ToolCallComponent 被 group 容器(`AgentGroupComponent` /
|
|
96455
96665
|
* `ReadGroupComponent`)借走做"隐身状态容器"时,由 group 注册回调;任何
|
|
@@ -96474,6 +96684,8 @@ var ToolCallComponent = class extends Container {
|
|
|
96474
96684
|
this.callPreviewEndIndex = this.children.length;
|
|
96475
96685
|
this.buildContent();
|
|
96476
96686
|
this.buildSubagentBlock();
|
|
96687
|
+
this.syncStreamingProgressTimer();
|
|
96688
|
+
this.syncSubagentElapsedTimer();
|
|
96477
96689
|
}
|
|
96478
96690
|
setExpanded(expanded) {
|
|
96479
96691
|
if (this.expanded === expanded) return;
|
|
@@ -96482,16 +96694,24 @@ var ToolCallComponent = class extends Container {
|
|
|
96482
96694
|
}
|
|
96483
96695
|
setResult(result) {
|
|
96484
96696
|
this.result = result;
|
|
96697
|
+
this.finalizeSubagentElapsedIfNeeded();
|
|
96698
|
+
this.syncStreamingProgressTimer();
|
|
96699
|
+
this.syncSubagentElapsedTimer();
|
|
96485
96700
|
this.headerText.setText(this.buildHeader());
|
|
96486
96701
|
this.rebuildBody();
|
|
96487
96702
|
this.notifySnapshotChange();
|
|
96488
96703
|
}
|
|
96489
96704
|
updateToolCall(toolCall) {
|
|
96490
96705
|
this.toolCall = toolCall;
|
|
96706
|
+
this.syncStreamingProgressTimer();
|
|
96491
96707
|
this.headerText.setText(this.buildHeader());
|
|
96492
96708
|
this.rebuildBody();
|
|
96493
96709
|
this.ui?.requestRender();
|
|
96494
96710
|
}
|
|
96711
|
+
dispose() {
|
|
96712
|
+
this.stopStreamingProgressTimer();
|
|
96713
|
+
this.stopSubagentElapsedTimer();
|
|
96714
|
+
}
|
|
96495
96715
|
/**
|
|
96496
96716
|
* 异步注入 plan body / path。仅 ExitPlanMode 工具卡使用:当 LLM 走
|
|
96497
96717
|
* plan-file 模式时 `args.plan` 为空,stream-ops 会从 `client.getPlan()`
|
|
@@ -96523,6 +96743,7 @@ var ToolCallComponent = class extends Container {
|
|
|
96523
96743
|
name: call.name,
|
|
96524
96744
|
args: call.args
|
|
96525
96745
|
});
|
|
96746
|
+
this.upsertSubToolActivity(call.id, call.name, call.args, "ongoing");
|
|
96526
96747
|
continue;
|
|
96527
96748
|
}
|
|
96528
96749
|
this.finishedSubCalls.push({
|
|
@@ -96531,6 +96752,7 @@ var ToolCallComponent = class extends Container {
|
|
|
96531
96752
|
output: call.result.output,
|
|
96532
96753
|
isError: call.result.is_error ?? false
|
|
96533
96754
|
});
|
|
96755
|
+
this.upsertSubToolActivity(call.id, call.name, call.args, call.result.is_error === true ? "failed" : "done");
|
|
96534
96756
|
}
|
|
96535
96757
|
while (this.finishedSubCalls.length > MAX_SUB_TOOL_CALLS_SHOWN) {
|
|
96536
96758
|
this.finishedSubCalls.shift();
|
|
@@ -96541,6 +96763,7 @@ var ToolCallComponent = class extends Container {
|
|
|
96541
96763
|
if (this.subagentAgentId === agentId && this.subagentAgentName === agentName) return;
|
|
96542
96764
|
this.subagentAgentId = agentId;
|
|
96543
96765
|
this.subagentAgentName = agentName;
|
|
96766
|
+
this.headerText.setText(this.buildHeader());
|
|
96544
96767
|
this.rebuildContent();
|
|
96545
96768
|
this.notifySnapshotChange();
|
|
96546
96769
|
this.ui?.requestRender();
|
|
@@ -96557,7 +96780,7 @@ var ToolCallComponent = class extends Container {
|
|
|
96557
96780
|
getSubagentSnapshot() {
|
|
96558
96781
|
const finished = this.finishedSubCalls.length + this.hiddenSubCallCount;
|
|
96559
96782
|
const tokens = this.subagentUsage ? this.subagentUsage.input + this.subagentUsage.output : 0;
|
|
96560
|
-
const latestActivity = computeLatestActivity(this.ongoingSubCalls, this.finishedSubCalls, this.
|
|
96783
|
+
const latestActivity = computeLatestActivity(this.ongoingSubCalls, this.finishedSubCalls, this.getCombinedSubagentText());
|
|
96561
96784
|
const derivedPhase = this.result !== void 0 ? this.result.is_error ? "failed" : "done" : this.subagentPhase;
|
|
96562
96785
|
return {
|
|
96563
96786
|
toolCallId: this.toolCall.id,
|
|
@@ -96607,6 +96830,74 @@ var ToolCallComponent = class extends Container {
|
|
|
96607
96830
|
notifySnapshotChange() {
|
|
96608
96831
|
this.onSnapshotChange?.();
|
|
96609
96832
|
}
|
|
96833
|
+
upsertSubToolActivity(id, name, args, phase) {
|
|
96834
|
+
const existing = this.subToolActivities.get(id);
|
|
96835
|
+
if (existing !== void 0) {
|
|
96836
|
+
existing.name = name;
|
|
96837
|
+
existing.args = args;
|
|
96838
|
+
existing.phase = phase;
|
|
96839
|
+
return;
|
|
96840
|
+
}
|
|
96841
|
+
this.subToolActivities.set(id, {
|
|
96842
|
+
id,
|
|
96843
|
+
name,
|
|
96844
|
+
args,
|
|
96845
|
+
phase,
|
|
96846
|
+
orderSeq: ++this.subToolOrderSeq
|
|
96847
|
+
});
|
|
96848
|
+
}
|
|
96849
|
+
getCombinedSubagentText() {
|
|
96850
|
+
return [this.subagentThinkingText, this.subagentText].filter((s) => s.length > 0).join("\n");
|
|
96851
|
+
}
|
|
96852
|
+
isStreamingEditPreview() {
|
|
96853
|
+
return this.toolCall.name === "Edit" && this.result === void 0 && this.toolCall.streamingArguments !== void 0;
|
|
96854
|
+
}
|
|
96855
|
+
syncStreamingProgressTimer() {
|
|
96856
|
+
if (!this.isStreamingEditPreview()) {
|
|
96857
|
+
this.stopStreamingProgressTimer();
|
|
96858
|
+
return;
|
|
96859
|
+
}
|
|
96860
|
+
if (this.ui === void 0 || this.streamingProgressTimer !== void 0) return;
|
|
96861
|
+
this.streamingProgressTimer = setInterval(() => {
|
|
96862
|
+
if (!this.isStreamingEditPreview()) {
|
|
96863
|
+
this.stopStreamingProgressTimer();
|
|
96864
|
+
return;
|
|
96865
|
+
}
|
|
96866
|
+
this.rebuildBody();
|
|
96867
|
+
this.ui?.requestRender();
|
|
96868
|
+
}, STREAMING_PROGRESS_INTERVAL_MS);
|
|
96869
|
+
}
|
|
96870
|
+
stopStreamingProgressTimer() {
|
|
96871
|
+
if (this.streamingProgressTimer === void 0) return;
|
|
96872
|
+
clearInterval(this.streamingProgressTimer);
|
|
96873
|
+
this.streamingProgressTimer = void 0;
|
|
96874
|
+
}
|
|
96875
|
+
syncSubagentElapsedTimer() {
|
|
96876
|
+
const phase = this.getDerivedSubagentPhase();
|
|
96877
|
+
if (!(this.isSingleSubagentView() && this.subagentStartedAtMs !== void 0 && (phase === "spawning" || phase === "running"))) {
|
|
96878
|
+
this.stopSubagentElapsedTimer();
|
|
96879
|
+
return;
|
|
96880
|
+
}
|
|
96881
|
+
if (this.ui === void 0 || this.subagentElapsedTimer !== void 0) return;
|
|
96882
|
+
this.subagentElapsedTimer = setInterval(() => {
|
|
96883
|
+
const latestPhase = this.getDerivedSubagentPhase();
|
|
96884
|
+
if (latestPhase !== "spawning" && latestPhase !== "running") {
|
|
96885
|
+
this.stopSubagentElapsedTimer();
|
|
96886
|
+
return;
|
|
96887
|
+
}
|
|
96888
|
+
this.headerText.setText(this.buildHeader());
|
|
96889
|
+
this.invalidate();
|
|
96890
|
+
this.ui?.requestRender();
|
|
96891
|
+
}, SUBAGENT_ELAPSED_INTERVAL_MS);
|
|
96892
|
+
}
|
|
96893
|
+
stopSubagentElapsedTimer() {
|
|
96894
|
+
if (this.subagentElapsedTimer === void 0) return;
|
|
96895
|
+
clearInterval(this.subagentElapsedTimer);
|
|
96896
|
+
this.subagentElapsedTimer = void 0;
|
|
96897
|
+
}
|
|
96898
|
+
finalizeSubagentElapsedIfNeeded() {
|
|
96899
|
+
if (this.toolCall.name === "Agent" && this.subagentStartedAtMs !== void 0 && this.subagentEndedAtMs === void 0) this.subagentEndedAtMs = Date.now();
|
|
96900
|
+
}
|
|
96610
96901
|
/**
|
|
96611
96902
|
* 来自 wire 'subagent.spawned'。子 agent 已被注册,但内部活动事件
|
|
96612
96903
|
* (content.delta / tool.call) 可能尚未到达——把 UI 切到 'spawning'
|
|
@@ -96616,6 +96907,10 @@ var ToolCallComponent = class extends Container {
|
|
|
96616
96907
|
this.subagentAgentId = meta.agentId;
|
|
96617
96908
|
this.subagentAgentName = meta.agentName;
|
|
96618
96909
|
this.subagentPhase = meta.runInBackground ? "backgrounded" : "spawning";
|
|
96910
|
+
this.subagentStartedAtMs = Date.now();
|
|
96911
|
+
this.subagentEndedAtMs = void 0;
|
|
96912
|
+
this.syncSubagentElapsedTimer();
|
|
96913
|
+
this.headerText.setText(this.buildHeader());
|
|
96619
96914
|
this.rebuildContent();
|
|
96620
96915
|
this.notifySnapshotChange();
|
|
96621
96916
|
this.ui?.requestRender();
|
|
@@ -96626,8 +96921,12 @@ var ToolCallComponent = class extends Container {
|
|
|
96626
96921
|
*/
|
|
96627
96922
|
onSubagentCompleted(payload) {
|
|
96628
96923
|
this.subagentPhase = "done";
|
|
96924
|
+
this.subagentEndedAtMs ??= Date.now();
|
|
96629
96925
|
this.subagentUsage = payload.usage;
|
|
96630
96926
|
this.subagentResultSummary = payload.resultSummary.length > 0 ? payload.resultSummary : void 0;
|
|
96927
|
+
if (this.subagentText.trim().length === 0 && this.subagentResultSummary !== void 0) this.subagentText = this.subagentResultSummary;
|
|
96928
|
+
this.syncSubagentElapsedTimer();
|
|
96929
|
+
this.headerText.setText(this.buildHeader());
|
|
96631
96930
|
this.rebuildContent();
|
|
96632
96931
|
this.notifySnapshotChange();
|
|
96633
96932
|
this.ui?.requestRender();
|
|
@@ -96637,14 +96936,19 @@ var ToolCallComponent = class extends Container {
|
|
|
96637
96936
|
*/
|
|
96638
96937
|
onSubagentFailed(payload) {
|
|
96639
96938
|
this.subagentPhase = "failed";
|
|
96939
|
+
this.subagentEndedAtMs ??= Date.now();
|
|
96640
96940
|
this.subagentError = payload.error;
|
|
96941
|
+
this.syncSubagentElapsedTimer();
|
|
96942
|
+
this.headerText.setText(this.buildHeader());
|
|
96641
96943
|
this.rebuildContent();
|
|
96642
96944
|
this.notifySnapshotChange();
|
|
96643
96945
|
this.ui?.requestRender();
|
|
96644
96946
|
}
|
|
96645
|
-
appendSubagentText(text) {
|
|
96646
|
-
this.
|
|
96947
|
+
appendSubagentText(text, kind = "text") {
|
|
96948
|
+
if (kind === "thinking") this.subagentThinkingText += text;
|
|
96949
|
+
else this.subagentText += text;
|
|
96647
96950
|
if (this.subagentPhase === void 0 || this.subagentPhase === "spawning") this.subagentPhase = "running";
|
|
96951
|
+
this.headerText.setText(this.buildHeader());
|
|
96648
96952
|
this.rebuildContent();
|
|
96649
96953
|
this.notifySnapshotChange();
|
|
96650
96954
|
this.ui?.requestRender();
|
|
@@ -96656,7 +96960,9 @@ var ToolCallComponent = class extends Container {
|
|
|
96656
96960
|
args: call.args,
|
|
96657
96961
|
...existing?.streamingArguments !== void 0 ? { streamingArguments: existing.streamingArguments } : {}
|
|
96658
96962
|
});
|
|
96963
|
+
this.upsertSubToolActivity(call.id, call.name, call.args, "ongoing");
|
|
96659
96964
|
if (this.subagentPhase === void 0 || this.subagentPhase === "spawning") this.subagentPhase = "running";
|
|
96965
|
+
this.headerText.setText(this.buildHeader());
|
|
96660
96966
|
this.rebuildContent();
|
|
96661
96967
|
this.notifySnapshotChange();
|
|
96662
96968
|
this.ui?.requestRender();
|
|
@@ -96670,6 +96976,8 @@ var ToolCallComponent = class extends Container {
|
|
|
96670
96976
|
args: parsed,
|
|
96671
96977
|
streamingArguments: nextArgsText
|
|
96672
96978
|
});
|
|
96979
|
+
this.upsertSubToolActivity(delta.id, delta.name ?? existing?.name ?? "Tool", parsed, "ongoing");
|
|
96980
|
+
this.headerText.setText(this.buildHeader());
|
|
96673
96981
|
this.rebuildContent();
|
|
96674
96982
|
this.notifySnapshotChange();
|
|
96675
96983
|
this.ui?.requestRender();
|
|
@@ -96684,10 +96992,12 @@ var ToolCallComponent = class extends Container {
|
|
|
96684
96992
|
output: result.output,
|
|
96685
96993
|
isError: result.is_error ?? false
|
|
96686
96994
|
});
|
|
96995
|
+
this.upsertSubToolActivity(result.tool_call_id, ongoing.name, ongoing.args, result.is_error === true ? "failed" : "done");
|
|
96687
96996
|
while (this.finishedSubCalls.length > MAX_SUB_TOOL_CALLS_SHOWN) {
|
|
96688
96997
|
this.finishedSubCalls.shift();
|
|
96689
96998
|
this.hiddenSubCallCount += 1;
|
|
96690
96999
|
}
|
|
97000
|
+
this.headerText.setText(this.buildHeader());
|
|
96691
97001
|
this.rebuildContent();
|
|
96692
97002
|
this.notifySnapshotChange();
|
|
96693
97003
|
this.ui?.requestRender();
|
|
@@ -96714,6 +97024,7 @@ var ToolCallComponent = class extends Container {
|
|
|
96714
97024
|
const tone = isError ? chalk.hex(colors.error) : chalk.hex(colors.primary);
|
|
96715
97025
|
return `${bullet}${tone.bold(label)}`;
|
|
96716
97026
|
}
|
|
97027
|
+
if (this.isSingleSubagentView()) return this.buildSingleSubagentHeader();
|
|
96717
97028
|
const verb = isFinished ? "Used" : toolCall.streamingArguments !== void 0 ? "Preparing" : "Using";
|
|
96718
97029
|
const keyArg = extractKeyArgument(toolCall.name, toolCall.args);
|
|
96719
97030
|
const toolRef = chalk.hex(colors.primary).bold(toolCall.name);
|
|
@@ -96743,6 +97054,10 @@ var ToolCallComponent = class extends Container {
|
|
|
96743
97054
|
}
|
|
96744
97055
|
buildSubagentBlock() {
|
|
96745
97056
|
if (this.subagentAgentId === void 0 && this.ongoingSubCalls.size === 0 && this.finishedSubCalls.length === 0 && this.subagentText.length === 0 && this.subagentPhase === void 0) return;
|
|
97057
|
+
if (this.isSingleSubagentView()) {
|
|
97058
|
+
this.buildSingleSubagentBlock();
|
|
97059
|
+
return;
|
|
97060
|
+
}
|
|
96746
97061
|
const dim = chalk.dim;
|
|
96747
97062
|
const phaseChip = this.formatPhaseChip();
|
|
96748
97063
|
const headerLabel = this.subagentAgentName !== void 0 ? `subagent ${this.subagentAgentName} (${this.formatAgentId()})` : `subagent (${this.formatAgentId()})`;
|
|
@@ -96817,6 +97132,78 @@ var ToolCallComponent = class extends Container {
|
|
|
96817
97132
|
const id = this.subagentAgentId ?? "";
|
|
96818
97133
|
return id.length > 10 ? id.slice(0, 10) + "…" : id;
|
|
96819
97134
|
}
|
|
97135
|
+
hasSubagentState() {
|
|
97136
|
+
return this.subagentAgentId !== void 0 || this.ongoingSubCalls.size > 0 || this.finishedSubCalls.length > 0 || this.subToolActivities.size > 0 || this.subagentText.length > 0 || this.subagentThinkingText.length > 0 || this.subagentPhase !== void 0;
|
|
97137
|
+
}
|
|
97138
|
+
isSingleSubagentView() {
|
|
97139
|
+
return this.toolCall.name === "Agent" && this.hasSubagentState();
|
|
97140
|
+
}
|
|
97141
|
+
getDerivedSubagentPhase() {
|
|
97142
|
+
if (this.result !== void 0) return this.result.is_error ? "failed" : "done";
|
|
97143
|
+
return this.subagentPhase;
|
|
97144
|
+
}
|
|
97145
|
+
buildSingleSubagentHeader() {
|
|
97146
|
+
const phase = this.getDerivedSubagentPhase();
|
|
97147
|
+
const isFailed = phase === "failed";
|
|
97148
|
+
const isDone = phase === "done";
|
|
97149
|
+
const bullet = isFailed ? chalk.hex(this.colors.error)("✗ ") : isDone ? chalk.hex(this.colors.success)(STATUS_BULLET) : chalk.hex(this.colors.roleAssistant)(STATUS_BULLET);
|
|
97150
|
+
const labelText = formatSubagentLabel(this.subagentAgentName);
|
|
97151
|
+
const label = chalk.hex(this.colors.primary).bold(labelText);
|
|
97152
|
+
const status = this.formatSingleSubagentStatus(phase);
|
|
97153
|
+
const description = str(this.toolCall.args["description"]);
|
|
97154
|
+
const descriptionPlain = description.length > 0 ? ` (${description})` : "";
|
|
97155
|
+
const descriptionText = descriptionPlain.length > 0 ? chalk.dim(descriptionPlain) : "";
|
|
97156
|
+
const statsText = this.formatSingleSubagentStatsText();
|
|
97157
|
+
if (isDone) {
|
|
97158
|
+
const success = chalk.hex(this.colors.success);
|
|
97159
|
+
return `${bullet}${success.bold(labelText)} ${success(`Completed${descriptionPlain}${statsText}`)}`;
|
|
97160
|
+
}
|
|
97161
|
+
return `${bullet}${label} ${status}${descriptionText}${chalk.dim(statsText)}`;
|
|
97162
|
+
}
|
|
97163
|
+
formatSingleSubagentStatus(phase) {
|
|
97164
|
+
switch (phase) {
|
|
97165
|
+
case "done": return chalk.hex(this.colors.success)("Completed");
|
|
97166
|
+
case "failed": return chalk.hex(this.colors.error)("Failed");
|
|
97167
|
+
case "running": return chalk.hex(this.colors.primary)("Running");
|
|
97168
|
+
case "backgrounded": return "Backgrounded";
|
|
97169
|
+
case "spawning":
|
|
97170
|
+
case void 0: return chalk.hex(this.colors.primary)("Starting");
|
|
97171
|
+
}
|
|
97172
|
+
}
|
|
97173
|
+
formatSingleSubagentStatsText() {
|
|
97174
|
+
const parts = [`${String(this.subToolActivities.size)} tool${this.subToolActivities.size === 1 ? "" : "s"}`];
|
|
97175
|
+
const elapsed = this.getSubagentElapsedSeconds();
|
|
97176
|
+
if (elapsed !== void 0) parts.push(formatElapsed(elapsed));
|
|
97177
|
+
return ` · ${parts.join(" · ")}`;
|
|
97178
|
+
}
|
|
97179
|
+
getSubagentElapsedSeconds() {
|
|
97180
|
+
if (this.subagentStartedAtMs === void 0) return void 0;
|
|
97181
|
+
const end = this.subagentEndedAtMs ?? Date.now();
|
|
97182
|
+
return Math.max(0, Math.floor((end - this.subagentStartedAtMs) / 1e3));
|
|
97183
|
+
}
|
|
97184
|
+
buildSingleSubagentBlock() {
|
|
97185
|
+
for (const activity of this.getRecentSubToolActivities()) {
|
|
97186
|
+
const mark = activity.phase === "failed" ? chalk.hex(this.colors.error)("✗") : activity.phase === "done" ? chalk.hex(this.colors.success)("•") : chalk.hex(this.colors.text)("•");
|
|
97187
|
+
const verb = activity.phase === "ongoing" ? "Using" : "Used";
|
|
97188
|
+
this.addChild(new Text(` ${mark} ${this.formatSubToolActivity(verb, activity)}`, 0, 0));
|
|
97189
|
+
}
|
|
97190
|
+
if (this.getDerivedSubagentPhase() === "failed" && this.subagentError !== void 0) {
|
|
97191
|
+
const errorLine = tailNonEmptyLines(this.subagentError, 1).at(-1);
|
|
97192
|
+
if (errorLine !== void 0) this.addChild(new PrefixedWrappedLine(` ${chalk.hex(this.colors.error)("└")} `, " ", chalk.hex(this.colors.error)(errorLine)));
|
|
97193
|
+
return;
|
|
97194
|
+
}
|
|
97195
|
+
const outputLine = tailNonEmptyLines(this.subagentText, 1).at(-1);
|
|
97196
|
+
const thinkingLine = tailNonEmptyLines(this.subagentThinkingText, 1).at(-1);
|
|
97197
|
+
if (this.getDerivedSubagentPhase() !== "done" && thinkingLine !== void 0) this.addChild(new PrefixedWrappedLine(` ${chalk.dim("◌")} `, " ", chalk.dim(thinkingLine)));
|
|
97198
|
+
if (outputLine !== void 0) this.addChild(new PrefixedWrappedLine(` ${chalk.hex(this.colors.text)("└")} `, " ", chalk.hex(this.colors.text)(outputLine)));
|
|
97199
|
+
}
|
|
97200
|
+
getRecentSubToolActivities() {
|
|
97201
|
+
return [...this.subToolActivities.values()].toSorted((a, b) => a.orderSeq - b.orderSeq).slice(-MAX_SINGLE_SUBAGENT_TOOL_ROWS);
|
|
97202
|
+
}
|
|
97203
|
+
formatSubToolActivity(verb, activity) {
|
|
97204
|
+
const keyArg = extractKeyArgument(activity.name, activity.args);
|
|
97205
|
+
return `${verb} ${chalk.hex(this.colors.primary)(activity.name)}${keyArg ? chalk.dim(` (${keyArg})`) : ""}`;
|
|
97206
|
+
}
|
|
96820
97207
|
buildCallPreview() {
|
|
96821
97208
|
const name = this.toolCall.name;
|
|
96822
97209
|
if (name === "ExitPlanMode") {
|
|
@@ -96854,11 +97241,12 @@ var ToolCallComponent = class extends Container {
|
|
|
96854
97241
|
* Live-rendering during the `tool.call.delta` streaming window.
|
|
96855
97242
|
*
|
|
96856
97243
|
* For tools we recognise, we reach into the partial JSON (via
|
|
96857
|
-
* `extractPartialStringField`) and render
|
|
96858
|
-
*
|
|
96859
|
-
* Bash's `$ command`, etc. While args are still
|
|
96860
|
-
* the body in full (no 10-line cap) — once the
|
|
96861
|
-
* preview snaps to the collapsed cap unless the user
|
|
97244
|
+
* `extractPartialStringField`) and render a stable high-signal
|
|
97245
|
+
* preview: Write's `content` as highlighted code, Edit's argument
|
|
97246
|
+
* receive progress, Bash's `$ command`, etc. While args are still
|
|
97247
|
+
* streaming we render the body in full (no 10-line cap) — once the
|
|
97248
|
+
* result lands, the preview snaps to the collapsed cap unless the user
|
|
97249
|
+
* has expanded.
|
|
96862
97250
|
*/
|
|
96863
97251
|
buildStreamingPreview(streamText) {
|
|
96864
97252
|
const name = this.toolCall.name;
|
|
@@ -96873,14 +97261,12 @@ var ToolCallComponent = class extends Container {
|
|
|
96873
97261
|
return;
|
|
96874
97262
|
}
|
|
96875
97263
|
if (name === "Edit") {
|
|
96876
|
-
const
|
|
96877
|
-
const
|
|
96878
|
-
|
|
96879
|
-
const
|
|
96880
|
-
|
|
96881
|
-
|
|
96882
|
-
});
|
|
96883
|
-
for (const line of lines) this.addChild(new Text(line, 2, 0));
|
|
97264
|
+
const filePath = extractPartialStringField(streamText, "file_path") ?? extractPartialStringField(streamText, "path") ?? "";
|
|
97265
|
+
const bytes = Buffer.byteLength(streamText, "utf8");
|
|
97266
|
+
const startedAtMs = this.toolCall.streamingStartedAtMs;
|
|
97267
|
+
const elapsedSeconds = startedAtMs === void 0 ? 0 : Math.max(0, Math.floor((Date.now() - startedAtMs) / 1e3));
|
|
97268
|
+
const progress = `Preparing changes${filePath.length > 0 ? ` for ${filePath}` : ""}... ${formatByteSize(bytes)} · ${formatElapsed(elapsedSeconds)} elapsed`;
|
|
97269
|
+
this.addChild(new Text(chalk.dim(progress), 2, 0));
|
|
96884
97270
|
return;
|
|
96885
97271
|
}
|
|
96886
97272
|
if (name === "Bash") {
|
|
@@ -96919,6 +97305,7 @@ var ToolCallComponent = class extends Container {
|
|
|
96919
97305
|
buildContent() {
|
|
96920
97306
|
const { result } = this;
|
|
96921
97307
|
if (result === void 0 || !result.output) return;
|
|
97308
|
+
if (this.isSingleSubagentView()) return;
|
|
96922
97309
|
if (this.toolCall.name === "ExitPlanMode" && !result.is_error) {
|
|
96923
97310
|
const outcome = interpretExitPlanModeOutcome(result.output);
|
|
96924
97311
|
if (outcome.kind === "rejected" && outcome.feedback !== void 0) {
|
|
@@ -97350,6 +97737,12 @@ function disposeActiveThinkingComponent(state) {
|
|
|
97350
97737
|
state.activeThinkingComponent = void 0;
|
|
97351
97738
|
}
|
|
97352
97739
|
}
|
|
97740
|
+
function hasDispose(value) {
|
|
97741
|
+
return typeof value === "object" && value !== null && "dispose" in value && typeof value.dispose === "function";
|
|
97742
|
+
}
|
|
97743
|
+
function disposePendingToolComponents(state) {
|
|
97744
|
+
for (const component of state.pendingToolComponents.values()) if (hasDispose(component)) component.dispose();
|
|
97745
|
+
}
|
|
97353
97746
|
/**
|
|
97354
97747
|
* Hard reset of the transcript UI: drop every entry, tool component,
|
|
97355
97748
|
* compaction block, streaming draft, todo panel, and attachment, then
|
|
@@ -97359,6 +97752,7 @@ function clearTranscriptAndRedraw(state) {
|
|
|
97359
97752
|
state.transcriptEntries = [];
|
|
97360
97753
|
disposeActiveCompactionBlock(state);
|
|
97361
97754
|
disposeActiveThinkingComponent(state);
|
|
97755
|
+
disposePendingToolComponents(state);
|
|
97362
97756
|
state.transcriptContainer.clear();
|
|
97363
97757
|
state.pendingToolComponents.clear();
|
|
97364
97758
|
state.streamingComponent = void 0;
|
|
@@ -97401,6 +97795,31 @@ function emitSuccess(state, message) {
|
|
|
97401
97795
|
function emitMuted(state, message) {
|
|
97402
97796
|
emitStatus(state, message, state.colors.textDim);
|
|
97403
97797
|
}
|
|
97798
|
+
/** Append the OAuth device-code panel directly to the transcript container. */
|
|
97799
|
+
function emitDeviceCodeBox(state, options) {
|
|
97800
|
+
state.transcriptContainer.addChild(new DeviceCodeBoxComponent({
|
|
97801
|
+
...options,
|
|
97802
|
+
colors: state.colors
|
|
97803
|
+
}));
|
|
97804
|
+
state.ui.requestRender();
|
|
97805
|
+
}
|
|
97806
|
+
/**
|
|
97807
|
+
* Append a braille spinner line that callers can finalize with a ✓/✗
|
|
97808
|
+
* static line once the awaited operation completes.
|
|
97809
|
+
*/
|
|
97810
|
+
function emitLiveSpinner(state, label) {
|
|
97811
|
+
const tint = (s) => chalk.hex(state.colors.primary)(s);
|
|
97812
|
+
const spinner = new MoonLoader(state.ui, "braille", tint, label);
|
|
97813
|
+
state.transcriptContainer.addChild(spinner);
|
|
97814
|
+
state.ui.requestRender();
|
|
97815
|
+
return { stop({ ok, label: finalLabel }) {
|
|
97816
|
+
spinner.stop();
|
|
97817
|
+
const tone = ok ? state.colors.success : state.colors.error;
|
|
97818
|
+
const symbol = ok ? "✓" : "✗";
|
|
97819
|
+
spinner.setText(chalk.hex(tone)(`${symbol} ${finalLabel}`));
|
|
97820
|
+
state.ui.requestRender();
|
|
97821
|
+
} };
|
|
97822
|
+
}
|
|
97404
97823
|
//#endregion
|
|
97405
97824
|
//#region src/utils/persistence.ts
|
|
97406
97825
|
/**
|
|
@@ -97553,8 +97972,9 @@ function handleSubagentSourceEvent(ectx, payload) {
|
|
|
97553
97972
|
tc.setSubagentMeta(payload.source_id, payload.source_name);
|
|
97554
97973
|
if (payload.method === "content.delta") {
|
|
97555
97974
|
const d = payload.data;
|
|
97556
|
-
const
|
|
97557
|
-
|
|
97975
|
+
const textKind = d.type === "text" && typeof d.text === "string" ? "text" : d.type === "thinking" && typeof d.thinking === "string" ? "thinking" : typeof d.think === "string" || typeof d.thinking === "string" ? "thinking" : void 0;
|
|
97976
|
+
const text = textKind === "text" ? d.text : textKind === "thinking" ? d.think ?? d.thinking : void 0;
|
|
97977
|
+
if (text !== void 0 && textKind !== void 0 && typeof tc.appendSubagentText === "function") tc.appendSubagentText(text, textKind);
|
|
97558
97978
|
return;
|
|
97559
97979
|
}
|
|
97560
97980
|
if (payload.method === "tool.call") {
|
|
@@ -97937,28 +98357,49 @@ function createAuthCommands(deps = {}) {
|
|
|
97937
98357
|
priority: 40,
|
|
97938
98358
|
async execute(_args, ctx) {
|
|
97939
98359
|
if (deps.client === void 0) return ok$2("OAuth is unavailable: no wire client is attached.");
|
|
98360
|
+
if ((await deps.client.authStatus(providerName)).providers.some((provider) => provider.provider_name === providerName && provider.has_token)) return ok$2("Already logged in. Run /logout first to switch accounts.");
|
|
98361
|
+
let spinner;
|
|
98362
|
+
const controller = new AbortController();
|
|
97940
98363
|
const disposeDeviceCodeHandler = deps.client.onRequest("auth.device_code", (req) => {
|
|
97941
98364
|
const data = req.data;
|
|
97942
98365
|
const url = data.verification_uri_complete ?? "";
|
|
97943
98366
|
if (url.length > 0) openUrl(url);
|
|
97944
|
-
ctx.
|
|
98367
|
+
ctx.showDeviceCodeBox({
|
|
98368
|
+
title: "Sign in to Kimi Code",
|
|
98369
|
+
url,
|
|
98370
|
+
code: data.user_code ?? "",
|
|
98371
|
+
hint: "Press Ctrl-C to cancel"
|
|
98372
|
+
});
|
|
98373
|
+
spinner = ctx.showLiveSpinner("Waiting for authorization…");
|
|
97945
98374
|
return { ok: true };
|
|
97946
98375
|
});
|
|
98376
|
+
const disposeCancel = ctx.registerCancellable(() => {
|
|
98377
|
+
controller.abort();
|
|
98378
|
+
});
|
|
97947
98379
|
try {
|
|
97948
|
-
await deps.client.authLogin(providerName);
|
|
98380
|
+
await deps.client.authLogin(providerName, { signal: controller.signal });
|
|
98381
|
+
spinner?.stop({
|
|
98382
|
+
ok: true,
|
|
98383
|
+
label: "Logged in."
|
|
98384
|
+
});
|
|
98385
|
+
spinner = void 0;
|
|
97949
98386
|
try {
|
|
97950
98387
|
await refreshConfigAfterLogin(deps.client, ctx);
|
|
97951
98388
|
} catch (refreshError) {
|
|
97952
98389
|
return ok$2(`Login successful, but failed to refresh config: ${refreshError instanceof Error ? refreshError.message : String(refreshError)}`);
|
|
97953
98390
|
}
|
|
97954
|
-
return {
|
|
97955
|
-
type: "ok",
|
|
97956
|
-
message: "✓ Login successful!",
|
|
97957
|
-
color: "green"
|
|
97958
|
-
};
|
|
98391
|
+
return { type: "ok" };
|
|
97959
98392
|
} catch (error) {
|
|
98393
|
+
const cancelled = controller.signal.aborted;
|
|
98394
|
+
spinner?.stop({
|
|
98395
|
+
ok: false,
|
|
98396
|
+
label: cancelled ? "Login cancelled." : "Login failed."
|
|
98397
|
+
});
|
|
98398
|
+
spinner = void 0;
|
|
98399
|
+
if (cancelled) return { type: "ok" };
|
|
97960
98400
|
return ok$2(`Login failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
97961
98401
|
} finally {
|
|
98402
|
+
disposeCancel();
|
|
97962
98403
|
disposeDeviceCodeHandler();
|
|
97963
98404
|
}
|
|
97964
98405
|
}
|
|
@@ -98279,7 +98720,9 @@ function createDefaultRegistry(authDeps) {
|
|
|
98279
98720
|
*/
|
|
98280
98721
|
const BRANCH_TTL_MS = 5e3;
|
|
98281
98722
|
const STATUS_TTL_MS = 15e3;
|
|
98723
|
+
const PULL_REQUEST_TTL_MS = 6e4;
|
|
98282
98724
|
const SPAWN_TIMEOUT_MS = 500;
|
|
98725
|
+
const PR_SPAWN_TIMEOUT_MS = 1e3;
|
|
98283
98726
|
const AHEAD_BEHIND_RE = /\[(?:ahead (\d+))?(?:, )?(?:behind (\d+))?\]/;
|
|
98284
98727
|
function createGitStatusCache(workDir) {
|
|
98285
98728
|
const isRepo = detectGitRepo(workDir);
|
|
@@ -98291,6 +98734,13 @@ function createGitStatusCache(workDir) {
|
|
|
98291
98734
|
dirty: false,
|
|
98292
98735
|
ahead: 0,
|
|
98293
98736
|
behind: 0,
|
|
98737
|
+
diffAdded: 0,
|
|
98738
|
+
diffDeleted: 0,
|
|
98739
|
+
fetchedAt: 0
|
|
98740
|
+
};
|
|
98741
|
+
let pullRequest = {
|
|
98742
|
+
value: null,
|
|
98743
|
+
branch: null,
|
|
98294
98744
|
fetchedAt: 0
|
|
98295
98745
|
};
|
|
98296
98746
|
return { getStatus: () => {
|
|
@@ -98305,11 +98755,19 @@ function createGitStatusCache(workDir) {
|
|
|
98305
98755
|
...readStatus(workDir),
|
|
98306
98756
|
fetchedAt: now
|
|
98307
98757
|
};
|
|
98758
|
+
if (pullRequest.branch !== branch.value || now - pullRequest.fetchedAt >= PULL_REQUEST_TTL_MS) pullRequest = {
|
|
98759
|
+
value: readPullRequest(workDir),
|
|
98760
|
+
branch: branch.value,
|
|
98761
|
+
fetchedAt: now
|
|
98762
|
+
};
|
|
98308
98763
|
return {
|
|
98309
98764
|
branch: branch.value,
|
|
98310
98765
|
dirty: status.dirty,
|
|
98311
98766
|
ahead: status.ahead,
|
|
98312
|
-
behind: status.behind
|
|
98767
|
+
behind: status.behind,
|
|
98768
|
+
diffAdded: status.diffAdded,
|
|
98769
|
+
diffDeleted: status.diffDeleted,
|
|
98770
|
+
pullRequest: pullRequest.value
|
|
98313
98771
|
};
|
|
98314
98772
|
} };
|
|
98315
98773
|
}
|
|
@@ -98363,7 +98821,9 @@ function readStatus(workDir) {
|
|
|
98363
98821
|
if (result.status !== 0) return {
|
|
98364
98822
|
dirty: false,
|
|
98365
98823
|
ahead: 0,
|
|
98366
|
-
behind: 0
|
|
98824
|
+
behind: 0,
|
|
98825
|
+
diffAdded: 0,
|
|
98826
|
+
diffDeleted: 0
|
|
98367
98827
|
};
|
|
98368
98828
|
let dirty = false;
|
|
98369
98829
|
let ahead = 0;
|
|
@@ -98375,28 +98835,149 @@ function readStatus(workDir) {
|
|
|
98375
98835
|
behind = Number.parseInt(m[2] ?? "0", 10) || 0;
|
|
98376
98836
|
}
|
|
98377
98837
|
} else if (line.trim().length > 0) dirty = true;
|
|
98838
|
+
const diff = dirty ? readDiffStats(workDir) : {
|
|
98839
|
+
added: 0,
|
|
98840
|
+
deleted: 0
|
|
98841
|
+
};
|
|
98378
98842
|
return {
|
|
98379
98843
|
dirty,
|
|
98380
98844
|
ahead,
|
|
98381
|
-
behind
|
|
98845
|
+
behind,
|
|
98846
|
+
diffAdded: diff.added,
|
|
98847
|
+
diffDeleted: diff.deleted
|
|
98382
98848
|
};
|
|
98383
98849
|
} catch {
|
|
98384
98850
|
return {
|
|
98385
98851
|
dirty: false,
|
|
98386
98852
|
ahead: 0,
|
|
98387
|
-
behind: 0
|
|
98853
|
+
behind: 0,
|
|
98854
|
+
diffAdded: 0,
|
|
98855
|
+
diffDeleted: 0
|
|
98856
|
+
};
|
|
98857
|
+
}
|
|
98858
|
+
}
|
|
98859
|
+
function readDiffStats(workDir) {
|
|
98860
|
+
try {
|
|
98861
|
+
const result = spawnSync("git", [
|
|
98862
|
+
"-C",
|
|
98863
|
+
workDir,
|
|
98864
|
+
"diff",
|
|
98865
|
+
"--numstat",
|
|
98866
|
+
"HEAD",
|
|
98867
|
+
"--"
|
|
98868
|
+
], {
|
|
98869
|
+
encoding: "utf8",
|
|
98870
|
+
timeout: SPAWN_TIMEOUT_MS,
|
|
98871
|
+
maxBuffer: 4 * 1024 * 1024
|
|
98872
|
+
});
|
|
98873
|
+
if (result.status !== 0) return {
|
|
98874
|
+
added: 0,
|
|
98875
|
+
deleted: 0
|
|
98876
|
+
};
|
|
98877
|
+
let added = 0;
|
|
98878
|
+
let deleted = 0;
|
|
98879
|
+
for (const line of result.stdout.split("\n")) {
|
|
98880
|
+
if (!line) continue;
|
|
98881
|
+
const [addedText, deletedText] = line.split(" ");
|
|
98882
|
+
added += parseDiffNumstatCount(addedText);
|
|
98883
|
+
deleted += parseDiffNumstatCount(deletedText);
|
|
98884
|
+
}
|
|
98885
|
+
return {
|
|
98886
|
+
added,
|
|
98887
|
+
deleted
|
|
98888
|
+
};
|
|
98889
|
+
} catch {
|
|
98890
|
+
return {
|
|
98891
|
+
added: 0,
|
|
98892
|
+
deleted: 0
|
|
98388
98893
|
};
|
|
98389
98894
|
}
|
|
98390
98895
|
}
|
|
98391
|
-
function
|
|
98896
|
+
function parseDiffNumstatCount(value) {
|
|
98897
|
+
if (value === void 0 || value === "-") return 0;
|
|
98898
|
+
const n = Number.parseInt(value, 10);
|
|
98899
|
+
return Number.isFinite(n) && n > 0 ? n : 0;
|
|
98900
|
+
}
|
|
98901
|
+
function readPullRequest(workDir) {
|
|
98902
|
+
try {
|
|
98903
|
+
const result = spawnSync("gh", [
|
|
98904
|
+
"pr",
|
|
98905
|
+
"view",
|
|
98906
|
+
"--json",
|
|
98907
|
+
"number,url"
|
|
98908
|
+
], {
|
|
98909
|
+
cwd: workDir,
|
|
98910
|
+
encoding: "utf8",
|
|
98911
|
+
env: {
|
|
98912
|
+
...process.env,
|
|
98913
|
+
GH_NO_UPDATE_NOTIFIER: "1",
|
|
98914
|
+
GH_PROMPT_DISABLED: "1"
|
|
98915
|
+
},
|
|
98916
|
+
timeout: PR_SPAWN_TIMEOUT_MS,
|
|
98917
|
+
maxBuffer: 256 * 1024
|
|
98918
|
+
});
|
|
98919
|
+
if (result.status !== 0) return null;
|
|
98920
|
+
return parsePullRequest(result.stdout);
|
|
98921
|
+
} catch {
|
|
98922
|
+
return null;
|
|
98923
|
+
}
|
|
98924
|
+
}
|
|
98925
|
+
function parsePullRequest(stdout) {
|
|
98926
|
+
try {
|
|
98927
|
+
const raw = JSON.parse(stdout);
|
|
98928
|
+
if (typeof raw !== "object" || raw === null) return null;
|
|
98929
|
+
const record = raw;
|
|
98930
|
+
const number = record["number"];
|
|
98931
|
+
const url = record["url"];
|
|
98932
|
+
if (typeof number !== "number" || !Number.isInteger(number) || number <= 0) return null;
|
|
98933
|
+
if (typeof url !== "string" || !isSafeHttpUrl(url)) return null;
|
|
98934
|
+
return {
|
|
98935
|
+
number,
|
|
98936
|
+
url
|
|
98937
|
+
};
|
|
98938
|
+
} catch {
|
|
98939
|
+
return null;
|
|
98940
|
+
}
|
|
98941
|
+
}
|
|
98942
|
+
function isSafeHttpUrl(value) {
|
|
98943
|
+
if (hasControlChars(value)) return false;
|
|
98944
|
+
try {
|
|
98945
|
+
const url = new URL(value);
|
|
98946
|
+
return url.protocol === "https:" || url.protocol === "http:";
|
|
98947
|
+
} catch {
|
|
98948
|
+
return false;
|
|
98949
|
+
}
|
|
98950
|
+
}
|
|
98951
|
+
function hasControlChars(value) {
|
|
98952
|
+
for (const char of value) {
|
|
98953
|
+
const code = char.codePointAt(0) ?? 0;
|
|
98954
|
+
if (code <= 31 || code === 127) return true;
|
|
98955
|
+
}
|
|
98956
|
+
return false;
|
|
98957
|
+
}
|
|
98958
|
+
function formatGitBadge(status, options = {}) {
|
|
98392
98959
|
const parts = [];
|
|
98393
|
-
|
|
98960
|
+
const diff = formatDiffStats(status);
|
|
98961
|
+
if (diff) parts.push(diff);
|
|
98394
98962
|
let sync = "";
|
|
98395
98963
|
if (status.ahead > 0) sync += `↑${status.ahead}`;
|
|
98396
98964
|
if (status.behind > 0) sync += `↓${status.behind}`;
|
|
98397
98965
|
if (sync) parts.push(sync);
|
|
98398
|
-
|
|
98399
|
-
|
|
98966
|
+
const base = parts.length === 0 ? status.branch : `${status.branch} [${parts.join(" ")}]`;
|
|
98967
|
+
if (status.pullRequest === null) return base;
|
|
98968
|
+
const prText = `[PR#${String(status.pullRequest.number)}]`;
|
|
98969
|
+
return `${base} ${options.linkPullRequest ? toTerminalHyperlink(prText, status.pullRequest.url) : prText}`;
|
|
98970
|
+
}
|
|
98971
|
+
function formatDiffStats(status) {
|
|
98972
|
+
const parts = [];
|
|
98973
|
+
if (status.diffAdded > 0) parts.push(`+${String(status.diffAdded)}`);
|
|
98974
|
+
if (status.diffDeleted > 0) parts.push(`-${String(status.diffDeleted)}`);
|
|
98975
|
+
if (parts.length > 0) return parts.join(" ");
|
|
98976
|
+
return status.dirty ? "±" : null;
|
|
98977
|
+
}
|
|
98978
|
+
function toTerminalHyperlink(text, url) {
|
|
98979
|
+
if (!isSafeHttpUrl(url)) return text;
|
|
98980
|
+
return `\u001B]8;;${url}\u0007${text}\u001B]8;;\u0007`;
|
|
98400
98981
|
}
|
|
98401
98982
|
//#endregion
|
|
98402
98983
|
//#region src/tui/components/chrome/footer.ts
|
|
@@ -98549,7 +99130,7 @@ var FooterComponent = class {
|
|
|
98549
99130
|
const cwd = shortenCwd(state.workDir);
|
|
98550
99131
|
if (cwd) left.push(chalk.hex(colors.status)(cwd));
|
|
98551
99132
|
const git = this.gitCache.getStatus();
|
|
98552
|
-
if (git !== null) left.push(chalk.hex(colors.status)(formatGitBadge(git)));
|
|
99133
|
+
if (git !== null) left.push(chalk.hex(colors.status)(formatGitBadge(git, { linkPullRequest: true })));
|
|
98553
99134
|
const leftLine = left.join(" ");
|
|
98554
99135
|
const leftWidth = visibleWidth(leftLine);
|
|
98555
99136
|
const tipIndex = currentTipIndex();
|
|
@@ -99347,6 +99928,7 @@ function createTUIState(options) {
|
|
|
99347
99928
|
streamingToolCallArguments: /* @__PURE__ */ new Map(),
|
|
99348
99929
|
toastTimers: /* @__PURE__ */ new Map(),
|
|
99349
99930
|
pendingExit: null,
|
|
99931
|
+
cancelInFlight: void 0,
|
|
99350
99932
|
queuedMessages: [],
|
|
99351
99933
|
queueIdCounter: 0,
|
|
99352
99934
|
aborted: false,
|
|
@@ -99522,6 +100104,7 @@ function sendMessageInternal(state, addEntry, input, options) {
|
|
|
99522
100104
|
state.streamingTranscriptEntry = void 0;
|
|
99523
100105
|
state.thinkingDraft = "";
|
|
99524
100106
|
disposeActiveThinkingComponent(state);
|
|
100107
|
+
disposePendingToolComponents(state);
|
|
99525
100108
|
state.activeToolCalls.clear();
|
|
99526
100109
|
state.streamingToolCallArguments.clear();
|
|
99527
100110
|
state.livePane = {
|
|
@@ -99585,6 +100168,7 @@ function sendSkillActivation(state, addEntry, skillName, skillArgs, fullPrompt)
|
|
|
99585
100168
|
state.streamingTranscriptEntry = void 0;
|
|
99586
100169
|
state.thinkingDraft = "";
|
|
99587
100170
|
disposeActiveThinkingComponent(state);
|
|
100171
|
+
disposePendingToolComponents(state);
|
|
99588
100172
|
state.activeToolCalls.clear();
|
|
99589
100173
|
state.streamingToolCallArguments.clear();
|
|
99590
100174
|
state.livePane = {
|
|
@@ -100478,6 +101062,7 @@ function releaseSessionSideEffects(state) {
|
|
|
100478
101062
|
state.streamingTranscriptEntry = void 0;
|
|
100479
101063
|
state.thinkingDraft = "";
|
|
100480
101064
|
disposeActiveThinkingComponent(state);
|
|
101065
|
+
disposePendingToolComponents(state);
|
|
100481
101066
|
}
|
|
100482
101067
|
//#endregion
|
|
100483
101068
|
//#region src/tui/components/dialogs/compaction.ts
|
|
@@ -101059,7 +101644,10 @@ async function dispatchSlashCommand(input, state, buildCtx, addEntry) {
|
|
|
101059
101644
|
appState: ctx.appState,
|
|
101060
101645
|
setAppState: ctx.setAppState,
|
|
101061
101646
|
showStatus: ctx.showStatus,
|
|
101062
|
-
showNotice: ctx.showNotice
|
|
101647
|
+
showNotice: ctx.showNotice,
|
|
101648
|
+
showDeviceCodeBox: ctx.showDeviceCodeBox,
|
|
101649
|
+
showLiveSpinner: ctx.showLiveSpinner,
|
|
101650
|
+
registerCancellable: ctx.registerCancellable
|
|
101063
101651
|
};
|
|
101064
101652
|
let result;
|
|
101065
101653
|
try {
|
|
@@ -101188,80 +101776,6 @@ function refreshQueueIfBusy(state, ctx) {
|
|
|
101188
101776
|
state.ui.requestRender();
|
|
101189
101777
|
}
|
|
101190
101778
|
//#endregion
|
|
101191
|
-
//#region src/tui/components/chrome/moon-loader.ts
|
|
101192
|
-
const MOON_PHASES = [
|
|
101193
|
-
"🌑",
|
|
101194
|
-
"🌒",
|
|
101195
|
-
"🌓",
|
|
101196
|
-
"🌔",
|
|
101197
|
-
"🌕",
|
|
101198
|
-
"🌖",
|
|
101199
|
-
"🌗",
|
|
101200
|
-
"🌘"
|
|
101201
|
-
];
|
|
101202
|
-
const MOON_INTERVAL = 120;
|
|
101203
|
-
const BRAILLE_FRAMES = [
|
|
101204
|
-
"⠋",
|
|
101205
|
-
"⠙",
|
|
101206
|
-
"⠹",
|
|
101207
|
-
"⠸",
|
|
101208
|
-
"⠼",
|
|
101209
|
-
"⠴",
|
|
101210
|
-
"⠦",
|
|
101211
|
-
"⠧",
|
|
101212
|
-
"⠇",
|
|
101213
|
-
"⠏"
|
|
101214
|
-
];
|
|
101215
|
-
const BRAILLE_INTERVAL = 80;
|
|
101216
|
-
var MoonLoader = class extends Text {
|
|
101217
|
-
currentFrame = 0;
|
|
101218
|
-
intervalId = null;
|
|
101219
|
-
ui;
|
|
101220
|
-
frames;
|
|
101221
|
-
interval;
|
|
101222
|
-
colorFn;
|
|
101223
|
-
label;
|
|
101224
|
-
constructor(ui, style = "moon", colorFn, label = "") {
|
|
101225
|
-
super("", 1, 0);
|
|
101226
|
-
this.ui = ui;
|
|
101227
|
-
this.frames = style === "moon" ? MOON_PHASES : BRAILLE_FRAMES;
|
|
101228
|
-
this.interval = style === "moon" ? MOON_INTERVAL : BRAILLE_INTERVAL;
|
|
101229
|
-
this.colorFn = colorFn;
|
|
101230
|
-
this.label = label;
|
|
101231
|
-
this.start();
|
|
101232
|
-
}
|
|
101233
|
-
render(width) {
|
|
101234
|
-
return ["", ...super.render(width)];
|
|
101235
|
-
}
|
|
101236
|
-
start() {
|
|
101237
|
-
this.updateDisplay();
|
|
101238
|
-
this.intervalId = setInterval(() => {
|
|
101239
|
-
this.currentFrame = (this.currentFrame + 1) % this.frames.length;
|
|
101240
|
-
this.updateDisplay();
|
|
101241
|
-
}, this.interval);
|
|
101242
|
-
}
|
|
101243
|
-
stop() {
|
|
101244
|
-
if (this.intervalId) {
|
|
101245
|
-
clearInterval(this.intervalId);
|
|
101246
|
-
this.intervalId = null;
|
|
101247
|
-
}
|
|
101248
|
-
}
|
|
101249
|
-
setLabel(label) {
|
|
101250
|
-
this.label = label;
|
|
101251
|
-
this.updateDisplay();
|
|
101252
|
-
}
|
|
101253
|
-
setColorFn(colorFn) {
|
|
101254
|
-
this.colorFn = colorFn;
|
|
101255
|
-
this.updateDisplay();
|
|
101256
|
-
}
|
|
101257
|
-
updateDisplay() {
|
|
101258
|
-
const frame = this.frames[this.currentFrame];
|
|
101259
|
-
const coloredFrame = this.colorFn ? this.colorFn(frame) : frame;
|
|
101260
|
-
this.setText(this.label ? `${coloredFrame} ${this.label}` : coloredFrame);
|
|
101261
|
-
this.ui.requestRender();
|
|
101262
|
-
}
|
|
101263
|
-
};
|
|
101264
|
-
//#endregion
|
|
101265
101779
|
//#region src/tui/components/dialogs/approval-panel.ts
|
|
101266
101780
|
/**
|
|
101267
101781
|
* ApprovalPanel — pi-tui version of the approval request UI.
|
|
@@ -102380,6 +102894,7 @@ var UsagePanelComponent = class {
|
|
|
102380
102894
|
//#region src/tui/handlers/turn-lifecycle.ts
|
|
102381
102895
|
function handleTurnBegin(ectx, _data) {
|
|
102382
102896
|
ectx.state.streamingToolCallArguments.clear();
|
|
102897
|
+
disposePendingToolComponents(ectx.state);
|
|
102383
102898
|
ectx.state.currentStep = 0;
|
|
102384
102899
|
closePendingAgentGroup(ectx.state);
|
|
102385
102900
|
closePendingReadGroup(ectx.state);
|
|
@@ -102401,12 +102916,14 @@ function handleTurnEnd(ectx, _data, sendQueued) {
|
|
|
102401
102916
|
const todos = ectx.state.todoPanel.getTodos();
|
|
102402
102917
|
if (todos.length > 0 && todos.every((t) => t.status === "done")) ectx.setTodoList([]);
|
|
102403
102918
|
ectx.state.streamingToolCallArguments.clear();
|
|
102919
|
+
disposePendingToolComponents(ectx.state);
|
|
102404
102920
|
closePendingAgentGroup(ectx.state);
|
|
102405
102921
|
closePendingReadGroup(ectx.state);
|
|
102406
102922
|
finalizeTurn(ectx, sendQueued);
|
|
102407
102923
|
}
|
|
102408
102924
|
function handleStepBegin(ectx, data) {
|
|
102409
102925
|
ectx.state.currentStep = data.step;
|
|
102926
|
+
disposePendingToolComponents(ectx.state);
|
|
102410
102927
|
closePendingAgentGroup(ectx.state);
|
|
102411
102928
|
closePendingReadGroup(ectx.state);
|
|
102412
102929
|
flushTurnBuffers(ectx, "waiting");
|
|
@@ -102424,6 +102941,7 @@ function handleStepBegin(ectx, data) {
|
|
|
102424
102941
|
function handleStepInterrupted(ectx, data) {
|
|
102425
102942
|
closePendingAgentGroup(ectx.state);
|
|
102426
102943
|
closePendingReadGroup(ectx.state);
|
|
102944
|
+
disposePendingToolComponents(ectx.state);
|
|
102427
102945
|
flushTurnBuffers(ectx, "idle");
|
|
102428
102946
|
const reason = data.reason;
|
|
102429
102947
|
if (reason === "error") return;
|
|
@@ -102541,15 +103059,18 @@ function handleToolCallDelta(ectx, data) {
|
|
|
102541
103059
|
const existing = ectx.state.streamingToolCallArguments.get(id);
|
|
102542
103060
|
const argumentsText = `${existing?.argumentsText ?? ""}${data.arguments_part ?? ""}`;
|
|
102543
103061
|
const name = data.name ?? existing?.name ?? ectx.state.activeToolCalls.get(id)?.name ?? "Tool";
|
|
103062
|
+
const startedAtMs = existing?.startedAtMs ?? Date.now();
|
|
102544
103063
|
ectx.state.streamingToolCallArguments.set(id, {
|
|
102545
103064
|
name,
|
|
102546
|
-
argumentsText
|
|
103065
|
+
argumentsText,
|
|
103066
|
+
startedAtMs
|
|
102547
103067
|
});
|
|
102548
103068
|
const toolCall = {
|
|
102549
103069
|
id,
|
|
102550
103070
|
name,
|
|
102551
103071
|
args: parseStreamingArgs(argumentsText),
|
|
102552
103072
|
streamingArguments: argumentsText,
|
|
103073
|
+
streamingStartedAtMs: startedAtMs,
|
|
102553
103074
|
step: ectx.state.currentStep,
|
|
102554
103075
|
turnId: ectx.state.currentTurnId
|
|
102555
103076
|
};
|
|
@@ -102603,6 +103124,18 @@ function isContextUsage(value) {
|
|
|
102603
103124
|
const rec = value;
|
|
102604
103125
|
return typeof rec["used"] === "number" && typeof rec["total"] === "number" && typeof rec["percent"] === "number";
|
|
102605
103126
|
}
|
|
103127
|
+
function sessionErrorTitle(errorType) {
|
|
103128
|
+
switch (errorType) {
|
|
103129
|
+
case "auth_error": return "Authentication error";
|
|
103130
|
+
case "api_error": return "API error";
|
|
103131
|
+
case "rate_limit": return "Rate limit";
|
|
103132
|
+
case "context_overflow": return "Context overflow";
|
|
103133
|
+
case "tool_error": return "Tool error";
|
|
103134
|
+
case "internal": return "Internal error";
|
|
103135
|
+
case void 0: return "Error";
|
|
103136
|
+
default: return "Error";
|
|
103137
|
+
}
|
|
103138
|
+
}
|
|
102606
103139
|
function handleStatusUpdate(ectx, data) {
|
|
102607
103140
|
const refined = data;
|
|
102608
103141
|
const patch = {};
|
|
@@ -102630,9 +103163,10 @@ function handleSessionMetaChanged(ectx, data) {
|
|
|
102630
103163
|
function handleSessionError(ectx, data) {
|
|
102631
103164
|
closePendingAgentGroup(ectx.state);
|
|
102632
103165
|
closePendingReadGroup(ectx.state);
|
|
103166
|
+
disposePendingToolComponents(ectx.state);
|
|
102633
103167
|
flushTurnBuffers(ectx, "idle");
|
|
102634
|
-
const
|
|
102635
|
-
ectx.addTranscriptEntry(makeEntry(ectx, "status",
|
|
103168
|
+
const title = sessionErrorTitle(data.error_type);
|
|
103169
|
+
ectx.addTranscriptEntry(makeEntry(ectx, "status", `${title}: ${data.error}`, "plain", { color: ectx.colors.error }));
|
|
102636
103170
|
}
|
|
102637
103171
|
//#endregion
|
|
102638
103172
|
//#region src/tui/handlers/compaction.ts
|
|
@@ -103913,6 +104447,13 @@ function setupEditor(state, cb) {
|
|
|
103913
104447
|
cb.onEditorChange(text);
|
|
103914
104448
|
};
|
|
103915
104449
|
editor.onCtrlC = () => {
|
|
104450
|
+
if (state.cancelInFlight !== void 0) {
|
|
104451
|
+
const cancel = state.cancelInFlight;
|
|
104452
|
+
state.cancelInFlight = void 0;
|
|
104453
|
+
clearPendingExit(state);
|
|
104454
|
+
cancel();
|
|
104455
|
+
return;
|
|
104456
|
+
}
|
|
103916
104457
|
if (state.appState.isStreaming) {
|
|
103917
104458
|
clearPendingExit(state);
|
|
103918
104459
|
cb.onCancelStream();
|
|
@@ -104860,6 +105401,16 @@ var KimiTUI = class {
|
|
|
104860
105401
|
showNotice: (title, detail) => {
|
|
104861
105402
|
emitNotice(this.state, title, detail);
|
|
104862
105403
|
},
|
|
105404
|
+
showDeviceCodeBox: (options) => {
|
|
105405
|
+
emitDeviceCodeBox(this.state, options);
|
|
105406
|
+
},
|
|
105407
|
+
showLiveSpinner: (label) => emitLiveSpinner(this.state, label),
|
|
105408
|
+
registerCancellable: (abort) => {
|
|
105409
|
+
this.state.cancelInFlight = abort;
|
|
105410
|
+
return () => {
|
|
105411
|
+
if (this.state.cancelInFlight === abort) this.state.cancelInFlight = void 0;
|
|
105412
|
+
};
|
|
105413
|
+
},
|
|
104863
105414
|
stop: () => {
|
|
104864
105415
|
this.stop();
|
|
104865
105416
|
},
|