@moonshot-ai/kimi-code 0.14.0 → 0.14.2
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 +1757 -694
- package/dist/{src-CeUdnMA4.mjs → src-D5Ej2mZZ.mjs} +3 -3
- package/package.json +5 -5
package/dist/main.mjs
CHANGED
|
@@ -22,6 +22,7 @@ import * as fs$10 from "node:fs";
|
|
|
22
22
|
import Vt, { appendFileSync, chmodSync, closeSync, constants, createReadStream, createWriteStream as createWriteStream$1, existsSync, fsyncSync, mkdirSync, openSync, promises, readFileSync, readSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
|
|
23
23
|
import * as path$10 from "node:path";
|
|
24
24
|
import path$1, { basename as basename$1, dirname as dirname$2, extname, isAbsolute as isAbsolute$1, join as join$1, posix, relative as relative$1, resolve as resolve$1, sep, win32 } from "node:path";
|
|
25
|
+
import { Blob as Blob$1, Buffer as Buffer$2, File as File$1 } from "node:buffer";
|
|
25
26
|
import jn, { access, appendFile, chmod, copyFile, cp, lstat, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, stat, unlink, utimes, writeFile as writeFile$1 } from "node:fs/promises";
|
|
26
27
|
import { z } from "zod";
|
|
27
28
|
import { execFile, execFileSync, execSync, spawn, spawnSync } from "node:child_process";
|
|
@@ -36,18 +37,17 @@ import { EventEmitter as EventEmitter$1 } from "node:events";
|
|
|
36
37
|
import { StringDecoder } from "node:string_decoder";
|
|
37
38
|
import Mi from "assert";
|
|
38
39
|
import so from "node:assert";
|
|
39
|
-
import { parse as parse$2, stringify } from "smol-toml";
|
|
40
|
+
import { TomlError, parse as parse$2, stringify } from "smol-toml";
|
|
40
41
|
import "zod/v3";
|
|
41
42
|
import * as z4mini from "zod/v4-mini";
|
|
42
43
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
43
|
-
import { Buffer as Buffer$2 } from "node:buffer";
|
|
44
44
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
45
45
|
import process$1 from "node:process";
|
|
46
|
-
import { CURSOR_MARKER, CombinedAutocompleteProvider, Container, Editor, Image, Input, Key, Markdown, ProcessTerminal, Spacer, TUI, Text, decodeKittyPrintable, deleteAllKittyImages, fuzzyFilter, getCapabilities, isKeyRelease, matchesKey, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
|
|
46
|
+
import { CURSOR_MARKER, CombinedAutocompleteProvider, Container, Editor, Image, Input, Key, Markdown, ProcessTerminal, SelectList, Spacer, TUI, Text, decodeKittyPrintable, deleteAllKittyImages, fuzzyFilter, fuzzyMatch, getCapabilities, isKeyRelease, matchesKey, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
|
|
47
47
|
import chalk, { chalkStderr } from "chalk";
|
|
48
48
|
import { Command, Option } from "commander";
|
|
49
49
|
import { createInterface } from "node:readline/promises";
|
|
50
|
-
import { gt, valid } from "semver";
|
|
50
|
+
import { gt, gte, valid } from "semver";
|
|
51
51
|
import { highlight, supportsLanguage } from "cli-highlight";
|
|
52
52
|
import { clearLine, cursorTo, emitKeypressEvents, moveCursor } from "node:readline";
|
|
53
53
|
//#region \0rolldown/runtime.js
|
|
@@ -8742,6 +8742,10 @@ function isToolResultOnly(message) {
|
|
|
8742
8742
|
if (!Array.isArray(content) || content.length === 0) return false;
|
|
8743
8743
|
return content.every((block) => block.type === "tool_result");
|
|
8744
8744
|
}
|
|
8745
|
+
const OMITTED_MEDIA_PLACEHOLDER = {
|
|
8746
|
+
audio_url: "(audio omitted: not supported by this provider)",
|
|
8747
|
+
video_url: "(video omitted: not supported by this provider)"
|
|
8748
|
+
};
|
|
8745
8749
|
const SUPPORTED_B64_MEDIA_TYPES = new Set([
|
|
8746
8750
|
"image/png",
|
|
8747
8751
|
"image/jpeg",
|
|
@@ -8787,6 +8791,14 @@ function toolResultToBlock(toolCallId, content) {
|
|
|
8787
8791
|
text: part.text
|
|
8788
8792
|
});
|
|
8789
8793
|
} else if (part.type === "image_url") blocks.push(imageUrlPartToAnthropic(part.imageUrl.url));
|
|
8794
|
+
else if (part.type === "audio_url" || part.type === "video_url") {
|
|
8795
|
+
const placeholder = OMITTED_MEDIA_PLACEHOLDER[part.type];
|
|
8796
|
+
const last = blocks.at(-1);
|
|
8797
|
+
if (!(last?.type === "text" && last.text === placeholder)) blocks.push({
|
|
8798
|
+
type: "text",
|
|
8799
|
+
text: placeholder
|
|
8800
|
+
});
|
|
8801
|
+
}
|
|
8790
8802
|
return {
|
|
8791
8803
|
type: "tool_result",
|
|
8792
8804
|
tool_use_id: toolCallId,
|
|
@@ -8825,6 +8837,13 @@ function convertMessage$3(message, model) {
|
|
|
8825
8837
|
type: "thinking",
|
|
8826
8838
|
thinking: part.think
|
|
8827
8839
|
});
|
|
8840
|
+
} else if (part.type === "audio_url" || part.type === "video_url") {
|
|
8841
|
+
const placeholder = OMITTED_MEDIA_PLACEHOLDER[part.type];
|
|
8842
|
+
const last = blocks.at(-1);
|
|
8843
|
+
if (!(last?.type === "text" && last.text === placeholder)) blocks.push({
|
|
8844
|
+
type: "text",
|
|
8845
|
+
text: placeholder
|
|
8846
|
+
});
|
|
8828
8847
|
}
|
|
8829
8848
|
if (message.toolCalls.length > 0) for (const tc of message.toolCalls) {
|
|
8830
8849
|
let toolInput = {};
|
|
@@ -10319,7 +10338,7 @@ var require_gaxios = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
10319
10338
|
}
|
|
10320
10339
|
static async #getFetch() {
|
|
10321
10340
|
const hasWindow = typeof window !== "undefined" && !!window;
|
|
10322
|
-
this.#fetch ||= hasWindow ? window.fetch : (await import("./src-
|
|
10341
|
+
this.#fetch ||= hasWindow ? window.fetch : (await import("./src-D5Ej2mZZ.mjs")).default;
|
|
10323
10342
|
return this.#fetch;
|
|
10324
10343
|
}
|
|
10325
10344
|
/**
|
|
@@ -45333,6 +45352,16 @@ function normalizeOpenAIFinishReason(raw) {
|
|
|
45333
45352
|
}
|
|
45334
45353
|
}
|
|
45335
45354
|
/**
|
|
45355
|
+
* Shared wording for tool-result media that cannot live inside the tool
|
|
45356
|
+
* message itself and is reattached as a follow-up user message instead.
|
|
45357
|
+
*/
|
|
45358
|
+
const TOOL_RESULT_MEDIA_PROMPT = "Attached media from tool result:";
|
|
45359
|
+
const TOOL_RESULT_MEDIA_PLACEHOLDER = "(see attached media)";
|
|
45360
|
+
/** A content part that is neither plain text nor reasoning. */
|
|
45361
|
+
function isMediaPart(part) {
|
|
45362
|
+
return part.type !== "text" && part.type !== "think";
|
|
45363
|
+
}
|
|
45364
|
+
/**
|
|
45336
45365
|
* Convert tool-role message content according to the chosen strategy.
|
|
45337
45366
|
*/
|
|
45338
45367
|
function convertToolMessageContent(message, conversion) {
|
|
@@ -45389,14 +45418,11 @@ var KimiFiles = class {
|
|
|
45389
45418
|
const mimeType = guessMimeTypeFromExt(filename);
|
|
45390
45419
|
if (mimeType === void 0 || !mimeType.startsWith("video/")) throw new ChatProviderError(`KimiFiles.uploadVideo: file extension does not indicate a video type: ${filename}`);
|
|
45391
45420
|
const data = await fs$10.promises.readFile(input);
|
|
45392
|
-
|
|
45393
|
-
file = new File([blob], filename, { type: mimeType });
|
|
45421
|
+
file = new File$1([new Blob$1([new Uint8Array(data)], { type: mimeType })], filename, { type: mimeType });
|
|
45394
45422
|
} else {
|
|
45395
45423
|
if (!input.mimeType.startsWith("video/")) throw new ChatProviderError(`Expected a video mime type, got ${input.mimeType}`);
|
|
45396
45424
|
const filename = input.filename ?? guessFilename(input.mimeType);
|
|
45397
|
-
|
|
45398
|
-
const blob = new Blob([bytes], { type: input.mimeType });
|
|
45399
|
-
file = new File([blob], filename, { type: input.mimeType });
|
|
45425
|
+
file = new File$1([new Blob$1([input.data instanceof Uint8Array ? input.data : new Uint8Array(input.data)], { type: input.mimeType })], filename, { type: input.mimeType });
|
|
45400
45426
|
}
|
|
45401
45427
|
let uploaded;
|
|
45402
45428
|
try {
|
|
@@ -45840,8 +45866,6 @@ const OPENAI_CHAT_TOOL_CALL_ID_POLICY = {
|
|
|
45840
45866
|
normalize: (id) => sanitizeToolCallId(id, 64),
|
|
45841
45867
|
maxLength: 64
|
|
45842
45868
|
};
|
|
45843
|
-
const TOOL_RESULT_IMAGE_PROMPT = "Attached image(s) from tool result:";
|
|
45844
|
-
const TOOL_RESULT_IMAGE_PLACEHOLDER = "(see attached image)";
|
|
45845
45869
|
function extractReasoningContent(source, explicitKey) {
|
|
45846
45870
|
if (typeof source !== "object" || source === null) return void 0;
|
|
45847
45871
|
const record = source;
|
|
@@ -45898,45 +45922,46 @@ function convertMessage$1(message, reasoningKey, toolMessageConversion) {
|
|
|
45898
45922
|
if (reasoningContent) result[reasoningKey ?? DEFAULT_OUTBOUND_REASONING_KEY] = reasoningContent;
|
|
45899
45923
|
return result;
|
|
45900
45924
|
}
|
|
45925
|
+
const OMITTED_AUDIO_PLACEHOLDER$1 = "(audio omitted: not supported by this provider)";
|
|
45926
|
+
const OMITTED_VIDEO_PLACEHOLDER$1 = "(video omitted: not supported by this provider)";
|
|
45901
45927
|
function convertToolMessageContentForChat(message, conversion) {
|
|
45902
45928
|
const content = convertToolMessageContent(message, conversion);
|
|
45903
|
-
if (typeof content
|
|
45904
|
-
|
|
45929
|
+
if (typeof content !== "string") return content;
|
|
45930
|
+
const lines = content.length > 0 ? [content] : [];
|
|
45931
|
+
if (message.content.some((part) => part.type === "audio_url")) lines.push(OMITTED_AUDIO_PLACEHOLDER$1);
|
|
45932
|
+
if (message.content.some((part) => part.type === "video_url")) lines.push(OMITTED_VIDEO_PLACEHOLDER$1);
|
|
45933
|
+
if (lines.length === 0 && message.content.some((part) => part.type === "image_url")) return TOOL_RESULT_MEDIA_PLACEHOLDER;
|
|
45934
|
+
return lines.join("\n");
|
|
45905
45935
|
}
|
|
45906
45936
|
function toolResultImageParts(message) {
|
|
45907
45937
|
const images = [];
|
|
45908
45938
|
for (const part of message.content) {
|
|
45909
45939
|
if (part.type !== "image_url") continue;
|
|
45910
|
-
|
|
45911
|
-
|
|
45912
|
-
image_url: part.imageUrl.id === void 0 ? { url: part.imageUrl.url } : {
|
|
45913
|
-
url: part.imageUrl.url,
|
|
45914
|
-
id: part.imageUrl.id
|
|
45915
|
-
}
|
|
45916
|
-
});
|
|
45940
|
+
const converted = convertContentPart(part);
|
|
45941
|
+
if (converted !== null) images.push(converted);
|
|
45917
45942
|
}
|
|
45918
45943
|
return images;
|
|
45919
45944
|
}
|
|
45920
|
-
function
|
|
45921
|
-
if (
|
|
45945
|
+
function appendToolResultMediaMessage(messages, pendingToolResultMedia) {
|
|
45946
|
+
if (pendingToolResultMedia.length === 0) return;
|
|
45922
45947
|
messages.push({
|
|
45923
45948
|
role: "user",
|
|
45924
45949
|
content: [{
|
|
45925
45950
|
type: "text",
|
|
45926
|
-
text:
|
|
45927
|
-
}, ...
|
|
45951
|
+
text: TOOL_RESULT_MEDIA_PROMPT
|
|
45952
|
+
}, ...pendingToolResultMedia]
|
|
45928
45953
|
});
|
|
45929
|
-
|
|
45954
|
+
pendingToolResultMedia.length = 0;
|
|
45930
45955
|
}
|
|
45931
|
-
function convertHistoryMessages(history, reasoningKey, toolMessageConversion) {
|
|
45956
|
+
function convertHistoryMessages$1(history, reasoningKey, toolMessageConversion) {
|
|
45932
45957
|
const messages = [];
|
|
45933
|
-
const
|
|
45958
|
+
const pendingToolResultMedia = [];
|
|
45934
45959
|
for (const msg of history) {
|
|
45935
|
-
if (msg.role !== "tool")
|
|
45960
|
+
if (msg.role !== "tool") appendToolResultMediaMessage(messages, pendingToolResultMedia);
|
|
45936
45961
|
messages.push(convertMessage$1(msg, reasoningKey, toolMessageConversion));
|
|
45937
|
-
if (msg.role === "tool")
|
|
45962
|
+
if (msg.role === "tool") pendingToolResultMedia.push(...toolResultImageParts(msg));
|
|
45938
45963
|
}
|
|
45939
|
-
|
|
45964
|
+
appendToolResultMediaMessage(messages, pendingToolResultMedia);
|
|
45940
45965
|
return messages;
|
|
45941
45966
|
}
|
|
45942
45967
|
var OpenAILegacyStreamedMessage = class {
|
|
@@ -46074,7 +46099,7 @@ var OpenAILegacyChatProvider = class {
|
|
|
46074
46099
|
content: systemPrompt
|
|
46075
46100
|
});
|
|
46076
46101
|
const normalizedHistory = normalizeToolCallIdsForProvider(history, OPENAI_CHAT_TOOL_CALL_ID_POLICY);
|
|
46077
|
-
messages.push(...convertHistoryMessages(normalizedHistory, this._reasoningKey, this._toolMessageConversion));
|
|
46102
|
+
messages.push(...convertHistoryMessages$1(normalizedHistory, this._reasoningKey, this._toolMessageConversion));
|
|
46078
46103
|
const kwargs = normalizeGenerationKwargs(this._model, this._generationKwargs);
|
|
46079
46104
|
let reasoningEffort = this._reasoningEffort;
|
|
46080
46105
|
if (reasoningEffort === void 0 && kwargs["reasoning_effort"] === void 0) {
|
|
@@ -46310,6 +46335,8 @@ function formatResponsesFailedResponse(response) {
|
|
|
46310
46335
|
const reason = incompleteDetails === void 0 ? void 0 : readStringField(incompleteDetails, "reason");
|
|
46311
46336
|
return reason === void 0 ? "Unknown error (no error details in response)" : `incomplete: ${reason}`;
|
|
46312
46337
|
}
|
|
46338
|
+
const OMITTED_AUDIO_PLACEHOLDER = "(audio omitted: unsupported audio format)";
|
|
46339
|
+
const OMITTED_VIDEO_PLACEHOLDER = "(video omitted: not supported by this provider)";
|
|
46313
46340
|
function contentPartsToInputItems(parts) {
|
|
46314
46341
|
const items = [];
|
|
46315
46342
|
for (const part of parts) switch (part.type) {
|
|
@@ -46328,11 +46355,19 @@ function contentPartsToInputItems(parts) {
|
|
|
46328
46355
|
break;
|
|
46329
46356
|
case "audio_url": {
|
|
46330
46357
|
const mapped = mapAudioUrlToInputItem(part.audioUrl.url);
|
|
46331
|
-
|
|
46358
|
+
items.push(mapped ?? {
|
|
46359
|
+
type: "input_text",
|
|
46360
|
+
text: OMITTED_AUDIO_PLACEHOLDER
|
|
46361
|
+
});
|
|
46332
46362
|
break;
|
|
46333
46363
|
}
|
|
46334
|
-
case "
|
|
46335
|
-
|
|
46364
|
+
case "video_url":
|
|
46365
|
+
items.push({
|
|
46366
|
+
type: "input_text",
|
|
46367
|
+
text: OMITTED_VIDEO_PLACEHOLDER
|
|
46368
|
+
});
|
|
46369
|
+
break;
|
|
46370
|
+
case "think": break;
|
|
46336
46371
|
}
|
|
46337
46372
|
return items;
|
|
46338
46373
|
}
|
|
@@ -46362,11 +46397,19 @@ function messageContentToFunctionOutputItems(content) {
|
|
|
46362
46397
|
break;
|
|
46363
46398
|
case "audio_url": {
|
|
46364
46399
|
const mapped = mapAudioUrlToInputItem(part.audioUrl.url);
|
|
46365
|
-
|
|
46400
|
+
items.push(mapped ?? {
|
|
46401
|
+
type: "input_text",
|
|
46402
|
+
text: OMITTED_AUDIO_PLACEHOLDER
|
|
46403
|
+
});
|
|
46366
46404
|
break;
|
|
46367
46405
|
}
|
|
46368
|
-
case "
|
|
46369
|
-
|
|
46406
|
+
case "video_url":
|
|
46407
|
+
items.push({
|
|
46408
|
+
type: "input_text",
|
|
46409
|
+
text: OMITTED_VIDEO_PLACEHOLDER
|
|
46410
|
+
});
|
|
46411
|
+
break;
|
|
46412
|
+
case "think": break;
|
|
46370
46413
|
}
|
|
46371
46414
|
return items;
|
|
46372
46415
|
}
|
|
@@ -46399,11 +46442,19 @@ function mapAudioUrlToInputItem(url) {
|
|
|
46399
46442
|
function convertMessage(message, modelName, toolMessageConversion) {
|
|
46400
46443
|
let role = message.role;
|
|
46401
46444
|
if (usesOpenAIResponsesDeveloperRole(modelName) && role === "system") role = "developer";
|
|
46402
|
-
if (role === "tool")
|
|
46403
|
-
|
|
46404
|
-
output
|
|
46405
|
-
|
|
46406
|
-
|
|
46445
|
+
if (role === "tool") {
|
|
46446
|
+
const callId = message.toolCallId ?? "";
|
|
46447
|
+
let output;
|
|
46448
|
+
if (toolMessageConversion === "extract_text") {
|
|
46449
|
+
const text = extractText(message);
|
|
46450
|
+
output = text.length === 0 && message.content.some(isMediaPart) ? TOOL_RESULT_MEDIA_PLACEHOLDER : text;
|
|
46451
|
+
} else output = messageContentToFunctionOutputItems(message.content);
|
|
46452
|
+
return [{
|
|
46453
|
+
call_id: callId,
|
|
46454
|
+
output,
|
|
46455
|
+
type: "function_call_output"
|
|
46456
|
+
}];
|
|
46457
|
+
}
|
|
46407
46458
|
const result = [];
|
|
46408
46459
|
if (message.content.length > 0) {
|
|
46409
46460
|
const pendingParts = [];
|
|
@@ -46474,6 +46525,35 @@ function convertTool(tool) {
|
|
|
46474
46525
|
strict: false
|
|
46475
46526
|
};
|
|
46476
46527
|
}
|
|
46528
|
+
/**
|
|
46529
|
+
* Convert the history, buffering tool-result media when `extract_text`
|
|
46530
|
+
* flattens tool outputs to plain strings. The buffered media items are
|
|
46531
|
+
* reattached as a single user message after each run of consecutive tool
|
|
46532
|
+
* messages — mirroring the OpenAI Chat Completions provider.
|
|
46533
|
+
*/
|
|
46534
|
+
function convertHistoryMessages(history, modelName, toolMessageConversion) {
|
|
46535
|
+
const input = [];
|
|
46536
|
+
const pendingToolResultMedia = [];
|
|
46537
|
+
const flushPendingMedia = () => {
|
|
46538
|
+
if (pendingToolResultMedia.length === 0) return;
|
|
46539
|
+
input.push({
|
|
46540
|
+
type: "message",
|
|
46541
|
+
role: "user",
|
|
46542
|
+
content: [{
|
|
46543
|
+
type: "input_text",
|
|
46544
|
+
text: TOOL_RESULT_MEDIA_PROMPT
|
|
46545
|
+
}, ...pendingToolResultMedia]
|
|
46546
|
+
});
|
|
46547
|
+
pendingToolResultMedia.length = 0;
|
|
46548
|
+
};
|
|
46549
|
+
for (const msg of history) {
|
|
46550
|
+
if (msg.role !== "tool") flushPendingMedia();
|
|
46551
|
+
input.push(...convertMessage(msg, modelName, toolMessageConversion));
|
|
46552
|
+
if (msg.role === "tool" && toolMessageConversion === "extract_text") pendingToolResultMedia.push(...messageContentToFunctionOutputItems(msg.content.filter(isMediaPart)));
|
|
46553
|
+
}
|
|
46554
|
+
flushPendingMedia();
|
|
46555
|
+
return input;
|
|
46556
|
+
}
|
|
46477
46557
|
var OpenAIResponsesStreamedMessage = class {
|
|
46478
46558
|
_id = null;
|
|
46479
46559
|
_usage = null;
|
|
@@ -46735,16 +46815,8 @@ var OpenAIResponsesChatProvider = class {
|
|
|
46735
46815
|
}
|
|
46736
46816
|
async generate(systemPrompt, tools, history, options) {
|
|
46737
46817
|
const input = [];
|
|
46738
|
-
if (systemPrompt) {
|
|
46739
|
-
const sysItem = {
|
|
46740
|
-
role: "system",
|
|
46741
|
-
content: systemPrompt
|
|
46742
|
-
};
|
|
46743
|
-
if (usesOpenAIResponsesDeveloperRole(this._model)) sysItem["role"] = "developer";
|
|
46744
|
-
input.push(sysItem);
|
|
46745
|
-
}
|
|
46746
46818
|
const normalizedHistory = normalizeToolCallIdsForProvider(history, OPENAI_RESPONSES_TOOL_CALL_ID_POLICY);
|
|
46747
|
-
|
|
46819
|
+
input.push(...convertHistoryMessages(normalizedHistory, this._model, this._toolMessageConversion));
|
|
46748
46820
|
const kwargs = { ...this._generationKwargs };
|
|
46749
46821
|
const reasoningEffort = kwargs["reasoning_effort"];
|
|
46750
46822
|
delete kwargs["reasoning_effort"];
|
|
@@ -46766,6 +46838,7 @@ var OpenAIResponsesChatProvider = class {
|
|
|
46766
46838
|
stream: this._stream,
|
|
46767
46839
|
...kwargs
|
|
46768
46840
|
};
|
|
46841
|
+
if (systemPrompt) createParams["instructions"] = systemPrompt;
|
|
46769
46842
|
if (!("responses" in client) || typeof client.responses?.create !== "function") throw new Error("OpenAI SDK version does not support Responses API. Upgrade to >=4.x with responses support.");
|
|
46770
46843
|
return new OpenAIResponsesStreamedMessage(await client.responses.create(createParams, options?.signal ? { signal: options.signal } : void 0), this._stream);
|
|
46771
46844
|
} catch (error) {
|
|
@@ -47221,7 +47294,7 @@ const REDACTED_KEYS = new Set([
|
|
|
47221
47294
|
"bearer"
|
|
47222
47295
|
]);
|
|
47223
47296
|
const SAFE_KEY_RE = /^[\w.-]+$/;
|
|
47224
|
-
const ELLIPSIS$
|
|
47297
|
+
const ELLIPSIS$9 = "…";
|
|
47225
47298
|
const TRUNCATED_TAIL = ` …truncated`;
|
|
47226
47299
|
const REDACTED = "[REDACTED]";
|
|
47227
47300
|
const RAW_SECRET_PATTERNS = [
|
|
@@ -47260,7 +47333,7 @@ function redactCtx(ctx) {
|
|
|
47260
47333
|
return walk(ctx, 0);
|
|
47261
47334
|
}
|
|
47262
47335
|
function truncate$2(value, max) {
|
|
47263
|
-
return value.length <= max ? value : value.slice(0, max - 1) + ELLIPSIS$
|
|
47336
|
+
return value.length <= max ? value : value.slice(0, max - 1) + ELLIPSIS$9;
|
|
47264
47337
|
}
|
|
47265
47338
|
function serializeValue(raw) {
|
|
47266
47339
|
if (typeof raw === "string") return redactString(raw);
|
|
@@ -47450,7 +47523,6 @@ var RotatingFileSink = class {
|
|
|
47450
47523
|
pending = [];
|
|
47451
47524
|
dropped = 0;
|
|
47452
47525
|
closed = false;
|
|
47453
|
-
failed = false;
|
|
47454
47526
|
lastStderrNotice = 0;
|
|
47455
47527
|
currentBytes = -1;
|
|
47456
47528
|
directorySynced = false;
|
|
@@ -47507,7 +47579,6 @@ var RotatingFileSink = class {
|
|
|
47507
47579
|
await syncDir(dirname(this.options.path));
|
|
47508
47580
|
this.directorySynced = true;
|
|
47509
47581
|
}
|
|
47510
|
-
this.failed = false;
|
|
47511
47582
|
return true;
|
|
47512
47583
|
} catch (error) {
|
|
47513
47584
|
this.noteFailure(error);
|
|
@@ -47591,7 +47662,6 @@ var RotatingFileSink = class {
|
|
|
47591
47662
|
return line;
|
|
47592
47663
|
}
|
|
47593
47664
|
noteFailure(error) {
|
|
47594
|
-
this.failed = true;
|
|
47595
47665
|
const now = Date.now();
|
|
47596
47666
|
if (now - this.lastStderrNotice < STDERR_NOTICE_INTERVAL_MS) return;
|
|
47597
47667
|
this.lastStderrNotice = now;
|
|
@@ -49156,8 +49226,8 @@ function buildBackgroundTaskNotificationBody(info) {
|
|
|
49156
49226
|
//#endregion
|
|
49157
49227
|
//#region ../../packages/agent-core/src/utils/abort.ts
|
|
49158
49228
|
var import_retry = /* @__PURE__ */ __toESM(require_retry$4(), 1);
|
|
49159
|
-
function abortError$1() {
|
|
49160
|
-
const error =
|
|
49229
|
+
function abortError$1(message = "Aborted") {
|
|
49230
|
+
const error = new Error(message);
|
|
49161
49231
|
error.name = "AbortError";
|
|
49162
49232
|
return error;
|
|
49163
49233
|
}
|
|
@@ -54296,7 +54366,7 @@ function applyCompletionBudget(args) {
|
|
|
54296
54366
|
return args.provider.withMaxCompletionTokens(cap);
|
|
54297
54367
|
}
|
|
54298
54368
|
//#endregion
|
|
54299
|
-
//#region ../../packages/agent-core/src/agent/compaction/compaction-instruction.md
|
|
54369
|
+
//#region ../../packages/agent-core/src/agent/compaction/compaction-instruction.md?raw
|
|
54300
54370
|
var compaction_instruction_default = "\n--- This message is a direct task, not part of the above conversation ---\n\nYou are now given a task to compact this conversation context according to specific priorities and output requirements.\n\nOutput text only. DO NOT CALL ANY TOOLS. Calling tools will be rejected and fails the task. You already have all the information you need in the conversation history. You have only one chance.\n\nThe goal of compaction is to keep essential code patterns, technical details, and architectural decisions for continuing development without losing context after the above messages are cleared work.\n\n{{ customInstruction }}\n\n<!-- Compression Priorities (in order) -->\n\n1. **Current Task State**: What is being worked on RIGHT NOW\n2. **Errors & Solutions**: All encountered errors and their resolutions\n3. **Code Evolution**: Final working versions only (remove intermediate attempts)\n4. **System Context**: Project structure, dependencies, environment setup\n5. **Design Decisions**: Architectural choices and their rationale\n6. **TODO Items**: Unfinished tasks and known issues\n\n<!-- Required Output Structure -->\n\n## Current Focus\n\n[What we're working on now]\n\n## Environment\n\n- [Key setup/config points]\n- ...\n\n## Completed Tasks\n\n- [Task]: [Brief outcome]\n- ...\n\n## Active Issues\n\n- [Issue]: [Status/Next steps]\n- ...\n\n## Code State\n\n### [Critical file name]\n\n[Brief description of the file's purpose and current state]\n\n```\n[The latest version of critical code snippets in this file, <20 lines]\n```\n\n### [Critical file name]\n\n- [Useful classes/methods/functions]: [Brief description/usage]\n- ...\n\n<!-- Omit non-critical code, intermediate attempts, and resolved errors -->\n\n## Important Context\n\n- [Any crucial information not covered above]\n- ...\n\n## All User Messages\n\n- [Detailed non tool use user message]\n- ...\n";
|
|
54301
54371
|
//#endregion
|
|
54302
54372
|
//#region ../../packages/agent-core/src/agent/compaction/render-messages.ts
|
|
@@ -54426,7 +54496,7 @@ function closeObjectNodes(value) {
|
|
|
54426
54496
|
for (const child of Object.values(node)) closeObjectNodes(child);
|
|
54427
54497
|
}
|
|
54428
54498
|
//#endregion
|
|
54429
|
-
//#region ../../packages/agent-core/src/tools/builtin/state/todo-list.md
|
|
54499
|
+
//#region ../../packages/agent-core/src/tools/builtin/state/todo-list.md?raw
|
|
54430
54500
|
var todo_list_default = "Use this tool to maintain a structured TODO list as you work through a multi-step task. Use it proactively and often when progress tracking helps the current work. This is especially useful in Plan mode, long-running investigations, and implementation tasks with several tool calls.\n\n**When to use:**\n- Multi-step tasks that span several tool calls\n- Tracking investigation progress across a large codebase search\n- Planning a sequence of edits before making them\n- After receiving new multi-step instructions, capture the requirements as todos\n- Before starting a tracked task, mark exactly one item as `in_progress`\n- Immediately after finishing a tracked task, mark it `done`; do not batch completions at the end\n\n**When NOT to use:**\n- Single-shot answers that complete in one or two tool calls\n- Trivial requests where tracking adds no clarity\n- Purely conversational or informational replies\n\n**Avoid churn:**\n- Do not re-call this tool when nothing meaningful has changed since the last call — update the list only after real progress.\n- When unsure of the current state, call query mode first (omit `todos`) to check the list before deciding what to update.\n- If no available tool can move any task forward, tell the user where you are stuck instead of repeatedly re-ordering the same todos.\n\n**How to use:**\n- Call with `todos: [...]` to replace the full list. Statuses: pending / in_progress / done.\n- Call with no arguments to retrieve the current list without changing it.\n- Call with `todos: []` to clear the list.\n- Keep titles short and actionable (e.g. \"Read session-control.ts\", \"Add planMode flag to TurnManager\").\n- Update statuses as you make progress.\n- When work is underway, keep exactly one task `in_progress`.\n- Only mark a task `done` when it is fully accomplished.\n- Never mark a task `done` if tests are failing, implementation is partial, unresolved errors remain, or required files/dependencies could not be found.\n- If you encounter a blocker, keep the blocked task `in_progress` or add a new pending task describing what must be resolved.\n";
|
|
54431
54501
|
//#endregion
|
|
54432
54502
|
//#region ../../packages/agent-core/src/tools/builtin/state/todo-list.ts
|
|
@@ -54630,7 +54700,13 @@ var FullCompaction = class {
|
|
|
54630
54700
|
if (data.source === "manual") this.compactionCountInTurn = 0;
|
|
54631
54701
|
else this.compactionCountInTurn += 1;
|
|
54632
54702
|
if (this.compactionCountInTurn > this.strategy.maxCompactionPerTurn) return;
|
|
54633
|
-
if (this.agent.records.restoring)
|
|
54703
|
+
if (this.agent.records.restoring) {
|
|
54704
|
+
this.agent.replayBuilder.push({
|
|
54705
|
+
type: "compaction",
|
|
54706
|
+
instruction: data.instruction
|
|
54707
|
+
});
|
|
54708
|
+
return;
|
|
54709
|
+
}
|
|
54634
54710
|
const compactedCount = this.strategy.computeCompactCount(this.agent.context.history, data.source);
|
|
54635
54711
|
if (compactedCount === 0) throw new KimiError(ErrorCodes.COMPACTION_UNABLE, "No prefix that can be compacted in current history.");
|
|
54636
54712
|
this.agent.records.logRecord({
|
|
@@ -54660,6 +54736,7 @@ var FullCompaction = class {
|
|
|
54660
54736
|
this.markCanceled();
|
|
54661
54737
|
}
|
|
54662
54738
|
markCanceled() {
|
|
54739
|
+
this.agent.replayBuilder.patchLast("compaction", { result: "cancelled" });
|
|
54663
54740
|
if (!this.compacting) return;
|
|
54664
54741
|
this.agent.records.logRecord({ type: "full_compaction.cancel" });
|
|
54665
54742
|
this.compacting.abortController.abort();
|
|
@@ -56376,8 +56453,12 @@ var ConfigState = class {
|
|
|
56376
56453
|
return this._modelAlias;
|
|
56377
56454
|
}
|
|
56378
56455
|
get thinkingLevel() {
|
|
56456
|
+
if (this._thinkingLevel === "off" && this.alwaysThinkingModel) return resolveThinkingEffort("on", this.agent.kimiConfig?.thinking);
|
|
56379
56457
|
return this._thinkingLevel;
|
|
56380
56458
|
}
|
|
56459
|
+
get alwaysThinkingModel() {
|
|
56460
|
+
return this.tryResolvedProviderConfig()?.alwaysThinking === true;
|
|
56461
|
+
}
|
|
56381
56462
|
get profileName() {
|
|
56382
56463
|
return this._profileName;
|
|
56383
56464
|
}
|
|
@@ -56570,26 +56651,32 @@ var ContextMemory = class {
|
|
|
56570
56651
|
stoppedAtCompaction: stoppedAtBoundary
|
|
56571
56652
|
} });
|
|
56572
56653
|
}
|
|
56573
|
-
applyCompaction(
|
|
56654
|
+
applyCompaction(result) {
|
|
56574
56655
|
this.agent.records.logRecord({
|
|
56575
56656
|
type: "context.apply_compaction",
|
|
56576
|
-
...
|
|
56657
|
+
...result
|
|
56577
56658
|
});
|
|
56659
|
+
this.agent.replayBuilder.patchLast("compaction", { result: {
|
|
56660
|
+
summary: result.summary,
|
|
56661
|
+
compactedCount: result.compactedCount,
|
|
56662
|
+
tokensBefore: result.tokensBefore,
|
|
56663
|
+
tokensAfter: result.tokensAfter
|
|
56664
|
+
} });
|
|
56578
56665
|
this._history = [{
|
|
56579
56666
|
role: "assistant",
|
|
56580
56667
|
content: [{
|
|
56581
56668
|
type: "text",
|
|
56582
|
-
text:
|
|
56669
|
+
text: result.summary
|
|
56583
56670
|
}],
|
|
56584
56671
|
toolCalls: [],
|
|
56585
56672
|
origin: { kind: "compaction_summary" }
|
|
56586
|
-
}, ...this._history.slice(
|
|
56673
|
+
}, ...this._history.slice(result.compactedCount)];
|
|
56587
56674
|
this.openSteps.clear();
|
|
56588
56675
|
this.flushDeferredMessagesIfToolExchangeClosed();
|
|
56589
|
-
this._tokenCount =
|
|
56676
|
+
this._tokenCount = result.tokensAfter;
|
|
56590
56677
|
this.tokenCountCoveredMessageCount = this._history.length;
|
|
56591
56678
|
this.agent.microCompaction.reset();
|
|
56592
|
-
this.agent.injection.onContextCompacted(
|
|
56679
|
+
this.agent.injection.onContextCompacted(result.compactedCount);
|
|
56593
56680
|
this.agent.emitStatusUpdated();
|
|
56594
56681
|
}
|
|
56595
56682
|
data() {
|
|
@@ -58024,6 +58111,31 @@ var InjectionManager = class {
|
|
|
58024
58111
|
}
|
|
58025
58112
|
};
|
|
58026
58113
|
//#endregion
|
|
58114
|
+
//#region ../../packages/agent-core/src/agent/permission/policies/agent-swarm-exclusive-deny.ts
|
|
58115
|
+
var AgentSwarmExclusiveDenyPermissionPolicy = class {
|
|
58116
|
+
name = "agent-swarm-exclusive-deny";
|
|
58117
|
+
evaluate(context) {
|
|
58118
|
+
const toolCalls = context.toolCalls;
|
|
58119
|
+
const agentSwarmCount = toolCalls.filter((toolCall) => toolCall.name === "AgentSwarm").length;
|
|
58120
|
+
if (agentSwarmCount === 0) return;
|
|
58121
|
+
if (agentSwarmCount === 1 && toolCalls.length === 1) return;
|
|
58122
|
+
return {
|
|
58123
|
+
kind: "deny",
|
|
58124
|
+
message: agentSwarmCount > 1 ? multipleAgentSwarmDeniedMessage(toolCalls.length > agentSwarmCount) : mixedAgentSwarmDeniedMessage(),
|
|
58125
|
+
reason: {
|
|
58126
|
+
agent_swarm_tool_calls: agentSwarmCount,
|
|
58127
|
+
tool_calls: toolCalls.length
|
|
58128
|
+
}
|
|
58129
|
+
};
|
|
58130
|
+
}
|
|
58131
|
+
};
|
|
58132
|
+
function multipleAgentSwarmDeniedMessage(hasOtherToolCalls) {
|
|
58133
|
+
return `AgentSwarm must be called one swarm at a time. Multiple AgentSwarm calls are not forbidden, but issue them sequentially: call one AgentSwarm, wait for its result, then call the next; or merge the work into a single AgentSwarm when one swarm can cover it.${hasOtherToolCalls ? " AgentSwarm also must not be combined with other tools in the same response." : ""}`;
|
|
58134
|
+
}
|
|
58135
|
+
function mixedAgentSwarmDeniedMessage() {
|
|
58136
|
+
return "AgentSwarm must be the only tool call in a model response. Retry with a single AgentSwarm call by itself, then call any other tools after it returns.";
|
|
58137
|
+
}
|
|
58138
|
+
//#endregion
|
|
58027
58139
|
//#region ../../packages/agent-core/src/agent/permission/policies/auto-mode-approve.ts
|
|
58028
58140
|
var AutoModeApprovePermissionPolicy = class {
|
|
58029
58141
|
agent;
|
|
@@ -58466,11 +58578,7 @@ function parseGitDir(content, markerParent) {
|
|
|
58466
58578
|
//#endregion
|
|
58467
58579
|
//#region ../../packages/agent-core/src/agent/permission/policies/file-access-ask.ts
|
|
58468
58580
|
var SensitiveFileAccessAskPermissionPolicy = class {
|
|
58469
|
-
agent;
|
|
58470
58581
|
name = "sensitive-file-access-ask";
|
|
58471
|
-
constructor(agent) {
|
|
58472
|
-
this.agent = agent;
|
|
58473
|
-
}
|
|
58474
58582
|
evaluate(context) {
|
|
58475
58583
|
const access = fileAccesses(context).find((fileAccess) => isSensitiveFile(fileAccess.path));
|
|
58476
58584
|
if (access === void 0) return;
|
|
@@ -60720,6 +60828,7 @@ var YoloModeApprovePermissionPolicy = class {
|
|
|
60720
60828
|
function createPermissionDecisionPolicies(agent) {
|
|
60721
60829
|
return [
|
|
60722
60830
|
new PreToolCallHookPermissionPolicy(agent),
|
|
60831
|
+
new AgentSwarmExclusiveDenyPermissionPolicy(),
|
|
60723
60832
|
new AutoModeAskUserQuestionDenyPermissionPolicy(agent),
|
|
60724
60833
|
new PlanModeGuardDenyPermissionPolicy(agent),
|
|
60725
60834
|
new UserConfiguredDenyPermissionPolicy(agent),
|
|
@@ -60729,7 +60838,7 @@ function createPermissionDecisionPolicies(agent) {
|
|
|
60729
60838
|
new UserConfiguredAllowPermissionPolicy(agent),
|
|
60730
60839
|
new ExitPlanModeReviewAskPermissionPolicy(agent),
|
|
60731
60840
|
new PlanModeToolApprovePermissionPolicy(agent),
|
|
60732
|
-
new SensitiveFileAccessAskPermissionPolicy(
|
|
60841
|
+
new SensitiveFileAccessAskPermissionPolicy(),
|
|
60733
60842
|
new GitControlPathAccessAskPermissionPolicy(agent),
|
|
60734
60843
|
new YoloModeApprovePermissionPolicy(agent),
|
|
60735
60844
|
new SwarmModeAgentSwarmApprovePermissionPolicy(agent),
|
|
@@ -62006,12 +62115,22 @@ var AgentRecords = class {
|
|
|
62006
62115
|
//#region ../../packages/agent-core/src/agent/replay/index.ts
|
|
62007
62116
|
var ReplayBuilder = class {
|
|
62008
62117
|
agent;
|
|
62118
|
+
captureLiveRecords = false;
|
|
62009
62119
|
records = [];
|
|
62010
62120
|
constructor(agent) {
|
|
62011
62121
|
this.agent = agent;
|
|
62012
62122
|
}
|
|
62013
62123
|
push(record) {
|
|
62014
|
-
if (this.agent.records.restoring) this.records.push(
|
|
62124
|
+
if (this.captureLiveRecords || this.agent.records.restoring) this.records.push({
|
|
62125
|
+
...record,
|
|
62126
|
+
time: this.agent.records.restoring?.time ?? Date.now()
|
|
62127
|
+
});
|
|
62128
|
+
}
|
|
62129
|
+
patchLast(type, patch) {
|
|
62130
|
+
if (this.agent.records.restoring) {
|
|
62131
|
+
const last = this.records.at(-1);
|
|
62132
|
+
if (last && last.type === type) Object.assign(last, patch);
|
|
62133
|
+
}
|
|
62015
62134
|
}
|
|
62016
62135
|
removeLastMessages(removedMessages) {
|
|
62017
62136
|
if (removedMessages.size === 0) return;
|
|
@@ -65487,7 +65606,7 @@ function isUserActivatableSkillType(type) {
|
|
|
65487
65606
|
return isInlineSkillType(type) || type === "flow";
|
|
65488
65607
|
}
|
|
65489
65608
|
function isSupportedSkillType(type) {
|
|
65490
|
-
return isUserActivatableSkillType(type);
|
|
65609
|
+
return isUserActivatableSkillType(type) || type === "reference";
|
|
65491
65610
|
}
|
|
65492
65611
|
function summarizeSkill(skill) {
|
|
65493
65612
|
return {
|
|
@@ -65496,7 +65615,8 @@ function summarizeSkill(skill) {
|
|
|
65496
65615
|
path: skill.path,
|
|
65497
65616
|
source: skill.source,
|
|
65498
65617
|
type: skill.metadata.type,
|
|
65499
|
-
disableModelInvocation: skill.metadata.disableModelInvocation
|
|
65618
|
+
disableModelInvocation: skill.metadata.disableModelInvocation,
|
|
65619
|
+
isSubSkill: skill.metadata.isSubSkill
|
|
65500
65620
|
};
|
|
65501
65621
|
}
|
|
65502
65622
|
//#endregion
|
|
@@ -65697,8 +65817,8 @@ function isRecord$11(value) {
|
|
|
65697
65817
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
65698
65818
|
}
|
|
65699
65819
|
//#endregion
|
|
65700
|
-
//#region ../../packages/agent-core/src/skill/builtin/custom-theme.md
|
|
65701
|
-
var custom_theme_default = "---\nname: custom-theme\ndescription: Create or edit a kimi-code custom color theme — a JSON file under
|
|
65820
|
+
//#region ../../packages/agent-core/src/skill/builtin/custom-theme.md?raw
|
|
65821
|
+
var custom_theme_default = "---\nname: custom-theme\ndescription: Create or edit a kimi-code custom color theme — a JSON file under the resolved KIMI_CODE_HOME data directory that recolors the TUI. Use when the user wants their own theme, asks for a specific palette or mood, or wants to tweak an existing custom theme's colors.\n---\n\n# Create a kimi-code custom theme (custom-theme)\n\nHelp the user design, write, and apply a custom color theme for the kimi-code TUI. A theme is a single JSON file; the TUI ships with `dark`, `light`, and `auto`, and any file the user adds becomes selectable alongside them.\n\n## Rules of engagement\n\n- **Never write a theme until the user has explicitly clarified what they want.** This skill may only run after the user has confirmed light vs dark, the style or mood, any specific colors they care about, and the intended filename. If any of these are missing, ask before creating files.\n- **Never assume the data directory is `~/.kimi-code`.** Always resolve `$KIMI_CODE_HOME` first with the Bash command below.\n- **Never edit a live theme file in place.** Always create a `.json.new` candidate, validate it, back up the old file, and then `mv` it into place.\n- **Never overwrite an existing theme without reading it first.** Read, back up, then overwrite only after the user confirms.\n\n## Where a theme lives\n\nThe kimi-code runtime resolves the data directory as `KIMI_CODE_HOME` first, falling back to `~/.kimi-code`. Theme files live inside the `themes/` subdirectory of that data directory.\n\nBefore doing anything, resolve the actual data root with Bash so you don't write to the wrong place. Check whether `KIMI_CODE_HOME` is set and fall back to `~/.kimi-code` when it is empty:\n\n```bash\necho \"$KIMI_CODE_HOME\"\necho \"$HOME/.kimi-code\"\n```\n\nUse the first line when it is non-empty; otherwise use the second line. In the rest of this skill, `<KIMI_CODE_HOME>` means that resolved data root — **never assume `~/.kimi-code`**. Theme files live at `<KIMI_CODE_HOME>/themes/<name>.json`. Create the `themes/` directory if it doesn't exist.\n\n## What a theme is\n\n- A theme lives at `<KIMI_CODE_HOME>/themes/<name>.json`.\n- **The filename is the theme name**: `ember.json` shows up in the `/theme` picker as `Custom: ember`.\n- Shape:\n\n ```json\n {\n \"name\": \"ember\",\n \"displayName\": \"Ember\",\n \"colors\": {\n \"primary\": \"#83A598\",\n \"accent\": \"#FE8019\"\n }\n }\n ```\n\n - `name` (required), `displayName` (optional), `base` (optional: `\"dark\"` default, or `\"light\"`), `colors` (each value a 6-digit hex `#RRGGBB`).\n- **Partial themes are fine**: any token you leave out falls back to the **base** palette (`dark` by default; set `\"base\": \"light\"` for a light theme), so you can recolor just a few tokens or all of them.\n\n## Source of truth: the docs token reference\n\nBefore choosing colors, use **FetchURL** to fetch the official custom-theme docs as the authoritative list of tokens and what each controls:\n\n```\nhttps://moonshotai.github.io/kimi-code/en/customization/themes.html\n```\n\nOnly set tokens from this set — unknown keys are silently ignored at load. If FetchURL is unavailable or the fetch fails, fall back to the embedded reference below (it mirrors the same tokens) and tell the user you're working from the built-in list rather than the live docs.\n\n## Color tokens (what each controls)\n\n| Token | Controls |\n| --- | --- |\n| `primary` | The most-used color: links, inline code, the selected item in nearly every dialog, the focused editor border, plan/\"running\" badges, spinners |\n| `accent` | Secondary highlight: approval `▶` prefix, device-code box, image placeholder, BTW / queue panes, registry import |\n| `text` | Body text: dialog bodies, todo titles, footer model label, Markdown headings, assistant/tool message bullets, list bullets |\n| `textStrong` | Emphasized / bold text: input dialogs, status messages |\n| `textDim` | Secondary, dimmed text (the most widely used dim shade): thinking, hints, descriptions, completed todos, Markdown quotes, footer status bar |\n| `textMuted` | Faintest text: counters, scroll info, descriptions, Markdown link URLs, code-block borders |\n| `border` | Pane and editor borders, Markdown horizontal rule |\n| `borderFocus` | Focus / attention border (currently only the approval panel) |\n| `success` | Success state: `✓`, \"enabled\", completed |\n| `warning` | Warning state: auto/yolo badges, stale markers, plan-mode hint |\n| `error` | Error state: error messages, failed tool output |\n| `diffAdded` | Diff added lines |\n| `diffRemoved` | Diff removed lines |\n| `diffAddedStrong` | Diff intra-line changed words, added (bold) |\n| `diffRemovedStrong` | Diff intra-line changed words, removed (bold) |\n| `diffGutter` | Diff line-number gutter |\n| `diffMeta` | Diff meta / hunk headers |\n| `roleUser` | User message bullet and text, skill-activation name (the one role color with its own hue) |\n\n## Workflow\n\n1. **Ask the user what they want first — before choosing any colors.** Clarify, in one short exchange:\n - **Light or dark?** A light theme (dark text on a light background) or a dark theme (light text on a dark background). This sets the whole direction, so settle it first. For a light theme, set `\"base\": \"light\"` so the tokens you leave out inherit the light palette instead of dark.\n - **What style / mood?** e.g. warm vs cool, vivid vs muted, high vs low contrast, a named vibe (\"nord\", \"solarized\", \"sunset\"), or a base to start from (an existing theme, or `dark` / `light`).\n - **Any specific colors?** Whether they have exact hex values to anchor on (a brand color, a preferred `primary`, etc.).\n\n For the discrete choices (light vs dark, a few style options), prefer **AskUserQuestion** if it is available. If you are running in **auto mode** and `AskUserQuestion` is unavailable, ask the same question as a plain-text message with clear numbered or bulleted options, and wait for the user's reply. Don't start picking colors until you at least know light-vs-dark and the rough style.\n\n2. **Resolve the actual theme directory and current theme(s).**\n - Resolve the data root by checking `echo \"$KIMI_CODE_HOME\"`; if empty, use `echo \"$HOME/.kimi-code\"`. Use `<root>/themes` for every subsequent step.\n - If tweaking an existing custom theme, **Read** `<KIMI_CODE_HOME>/themes/<name>.json` first — never overwrite a theme you haven't read.\n - Starting fresh: build a `colors` object from the token table. You can `ls <KIMI_CODE_HOME>/themes/` and Read one of the user's existing themes as a reference for the format.\n\n3. **Pick a starting point and choose colors deliberately.**\n - Every value is a 6-digit hex `#RRGGBB` (not 3-digit, not a named color).\n - Keep contrast usable against the user's terminal background: don't let `text` / `textDim` sit too close to the background, and keep `success` / `warning` / `error` clearly distinguishable from each other.\n - `primary` is the most-seen color (links, selection, focus) — make it readable and distinct from `text`.\n - `roleUser` is the one role color meant to stand on its own — give it a distinct hue.\n\n4. **Create a candidate file; never edit the live theme in place.**\n - Use Bash to create a candidate. If the target theme already exists, copy it verbatim: `cp <name>.json <name>.json.new` (inside `<KIMI_CODE_HOME>/themes/`). If it doesn't exist, use **Write** to create a minimal skeleton named `<name>.json.new`.\n - Use **Edit** on the candidate to change only the intended keys. Keep every existing entry, comment, and formatting intact.\n\n5. **Validate the candidate before overwriting.**\n - Read the candidate with **Read** to visually confirm it is well-formed JSON and that every `colors` value is a full 6-digit hex `#RRGGBB` (not 3-digit, not a named color).\n - Invalid hex values are silently skipped at load (they fall back to the base palette), but fix them so the theme renders as intended.\n\n6. **Back up and overwrite.**\n - Back up the old file first — **always** create a new timestamped backup and never overwrite an existing backup: `cp <name>.json \"<name>.json.$(date +%Y%m%d-%H%M%S).bak\"`.\n - If the target didn't exist, skip the backup.\n - Overwrite with the candidate: `mv <name>.json.new <name>.json`.\n\n7. **Tell the user how to apply it** (next section).\n\n## Applying the theme\n\n- The `/theme` picker re-scans the themes directory every time it opens, so a newly added file shows up **without restarting** — tell the user to run `/theme` and choose `Custom: <name>`.\n- Or set it in `tui.toml`: `theme = \"<name>\"`.\n- **Editing the active theme**: changes to the theme that's *currently in use* are not auto-reloaded. Tell the user to run **`/reload-tui`** (or switch to another theme and back). Re-selecting the **same** theme in `/theme` is a no-op (\"Theme unchanged\").\n\n## Don'ts\n\n- **Don't start creating or editing a theme until the user has clarified light/dark, style/mood, any specific colors, and the filename.** If anything is unclear, ask — don't guess.\n- Don't invent token names — only use the documented set; unknown keys are silently ignored.\n- Don't write 3-digit hex or named colors — use full `#RRGGBB`.\n- Never edit the live theme file in place; work through a candidate and validate before `mv`.\n- Before overwriting an existing theme file, **read it and back it up** so the user can recover.\n- Don't tell the user to restart the app to apply a theme — `/theme` or `/reload-tui` is enough.\n";
|
|
65702
65822
|
//#endregion
|
|
65703
65823
|
//#region ../../packages/agent-core/src/skill/builtin/custom-theme.ts
|
|
65704
65824
|
const PSEUDO_PATH$3 = "builtin://custom-theme";
|
|
@@ -65719,7 +65839,7 @@ const CUSTOM_THEME_SKILL = {
|
|
|
65719
65839
|
}
|
|
65720
65840
|
};
|
|
65721
65841
|
//#endregion
|
|
65722
|
-
//#region ../../packages/agent-core/src/skill/builtin/import-from-cc-codex.md
|
|
65842
|
+
//#region ../../packages/agent-core/src/skill/builtin/import-from-cc-codex.md?raw
|
|
65723
65843
|
var import_from_cc_codex_default = "---\nname: import-from-cc-codex\ndescription: Import Claude Code and Codex instructions, skills, and MCP settings into Kimi Code.\ndisable-model-invocation: true\n---\n\n# Import from Claude Code and Codex\n\nThe user invoked `/import-from-cc-codex` (or `/skill:import-from-cc-codex`).\nHelp them migrate selected local Claude Code and Codex assets into Kimi Code.\nThis skill is intentionally conservative: it imports only instructions, skills,\nand MCP server declarations from `.claude` / `.codex` surfaces, with a user\npreview before any write.\n\n## Non-negotiable rules\n\n- Do **not** migrate `.agents` content. Kimi Code already supports `.agents`\n skills and AGENTS files by default.\n- Do **not** migrate Claude custom commands (`.claude/commands/**`). They are\n out of scope for this importer.\n- Do **not** migrate credentials, OAuth tokens, sessions, history, logs, hooks,\n plugins, plugin caches, output styles, or custom agents/subagents.\n- Do **not** run or install anything from the source directories.\n- Do **not** write anything until the user has chosen what to migrate, reviewed\n the final preview, and explicitly confirmed applying it.\n- Only write under Kimi Code targets:\n - User-global: `$KIMI_CODE_HOME` if set, otherwise `~/.kimi-code`.\n - Project instructions/skills: `<project root>/.kimi-code`, where the project\n root is the nearest parent directory containing `.git`; if no `.git` exists,\n use the current working directory.\n - Project-local MCP: `<cwd>/.kimi-code/mcp.json`, because Kimi reads the\n current working directory's Kimi-specific MCP file, not every project-root\n `.kimi-code/mcp.json` from subdirectories.\n- Preserve existing Kimi files. Never overwrite existing skills or replace an\n existing AGENTS.md / mcp.json wholesale.\n\n## Conversation flow\n\n### 1. Ask what to migrate first\n\nBefore reading source files, ask the user which categories to migrate. Use\n`AskUserQuestion` when available; otherwise ask in plain text and stop. Offer a\nmulti-select choice:\n\n- Instructions (`AGENTS.md` / `CLAUDE.md`)\n- Skills\n- MCP settings\n- All of the above\n\nIf the user already gave a preference in the invocation arguments, present it as\nthe default/recommended choice, but still ask for confirmation of the categories.\nIf the user dismisses or refuses the question, stop.\n\n### 2. Scan only the chosen categories\n\nResolve paths explicitly; `~` is the real OS home, and Kimi home follows\n`$KIMI_CODE_HOME` before `~/.kimi-code`.\n\nUser-level sources:\n\n- Claude instructions:\n - `~/.claude/AGENTS.md`\n - `~/.claude/CLAUDE.md`\n- Claude skills:\n - `~/.claude/skills/`\n- Claude MCP candidates:\n - `~/.claude.json` only when MCP is selected. Claude Code stores user-level\n MCP declarations there; do not read it for instruction/skill-only imports.\n- Codex instructions:\n - `~/.codex/AGENTS.md`\n - `~/.codex/CLAUDE.md` if present\n- Codex skills:\n - `~/.codex/skills/`\n- Codex MCP candidates:\n - `~/.codex/config.toml`\n\nProject-level sources, rooted at the project root:\n\n- Claude instructions:\n - `<project root>/.claude/AGENTS.md`\n - `<project root>/.claude/CLAUDE.md`\n- Claude skills:\n - `<project root>/.claude/skills/`\n- Codex instructions:\n - `<project root>/.codex/AGENTS.md`\n - `<project root>/.codex/CLAUDE.md` if present\n- Codex skills:\n - `<project root>/.codex/skills/`\n- Codex MCP candidates:\n - `<project root>/.codex/config.toml`\n\nDo not scan project-root `AGENTS.md`, project-root `CLAUDE.md`, `.agents/**`, or\nproject-root `.mcp.json` in this skill. `AGENTS.md` and `.agents/**` are already\nKimi-readable, and project-root `.mcp.json` is already read by Kimi as a\nClaude-compatible MCP file.\n\n### 3. Build an import plan\n\nCreate a plan with three sections: instructions, skills, and MCP. Include exact\nsource and target paths.\n\n#### Instructions plan\n\nMap user-level instruction sources to:\n\n- `$KIMI_CODE_HOME/AGENTS.md`, or `~/.kimi-code/AGENTS.md` if the env var is not\n set.\n\nMap project-level instruction sources to:\n\n- `<project root>/.kimi-code/AGENTS.md`\n\nAppend imported instruction content as marked blocks. Do not duplicate a block\nthat already exists in the target file.\n\nUse this marker shape:\n\n```md\n<!-- Imported from Claude Code: /absolute/source/path -->\n\n<source content>\n\n<!-- End imported from Claude Code: /absolute/source/path -->\n```\n\nFor Codex, use `Imported from Codex` / `End imported from Codex`.\n\nIf a source file is empty, skip it and report it as skipped. If the target exists\nand cannot be read as UTF-8 text, stop before writing and report the blocker.\n\n#### Skills plan\n\nMap user-level skill sources to:\n\n- `$KIMI_CODE_HOME/skills/`, or `~/.kimi-code/skills/` if the env var is not set.\n\nMap project-level skill sources to:\n\n- `<project root>/.kimi-code/skills/`\n\nRecognize these skill shapes under `.claude/skills/` or `.codex/skills/`:\n\n- Directory bundle: `<skill-name>/SKILL.md`\n- Flat markdown skill: `<skill-name>.md`\n\nCopy the entire directory bundle or flat markdown file. Preserve supporting\nfiles inside bundles. Do not copy hidden directories, `node_modules`, caches, or\nplugin-managed folders.\n\nBefore planning a copy:\n\n- Read a bundle's `SKILL.md` enough to verify that directory skills have\n frontmatter with non-empty `name` and `description`, because Kimi requires\n those fields for directory skills.\n- If the target top-level entry already exists, skip it; do not overwrite.\n- If two source entries would write the same target path, keep the first one in\n this order and report the later one as skipped:\n 1. project Claude\n 2. project Codex\n 3. user Claude\n 4. user Codex\n- Warn when a source skill uses Claude/Codex-specific fields or syntax that Kimi\n may not interpret the same way, such as `allowed-tools`, `disallowed-tools`,\n `context: fork`, `agent`, `hooks`, `paths`, dynamic shell injection with\n ``!`command` ``, or `agents/openai.yaml`. Preserve the file; do not rewrite it\n unless the user explicitly asks.\n\nDo not convert `.claude/commands/*.md`. Commands are out of scope.\n\n#### MCP plan\n\nDo not edit `mcp.json` directly in this import skill. Prepare MCP entries for\nmanual follow-up with `/mcp-config`; that built-in skill is user-invocable only,\nso you must not try to call it through the `Skill` tool.\n\nFor the preview, collect MCP candidates and normalize them into Kimi's MCP shape\nwhen possible:\n\n```json\n{\n \"mcpServers\": {\n \"name\": {\n \"command\": \"...\",\n \"args\": [\"...\"],\n \"env\": { \"KEY\": \"VALUE\" }\n }\n }\n}\n```\n\nClaude user MCP:\n\n- Read `~/.claude.json` only if MCP was selected.\n- Look for a top-level `mcpServers` object.\n- Keep stdio entries with `command`; keep HTTP entries with `url`.\n- Preserve `args`, `env`, `cwd`, `enabled`, `enabledTools`, `disabledTools`,\n `startupTimeoutMs`, `toolTimeoutMs`, `headers`, and `bearerTokenEnvVar` when\n present and valid.\n- Drop unsupported or malformed entries and report why.\n\nCodex MCP:\n\n- Read selected `config.toml` files only if MCP was selected.\n- Look for `[mcp_servers.<name>]` tables.\n- Map Codex fields to Kimi fields:\n - `command` -> `command`\n - `args` -> `args`\n - `env` -> `env`\n - `cwd` -> `cwd`\n - `url` -> `url`\n - `bearer_token_env_var` -> `bearerTokenEnvVar`\n - `enabled` -> `enabled`\n - `enabled_tools` -> `enabledTools`\n - `disabled_tools` -> `disabledTools`\n - `startup_timeout_sec` -> `startupTimeoutMs` in milliseconds\n - `tool_timeout_sec` -> `toolTimeoutMs` in milliseconds\n - `http_headers` -> `headers`\n- Drop unsupported Codex-only fields and report them, especially `required`,\n `default_tools_approval_mode`, `tools.<tool>.approval_mode`,\n `env_vars`, `env_http_headers`, and `experimental_environment`.\n- Do not import project-root `.mcp.json`; Kimi already reads it.\n\nFor each MCP candidate, choose the target scope in the preview:\n\n- User-level source -> user-global MCP target (`$KIMI_CODE_HOME/mcp.json` or\n `~/.kimi-code/mcp.json`).\n- Project-level source -> project-local Kimi MCP target (`<cwd>/.kimi-code/mcp.json`). If `<cwd>` is not the project root, call this out in the preview so the user understands when Kimi will load it.\n\nWarn that stdio MCP entries spawn commands at session start, and the user should\nonly import MCP servers they trust. Warn if an MCP entry contains apparent\nliteral secrets in `env`, `headers`, or token-like fields; prefer env-var\nreferences.\n\nAfter the user confirms applying the final preview, do not write MCP config and\ndo not invoke `mcp-config` programmatically. Instead, finish the non-MCP writes\nand show a copy-pasteable manual follow-up for the user, including:\n\n- the `/mcp-config` command they should run,\n- target scope and target path,\n- the normalized JSON entry or entries to add,\n- collision policy: keep existing Kimi entries on name conflict,\n- the reminder that unrelated entries must be preserved.\n\nMake it clear that MCP import is pending until the user manually runs\n`/mcp-config` with the prepared entries.\n\n### 4. Show the final preview and stop\n\nAfter scanning, show a concise final preview grouped by target file/directory:\n\n- Will append instruction blocks\n- Will copy skill bundles/files\n- Will leave these MCP entries pending for a manual `/mcp-config` follow-up\n- Already present / skipped\n- Warnings and blockers\n\nThen ask for explicit confirmation before writing. Use a clear choice such as:\n\n- Apply import\n- Cancel\n\nIf there are blockers, do not offer apply; explain what must be fixed first.\n\n### 5. Apply only after confirmation\n\nWhen the user confirms:\n\n- Create target directories with private permissions where possible.\n- Append instruction blocks without duplicating existing imported source blocks.\n- Copy skills without overwriting existing target entries.\n- Do not write MCP entries. Show the prepared `/mcp-config` follow-up command\n and mark MCP import as pending user action.\n- Report exactly what changed and what was skipped.\n- Tell the user to start a new session (for example `/new`) or restart Kimi Code\n for newly imported skills, instructions, and MCP servers to be picked up.\n\n## Output style\n\nBe brief but precise. Use absolute paths in previews and summaries. Prefer a\nsmall table or bullet list over long prose. If nothing is found for a selected\ncategory, say so and do not treat it as an error.\n";
|
|
65724
65844
|
//#endregion
|
|
65725
65845
|
//#region ../../packages/agent-core/src/skill/builtin/import-from-cc-codex.ts
|
|
@@ -65741,8 +65861,8 @@ const IMPORT_FROM_CC_CODEX_SKILL = {
|
|
|
65741
65861
|
}
|
|
65742
65862
|
};
|
|
65743
65863
|
//#endregion
|
|
65744
|
-
//#region ../../packages/agent-core/src/skill/builtin/mcp-config.md
|
|
65745
|
-
var mcp_config_default = "---\nname: mcp-config\ndescription: Configure MCP servers and handle MCP OAuth login.\n---\n\n# Interactive MCP server configuration\n\nThe user invoked this skill through `/mcp-config` or `/skill:mcp-config`.\nEither they want to log into an MCP server that asked for OAuth, or they\nwant to edit the `mcp.json` that lists MCP servers. The work is small and\nlocal — handle it on this turn yourself, no agents or planning todos.\n\nPick the flow from the user's message and your tool list:\n\n- An `mcp__<server>__authenticate` tool is in your list, the user says\n \"log in\" / \"auth\" / \"sign in\", they invoke `/mcp-config login\n <server>`, or they quote a `needs-auth` status → **Login**.\n- Add / edit / remove / list of an `mcp.json` entry → **Config edit**.\n- Bare `/mcp-config` with no `authenticate` tool in your list →\n **Config edit**. If there were a pending login, the authenticate tool\n would be in your list.\n\n## Login\n\nEach MCP server in `needs-auth` exposes one `mcp__<server>__authenticate`\ntool. Call it for the server the user means — its own description owns\nthe OAuth UX (printing the URL, blocking on the callback, reconnecting on\nsuccess). Surface its output verbatim, including the authorization URL\nunchanged; the URL contains state and PKCE parameters that break if\nedited.\n\nIf the user named a server that has no authenticate tool, say so in one\nsentence and stop — do **not** fall into config edit. They're trying to\nlog in to a server that isn't currently waiting for login; quietly\nrewriting `mcp.json` would be the wrong fix. If multiple authenticate\ntools exist and the user didn't name one, ask which.\n\n## Config edit\n\nConfig lives in three files; on key collision, later entries in this\nprecedence order override earlier ones
|
|
65864
|
+
//#region ../../packages/agent-core/src/skill/builtin/mcp-config.md?raw
|
|
65865
|
+
var mcp_config_default = "---\nname: mcp-config\ndescription: Configure MCP servers and handle MCP OAuth login.\n---\n\n# Interactive MCP server configuration\n\nThe user invoked this skill through `/mcp-config` or `/skill:mcp-config`.\nEither they want to log into an MCP server that asked for OAuth, or they\nwant to edit the `mcp.json` that lists MCP servers. The work is small and\nlocal — handle it on this turn yourself, no agents or planning todos.\n\nPick the flow from the user's message and your tool list:\n\n- An `mcp__<server>__authenticate` tool is in your list, the user says\n \"log in\" / \"auth\" / \"sign in\", they invoke `/mcp-config login\n <server>`, or they quote a `needs-auth` status → **Login**.\n- Add / edit / remove / list of an `mcp.json` entry → **Config edit**.\n- Bare `/mcp-config` with no `authenticate` tool in your list →\n **Config edit**. If there were a pending login, the authenticate tool\n would be in your list.\n\n## Login\n\nEach MCP server in `needs-auth` exposes one `mcp__<server>__authenticate`\ntool. Call it for the server the user means — its own description owns\nthe OAuth UX (printing the URL, blocking on the callback, reconnecting on\nsuccess). Surface its output verbatim, including the authorization URL\nunchanged; the URL contains state and PKCE parameters that break if\nedited.\n\nIf the user named a server that has no authenticate tool, say so in one\nsentence and stop — do **not** fall into config edit. They're trying to\nlog in to a server that isn't currently waiting for login; quietly\nrewriting `mcp.json` would be the wrong fix. If multiple authenticate\ntools exist and the user didn't name one, ask which.\n\n## Config edit\n\nConfig lives in three files; on key collision, later entries in this\nprecedence order override earlier ones.\n\nThe kimi-code runtime resolves the user-global directory as `KIMI_CODE_HOME`\nfirst, falling back to `~/.kimi-code`. Before touching the user-global file,\nresolve the actual directory with Bash so you don't read or write the wrong\none. Check whether `KIMI_CODE_HOME` is set and fall back to `~/.kimi-code`\nwhen it is empty:\n\n```bash\necho \"$KIMI_CODE_HOME\"\necho \"$HOME/.kimi-code\"\n```\n\nUse the first line when it is non-empty; otherwise use the second line. In the\nrest of this skill, `<KIMI_CODE_HOME>` means that resolved data root —\n**never assume `~/.kimi-code`**.\n\n- User-global: `<KIMI_CODE_HOME>/mcp.json`. Use for servers you want\n everywhere.\n- Project-root: `<project root>/.mcp.json`, where project root is found\n by walking up from `<cwd>` to the nearest `.git`. Use for\n Claude-compatible, repo-shared, or cross-agent servers.\n- Project-local: `<cwd>/.kimi-code/mcp.json`. Use for Kimi-specific\n overrides in the current working directory.\n\nMention once that project-root and project-local stdio entries spawn\ncommands at session start, so they should only live in trusted repos.\n\nAll three files wrap their entries the same way:\n\n```json\n{ \"mcpServers\": { \"<name>\": { /* entry */ } } }\n```\n\nA minimal stdio entry needs `command` (+ optional `args`, `env`, `cwd`).\nFor project-root `.mcp.json`, stdio entries run from the project root by\ndefault; relative `cwd` values are resolved against the directory that\ncontains `.mcp.json`.\nA minimal http entry needs `url`; add `bearerTokenEnvVar: \"ENV_NAME\"` for\nservers that authenticate with a static bearer token from the\nenvironment. Servers that use OAuth take no token field — the login flow\nabove handles them. `transport` is inferred from `command` vs `url`, so\nomit it. For less common fields (`enabled`, `startupTimeoutMs`,\n`toolTimeoutMs`, `enabledTools`, `disabledTools`, `headers`) the source of\ntruth is `McpServerStdioConfigSchema` / `McpServerHttpConfigSchema` in\n`packages/agent-core/src/config/schema.ts`.\n\nIf the user only wants to **see** what's configured, read all three files,\nshow a merged view with enough source-path context to inspect or remove a\nserver from the file that actually declared it, and stop — no scope\nprompt, no write.\n\nFor changes, the flow is:\n\n1. **Pick a scope.** Infer it from the user's words when you can\n (global / everywhere / all projects → user-global; root / repo /\n shared / cross-agent / Claude / `.mcp.json` → project-root; cwd /\n current directory / Kimi-specific / `.kimi-code` → project-local). When\n the request is genuinely scope-less, use one `AskUserQuestion` to ask\n user-global vs project-root vs project-local, defaulting to\n user-global. Use plain text for every other question — `AskUserQuestion`\n is a poor fit for free-form input. If the user dismisses the scope\n question, stop; you can't safely guess where they wanted the change.\n2. **Read and announce.** Read the target file (a missing or empty file\n is fine; you'll create `{ \"mcpServers\": {} }`). If JSON parsing fails,\n surface the error verbatim and stop — silently overwriting a broken\n file could destroy work. Then show the user the target path, what's\n currently in it, and the entry you're about to write or delete. This\n is for transparency, not a confirmation gate — the Edit/Write\n permission prompt is the real gate, and your message is what gives\n the user context when that prompt appears. In yolo / afk modes there\n is no prompt, which is those modes' explicit contract.\n3. **Write and tell them how to reload MCP servers.** Preserve unrelated\n entries and the `mcpServers` wrapper. MCP servers load at session\n start, so tell the user to start a new session (for example `/new`) or\n restart `kimi-code` for the change to take effect.\n\n## Secrets\n\nDon't store secrets (tokens, keys, passwords) as literals in\n`mcp.json` — it's a plain config file on disk. http servers should use\n`bearerTokenEnvVar` to reference an env var instead; if a stdio entry\nmust inline one in `env`, warn the user before writing.\n";
|
|
65746
65866
|
//#endregion
|
|
65747
65867
|
//#region ../../packages/agent-core/src/skill/builtin/mcp-config.ts
|
|
65748
65868
|
const PSEUDO_PATH$1 = "builtin://mcp-config";
|
|
@@ -65763,13 +65883,13 @@ const MCP_CONFIG_SKILL = {
|
|
|
65763
65883
|
}
|
|
65764
65884
|
};
|
|
65765
65885
|
//#endregion
|
|
65766
|
-
//#region ../../packages/agent-core/src/skill/builtin/sub-skill/consolidate/SKILL.md
|
|
65767
|
-
var SKILL_default$2 = "---\nname:
|
|
65886
|
+
//#region ../../packages/agent-core/src/skill/builtin/sub-skill/consolidate/SKILL.md?raw
|
|
65887
|
+
var SKILL_default$2 = "---\nname: consolidate\ndescription: Apply an approved sub-skill grouping by moving user-specified skills into a parent bundle, with timestamped backups of every modified directory.\ndisable-model-invocation: true\n---\n\n# Consolidate sub-skills (`sub-skill.consolidate`)\n\nExecute the reorganization by moving user-specified skills into a parent bundle, forming a sub-skill hierarchy.\n\n## When to use\n\n- The user has approved a grouping proposal (typically from `sub-skill.review`) and wants to apply it.\n- Migrating standalone skills into a new or existing parent bundle.\n\n## Process\n\n1. **Confirm the plan.** Restate which skills will move and where, and ask the user to confirm **before** making any file changes.\n2. **Back up every original skill directory.** Before moving anything, create a timestamped backup of each skill directory that will be modified.\n - For a skill at `<root>/<skill-name>/SKILL.md`, back up the entire `<skill-name>` directory:\n ```bash\n cp -r <skill-name> \"<skill-name>.$(date +%Y%m%d-%H%M%S).bak\"\n ```\n - Keep all backups; never overwrite an existing backup file.\n3. **Create or update the parent bundle.**\n - If the parent does not exist, create `<parent-name>/SKILL.md` with `has-sub-skill: true` in the frontmatter.\n - If the parent already exists, ensure its frontmatter includes `has-sub-skill: true`.\n4. **Move child skills into the parent.** Move each child skill's entire directory under the parent bundle.\n - Example: `web-search/` → `web-research/web-search/`\n5. **Keep documentation directory alignment.** When moving documentation, references, examples, assets, or other payload directories, align them with the new skill directory layout.\n - Preserve relative links from `SKILL.md` to files such as `references/`, `assets/`, `examples/`, or templates.\n - If a child skill moves from `<root>/<child>/` to `<root>/<parent>/<child>/`, its documentation payload should move with that child unless the approved plan says otherwise.\n - Do not leave documentation in the old location or merge unrelated documentation directories together.\n6. **Verify the result.** List the new directory structure and confirm each moved skill still has a valid `SKILL.md` with required frontmatter (`name` and `description`). Check documentation directory alignment and relative links after the move.\n7. **Report the change.** Summarize what was moved, the new structure, any documentation directories that moved, and where backups are located.\n\n## Don'ts\n\n- **Never move skills without backing up first.**\n- **Never overwrite an existing backup** — always use a fresh timestamped suffix.\n- **Don't drop frontmatter or payload files** during the move; the entire directory must be preserved.\n- **Don't break documentation directory alignment** — references, assets, examples, and templates must stay aligned with the skill directory that uses them.\n- **Don't create deeply nested hierarchies** (3+ levels) unless the user explicitly requests it.\n";
|
|
65768
65888
|
//#endregion
|
|
65769
|
-
//#region ../../packages/agent-core/src/skill/builtin/sub-skill/review/SKILL.md
|
|
65770
|
-
var SKILL_default$1 = "---\nname:
|
|
65889
|
+
//#region ../../packages/agent-core/src/skill/builtin/sub-skill/review/SKILL.md?raw
|
|
65890
|
+
var SKILL_default$1 = "---\nname: review\ndescription: Analyze the available skill set and recommend candidate groups that could be consolidated into sub-skill bundles. Read-only — proposes a plan, does not move files.\ndisable-model-invocation: true\n---\n\n# Review sub-skills (`sub-skill.review`)\n\nAnalyze the current skill inventory and identify candidate groups that could be consolidated into sub-skill bundles. This sub-skill is **read-only**: it produces a proposal for the user to review before any file changes are made by `sub-skill.consolidate`.\n\n## When to use\n\n- The user asks to review, reorganize, or audit the skill inventory.\n- There are many loosely-related skills that might benefit from hierarchical grouping.\n- The user wants to evaluate whether a new skill should be a sub-skill of an existing parent.\n\n## Process\n\n1. **List the current inventory.** Use the skill registry (or scan the configured skill roots) to get a full list of skill names, descriptions, and source scopes.\n2. **Categorize by domain.** Group skills by functional domain — e.g. file operations, web tools, collaboration, observability.\n3. **Detect coupling.** Identify skills that are frequently used together or share similar `whenToUse` conditions.\n4. **Flag granularity issues.** Call out skills that are too fine-grained (e.g. one skill per CLI flag) or too broad to land in any single domain.\n5. **Propose sub-skill structures.** For each candidate group, list:\n - The parent skill name and a one-line description.\n - The children that should move under it.\n - Any documentation, reference, example, asset, or template directories that must move with each child so the final directory layout stays aligned.\n - Whether the parent needs `has-sub-skill: true` (it does, if children should be discovered).\n6. **Output a summary report.** Present findings as a concise grouped list with rationale, and stop. Do **not** edit any file — that's `sub-skill.consolidate`'s job.\n\n## Criteria for a good sub-skill grouping\n\n- **Shared context.** Children operate within the same domain or workflow.\n- **Composable entry point.** The parent gives a natural top-level handle; children handle specifics.\n- **Shallow nesting.** Prefer 2 levels (parent → child). Avoid 3+ unless strictly necessary.\n- **Backward compatibility.** Existing skill names should ideally remain discoverable.\n\n## Example output format\n\n```\nProposed sub-skill: web-research\n - Parent: web-research (has-sub-skill: true)\n - Children:\n - web-search → move under web-research/search\n - fetch-url → move under web-research/fetch\n - Documentation alignment: move each child's references/examples/assets with that child.\n - Rationale: Both deal with online information retrieval and are often chained together.\n```\n";
|
|
65771
65891
|
//#endregion
|
|
65772
|
-
//#region ../../packages/agent-core/src/skill/builtin/sub-skill/SKILL.md
|
|
65892
|
+
//#region ../../packages/agent-core/src/skill/builtin/sub-skill/SKILL.md?raw
|
|
65773
65893
|
var SKILL_default = "---\nname: sub-skill\ndescription: Discover and reorganize the skill inventory into hierarchical sub-skill bundles. Use when the user asks to review, group, or consolidate skills into a parent bundle.\ndisable-model-invocation: true\nhas-sub-skill: true\n---\n\n# Sub-skill\n\nContainer skill for analyzing the local skill inventory and reorganizing it into hierarchical sub-skill bundles (`has-sub-skill: true` parents with children inside).\n\n## When to use\n\n- The user asks to review, reorganize, or consolidate skills.\n- There are many loosely-related skills that might benefit from hierarchical grouping.\n- The user wants to evaluate whether a new skill should be a sub-skill of an existing one.\n\n## Sub-skills\n\n- **`sub-skill.review`** — Analyze the current inventory and propose candidate sub-skill groupings.\n- **`sub-skill.consolidate`** — Apply an approved grouping by moving skills into a parent bundle, with timestamped backups.\n\nThe usual flow is `sub-skill.review` first (read-only proposal), then `sub-skill.consolidate` after the user approves a plan. Never run consolidate without an explicit go-ahead from the user.\n";
|
|
65774
65894
|
//#endregion
|
|
65775
65895
|
//#region ../../packages/agent-core/src/skill/builtin/sub-skill.ts
|
|
@@ -65782,6 +65902,7 @@ function makeBuiltin(body, dirName, pseudoPath, extraMetadata = {}) {
|
|
|
65782
65902
|
});
|
|
65783
65903
|
return {
|
|
65784
65904
|
...parsed,
|
|
65905
|
+
name: dirName,
|
|
65785
65906
|
path: pseudoPath,
|
|
65786
65907
|
dir: pseudoPath,
|
|
65787
65908
|
metadata: {
|
|
@@ -65795,11 +65916,17 @@ const SUB_SKILL_PARENT = makeBuiltin(SKILL_default, "sub-skill", "builtin://sub-
|
|
|
65795
65916
|
disableModelInvocation: true,
|
|
65796
65917
|
"has-sub-skill": true
|
|
65797
65918
|
});
|
|
65798
|
-
const SUB_SKILL_REVIEW = makeBuiltin(SKILL_default$1, "sub-skill.review", "builtin://sub-skill/review", {
|
|
65799
|
-
|
|
65919
|
+
const SUB_SKILL_REVIEW = makeBuiltin(SKILL_default$1, "sub-skill.review", "builtin://sub-skill/review", {
|
|
65920
|
+
disableModelInvocation: true,
|
|
65921
|
+
isSubSkill: true
|
|
65922
|
+
});
|
|
65923
|
+
const SUB_SKILL_CONSOLIDATE = makeBuiltin(SKILL_default$2, "sub-skill.consolidate", "builtin://sub-skill/consolidate", {
|
|
65924
|
+
disableModelInvocation: true,
|
|
65925
|
+
isSubSkill: true
|
|
65926
|
+
});
|
|
65800
65927
|
//#endregion
|
|
65801
|
-
//#region ../../packages/agent-core/src/skill/builtin/update-config.md
|
|
65802
|
-
var update_config_default = "---\nname: update-config\ndescription: Inspect or edit kimi-code's own config — `config.toml` (model, provider, permission, hooks) and `tui.toml` (theme, editor, notifications, auto-update). Use when the user asks what a setting does or wants to change one.\n---\n\n# Configure kimi-code (update-config)\n\nHelp the user inspect, change, and validate kimi-code's configuration files. The files are **TOML** with **snake_case** keys.\n\n## The two config files\n\nkimi-code has two TOML config files, both under
|
|
65928
|
+
//#region ../../packages/agent-core/src/skill/builtin/update-config.md?raw
|
|
65929
|
+
var update_config_default = "---\nname: update-config\ndescription: Inspect or edit kimi-code's own config — `config.toml` (model, provider, permission, hooks) and `tui.toml` (theme, editor, notifications, auto-update). Use when the user asks what a setting does or wants to change one.\n---\n\n# Configure kimi-code (update-config)\n\nHelp the user inspect, change, and validate kimi-code's configuration files. The files are **TOML** with **snake_case** keys.\n\n## The two config files\n\nkimi-code has two TOML config files, both under `<KIMI_CODE_HOME>/`, both snake_case, but with different ownership — decide which one the user means before doing anything.\n\nThe runtime resolves the data directory as `KIMI_CODE_HOME` first, falling back to `~/.kimi-code`. Before doing anything, resolve the actual directory with Bash so you don't write to the wrong place. Check whether `KIMI_CODE_HOME` is set and fall back to `~/.kimi-code` when it is empty:\n\n```bash\necho \"$KIMI_CODE_HOME\"\necho \"$HOME/.kimi-code\"\n```\n\nUse the first line when it is non-empty; otherwise use the second line. In the rest of this skill, `<KIMI_CODE_HOME>` means that resolved root — **never assume `~/.kimi-code`**.\n\n- **`config.toml`** — agent / runtime settings: `default_model`, `providers`, `models`, `thinking`, `permission`, `hooks`, `loop_control`, etc.\n- **`tui.toml`** — terminal-UI / client preferences: `theme`, `[editor].command`, `[notifications]`, `[upgrade].auto_install` (auto-update). These can usually also be changed with the interactive commands `/config`, `/theme`, `/editor`, which is easier — prefer pointing the user at those.\n\nThe \"read → copy → Edit → validate → back up → overwrite\" flow below applies to both files; only **which reload command applies** differs (see Capability 4).\n\n## Prerequisite 1: the official docs are the single source of truth\n\nBefore touching any config, use **FetchURL** to fetch the official config docs as the one authoritative reference for fields (key names, types, allowed values, owning section):\n\n```\nhttps://moonshotai.github.io/kimi-code/en/configuration/config-files.html\n```\n\n- Use the **snake_case key names and sections exactly as documented** — don't invent them, don't guess camelCase.\n- If FetchURL is unavailable or the fetch fails, tell the user plainly that you can't reach the online docs, and ask them to paste the relevant section or confirm whether to proceed from what you already know. **Never edit blindly without an authoritative reference.**\n\n## Prerequisite 2: read the target file before any change\n\nBefore any modification, use **Read** on the target config file (decide whether it's `config.toml` or `tui.toml` per the above):\n\n- Location: `<KIMI_CODE_HOME>/config.toml` or `<KIMI_CODE_HOME>/tui.toml`. For other scopes/files, defer to the official docs.\n- A missing or empty file is fine — you'll create a minimal skeleton later.\n- If the file exists but **fails to parse as TOML**, report the error verbatim and **stop** — never overwrite a broken file in place (it could destroy the user's existing config).\n\n---\n\n## Capability 1: explain configuration (read-only, no file changes)\n\nWhen the user asks \"what config is there\", \"what does this setting do\", or \"how do I use it\":\n\n1. Fetch the official docs (Prerequisite 1).\n2. Read the current `config.toml` (Prerequisite 2).\n3. Answer against both: list the relevant sections / keys, what each is for, **current value vs default**, and the allowed-value range; say which file and section each lives in.\n4. Present it as a compact grouped list or table. **Stay read-only — write no files.**\n\n## Capability 2: make changes for the user (copy → Edit → validate → back up → overwrite)\n\nDon't edit the target file in place, and **don't rewrite it from scratch** — instead copy it, Edit the copy, and keep the original out of any broken state the whole time:\n\n1. **Clarify intent**: which key, what value, and which file (`config.toml` or `tui.toml`). Ask in one line if ambiguous; for discrete choices (e.g. scope) AskUserQuestion is fine, but use plain questions for free-form input.\n2. **Read the target file** (Prerequisite 2): Read it to understand the current state and confirm it parses.\n3. **Copy out a candidate (do not create from scratch)**: use **Bash** to copy the target verbatim — `cp config.toml config-new.toml` (same directory, `-new` suffix; for tui.toml, `cp tui.toml tui-new.toml`). **Leave the original untouched for now.**\n - Only when the target doesn't exist (nothing to copy) should you use **Write** to create a minimal skeleton candidate (e.g. just the comment line `# <KIMI_CODE_HOME>/config.toml`).\n4. **Edit the candidate**: use the **Edit** tool on the candidate to **change/add only the target key** — never rewrite the whole file. That way every existing section, entry, comment, and bit of formatting stays exactly as-is; only what should change changes. The candidate is identical to the original, so use the content you read in step 2 to locate the Edit anchor. Check the change against the official docs (key / section / value type / allowed values, snake_case).\n5. **Validate the candidate** (see Capability 3, via `kimi doctor`). **If anything fails, keep Editing the candidate and re-validate, looping until it all passes.**\n6. **Back up and overwrite** (only after validation fully passes):\n - **Back up the old file — always create a new timestamped backup, keep all of them, never overwrite an existing backup.** Copy this exactly with **Bash** (for config.toml): `cp config.toml \"config.toml.$(date +%Y%m%d-%H%M%S).bak\"`; for tui.toml: `cp tui.toml \"tui.toml.$(date +%Y%m%d-%H%M%S).bak\"`. Skip the backup only if the target didn't exist.\n - Overwrite with the candidate: `mv config-new.toml config.toml`.\n - If reload errors after the overwrite, the user can recover from **the most recent timestamped backup**.\n7. Tell the user how to apply it (see Capability 4).\n\n## Capability 3: validate the candidate file (must pass before overwrite)\n\nUse **`kimi doctor`** to validate the candidate you wrote — it doesn't start the TUI and doesn't modify any file; it runs kimi's own parser + schema (syntax and schema together), so it's the authoritative check. Pick the subcommand by which file you changed, and pass the **candidate** path explicitly:\n\n- changed `config.toml` → `kimi doctor config <config-new.toml path>`\n- changed `tui.toml` → `kimi doctor tui <tui-new.toml path>`\n\nWhen a path is passed explicitly the file must exist (your candidate does, so that's fine). **Exit code 0 = pass (valid or skipped); non-zero = a specified file is missing or the config is invalid** — show the output verbatim, fix the candidate, and re-run, looping until it's 0.\n\nThen do two checks `kimi doctor` can't:\n\n1. **Cross-check values against the official docs** (single source of truth): are the key / section / enum values as documented, and snake_case? doctor guarantees \"schema-valid\", but \"valid yet not what the user wanted\" (e.g. a misspelled model alias) needs the docs.\n2. **Completeness**: every existing entry is still present (the candidate fully replaces the target — a dropped line is a deletion).\n\n> To also check whether the currently **active** config is OK overall, run `kimi doctor` with no path (it checks the default `config.toml` + `tui.toml`, showing a missing one as skipped).\n\n## Capability 4: tell the user how to apply changes\n\nOnce local validation passes, tell the user how to make the change take effect — **the reload command depends on which file you changed**:\n\n- changed **`config.toml`** → run **`/reload`** in the TUI (reloads the session and applies `config.toml`; it also reloads `tui.toml`).\n- changed **`tui.toml`** → run **`/reload-tui`** (reloads only `tui.toml`, lighter); `/reload` works too (reloads both).\n- changed both → a single **`/reload`** covers it.\n\nNote: `/reload` is available **only when idle** — if a reply is streaming, press Esc / Ctrl-C to stop first. `kimi doctor` already validated the schema before the overwrite, so reload should apply cleanly; if it still errors, follow the message to fix it or recover from the most recent timestamped backup. If you don't want to reload now, the **next new session** picks it up automatically.\n\n## Don'ts\n\n- **Always back up before overwriting**, with a **timestamped name and all history kept** — don't skip the backup, don't keep only a single `.bak`, don't overwrite an old backup.\n- Don't drop unrelated entries (the candidate fully replaces the target — a dropped line is a deletion).\n- When you can't reach the docs / have no authoritative reference, don't edit by guessing.\n";
|
|
65803
65930
|
//#endregion
|
|
65804
65931
|
//#region ../../packages/agent-core/src/skill/builtin/update-config.ts
|
|
65805
65932
|
const PSEUDO_PATH = "builtin://update-config";
|
|
@@ -65864,7 +65991,7 @@ async function discoverSkills(options) {
|
|
|
65864
65991
|
const warn = options.onWarning ?? (() => {});
|
|
65865
65992
|
const skip = options.onSkippedByPolicy ?? (() => {});
|
|
65866
65993
|
const byName = /* @__PURE__ */ new Map();
|
|
65867
|
-
async function walkSkillDir(dirPath, root, isTopLevel, depth) {
|
|
65994
|
+
async function walkSkillDir(dirPath, root, isTopLevel, depth, subSkillParentName) {
|
|
65868
65995
|
if (depth > MAX_SKILL_SCAN_DEPTH) return;
|
|
65869
65996
|
let entries;
|
|
65870
65997
|
try {
|
|
@@ -65881,7 +66008,7 @@ async function discoverSkills(options) {
|
|
|
65881
66008
|
if (entry === "node_modules" || entry.startsWith(".")) continue;
|
|
65882
66009
|
if (await isDir(entryPath)) subdirs.push(entry);
|
|
65883
66010
|
}
|
|
65884
|
-
const allowedSubSkillBundles = /* @__PURE__ */ new
|
|
66011
|
+
const allowedSubSkillBundles = /* @__PURE__ */ new Map();
|
|
65885
66012
|
for (const entry of directorySkills) {
|
|
65886
66013
|
const skill = await parseAndRegister({
|
|
65887
66014
|
parse,
|
|
@@ -65891,9 +66018,10 @@ async function discoverSkills(options) {
|
|
|
65891
66018
|
root,
|
|
65892
66019
|
onDiscoveredSkill: options.onDiscoveredSkill,
|
|
65893
66020
|
warn,
|
|
65894
|
-
skip
|
|
66021
|
+
skip,
|
|
66022
|
+
subSkillParentName
|
|
65895
66023
|
});
|
|
65896
|
-
if (skill !== void 0 && hasSubSkillEnabled(skill)) allowedSubSkillBundles.
|
|
66024
|
+
if (skill !== void 0 && hasSubSkillEnabled(skill)) allowedSubSkillBundles.set(entry, skill.name);
|
|
65897
66025
|
}
|
|
65898
66026
|
if (isTopLevel) {
|
|
65899
66027
|
if (root.plugin !== void 0) {
|
|
@@ -65933,7 +66061,8 @@ async function discoverSkills(options) {
|
|
|
65933
66061
|
}
|
|
65934
66062
|
for (const entry of subdirs) {
|
|
65935
66063
|
if (directorySkills.has(entry) && !allowedSubSkillBundles.has(entry)) continue;
|
|
65936
|
-
|
|
66064
|
+
const allowedSubSkillParentName = allowedSubSkillBundles.get(entry);
|
|
66065
|
+
await walkSkillDir(path.join(dirPath, entry), root, false, depth + 1, allowedSubSkillParentName ?? subSkillParentName);
|
|
65937
66066
|
}
|
|
65938
66067
|
}
|
|
65939
66068
|
for (const root of options.roots) await walkSkillDir(root.path, root, true, 0);
|
|
@@ -65997,11 +66126,20 @@ async function pushProvidedRoot(out, root, isDir, realpath) {
|
|
|
65997
66126
|
}
|
|
65998
66127
|
async function parseAndRegister(input) {
|
|
65999
66128
|
try {
|
|
66000
|
-
const
|
|
66129
|
+
const parsed = await input.parse({
|
|
66001
66130
|
skillMdPath: input.skillMdPath,
|
|
66002
66131
|
skillDirName: input.skillDirName,
|
|
66003
66132
|
source: input.root.source
|
|
66004
66133
|
});
|
|
66134
|
+
const subSkillParentName = input.subSkillParentName;
|
|
66135
|
+
const skill = subSkillParentName !== void 0 ? {
|
|
66136
|
+
...parsed,
|
|
66137
|
+
name: qualifySubSkillName(subSkillParentName, parsed.name),
|
|
66138
|
+
metadata: {
|
|
66139
|
+
...parsed.metadata,
|
|
66140
|
+
isSubSkill: true
|
|
66141
|
+
}
|
|
66142
|
+
} : parsed;
|
|
66005
66143
|
const discovered = input.root.plugin === void 0 ? skill : {
|
|
66006
66144
|
...skill,
|
|
66007
66145
|
plugin: input.root.plugin
|
|
@@ -66009,7 +66147,7 @@ async function parseAndRegister(input) {
|
|
|
66009
66147
|
input.onDiscoveredSkill?.(discovered);
|
|
66010
66148
|
const key = normalizeSkillName(discovered.name);
|
|
66011
66149
|
if (!input.byName.has(key)) input.byName.set(key, discovered);
|
|
66012
|
-
return
|
|
66150
|
+
return discovered;
|
|
66013
66151
|
} catch (error) {
|
|
66014
66152
|
if (error instanceof UnsupportedSkillTypeError) input.skip({
|
|
66015
66153
|
path: input.skillMdPath,
|
|
@@ -66021,6 +66159,10 @@ async function parseAndRegister(input) {
|
|
|
66021
66159
|
return;
|
|
66022
66160
|
}
|
|
66023
66161
|
}
|
|
66162
|
+
function qualifySubSkillName(parentName, skillName) {
|
|
66163
|
+
if (skillName === parentName || skillName.startsWith(`${parentName}.`)) return skillName;
|
|
66164
|
+
return `${parentName}.${skillName}`;
|
|
66165
|
+
}
|
|
66024
66166
|
function hasSubSkillEnabled(skill) {
|
|
66025
66167
|
const nested = skill.metadata["metadata"];
|
|
66026
66168
|
const nestedFlag = typeof nested === "object" && nested !== null ? nested["has-sub-skill"] === true || nested["hasSubSkill"] === true : false;
|
|
@@ -66149,7 +66291,7 @@ var SkillRegistry = class {
|
|
|
66149
66291
|
}
|
|
66150
66292
|
getModelSkillListing() {
|
|
66151
66293
|
const lines = ["DISREGARD any earlier skill listings. Current available skills:"];
|
|
66152
|
-
const listing = renderGroupedSkills(this.listInvocableSkills(), formatModelSkill);
|
|
66294
|
+
const listing = renderGroupedSkills(this.listInvocableSkills().filter((skill) => skill.metadata.isSubSkill !== true), formatModelSkill);
|
|
66153
66295
|
if (listing.length > 0) lines.push(listing);
|
|
66154
66296
|
return lines.length === 1 ? "" : lines.join("\n");
|
|
66155
66297
|
}
|
|
@@ -66292,10 +66434,10 @@ var SkillManager = class {
|
|
|
66292
66434
|
}
|
|
66293
66435
|
};
|
|
66294
66436
|
//#endregion
|
|
66295
|
-
//#region ../../packages/agent-core/src/agent/swarm/enter-reminder.md
|
|
66437
|
+
//#region ../../packages/agent-core/src/agent/swarm/enter-reminder.md?raw
|
|
66296
66438
|
var enter_reminder_default = "## Swarm Mode\n\nYou are now in \"agent swarm\" mode. The user may send tasks that require a large number of parallel subagents.\n\n## Workflow\n\nYou do not need to use TodoList to record this workflow.\n\n1. First, you may need to do a small amount of exploratory work before deciding how to divide the task across subagents. You may not need subagents during this exploratory phase.\n\n2. After exploring, if you are convinced no subagent is needed to complete the task, tell the user why and wait for further instructions; otherwise, continue with the appropriate delegation.\n\n3. Once you have enough context, do not handle the main work yourself. Use AgentSwarm with a `prompt_template` containing the `{{item}}` placeholder and an `items` array for the requested or appropriate number of subagents, partitioning the problem so each item gives one subagent a distinct part of the work. Pass `subagent_type` when the whole swarm should use a non-default subagent profile.\n\n## Coordination\n\n- Give each subagent a distinct scope of work.\n- Avoid duplicating work across subagents.\n- Avoid assigning conflicting changes or responsibilities to different subagents.\n- Remember that subagents have your full capabilities. Do not overload their prompts with excessive detail; only describe the necessary background and each subagent's specific task.\n- Unless the user explicitly specifies a lower limit, do not try to conserve the number of agents. AgentSwarm supports up to 128 subagents and queues launches automatically, so decompose work as finely as possible while keeping subagent responsibilities non-conflicting; combine tasks only when they are genuinely inseparable. If the subagents only need to read, inspect, or report back without making changes, their scopes may overlap slightly.\n";
|
|
66297
66439
|
//#endregion
|
|
66298
|
-
//#region ../../packages/agent-core/src/agent/swarm/exit-reminder.md
|
|
66440
|
+
//#region ../../packages/agent-core/src/agent/swarm/exit-reminder.md?raw
|
|
66299
66441
|
var exit_reminder_default = "## Swarm Mode Ended\n\nSwarm Mode has ended. You are no longer required to follow the Swarm Mode workflow.\n\nThe user's next request is likely to be a regular request that does not need AgentSwarm. If the request still benefits from parallel subagents, you may call the AgentSwarm tool, but decide from the new request itself rather than the ended Swarm Mode workflow.\n";
|
|
66300
66442
|
//#endregion
|
|
66301
66443
|
//#region ../../packages/agent-core/src/agent/swarm/index.ts
|
|
@@ -73815,6 +73957,10 @@ function abortedToolOutput(toolName, signal) {
|
|
|
73815
73957
|
}
|
|
73816
73958
|
async function runToolCallBatch(step, response) {
|
|
73817
73959
|
if (response.toolCalls.length === 0) return { stopTurn: false };
|
|
73960
|
+
const batchStep = {
|
|
73961
|
+
...step,
|
|
73962
|
+
toolCalls: response.toolCalls
|
|
73963
|
+
};
|
|
73818
73964
|
const calls = response.toolCalls.map((toolCall) => preflightToolCall(step.tools, toolCall));
|
|
73819
73965
|
const scheduler = new ToolScheduler();
|
|
73820
73966
|
const pendingResults = [];
|
|
@@ -73822,19 +73968,19 @@ async function runToolCallBatch(step, response) {
|
|
|
73822
73968
|
try {
|
|
73823
73969
|
for (let index = 0; index < calls.length; index += 1) {
|
|
73824
73970
|
const call = calls[index];
|
|
73825
|
-
const prepared = await prepareToolCall(
|
|
73971
|
+
const prepared = await prepareToolCall(batchStep, call);
|
|
73826
73972
|
pendingResults.push(scheduler.add(prepared.task));
|
|
73827
73973
|
if (prepared.stopBatchAfterThis === true) {
|
|
73828
73974
|
stopTurn = true;
|
|
73829
73975
|
for (const skippedCall of calls.slice(index + 1)) {
|
|
73830
|
-
const skippedTask = await prepareSkippedToolCall(
|
|
73976
|
+
const skippedTask = await prepareSkippedToolCall(batchStep, skippedCall);
|
|
73831
73977
|
pendingResults.push(scheduler.add(skippedTask));
|
|
73832
73978
|
}
|
|
73833
73979
|
break;
|
|
73834
73980
|
}
|
|
73835
73981
|
}
|
|
73836
73982
|
for (const pendingResult of pendingResults) {
|
|
73837
|
-
const result = await finalizePendingToolResult(
|
|
73983
|
+
const result = await finalizePendingToolResult(batchStep, await pendingResult);
|
|
73838
73984
|
if (result.stopTurn === true) stopTurn = true;
|
|
73839
73985
|
await step.dispatchEvent({
|
|
73840
73986
|
type: "tool.result",
|
|
@@ -73989,6 +74135,7 @@ async function runPrepareToolExecutionHook(step, call) {
|
|
|
73989
74135
|
try {
|
|
73990
74136
|
hookResult = await hooks.prepareToolExecution({
|
|
73991
74137
|
toolCall,
|
|
74138
|
+
toolCalls: step.toolCalls,
|
|
73992
74139
|
tool: call.tool,
|
|
73993
74140
|
args,
|
|
73994
74141
|
turnId,
|
|
@@ -74031,6 +74178,7 @@ async function runAuthorizeToolExecutionHook(step, call, args, execution) {
|
|
|
74031
74178
|
try {
|
|
74032
74179
|
return await hooks.authorizeToolExecution({
|
|
74033
74180
|
toolCall: call.toolCall,
|
|
74181
|
+
toolCalls: step.toolCalls,
|
|
74034
74182
|
tool: call.tool,
|
|
74035
74183
|
args,
|
|
74036
74184
|
execution,
|
|
@@ -74086,6 +74234,7 @@ async function finalizePendingToolResult(step, pendingResult) {
|
|
|
74086
74234
|
try {
|
|
74087
74235
|
const effectiveResult = coerceToolResult(await hooks.finalizeToolResult({
|
|
74088
74236
|
toolCall: pendingResult.toolCall,
|
|
74237
|
+
toolCalls: step.toolCalls,
|
|
74089
74238
|
args: pendingResult.args,
|
|
74090
74239
|
result: pendingResult.result,
|
|
74091
74240
|
turnId,
|
|
@@ -79961,16 +80110,16 @@ function normalizeSourcePath(path) {
|
|
|
79961
80110
|
return normalize(path.replaceAll("\\", "/")).replace(/^\.\//, "");
|
|
79962
80111
|
}
|
|
79963
80112
|
//#endregion
|
|
79964
|
-
//#region ../../packages/agent-core/src/profile/default/agent.yaml
|
|
80113
|
+
//#region ../../packages/agent-core/src/profile/default/agent.yaml?raw
|
|
79965
80114
|
var agent_default$1 = "name: agent\ndescription: Default Kimi Code agent\n\nsystemPromptPath: ./system.md\npromptVars:\n roleAdditional: ''\n\ntools:\n - Read\n - Write\n - Edit\n - Grep\n - Glob\n - Bash\n - TaskList\n - TaskOutput\n - TaskStop\n - CronCreate\n - CronList\n - CronDelete\n - ReadMediaFile\n - TodoList\n - Skill\n - WebSearch\n - Agent\n - AgentSwarm\n - FetchURL\n - AskUserQuestion\n - EnterPlanMode\n - ExitPlanMode\n - CreateGoal\n - GetGoal\n - SetGoalBudget\n - UpdateGoal\n - mcp__*\n\nsubagents:\n coder:\n description: Good at general software engineering tasks.\n explore:\n description: Fast codebase exploration with prompt-enforced read-only behavior.\n plan:\n description: Read-only implementation planning and architecture design.\n";
|
|
79966
80115
|
//#endregion
|
|
79967
|
-
//#region ../../packages/agent-core/src/profile/default/coder.yaml
|
|
80116
|
+
//#region ../../packages/agent-core/src/profile/default/coder.yaml?raw
|
|
79968
80117
|
var coder_default = "extends: agent\nname: coder\npromptVars:\n roleAdditional: |\n You are now running as a subagent. All the `user` messages are sent by the main agent. The main agent cannot see your context, it can only see your last message when you finish the task. You must treat the parent agent as your caller. Do not directly ask the end user questions. If something is unclear, explain the ambiguity in your final summary to the parent agent.\nwhenToUse: |\n Use this agent for non-trivial software engineering work that may require reading files, editing code, running commands, and returning a compact but technically complete summary to the parent agent.\ntools:\n - Bash\n - Read\n - ReadMediaFile\n - Glob\n - Grep\n - Write\n - Edit\n - WebSearch\n - FetchURL\n - mcp__*\n";
|
|
79969
80118
|
//#endregion
|
|
79970
|
-
//#region ../../packages/agent-core/src/profile/default/explore.yaml
|
|
80119
|
+
//#region ../../packages/agent-core/src/profile/default/explore.yaml?raw
|
|
79971
80120
|
var explore_default = "extends: agent\nname: explore\npromptVars:\n roleAdditional: |\n You are now running as a subagent. All the `user` messages are sent by the main agent. The main agent cannot see your context, it can only see your last message when you finish the task. You must treat the parent agent as your caller. Do not directly ask the end user questions. If something is unclear, explain the ambiguity in your final summary to the parent agent.\n\n You are a codebase exploration specialist. Your role is EXCLUSIVELY to search, read, and analyze existing code and resources. You do NOT have access to file editing tools.\n\n Your strengths:\n - Rapidly finding files using glob patterns\n - Searching code and text with powerful regex patterns\n - Reading and analyzing file contents\n - Running read-only shell commands (git log, git diff, ls, find, etc.)\n\n Guidelines:\n - Use Glob for broad file pattern matching. Patterns MUST contain a literal anchor (extension or subdirectory); pure wildcards like `*` or `**/*` are rejected by the tool.\n - Use Grep for searching file contents with regex\n - Use Read when you know the specific file path\n - Use Bash ONLY for read-only operations (ls, git status, git log, git diff, find)\n - NEVER use Bash for any file creation or modification commands\n - Adapt your search depth based on the thoroughness level specified by the caller\n - Wherever possible, spawn multiple parallel tool calls for grepping and reading files to maximize speed\n\n If the prompt includes a <git-context> block, use it to orient yourself about the repository state before starting your investigation.\n\n You are meant to be a fast agent. Complete the search request efficiently and report your findings clearly in a structured format.\nwhenToUse: |\n Fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns (e.g. \"src/**/*.yaml\"), search code for keywords (e.g. \"database connection\"), or answer questions about the codebase (e.g. \"how does the auth module work?\"). When calling this agent, specify the desired thoroughness level: \"quick\" for basic searches, \"medium\" for moderate exploration, or \"thorough\" for comprehensive analysis across multiple locations and naming conventions. Use this agent for any read-only exploration that will clearly require more than 3 search queries. Prefer launching multiple explore agents concurrently when investigating independent questions.\ntools:\n - Bash\n - Read\n - ReadMediaFile\n - Glob\n - Grep\n - WebSearch\n - FetchURL\n";
|
|
79972
80121
|
//#endregion
|
|
79973
|
-
//#region ../../packages/agent-core/src/profile/default/init.md
|
|
80122
|
+
//#region ../../packages/agent-core/src/profile/default/init.md?raw
|
|
79974
80123
|
var init_default = "You are a software engineering expert with many years of programming experience. Please explore the current project directory to understand the project's architecture and main details.\n\nTask requirements:\n1. Analyze the project structure and identify key configuration files (such as pyproject.toml, package.json, Cargo.toml, etc.).\n2. Understand the project's technology stack, build process and runtime architecture.\n3. Identify how the code is organized and main module divisions.\n4. Discover project-specific development conventions, testing strategies, and deployment processes.\n\nAfter the exploration, you should do a thorough summary of your findings and overwrite it into `AGENTS.md` file in the project root. You need to refer to what is already in the file when you do so.\n\nFor your information, `AGENTS.md` is a file intended to be read by AI coding agents. Expect the reader of this file know nothing about the project.\n\nYou should compose this file according to the actual project content. Do not make any assumptions or generalizations. Ensure the information is accurate and useful. You must use the natural language that is mainly used in the project's comments and documentation.\n\nPopular sections that people usually write in `AGENTS.md` are:\n\n- Project overview\n- Build and test commands\n- Code style guidelines\n- Testing instructions\n- Security considerations\n";
|
|
79975
80124
|
//#endregion
|
|
79976
80125
|
//#region ../../packages/agent-core/src/profile/default.ts
|
|
@@ -80101,7 +80250,7 @@ function formatPlainObject(record) {
|
|
|
80101
80250
|
return Object.entries(record).filter(([, value]) => value !== void 0 && value !== null).map(([key, value]) => `${fieldName(key)}: ${formatValue(value)}`).join("\n");
|
|
80102
80251
|
}
|
|
80103
80252
|
//#endregion
|
|
80104
|
-
//#region ../../packages/agent-core/src/tools/background/task-list.md
|
|
80253
|
+
//#region ../../packages/agent-core/src/tools/background/task-list.md?raw
|
|
80105
80254
|
var task_list_default = "List background tasks and their current status.\n\nUse this tool to discover which background tasks exist and where each one\nstands. It is the entry point for inspecting background work: it returns a\ntask ID, status, command, description, and PID for every task it reports,\nplus the exit code and stop reason for tasks that have already finished.\n\nGuidelines:\n\n- After a context compaction, or whenever you are unsure which background\n tasks are running or what their task IDs are, call this tool to\n re-enumerate them instead of guessing a task ID.\n- Prefer the default `active_only=true`, which lists only non-terminal tasks.\n Pass `active_only=false` only when you specifically need to see tasks that\n have already finished. With `active_only=false` the result may also include\n `lost` tasks — tasks left over from a previous process that can no longer be\n inspected or controlled; treat them as already terminated.\n- `limit` caps how many tasks are returned. It accepts a value between 1 and\n 100 and defaults to 20 when omitted.\n- This tool only lists tasks; it does not return their output. Use it first\n to locate the task ID you need, then call `TaskOutput` with that ID to read\n the task's output and details.\n- This tool is read-only and does not change any state, so it is always safe\n to call, including in plan mode.\n";
|
|
80106
80255
|
//#endregion
|
|
80107
80256
|
//#region ../../packages/agent-core/src/tools/background/task-list.ts
|
|
@@ -80142,7 +80291,7 @@ var TaskListTool = class {
|
|
|
80142
80291
|
}
|
|
80143
80292
|
};
|
|
80144
80293
|
//#endregion
|
|
80145
|
-
//#region ../../packages/agent-core/src/tools/background/task-output.md
|
|
80294
|
+
//#region ../../packages/agent-core/src/tools/background/task-output.md?raw
|
|
80146
80295
|
var task_output_default = "Retrieve output from a running or completed background task.\n\nUse this after `Bash(run_in_background=true)` or `Agent(run_in_background=true)` when you need to inspect progress or explicitly wait for completion.\n\nGuidelines:\n- Prefer relying on automatic completion notifications. Use this tool only when you need task output before the automatic notification arrives.\n- By default this tool is non-blocking and returns a current status/output snapshot.\n- Use block=true only when you intentionally want to wait for completion or timeout.\n- This tool returns structured task metadata, a fixed-size output preview, and an output_path for the full log.\n- For a terminal task, the metadata also explains why it ended: `status: timed_out` when a task was aborted by its deadline, and `stop_reason` when the task was explicitly stopped. `terminal_reason` is a categorical label for the same event — its value is `timed_out` or `stopped` — and is emitted alongside the matching status / `stop_reason` field. A task that ended on its own emits neither `stop_reason` nor `terminal_reason`.\n- The full, never-truncated log is always available at output_path; use the `Read` tool with that path to page through it, whether or not the preview was truncated.\n- This tool works with the generic background task system and should remain the primary read path for future task types, not just bash.\n";
|
|
80147
80296
|
//#endregion
|
|
80148
80297
|
//#region ../../packages/agent-core/src/tools/background/task-output.ts
|
|
@@ -80237,7 +80386,7 @@ var TaskOutputTool = class {
|
|
|
80237
80386
|
}
|
|
80238
80387
|
};
|
|
80239
80388
|
//#endregion
|
|
80240
|
-
//#region ../../packages/agent-core/src/tools/background/task-stop.md
|
|
80389
|
+
//#region ../../packages/agent-core/src/tools/background/task-stop.md?raw
|
|
80241
80390
|
var task_stop_default = "Stop a running background task.\n\nOnly use this when a task must genuinely be cancelled — for a task that is\nfinishing normally, wait for its completion notification or inspect it with\n`TaskOutput` instead of stopping it.\n\nGuidelines:\n- This is a general-purpose stop capability for any background task. It is not\n a bash-specific kill.\n- Stopping a task is destructive: it may leave partial side effects behind.\n Use it with care.\n- If the task has already finished, this tool simply returns its current\n status.\n";
|
|
80242
80391
|
//#endregion
|
|
80243
80392
|
//#region ../../packages/agent-core/src/tools/background/task-stop.ts
|
|
@@ -80311,7 +80460,7 @@ function pad(n) {
|
|
|
80311
80460
|
return String(n).padStart(2, "0");
|
|
80312
80461
|
}
|
|
80313
80462
|
//#endregion
|
|
80314
|
-
//#region ../../packages/agent-core/src/tools/cron/cron-create.md
|
|
80463
|
+
//#region ../../packages/agent-core/src/tools/cron/cron-create.md?raw
|
|
80315
80464
|
var cron_create_default = "Schedule a prompt to be enqueued at a future time. Use for both recurring schedules and one-shot reminders.\n\nUses standard 5-field cron in the user's local timezone: minute hour day-of-month month day-of-week. `0 9 * * *` means 9am local — no timezone conversion needed.\n\n## One-shot tasks (recurring: false)\n\nFor \"remind me at X\" or \"at <time>, do Y\" requests — fire once then auto-delete.\nPin minute/hour/day-of-month/month to specific values:\n \"remind me at 2:30pm today to check the deploy\" → cron: \"30 14 <today_dom> <today_month> *\", recurring: false\n \"tomorrow morning, run the smoke test\" → cron: \"57 8 <tomorrow_dom> <tomorrow_month> *\", recurring: false\n\n## Recurring jobs (recurring: true, the default)\n\nFor \"every N minutes\" / \"every hour\" / \"weekdays at 9am\" requests:\n \"*/5 * * * *\" (every 5 min), \"0 * * * *\" (hourly), \"0 9 * * 1-5\" (weekdays at 9am local)\n\n## Avoid the :00 and :30 minute marks when the task allows it\n\nEvery user who asks for \"9am\" gets `0 9`, and every user who asks for \"hourly\" gets `0 *` — which means requests from across the planet land on the API at the same instant. When the user's request is approximate, pick a minute that is NOT 0 or 30:\n \"every morning around 9\" → \"57 8 * * *\" or \"3 9 * * *\" (not \"0 9 * * *\")\n \"hourly\" → \"7 * * * *\" (not \"0 * * * *\")\n \"in an hour or so, remind me to...\" → pick whatever minute you land on, don't round\n\nOnly use minute 0 or 30 when the user names that exact time and clearly means it (\"at 9:00 sharp\", \"at half past\", coordinating with a meeting). When in doubt, nudge a few minutes early or late — the user will not notice, and the fleet will.\n\n## Coalesce semantics\n\nIf the scheduler slept past multiple ideal fire times (laptop closed, long-running turn, etc.), only **one** fire is delivered when it wakes up. The origin carries `coalescedCount` showing how many ideal fires were collapsed into this single delivery. You should treat `coalescedCount > 1` as \"I missed some checks; only the latest state matters\" rather than running the prompt that many times.\n\n## Cron-fire envelope\n\nWhen a cron task fires, the prompt you scheduled is re-injected wrapped in an XML envelope that exposes the fire context:\n\n```\n<cron-fire jobId=\"...\" cron=\"...\" recurring=\"true|false\" coalescedCount=\"N\" stale=\"true|false\">\n<prompt>\nyour original prompt text, verbatim\n</prompt>\n</cron-fire>\n```\n\nThe envelope is parseable. Use `coalescedCount > 1` to know multiple ideal fires were collapsed into a single delivery (treat as \"only the latest state matters\"), and `stale=\"true\"` as a cue that the task is past its 7-day threshold.\n\n## 7-day stale behavior\n\nRecurring tasks that have been alive for more than 7 days fire one\nfinal time with `stale: true` on the envelope, and the system then\nauto-deletes the task. The flag is the model's notice that this is\nthe last delivery. If the schedule is still wanted, call `CronCreate`\nagain with the same `cron` and `prompt` — that resets `createdAt` and\nstarts a fresh 7-day window. One-shot tasks are never marked stale.\n\nBench / acceptance runs can set `KIMI_CRON_NO_STALE=1` to disable the\njudgment entirely.\n\n## Jitter behavior\n\nAnti-herd jitter is applied deterministically per task id:\n - Recurring: ideal fire time is shifted **forward** by an offset ≤ min(10% of the cron period, 15 minutes). A `*/5 * * * *` task can drift up to 30s; a `0 9 * * *` task can drift up to 15 minutes.\n - One-shot: only when the ideal fire lands on `:00` or `:30` of the hour, the fire is pulled **earlier** by ≤ 90 seconds. Other minutes pass through unchanged.\n\nBench / acceptance tests can set `KIMI_CRON_NO_JITTER=1` to disable jitter entirely.\n\n## One-shot vs recurring — when to pick which\n\nUse `recurring: false` for \"remind me at X\" style requests, single deadlines, \"in N minutes do Y\", and any task that should not repeat. Use `recurring: true` for periodic polling (CI status, build watchers, scheduled reports), workday rituals, and anything the user explicitly described as recurring.\n\n## Session lifetime\n\nCron tasks live in the current kimi CLI session. When you exit, they\nare persisted under the session homedir; the next `kimi resume` of the\nsame session reloads them and the scheduler resumes from each task's\n`createdAt`. Fire times that fell during the offline window are\ncollapsed into a single delivery via `coalescedCount` (and recurring\ntasks past their 7-day window arrive with `stale: true` as their final\ndelivery).\n\nTasks do **not** carry over into a brand-new session — they are scoped\nto the resumed session id, not to the working directory.\n\n## Returned fields\n\n`id` (8-hex), `humanSchedule` (English summary), `recurring`,\n`nextFireAt` (local ISO timestamp with numeric offset, or null). `id` is needed by `CronDelete`.\n\n## Tell the user how to cancel or modify\n\nAfter successfully creating a task, proactively tell the user how they can cancel or modify it later. Users have no direct `/cron` command or self-service UI to manage reminders themselves; they must ask the model to make changes (e.g. \"cancel my 9am reminder\" or \"change my daily check to 10am\"). Include the task `id` in your message so the user can reference it.\n";
|
|
80316
80465
|
/**
|
|
80317
80466
|
* Hard ceiling on `prompt` byte length (UTF-8). The zod `.max(...)`
|
|
@@ -80433,7 +80582,7 @@ function formatOutput(o) {
|
|
|
80433
80582
|
].join("\n");
|
|
80434
80583
|
}
|
|
80435
80584
|
//#endregion
|
|
80436
|
-
//#region ../../packages/agent-core/src/tools/cron/cron-delete.md
|
|
80585
|
+
//#region ../../packages/agent-core/src/tools/cron/cron-delete.md?raw
|
|
80437
80586
|
var cron_delete_default = "Cancel a scheduled cron job by id.\n\nUse this tool to remove a cron task previously scheduled with\n`CronCreate`. The `id` is the 8-hex value returned by `CronCreate`, or\nshown in the `id:` column of `CronList` — quote it verbatim, no\nprefix.\n\nBehaviour by task kind:\n\n- **Recurring task** (`recurring: true`): stops all future fires\n immediately. The scheduler picks up the deletion on its next tick.\n- **One-shot task** (`recurring: false`): cancels the pending fire if\n it has not happened yet. One-shots that have already fired\n auto-delete themselves, so calling `CronDelete` on a fired one-shot\n returns \"no cron job with id ...\".\n\nNot-found is reported as an error (not a silent no-op) so you can\ncorrect yourself — typically by calling `CronList` to see which ids\nare actually live, rather than re-trying with the same stale id.\n\nRefresh pattern (use when you want a stale recurring schedule to\ncontinue):\n\nStale recurring tasks are auto-deleted by the system after their final\nfire — there is nothing for `CronDelete` to remove at that point. To\nkeep the schedule running, just call `CronCreate` with the same `cron`\nand `prompt`. Use `CronList`'s `prompt` field to recall the original\ntext after a context compaction.\n\n`CronDelete` remains the right call when you want to cancel a task\nthat is still live (recurring not yet stale, or a one-shot still\npending).\n\nGuidelines:\n\n- Users have no direct `/cron` command or self-service UI to delete\n tasks themselves; they must ask the model to cancel a reminder.\n When deleting on behalf of a user, confirm the action and report\n the result plainly.\n- Cron deletion is irreversible — there is no undo. If you delete the\n wrong task, you must re-create it with `CronCreate`.\n- If the model is unsure which id is current (e.g. after a context\n compaction), call `CronList` first rather than guessing.\n";
|
|
80438
80587
|
//#endregion
|
|
80439
80588
|
//#region ../../packages/agent-core/src/tools/cron/cron-delete.ts
|
|
@@ -80514,7 +80663,7 @@ var CronDeleteTool = class {
|
|
|
80514
80663
|
}
|
|
80515
80664
|
};
|
|
80516
80665
|
//#endregion
|
|
80517
|
-
//#region ../../packages/agent-core/src/tools/cron/cron-list.md
|
|
80666
|
+
//#region ../../packages/agent-core/src/tools/cron/cron-list.md?raw
|
|
80518
80667
|
var cron_list_default = "List all cron jobs currently scheduled in this session.\n\nUse this tool to see every pending cron task — both recurring jobs and\none-shot reminders — that you (or the user) have scheduled with\n`CronCreate`. The output is the entry point for inspecting scheduled\nwork: it returns a stable id, the original cron expression, a human\nrendering, the next post-jitter fire time, the recurring flag, the\ntask's age in days, and a stale indicator.\n\nEach record carries:\n\n- `id` — the 8-hex task id. Pass this to `CronDelete` to remove the\n task, or quote it in user-facing messages when asking for\n confirmation.\n- `cron` — the verbatim 5-field cron expression as scheduled.\n- `humanSchedule` — plain-English rendering (e.g. `every 5 minutes`).\n- `prompt` — the scheduled prompt text, JSON-encoded so embedded\n newlines stay on one line. Truncated to 200 UTF-8 bytes with\n `…(truncated)` if longer. Use this to recall what a task is for\n after a context compaction, and as the source for the\n `CronCreate` refresh ritual.\n- `nextFireAt` — local ISO timestamp with an explicit numeric offset\n for the next fire **after jitter has been applied**. The actual fire\n may land slightly before or after a round `:00` / `:30` minute mark\n due to herd-avoidance jitter; this is the value the scheduler will\n compare against, so it reflects what will really happen. `null` if\n the expression has no fire in the next 5 years (should not happen\n for tasks created through `CronCreate`, which validates).\n- `recurring` — `true` for cadenced jobs, `false` for one-shots.\n- `ageDays` — `(now - createdAt) / day`, two decimal places. Useful\n when deciding whether a long-running cron is still relevant.\n- `stale` — `true` when a recurring task is older than 7 days. The\n system **auto-deletes the task after this fire** to bound session\n lifetime; the `stale: true` flag is the model's notice that this is\n the final delivery. To resume the same schedule, call `CronCreate`\n again with the original `cron` and `prompt` (the `prompt` row above\n carries it for exactly this purpose). One-shots are never marked\n stale — they fire at most once by construction.\n `KIMI_CRON_NO_STALE=1` disables the judgment entirely (bench /\n acceptance runs).\n\nGuidelines:\n\n- This tool is read-only and never mutates state, so it is always\n safe to call (including in plan mode).\n- Users cannot directly manage cron tasks themselves; if they want to\n cancel or modify a schedule, route the request through the model\n (i.e. call `CronDelete` or `CronCreate` on their behalf).\n- The empty case returns `cron_jobs: 0\\nNo cron jobs scheduled.`. Cron\n tasks survive a `kimi resume` of the same session but do not bleed\n into new sessions.\n- After a context compaction, or whenever you are unsure which cron\n jobs are live, call this tool to re-enumerate them rather than\n guessing ids from earlier in the conversation.\n- Records are separated by a line containing just `---`, in the\n insertion order they were scheduled.\n";
|
|
80519
80668
|
//#endregion
|
|
80520
80669
|
//#region ../../packages/agent-core/src/tools/cron/cron-list.ts
|
|
@@ -81170,7 +81319,7 @@ var SubagentBatch = class {
|
|
|
81170
81319
|
}
|
|
81171
81320
|
};
|
|
81172
81321
|
//#endregion
|
|
81173
|
-
//#region ../../packages/agent-core/src/session/summary-continuation.md
|
|
81322
|
+
//#region ../../packages/agent-core/src/session/summary-continuation.md?raw
|
|
81174
81323
|
var summary_continuation_default = "Your previous response was too brief. Please provide a more comprehensive summary that includes:\n\n1. Specific technical details and implementations\n2. Detailed findings and analysis\n3. All important information that the parent agent should know";
|
|
81175
81324
|
//#endregion
|
|
81176
81325
|
//#region ../../packages/agent-core/src/session/subagent-host.ts
|
|
@@ -81504,13 +81653,13 @@ function shouldSuppressQueuedAttemptFailureEvent(options, error) {
|
|
|
81504
81653
|
return isAbortError$3(error) || options.signal.aborted;
|
|
81505
81654
|
}
|
|
81506
81655
|
//#endregion
|
|
81507
|
-
//#region ../../packages/agent-core/src/tools/builtin/collaboration/agent-background-disabled.md
|
|
81656
|
+
//#region ../../packages/agent-core/src/tools/builtin/collaboration/agent-background-disabled.md?raw
|
|
81508
81657
|
var agent_background_disabled_default = "Background agent execution is disabled for this agent. Do not set `run_in_background=true`.";
|
|
81509
81658
|
//#endregion
|
|
81510
|
-
//#region ../../packages/agent-core/src/tools/builtin/collaboration/agent-background-enabled.md
|
|
81659
|
+
//#region ../../packages/agent-core/src/tools/builtin/collaboration/agent-background-enabled.md?raw
|
|
81511
81660
|
var agent_background_enabled_default = "When `run_in_background=true`, the subagent runs detached from this turn. The completion arrives in a later turn as a synthetic user-role message containing its result — you do not need to poll, sleep, or check on its progress. Continue with other work or respond to the user. Never fabricate or predict what the result will say.\n";
|
|
81512
81661
|
//#endregion
|
|
81513
|
-
//#region ../../packages/agent-core/src/tools/builtin/collaboration/agent.md
|
|
81662
|
+
//#region ../../packages/agent-core/src/tools/builtin/collaboration/agent.md?raw
|
|
81514
81663
|
var agent_default = "Launch a subagent to handle a task. The subagent runs as a same-process loop instance with its own context and wire file.\n\nWriting the prompt:\n- The subagent starts with zero context — it has not seen this conversation. Brief it like a colleague who just walked into the room: state the goal, list what you already know, hand over the specifics.\n- Lookups (read this file, run that test): put the exact path or command in the prompt. The subagent should not have to search for things you already know.\n- Investigations (figure out X, find why Y): give the question, not prescribed steps — fixed steps become dead weight when the premise is wrong.\n- Do not delegate understanding. If the task hinges on a file path or line number, find it yourself first and write it into the prompt.\n\nUsage notes:\n- When the task continues earlier work a subagent already did, prefer resuming that agent (pass its `resume` id) over spawning a fresh instance — the resumed agent keeps its prior context.\n- A subagent's result is only visible to you, not to the user. When the user needs to see what a subagent produced, summarize the relevant parts yourself in your own reply.\n- Subagents use a fixed 30-minute timeout. If one times out, resume the same agent instead of starting over.\n\nWhen NOT to use Agent: skip delegation for trivial work you can do directly — reading a file whose path you already know, searching a small known set of files, or any task that takes only a step or two. Delegation has a context-handoff cost; it pays off only when the task is substantial enough to outweigh it.\n\nOnce a subagent is running, leave that scope to it: do not redo its searches or reads in parallel, and do not abandon it midway and finish the job manually. Both undo the context savings the delegation was meant to buy.\n";
|
|
81515
81664
|
//#endregion
|
|
81516
81665
|
//#region ../../packages/agent-core/src/tools/builtin/collaboration/agent.ts
|
|
@@ -81731,8 +81880,8 @@ function buildSubagentDescriptions(subagents) {
|
|
|
81731
81880
|
}).join("\n");
|
|
81732
81881
|
}
|
|
81733
81882
|
//#endregion
|
|
81734
|
-
//#region ../../packages/agent-core/src/tools/builtin/collaboration/agent-swarm.md
|
|
81735
|
-
var agent_swarm_default = "Launch multiple subagents from one prompt template, existing agent resumes, or both.\n\nUse AgentSwarm when many subagents should run the same kind of task over different inputs. The placeholder is exactly `{{item}}`. For example, with `prompt_template` set to `Review {{item}} for likely regressions.` and `items` set to `[\"src/a.ts\", \"src/b.ts\"]`, AgentSwarm launches two new subagents with those two concrete prompts.\n\nUse `resume_agent_ids` to continue subagents that already exist from earlier work, such as ones that failed or timed out: map each agent id to the prompt for that resumed subagent (usually `continue` if no extra information is needed). You may combine `resume_agent_ids` with `items` in the same call to resume existing subagents and launch new ones. Do not duplicate resumed work in `items`.\n\nUse enough subagents to keep the work focused and parallel. AgentSwarm supports up to 128 subagents, and launches are queued automatically, so it is safe to split large tasks into many clear, independent items.\n";
|
|
81883
|
+
//#region ../../packages/agent-core/src/tools/builtin/collaboration/agent-swarm.md?raw
|
|
81884
|
+
var agent_swarm_default = "Launch multiple subagents from one prompt template, existing agent resumes, or both.\n\nUse AgentSwarm when many subagents should run the same kind of task over different inputs. The placeholder is exactly `{{item}}`. For example, with `prompt_template` set to `Review {{item}} for likely regressions.` and `items` set to `[\"src/a.ts\", \"src/b.ts\"]`, AgentSwarm launches two new subagents with those two concrete prompts.\n\nUse `resume_agent_ids` to continue subagents that already exist from earlier work, such as ones that failed or timed out: map each agent id to the prompt for that resumed subagent (usually `continue` if no extra information is needed). You may combine `resume_agent_ids` with `items` in the same call to resume existing subagents and launch new ones. Do not duplicate resumed work in `items`.\n\nUse enough subagents to keep the work focused and parallel. AgentSwarm supports up to 128 subagents, and launches are queued automatically, so it is safe to split large tasks into many clear, independent items.\n\nIf `AgentSwarm` is called, that call must be the only tool call in the response.\n";
|
|
81736
81885
|
//#endregion
|
|
81737
81886
|
//#region ../../packages/agent-core/src/tools/builtin/collaboration/agent-swarm.ts
|
|
81738
81887
|
const DEFAULT_SUBAGENT_TYPE = "coder";
|
|
@@ -81892,7 +82041,7 @@ function escapeXmlAttribute(value) {
|
|
|
81892
82041
|
return value.replaceAll("&", "&").replaceAll("\"", """).replaceAll("<", "<").replaceAll(">", ">");
|
|
81893
82042
|
}
|
|
81894
82043
|
//#endregion
|
|
81895
|
-
//#region ../../packages/agent-core/src/tools/builtin/collaboration/ask-user.md
|
|
82044
|
+
//#region ../../packages/agent-core/src/tools/builtin/collaboration/ask-user.md?raw
|
|
81896
82045
|
var ask_user_default = "Use this tool when you need to ask the user questions with structured options during execution. This allows you to:\n1. Collect user preferences or requirements before proceeding\n2. Resolve ambiguous or underspecified instructions\n3. Let the user decide between implementation approaches as you work\n4. Present concrete options when multiple valid directions exist\n\n**When NOT to use:**\n- When you can infer the answer from context — be decisive and proceed\n- Trivial decisions that don't materially affect the outcome\n\nOverusing this tool interrupts the user's flow. Only use it when the user's input genuinely changes your next action.\n\n**Usage notes:**\n- Users always have an \"Other\" option for custom input — don't create one yourself\n- Use multi_select to allow multiple answers to be selected for a question\n- Keep option labels concise (1-5 words), use descriptions for trade-offs and details\n- Each question should have 2-4 meaningful, distinct options\n- You can ask 1-4 questions at a time; group related questions to minimize interruptions\n- If you recommend a specific option, list it first and append \"(Recommended)\" to its label\n";
|
|
81897
82046
|
//#endregion
|
|
81898
82047
|
//#region ../../packages/agent-core/src/tools/builtin/collaboration/ask-user.ts
|
|
@@ -82054,7 +82203,7 @@ function isQuestionResponse(result) {
|
|
|
82054
82203
|
return typeof answers === "object" && answers !== null && !Array.isArray(answers);
|
|
82055
82204
|
}
|
|
82056
82205
|
//#endregion
|
|
82057
|
-
//#region ../../packages/agent-core/src/tools/builtin/collaboration/skill-tool.md
|
|
82206
|
+
//#region ../../packages/agent-core/src/tools/builtin/collaboration/skill-tool.md?raw
|
|
82058
82207
|
var skill_tool_default = "Invoke a registered skill from the current skill listing. BLOCKING REQUIREMENT: when a skill from the listing matches the user's request, you MUST call this tool (not free-form text). Do NOT call the same skill repeatedly inside one turn — recursive depth is capped at {{ MAX_SKILL_QUERY_DEPTH }}.";
|
|
82059
82208
|
var NestedSkillTooDeepError = class extends Error {
|
|
82060
82209
|
skillName;
|
|
@@ -82182,7 +82331,7 @@ function makeCarriageReturnsVisible(text) {
|
|
|
82182
82331
|
return text.replaceAll("\r", "\\r");
|
|
82183
82332
|
}
|
|
82184
82333
|
//#endregion
|
|
82185
|
-
//#region ../../packages/agent-core/src/tools/builtin/file/edit.md
|
|
82334
|
+
//#region ../../packages/agent-core/src/tools/builtin/file/edit.md?raw
|
|
82186
82335
|
var edit_default = "Perform exact replacements in existing files.\n\n- Edit is mandatory for every incremental change, especially small edits. DO NOT use Write or Bash `sed`.\n- Read the target file before every Edit. DO NOT call Edit from memory, stale context, or a guessed `old_string`.\n- Take `old_string` and `new_string` from the Read output view.\n- Drop the line-number prefix and tab; match only file content.\n- `old_string` must be unique unless `replace_all` is set.\n- If `old_string` is ambiguous, add surrounding context. Use `replace_all` only when every occurrence should change.\n- Multiple Edit calls may run in one response only when they do not target the same file.\n- DO NOT issue consecutive Edit calls on the same file. A previous Edit can invalidate a later Edit's `old_string`, causing `old_string not found`. Read the file again before the next Edit.\n- A write lock serializes same-file edits in response order, but serialization does not make stale `old_string` valid.\n- For pure CRLF files, Read shows LF; use LF in `old_string` and `new_string`, and Edit writes CRLF back.\n- For mixed endings or lone carriage returns, Read shows carriage returns as \\r; include actual \\r escapes in those positions.\n";
|
|
82187
82336
|
//#endregion
|
|
82188
82337
|
//#region ../../packages/agent-core/src/tools/builtin/file/edit.ts
|
|
@@ -82285,7 +82434,7 @@ var EditTool = class {
|
|
|
82285
82434
|
}
|
|
82286
82435
|
};
|
|
82287
82436
|
//#endregion
|
|
82288
|
-
//#region ../../packages/agent-core/src/tools/builtin/file/glob.md
|
|
82437
|
+
//#region ../../packages/agent-core/src/tools/builtin/file/glob.md?raw
|
|
82289
82438
|
var glob_default = "Find files (and optionally directories) by glob pattern, sorted by modification time (most recent first).\n\nGood patterns:\n- `*.ts` — files in the current directory matching an extension\n- `src/**/*.ts` — recursive walk with a subdirectory anchor and extension\n- `**/*.py` — recursive walk from the search root for an extension\n- `*.{ts,tsx}` — brace expansion is supported; expanded into `*.ts` and `*.tsx` before walking\n- `{src,test}/**/*.ts` — cartesian brace expansion is supported too\n\nResults are capped at the first 100 matching paths (walk order, not global modification-time order). If a search would return more, a truncation marker is appended with the count of matches seen so far. Refine the pattern (extension, subdirectory) when 100 is not enough, or call again with a narrower anchor.\n\nLarge-directory caveat — avoid recursing into dependency / build output even with an anchor:\n- `node_modules/**/*.js`, `.venv/**/*.py`, `__pycache__/**`, `target/**` all match technically but\n typically produce thousands of results that truncate at the match cap and waste the caller context.\n Prefer specific subpaths like `node_modules/react/src/**/*.js`.\n";
|
|
82290
82439
|
//#endregion
|
|
82291
82440
|
//#region ../../packages/agent-core/src/tools/builtin/file/glob.ts
|
|
@@ -87012,7 +87161,7 @@ var ToolResultBuilder = class {
|
|
|
87012
87161
|
}
|
|
87013
87162
|
};
|
|
87014
87163
|
//#endregion
|
|
87015
|
-
//#region ../../packages/agent-core/src/tools/builtin/file/grep.md
|
|
87164
|
+
//#region ../../packages/agent-core/src/tools/builtin/file/grep.md?raw
|
|
87016
87165
|
var grep_default = "Search file contents using regular expressions (powered by ripgrep).\n\nUse Grep when the task is to find unknown content or unknown file locations. Do not use shell `grep` or `rg` directly; this tool applies workspace path policy, output limits, and sensitive-file filtering.\nALWAYS use Grep tool instead of running `grep` or `rg` from a shell — direct shell calls bypass workspace policy, output limits, and sensitive-file filtering.\nIf you already know a concrete file path and need to inspect its contents, use Read directly instead.\n\nWrite patterns in ripgrep regex syntax, which differs from POSIX `grep` syntax. For example, braces are special, so escape them as `\\{` to match a literal `{`.\n\nHidden files (dotfiles such as `.gitlab-ci.yml` or `.eslintrc.json`) are searched by default. To also search files excluded by `.gitignore` (such as `node_modules` or build outputs), set `include_ignored` to `true`. Sensitive files (such as `.env`) are always skipped for safety, even when `include_ignored` is `true`.\n";
|
|
87017
87166
|
//#endregion
|
|
87018
87167
|
//#region ../../packages/agent-core/src/tools/builtin/file/grep.ts
|
|
@@ -88000,7 +88149,7 @@ function detectFileType(path, header) {
|
|
|
88000
88149
|
};
|
|
88001
88150
|
}
|
|
88002
88151
|
//#endregion
|
|
88003
|
-
//#region ../../packages/agent-core/src/tools/builtin/file/read.md
|
|
88152
|
+
//#region ../../packages/agent-core/src/tools/builtin/file/read.md?raw
|
|
88004
88153
|
var read_default = "Read a text file from the local filesystem.\n\nIf the user provides a concrete file path to a text file, call Read directly. Do not `Glob`, `ls`, or otherwise pre-check known text file paths; missing or invalid file paths return errors you can handle. Do not use Read for directories; use `ls` via Bash for a known directory, or Glob when you need files/directories matching a pattern. Use `Grep` only when the task is to search for unknown content or locations.\n\nWhen you need several files, prefer to read them in parallel: emit multiple `Read` calls in a single response instead of reading one file per turn.\n\n- Relative paths resolve against the working directory; a path outside the working directory must be absolute.\n- Returns up to {{ MAX_LINES }} lines or {{ MAX_BYTES_KB }} KB per call, whichever comes first; lines longer than {{ MAX_LINE_LENGTH }} chars are truncated mid-line.\n- Page larger files with `line_offset` (1-based start line) and `n_lines`. Omit `n_lines` to read up to the {{ MAX_LINES }}-line cap.\n- Sensitive files (`.env` files, credential stores, SSH keys, and similar secrets) are refused to protect secrets; do not attempt to read them.\n- Only UTF-8 text files can be read. Non-UTF-8 encodings, binary files, and files containing NUL bytes are refused; use `ReadMediaFile` for images or video, and Bash or an MCP tool for other binary formats.\n- Negative line_offset reads from the end of the file (for example, -100 reads the last 100 lines); the absolute value cannot exceed {{ MAX_LINES }}.\n- Output format: `<line-number>\\t<content>` per line.\n- A `<system>...</system>` status block is appended after the file content; it summarizes how much was read (line and byte counts, truncation, line-ending notes) and is not part of the file itself.\n- Pure CRLF files are displayed with LF line endings; `Edit` matches this output and preserves CRLF when writing back.\n- Mixed or lone carriage-return line endings are shown as `\\r` and require exact `Edit.old_string` escapes.\n- After a successful `Edit`/`Write`, do not re-read solely to prove the write landed. When the task depends on an exact file, API, or output shape, inspect the final external contract before finishing.\n";
|
|
88005
88154
|
//#endregion
|
|
88006
88155
|
//#region ../../packages/agent-core/src/tools/builtin/file/read.ts
|
|
@@ -88307,7 +88456,7 @@ var ReadTool = class {
|
|
|
88307
88456
|
}
|
|
88308
88457
|
};
|
|
88309
88458
|
//#endregion
|
|
88310
|
-
//#region ../../packages/agent-core/src/tools/builtin/file/read-media.md
|
|
88459
|
+
//#region ../../packages/agent-core/src/tools/builtin/file/read-media.md?raw
|
|
88311
88460
|
var read_media_default = "Read media content from a file.\n\n**Tips:**\n- Make sure you follow the description of each tool parameter.\n- A `<system>` tag is given before the file content; it summarizes the mime type, byte size and, for images, the original pixel dimensions. When outputting coordinates, give relative coordinates first and compute absolute coordinates from the original image size. After generating or editing media via commands or scripts, read the result back before continuing.\n- The system will notify you when there is anything wrong when reading the file.\n- This tool is a tool that you typically want to use in parallel. Always read multiple files in one response when possible.\n- This tool can only read image or video files. To read text files, use the Read tool. To list directories, use `ls` via Bash for a known directory, or Glob for pattern search.\n- If the file doesn't exist or path is invalid, an error will be returned.\n- The maximum size that can be read is {{ MAX_MEDIA_MEGABYTES }}MB. An error will be returned if the file is larger than this limit.\n- The media content will be returned in a form that you can directly view and understand.\n\n**Capabilities**";
|
|
88312
88461
|
//#endregion
|
|
88313
88462
|
//#region ../../packages/agent-core/src/tools/builtin/file/read-media.ts
|
|
@@ -88469,7 +88618,7 @@ var ReadMediaFileTool = class {
|
|
|
88469
88618
|
}
|
|
88470
88619
|
};
|
|
88471
88620
|
//#endregion
|
|
88472
|
-
//#region ../../packages/agent-core/src/tools/builtin/file/write.md
|
|
88621
|
+
//#region ../../packages/agent-core/src/tools/builtin/file/write.md?raw
|
|
88473
88622
|
var write_default = "Create, append to, or replace a file entirely.\n\n- The parent directory must already exist.\n- Mode defaults to overwrite; append adds content at EOF without adding a newline.\n- Write is NOT ALLOWED for incremental changes to existing files, including trivial, one-line, quick, or cosmetic edits. Use Edit instead.\n- Use Write only when the file does not exist, you intend a complete replacement, or the new contents have little continuity with the old contents.\n- Read before overwriting an existing file.\n- Write ignores the Read/Edit line-number view. NEVER include line prefixes.\n- Write outputs content literally, including supplied line endings: \\n stays LF, \\r\\n stays CRLF.\n- For new content too large for one call, overwrite the first chunk, then append subsequent chunks. Never chunk Write to modify an existing file.\n";
|
|
88474
88623
|
//#endregion
|
|
88475
88624
|
//#region ../../packages/agent-core/src/tools/builtin/file/write.ts
|
|
@@ -88565,7 +88714,7 @@ var WriteTool = class {
|
|
|
88565
88714
|
}
|
|
88566
88715
|
};
|
|
88567
88716
|
//#endregion
|
|
88568
|
-
//#region ../../packages/agent-core/src/tools/builtin/goal/create-goal.md
|
|
88717
|
+
//#region ../../packages/agent-core/src/tools/builtin/goal/create-goal.md?raw
|
|
88569
88718
|
var create_goal_default = "Create a durable, structured goal that the runtime will pursue across multiple turns.\n\nCall `CreateGoal` only when:\n\n- the user explicitly asks you to start a goal or work autonomously toward an outcome, or\n- a host goal-intake prompt asks you to create one.\n\nDo NOT create a goal for greetings, ordinary questions, or vague requests that lack a\nverifiable completion condition. A goal needs a checkable end state.\n\nWhen the request is vague, ask the user for the missing completion criterion before creating\nthe goal. If the user clearly insists after you warn them that the wording is vague or risky,\nrespect that and create the goal.\n\nInclude a `completionCriterion` when the user provides one, or when it can be stated without\ninventing new requirements. Keep `objective` concise; reference long task descriptions by file\npath rather than pasting them.\n\nUse `replace: true` only when the user explicitly wants to abandon the current goal and start a\nnew one.\n";
|
|
88570
88719
|
//#endregion
|
|
88571
88720
|
//#region ../../packages/agent-core/src/tools/builtin/goal/create-goal.ts
|
|
@@ -88599,7 +88748,7 @@ var CreateGoalTool = class {
|
|
|
88599
88748
|
}
|
|
88600
88749
|
};
|
|
88601
88750
|
//#endregion
|
|
88602
|
-
//#region ../../packages/agent-core/src/tools/builtin/goal/get-goal.md
|
|
88751
|
+
//#region ../../packages/agent-core/src/tools/builtin/goal/get-goal.md?raw
|
|
88603
88752
|
var get_goal_default = "Read the current goal: its objective, completion criterion, status, budgets (turns, tokens,\ntime, and how much remains), the latest self-report, and the latest evaluator verdict.\n\nUse `GetGoal` before deciding whether to continue working, report completion, report a blocker,\nor respect a pause. It returns `{ \"goal\": null }` when there is no current goal.\n";
|
|
88604
88753
|
//#endregion
|
|
88605
88754
|
//#region ../../packages/agent-core/src/tools/builtin/goal/get-goal.ts
|
|
@@ -88625,7 +88774,7 @@ var GetGoalTool = class {
|
|
|
88625
88774
|
}
|
|
88626
88775
|
};
|
|
88627
88776
|
//#endregion
|
|
88628
|
-
//#region ../../packages/agent-core/src/tools/builtin/goal/set-goal-budget.md
|
|
88777
|
+
//#region ../../packages/agent-core/src/tools/builtin/goal/set-goal-budget.md?raw
|
|
88629
88778
|
var set_goal_budget_default = "Set a hard budget limit for the current goal.\n\nUse this only when the user clearly gives a runtime limit, such as:\n\n- \"stop after 20 turns\"\n- \"use no more than 500k tokens\"\n- \"finish within 30 minutes\"\n\nDo not invent limits. Do not call this for vague wording such as \"spend some time\" or\n\"try to be quick\".\n\nIf the user gives a compound time, convert it to one supported unit before calling this tool.\nFor example, \"2 hours and 3 minutes\" can be set as `value: 123, unit: \"minutes\"`.\n\nIf the requested budget is not reasonable, do not set it. Tell the user that the requested\nbudget is not reasonable. Examples include a time budget that is too short to act on, such as\n1 millisecond, or too long for an interactive goal run, such as 1 year.\n\nSupported units:\n\n- `turns`\n- `tokens`\n- `milliseconds`\n- `seconds`\n- `minutes`\n- `hours`\n";
|
|
88630
88779
|
//#endregion
|
|
88631
88780
|
//#region ../../packages/agent-core/src/tools/builtin/goal/set-goal-budget.ts
|
|
@@ -89813,7 +89962,7 @@ function formatTokens$3(tokens) {
|
|
|
89813
89962
|
return `${(tokens / 1e6).toFixed(1)}M`;
|
|
89814
89963
|
}
|
|
89815
89964
|
//#endregion
|
|
89816
|
-
//#region ../../packages/agent-core/src/tools/builtin/goal/update-goal.md
|
|
89965
|
+
//#region ../../packages/agent-core/src/tools/builtin/goal/update-goal.md?raw
|
|
89817
89966
|
var update_goal_default = "Set the status of the current goal. This is how you resume, end, or yield an autonomous goal.\n\n- `active` — resume a paused or blocked goal when the user explicitly asks you to work on that goal.\n- `complete` — the objective is satisfied and any stated validation has passed. The goal ends and a completion summary is recorded.\n- `blocked` — an external condition or required user input prevents progress, or the objective cannot be completed as stated. The goal stops but can be resumed later.\n- `paused` — set the goal aside for now (e.g. to hand control back to the user). It can be resumed later.\n\nIf the goal is active and you do not call this, the goal keeps running: after your turn ends you will be prompted to continue. Call `complete` only when all required work is done, any stated validation has passed, and there is no useful next action. Do not call `complete` after only producing a plan, summary, first pass, or partial result. If you call `blocked`, you will be prompted to explain the blocker in your next message. This tool only records the status.\n";
|
|
89818
89967
|
//#endregion
|
|
89819
89968
|
//#region ../../packages/agent-core/src/tools/builtin/goal/update-goal.ts
|
|
@@ -89874,7 +90023,7 @@ var UpdateGoalTool = class {
|
|
|
89874
90023
|
}
|
|
89875
90024
|
};
|
|
89876
90025
|
//#endregion
|
|
89877
|
-
//#region ../../packages/agent-core/src/tools/builtin/planning/enter-plan-mode.md
|
|
90026
|
+
//#region ../../packages/agent-core/src/tools/builtin/planning/enter-plan-mode.md?raw
|
|
89878
90027
|
var enter_plan_mode_default = "Use this tool proactively when you're about to start a non-trivial implementation task.\nGetting user sign-off on your approach via ExitPlanMode before writing code prevents wasted effort.\n\nUse it when ANY of these conditions apply:\n\n1. New Feature Implementation - e.g. \"Add a caching layer to the API\"\n2. Multiple Valid Approaches - e.g. \"Optimize database queries\" (indexing vs rewrite vs caching)\n3. Code Modifications - e.g. \"Refactor auth module to support OAuth\"\n4. Architectural Decisions - e.g. \"Add WebSocket support\"\n5. Multi-File Changes - involves more than 2-3 files\n6. Unclear Requirements - need exploration to understand scope\n7. User Preferences Matter - if user input would materially change the implementation approach, use EnterPlanMode to structure the decision\n\nPermission mode notes:\n- EnterPlanMode enters plan mode automatically without an approval prompt in all permission modes.\n- In yolo and manual modes, ExitPlanMode still presents the plan to the user for approval.\n- In auto permission mode, do not use AskUserQuestion; make the best decision from available context.\n- In auto permission mode, ExitPlanMode exits plan mode without asking the user.\n- Use EnterPlanMode only when planning itself adds value.\n\nWhen NOT to use:\n- Single-line or few-line fixes (typos, obvious bugs, small tweaks)\n- User gave very specific, detailed instructions\n- Pure research/exploration tasks\n\n## What Happens in Plan Mode\nIn plan mode, you will:\n1. Identify 2-3 key questions about the codebase that are critical to your plan. If you are not confident about the codebase structure or relevant code paths, use `Agent(subagent_type=\"explore\")` to investigate these questions first - this is strongly recommended for non-trivial tasks.\n2. Explore the codebase using Glob, Grep, Read, and other read-only tools for any remaining quick lookups. Use Bash only when needed; Bash follows the normal permission mode and rules.\n3. Design an implementation approach based on your findings\n4. Write your plan to the current plan file with Write or Edit\n5. Present your plan to the user via ExitPlanMode for approval\n";
|
|
89879
90028
|
//#endregion
|
|
89880
90029
|
//#region ../../packages/agent-core/src/tools/builtin/planning/enter-plan-mode.ts
|
|
@@ -89936,7 +90085,7 @@ function enteredPlanModeMessage(planPath) {
|
|
|
89936
90085
|
].join("\n");
|
|
89937
90086
|
}
|
|
89938
90087
|
//#endregion
|
|
89939
|
-
//#region ../../packages/agent-core/src/tools/builtin/planning/exit-plan-mode.md
|
|
90088
|
+
//#region ../../packages/agent-core/src/tools/builtin/planning/exit-plan-mode.md?raw
|
|
89940
90089
|
var exit_plan_mode_default = "Use this tool when you are in plan mode and have finished writing your plan to the plan file and are ready for user approval.\n\n## How This Tool Works\n- You should have already written your plan to the plan file specified in the plan mode reminder.\n- This tool does NOT take the plan content as a parameter - it reads the plan from the file you wrote.\n- The user will see the contents of your plan file when they review it. In auto permission mode, the tool reads the file and exits plan mode without asking the user.\n\n## When to Use\nOnly use this tool for tasks that require planning implementation steps. For research tasks (searching files, reading code, understanding the codebase), do NOT use this tool.\n\n## Multiple Approaches\nIf your plan contains multiple alternative approaches:\n- Pass them via the `options` parameter so the user can choose which approach to execute.\n- Each option should have a concise label and a brief description of trade-offs.\n- If you recommend one option, append \"(Recommended)\" to its label.\n- In yolo and manual modes, the user will see all options alongside Reject and Revise choices.\n- Provide up to 3 options; the host adds the standard rejection and revision controls. When the plan offers a real choice, 2-3 distinct approaches work best.\n- Passing a single option is allowed and is equivalent to a plain plan approval (no approach choice is surfaced to the user).\n- Do NOT use \"Reject\", \"Reject and Exit\", \"Revise\", or \"Approve\" as option labels - these are reserved by the system.\n\n## Before Using\n- In auto permission mode, do NOT use AskUserQuestion; make the best decision from available context.\n- In auto permission mode, this tool exits plan mode without asking the user.\n- In yolo and manual modes, this tool still presents the plan to the user for approval.\n- If auto permission mode is not active and you have unresolved questions, use AskUserQuestion first.\n- If auto permission mode is not active and you have multiple approaches and haven't narrowed down yet, consider using AskUserQuestion first to let the user choose, then write a plan for the chosen approach only.\n- Once your plan is finalized, use THIS tool to request approval.\n- Do NOT use AskUserQuestion to ask \"Is this plan OK?\" or \"Should I proceed?\" - that is exactly what ExitPlanMode does.\n- If rejected, revise based on feedback and call ExitPlanMode again.\n";
|
|
89941
90090
|
//#endregion
|
|
89942
90091
|
//#region ../../packages/agent-core/src/tools/builtin/planning/exit-plan-mode.ts
|
|
@@ -90061,7 +90210,7 @@ function formatPlanForOutput(plan, path) {
|
|
|
90061
90210
|
return `Plan mode deactivated. All tools are now available.\n${path !== void 0 ? `Plan saved to: ${path}\n\n` : ""}## Approved Plan:\n${plan}`;
|
|
90062
90211
|
}
|
|
90063
90212
|
//#endregion
|
|
90064
|
-
//#region ../../packages/agent-core/src/tools/builtin/shell/bash.md
|
|
90213
|
+
//#region ../../packages/agent-core/src/tools/builtin/shell/bash.md?raw
|
|
90065
90214
|
var bash_default = "Execute a `{{ SHELL_NAME }}` command. Use this for shell semantics — pipes, env, processes, git, package managers, build/test runners, anything genuinely interactive or multi-step.\n\n**Translate these to a dedicated tool instead:**\n- `cat` / `head` / `tail` (known path) → `Read`\n- `sed` / `awk` (in-place edit) → `Edit`\n- `echo > file` / `cat <<EOF` → `Write`\n- `find` / recursive `ls` to locate files by name pattern → `Glob` (plain `ls <known-directory>` is fine for listing a directory)\n- `grep` / `rg` (search file contents) → `Grep`\n- `echo` / `printf` (talk to the user) → just output text directly\n\nThe dedicated tools render in the per-tool permission UI and keep raw stdout out of the conversation; that is why they are worth reaching for whenever one fits.\n\n**Output:**\nThe stdout and stderr will be combined and returned as a string. The output may be truncated if it is too long. If the command failed, the output will end with a `Command failed with exit code: N` line stating the non-zero exit code.\n\nIf `run_in_background=true`, the command will be started as a background task and this tool will return a task ID instead of waiting for command completion. When doing that, you must provide a short `description`. Background commands default to a {{ DEFAULT_BACKGROUND_TIMEOUT_S }}s timeout and `timeout` is capped at {{ MAX_BACKGROUND_TIMEOUT_S }}s; set `disable_timeout=true` only when the task should run without a timeout. You will be automatically notified when the task completes. Use `TaskOutput` for a non-blocking status/output snapshot, and only set `block=true` when you explicitly want to wait for completion. Use `TaskStop` only if the task must be cancelled. If a human user wants to inspect background tasks themselves, point them to the `/tasks` command, which opens an interactive panel; it has no subcommands.\n\n**Guidelines for safety and security:**\n- Each shell tool call will be executed in a fresh shell environment. The shell variables, current working directory changes, and the shell history is not preserved between calls.\n- The tool call will return after the command is finished. You shall not use this tool to execute an interactive command or a command that may run forever. For possibly long-running foreground commands, set the `timeout` argument in seconds. Foreground commands default to {{ DEFAULT_TIMEOUT_S }}s and allow up to {{ MAX_TIMEOUT_S }}s.\n- Avoid using `..` to access files or directories outside of the working directory.\n- Avoid modifying files outside of the working directory unless explicitly instructed to do so.\n- Never run commands that require superuser privileges unless explicitly instructed to do so.\n\n**Guidelines for efficiency:**\n- For multiple related commands, use `&&` to chain them in a single call, e.g. `cd /path && ls -la`\n- Use `;` to run commands sequentially regardless of success/failure\n- Use `||` for conditional execution (run second command only if first fails)\n- Use pipe operations (`|`) and redirections (`>`, `>>`) to chain input and output between commands\n- Always quote file paths containing spaces with double quotes (e.g., cd \"/path with spaces/\")\n- Compose multi-step logic in a single call with `if` / `case` / `for` / `while` control flows.\n- Prefer `run_in_background=true` for long-running builds, tests, watchers, or servers when you need the conversation to continue before the command finishes.\n\n**Commands available:**\nThe following common command categories are usually available. Availability still depends on the host, so when in doubt run `which <command>` first to confirm a command exists before relying on it.\n- Navigation and inspection: `ls`, `pwd`, `cd`, `stat`, `file`, `du`, `df`, `tree`\n- File and directory management: `cp`, `mv`, `rm`, `mkdir`, `touch`, `ln`, `chmod`, `chown`\n- Text and data processing: `wc`, `sort`, `uniq`, `cut`, `tr`, `diff`, `xargs`\n- Archives and compression: `tar`, `gzip`, `gunzip`, `zip`, `unzip`\n- Networking and transfer: `curl`, `wget`, `ping`, `ssh`, `scp`\n- Version control: `git`\n- Process and system: `ps`, `kill`, `top`, `env`, `date`, `uname`, `whoami`\n- Language and package toolchains: `node`, `npm`, `pnpm`, `yarn`, `python`, `pip` (use whichever the project actually relies on)\n";
|
|
90066
90215
|
//#endregion
|
|
90067
90216
|
//#region ../../packages/agent-core/src/tools/builtin/shell/bash.ts
|
|
@@ -90150,7 +90299,7 @@ var BashTool = class {
|
|
|
90150
90299
|
},
|
|
90151
90300
|
approvalRule: literalRulePattern(this.name, args.command),
|
|
90152
90301
|
matchesRule: (ruleArgs) => matchesGlobRuleSubject(ruleArgs, args.command),
|
|
90153
|
-
execute: ({ signal }) => this.execution(args, signal)
|
|
90302
|
+
execute: ({ signal, onUpdate }) => this.execution(args, signal, onUpdate)
|
|
90154
90303
|
};
|
|
90155
90304
|
}
|
|
90156
90305
|
spawn(effectiveCwd, command) {
|
|
@@ -90172,7 +90321,7 @@ var BashTool = class {
|
|
|
90172
90321
|
};
|
|
90173
90322
|
return this.kaos.execWithEnv(shellArgs, mergedEnv);
|
|
90174
90323
|
}
|
|
90175
|
-
async execution(args, signal) {
|
|
90324
|
+
async execution(args, signal, onUpdate) {
|
|
90176
90325
|
if (signal.aborted) return {
|
|
90177
90326
|
isError: true,
|
|
90178
90327
|
output: "Aborted before command started"
|
|
@@ -90238,7 +90387,8 @@ var BashTool = class {
|
|
|
90238
90387
|
}, timeoutMs);
|
|
90239
90388
|
try {
|
|
90240
90389
|
const builder = new ToolResultBuilder();
|
|
90241
|
-
const
|
|
90390
|
+
const isTerminating = () => timedOut || aborted || killed;
|
|
90391
|
+
const [, exitCode] = await Promise.all([Promise.all([readStreamIntoBuilder(proc.stdout, builder, "stdout", onUpdate, isTerminating), readStreamIntoBuilder(proc.stderr, builder, "stderr", onUpdate, isTerminating)]), proc.wait()]);
|
|
90242
90392
|
if (timedOut) {
|
|
90243
90393
|
const timeoutLabel = timeoutMs % 1e3 === 0 ? `${String(timeoutMs / 1e3)}s` : `${String(timeoutMs)}ms`;
|
|
90244
90394
|
return builder.error(`Command killed by timeout (${timeoutLabel})`, { brief: `Killed by timeout (${timeoutLabel})` });
|
|
@@ -90301,7 +90451,7 @@ var BashTool = class {
|
|
|
90301
90451
|
const info = backgroundManager.getTask(taskId);
|
|
90302
90452
|
if (info && info.status === "running") backgroundManager.stop(taskId, "Timed out");
|
|
90303
90453
|
})();
|
|
90304
|
-
}, timeoutMs);
|
|
90454
|
+
}, timeoutMs).unref?.();
|
|
90305
90455
|
const status = backgroundManager.getTask(taskId).status;
|
|
90306
90456
|
const builder = new ToolResultBuilder();
|
|
90307
90457
|
builder.write(`task_id: ${taskId}\npid: ${String(proc.pid)}\ndescription: ${args.description.trim()}\nstatus: ${status}\nautomatic_notification: true\nnext_step: You will be automatically notified when it completes.
|
|
@@ -90311,13 +90461,30 @@ human_shell_hint: Tell the human to run /tasks to open the interactive backgroun
|
|
|
90311
90461
|
return builder.ok("Background task started", { brief: `Started ${taskId}` });
|
|
90312
90462
|
}
|
|
90313
90463
|
};
|
|
90314
|
-
async function readStreamIntoBuilder(stream, builder) {
|
|
90464
|
+
async function readStreamIntoBuilder(stream, builder, kind, onUpdate, suppressPrematureClose) {
|
|
90315
90465
|
const decoder = new StringDecoder("utf8");
|
|
90316
|
-
|
|
90317
|
-
|
|
90318
|
-
|
|
90466
|
+
try {
|
|
90467
|
+
for await (const chunk of stream) {
|
|
90468
|
+
const buf = typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
|
|
90469
|
+
const text = decoder.write(buf);
|
|
90470
|
+
if (text.length > 0) onUpdate?.({
|
|
90471
|
+
kind,
|
|
90472
|
+
text
|
|
90473
|
+
});
|
|
90474
|
+
builder.write(text);
|
|
90475
|
+
}
|
|
90476
|
+
} catch (error) {
|
|
90477
|
+
if (!isPrematureCloseError(error) || suppressPrematureClose?.() !== true) throw error;
|
|
90319
90478
|
}
|
|
90320
|
-
|
|
90479
|
+
const trailing = decoder.end();
|
|
90480
|
+
if (trailing.length > 0) onUpdate?.({
|
|
90481
|
+
kind,
|
|
90482
|
+
text: trailing
|
|
90483
|
+
});
|
|
90484
|
+
builder.write(trailing);
|
|
90485
|
+
}
|
|
90486
|
+
function isPrematureCloseError(error) {
|
|
90487
|
+
return error instanceof Error && error.code === "ERR_STREAM_PREMATURE_CLOSE";
|
|
90321
90488
|
}
|
|
90322
90489
|
function shellQuote(s) {
|
|
90323
90490
|
return `'${s.replaceAll("'", "'\\''")}'`;
|
|
@@ -90337,7 +90504,7 @@ function rewriteWindowsNullRedirect(command) {
|
|
|
90337
90504
|
return command.replace(WINDOWS_NUL_REDIRECT, "$1/dev/null");
|
|
90338
90505
|
}
|
|
90339
90506
|
//#endregion
|
|
90340
|
-
//#region ../../packages/agent-core/src/tools/builtin/web/fetch-url.md
|
|
90507
|
+
//#region ../../packages/agent-core/src/tools/builtin/web/fetch-url.md?raw
|
|
90341
90508
|
var fetch_url_default = "Fetch content from a URL. Returns the main text content extracted from the page. Use this when you need to read a specific web page.\n\nOnly public `http`/`https` URLs are supported. Requests to private, loopback, or link-local addresses are refused, and responses larger than 10 MiB are rejected.\n";
|
|
90342
90509
|
//#endregion
|
|
90343
90510
|
//#region ../../packages/agent-core/src/tools/builtin/web/fetch-url.ts
|
|
@@ -90410,7 +90577,7 @@ var FetchURLTool = class {
|
|
|
90410
90577
|
}
|
|
90411
90578
|
};
|
|
90412
90579
|
//#endregion
|
|
90413
|
-
//#region ../../packages/agent-core/src/tools/builtin/web/web-search.md
|
|
90580
|
+
//#region ../../packages/agent-core/src/tools/builtin/web/web-search.md?raw
|
|
90414
90581
|
var web_search_default = "Search the web for information. Use this when you need up-to-date information from the internet.\n\nEach result includes its title, URL, snippet, and—when available—a publication date. When `include_content` is enabled, the full page content—when available—is appended after the snippet.\n";
|
|
90415
90582
|
//#endregion
|
|
90416
90583
|
//#region ../../packages/agent-core/src/tools/builtin/web/web-search.ts
|
|
@@ -91843,13 +92010,119 @@ function readConfigFile(filePath) {
|
|
|
91843
92010
|
return parseConfigString(readFileSync(filePath, "utf-8"), filePath);
|
|
91844
92011
|
}
|
|
91845
92012
|
/**
|
|
91846
|
-
*
|
|
91847
|
-
*
|
|
91848
|
-
*
|
|
91849
|
-
*
|
|
92013
|
+
* Strict read for write paths (read-merge-write must never use a salvaged
|
|
92014
|
+
* config as its base, or the rewrite would drop the user's broken-but-fixable
|
|
92015
|
+
* sections). Re-throws validation failures with a short actionable message —
|
|
92016
|
+
* UIs surface it directly — instead of the raw validation details.
|
|
92017
|
+
*/
|
|
92018
|
+
function readConfigFileForUpdate(filePath) {
|
|
92019
|
+
try {
|
|
92020
|
+
return readConfigFile(filePath);
|
|
92021
|
+
} catch (error) {
|
|
92022
|
+
if (error instanceof KimiError && error.code === ErrorCodes.CONFIG_INVALID) throw new KimiError(ErrorCodes.CONFIG_INVALID, `Cannot change settings while ${filePath} is invalid — fix it first (run \`kimi doctor\` for details).`, { cause: error });
|
|
92023
|
+
throw error;
|
|
92024
|
+
}
|
|
92025
|
+
}
|
|
92026
|
+
/**
|
|
92027
|
+
* Lenient variant of `loadRuntimeConfig` that never throws: schema errors
|
|
92028
|
+
* drop only the offending sections (whole entry for `providers`/`models`,
|
|
92029
|
+
* whole top-level section otherwise) and a bad KIMI_MODEL_* env overlay is
|
|
92030
|
+
* skipped, each reported as a warning. A file that cannot be used at all
|
|
92031
|
+
* additionally sets `fileError` so startup can fail fast while mid-run
|
|
92032
|
+
* reloads degrade. Runtime read paths use this; write paths must keep using
|
|
92033
|
+
* the strict readers so a broken file is never silently rewritten.
|
|
92034
|
+
*/
|
|
92035
|
+
function loadRuntimeConfigSafe(filePath, env = process.env) {
|
|
92036
|
+
const fileWarnings = [];
|
|
92037
|
+
let fileError;
|
|
92038
|
+
let config = getDefaultConfig();
|
|
92039
|
+
let text;
|
|
92040
|
+
try {
|
|
92041
|
+
text = existsSync(filePath) ? readFileSync(filePath, "utf-8") : void 0;
|
|
92042
|
+
} catch (error) {
|
|
92043
|
+
fileError = new KimiError(ErrorCodes.CONFIG_INVALID, `Failed to read ${filePath}: ${describeUnknownError(error)}`, { cause: error });
|
|
92044
|
+
fileWarnings.push(`Failed to read ${filePath}: ${describeUnknownError(error)}.`);
|
|
92045
|
+
}
|
|
92046
|
+
if (text !== void 0 && text.trim().length > 0) {
|
|
92047
|
+
let data;
|
|
92048
|
+
try {
|
|
92049
|
+
data = parse$2(text);
|
|
92050
|
+
} catch (error) {
|
|
92051
|
+
fileError = new KimiError(ErrorCodes.CONFIG_INVALID, `Invalid TOML in ${filePath}: ${describeUnknownError(error)}`, { cause: error });
|
|
92052
|
+
fileWarnings.push(`Invalid TOML in ${filePath}: ${describeTomlSyntaxError(error)}.`);
|
|
92053
|
+
}
|
|
92054
|
+
if (data !== void 0) {
|
|
92055
|
+
const raw = cloneRecord(data);
|
|
92056
|
+
const transformed = transformTomlData(data);
|
|
92057
|
+
transformed["raw"] = raw;
|
|
92058
|
+
const salvaged = salvageConfigData(transformed);
|
|
92059
|
+
if (salvaged.config === void 0) {
|
|
92060
|
+
fileError = new KimiError(ErrorCodes.CONFIG_INVALID, `Invalid configuration in ${filePath}: ${formatConfigValidationError(salvaged.error)}`, { cause: salvaged.error });
|
|
92061
|
+
fileWarnings.push(`Invalid configuration in ${filePath}: ${formatConfigValidationError(salvaged.error)}.`);
|
|
92062
|
+
} else {
|
|
92063
|
+
config = salvaged.config;
|
|
92064
|
+
if (salvaged.dropped.length > 0) fileWarnings.push(`Ignored invalid config in ${filePath}: ${salvaged.dropped.join(", ")}. Run \`kimi doctor\` for details.`);
|
|
92065
|
+
}
|
|
92066
|
+
}
|
|
92067
|
+
}
|
|
92068
|
+
const envWarnings = [];
|
|
92069
|
+
try {
|
|
92070
|
+
config = applyEnvModelConfig(config, env);
|
|
92071
|
+
} catch (error) {
|
|
92072
|
+
envWarnings.push(`Ignoring KIMI_MODEL_* environment overrides: ${describeUnknownError(error)}`);
|
|
92073
|
+
}
|
|
92074
|
+
return {
|
|
92075
|
+
config,
|
|
92076
|
+
fileWarnings,
|
|
92077
|
+
envWarnings,
|
|
92078
|
+
fileError
|
|
92079
|
+
};
|
|
92080
|
+
}
|
|
92081
|
+
/** Sections keyed by user-chosen names where single entries can be dropped. */
|
|
92082
|
+
const ENTRY_KEYED_SECTIONS = new Set(["providers", "models"]);
|
|
92083
|
+
function salvageConfigData(transformed) {
|
|
92084
|
+
const dropped = [];
|
|
92085
|
+
for (;;) {
|
|
92086
|
+
const result = KimiConfigSchema.safeParse(transformed);
|
|
92087
|
+
if (result.success) return {
|
|
92088
|
+
config: result.data,
|
|
92089
|
+
dropped
|
|
92090
|
+
};
|
|
92091
|
+
let deletedAny = false;
|
|
92092
|
+
for (const issue of result.error.issues) {
|
|
92093
|
+
const [section, entry] = issue.path;
|
|
92094
|
+
if (typeof section !== "string" || !(section in transformed)) continue;
|
|
92095
|
+
const sectionValue = transformed[section];
|
|
92096
|
+
if (ENTRY_KEYED_SECTIONS.has(section) && typeof entry === "string" && isPlainObject$1(sectionValue)) {
|
|
92097
|
+
if (entry in sectionValue) {
|
|
92098
|
+
delete sectionValue[entry];
|
|
92099
|
+
dropped.push(`${camelToSnake$2(section)}.${entry}`);
|
|
92100
|
+
deletedAny = true;
|
|
92101
|
+
}
|
|
92102
|
+
continue;
|
|
92103
|
+
}
|
|
92104
|
+
delete transformed[section];
|
|
92105
|
+
dropped.push(camelToSnake$2(section));
|
|
92106
|
+
deletedAny = true;
|
|
92107
|
+
}
|
|
92108
|
+
if (!deletedAny) return {
|
|
92109
|
+
config: void 0,
|
|
92110
|
+
dropped,
|
|
92111
|
+
error: result.error
|
|
92112
|
+
};
|
|
92113
|
+
}
|
|
92114
|
+
}
|
|
92115
|
+
function describeUnknownError(error) {
|
|
92116
|
+
return error instanceof Error ? error.message : String(error);
|
|
92117
|
+
}
|
|
92118
|
+
/**
|
|
92119
|
+
* One-line summary of a smol-toml parse error: first message line plus the
|
|
92120
|
+
* line/column location, without the multi-line code-frame block.
|
|
91850
92121
|
*/
|
|
91851
|
-
function
|
|
91852
|
-
|
|
92122
|
+
function describeTomlSyntaxError(error) {
|
|
92123
|
+
const firstLine = describeUnknownError(error).split("\n", 1)[0] ?? "";
|
|
92124
|
+
if (error instanceof TomlError) return `${firstLine} (line ${error.line}, column ${error.column})`;
|
|
92125
|
+
return firstLine;
|
|
91853
92126
|
}
|
|
91854
92127
|
function parseConfigString(tomlText, filePath = "config.toml") {
|
|
91855
92128
|
if (tomlText.trim().length === 0) return getDefaultConfig();
|
|
@@ -121101,6 +121374,32 @@ var McpConnectionManager = class {
|
|
|
121101
121374
|
this.initialLoad = initialLoad;
|
|
121102
121375
|
return initialLoad;
|
|
121103
121376
|
}
|
|
121377
|
+
async connect(name, config) {
|
|
121378
|
+
const previous = this.entries.get(name);
|
|
121379
|
+
if (previous !== void 0) await this.closeClient(previous);
|
|
121380
|
+
const disabled = config.enabled === false;
|
|
121381
|
+
const entry = {
|
|
121382
|
+
name,
|
|
121383
|
+
config,
|
|
121384
|
+
attemptId: 0,
|
|
121385
|
+
status: disabled ? "disabled" : "pending"
|
|
121386
|
+
};
|
|
121387
|
+
this.entries.set(name, entry);
|
|
121388
|
+
this.emit(entry);
|
|
121389
|
+
if (!disabled) await this.connectOne(entry, this.beginConnectAttempt(entry));
|
|
121390
|
+
}
|
|
121391
|
+
async remove(name) {
|
|
121392
|
+
const entry = this.entries.get(name);
|
|
121393
|
+
if (entry === void 0) return false;
|
|
121394
|
+
await this.closeClient(entry);
|
|
121395
|
+
entry.status = "disabled";
|
|
121396
|
+
entry.tools = void 0;
|
|
121397
|
+
entry.enabledNames = void 0;
|
|
121398
|
+
entry.error = void 0;
|
|
121399
|
+
this.emit(entry);
|
|
121400
|
+
this.entries.delete(name);
|
|
121401
|
+
return true;
|
|
121402
|
+
}
|
|
121104
121403
|
waitForInitialLoad(signal) {
|
|
121105
121404
|
signal?.throwIfAborted();
|
|
121106
121405
|
if (signal === void 0) return this.initialLoad;
|
|
@@ -121450,6 +121749,20 @@ function mergeCallerMcpServers(base, callerServers) {
|
|
|
121450
121749
|
//#endregion
|
|
121451
121750
|
//#region ../../packages/agent-core/src/session/index.ts
|
|
121452
121751
|
const BACKGROUND_KEEP_ALIVE_ON_EXIT_ENV = "KIMI_CODE_BACKGROUND_KEEP_ALIVE_ON_EXIT";
|
|
121752
|
+
const ACTIVE_TURN_CLOSE_TIMEOUT_MS = 8e3;
|
|
121753
|
+
async function waitForSettlementOrTimeout(promise, timeoutMs) {
|
|
121754
|
+
let timeout;
|
|
121755
|
+
try {
|
|
121756
|
+
return await Promise.race([promise.then(() => true, () => true), new Promise((resolve) => {
|
|
121757
|
+
timeout = setTimeout(() => {
|
|
121758
|
+
resolve(false);
|
|
121759
|
+
}, timeoutMs);
|
|
121760
|
+
timeout.unref?.();
|
|
121761
|
+
})]);
|
|
121762
|
+
} finally {
|
|
121763
|
+
if (timeout !== void 0) clearTimeout(timeout);
|
|
121764
|
+
}
|
|
121765
|
+
}
|
|
121453
121766
|
var Session$1 = class {
|
|
121454
121767
|
options;
|
|
121455
121768
|
rpc;
|
|
@@ -121541,6 +121854,7 @@ var Session$1 = class {
|
|
|
121541
121854
|
async close() {
|
|
121542
121855
|
try {
|
|
121543
121856
|
await Promise.allSettled(Array.from(this.readyAgents(), async (agent) => agent.cron?.stop()));
|
|
121857
|
+
await this.cancelActiveTurnsOnClose();
|
|
121544
121858
|
await this.stopBackgroundTasksOnExit();
|
|
121545
121859
|
await this.flushMetadata();
|
|
121546
121860
|
await this.triggerSessionEnd("exit");
|
|
@@ -121564,12 +121878,46 @@ var Session$1 = class {
|
|
|
121564
121878
|
}
|
|
121565
121879
|
}
|
|
121566
121880
|
}
|
|
121881
|
+
async cancelActiveTurnsOnClose() {
|
|
121882
|
+
const backgroundAgentIds = this.activeBackgroundAgentIds();
|
|
121883
|
+
const cancellations = [];
|
|
121884
|
+
for (const [agentId, entry] of this.agents) {
|
|
121885
|
+
if (!(entry instanceof Agent$1) || backgroundAgentIds.has(agentId)) continue;
|
|
121886
|
+
cancellations.push(this.cancelAgentTurnOnClose(entry));
|
|
121887
|
+
}
|
|
121888
|
+
await Promise.allSettled(cancellations);
|
|
121889
|
+
}
|
|
121890
|
+
activeBackgroundAgentIds() {
|
|
121891
|
+
const agentIds = /* @__PURE__ */ new Set();
|
|
121892
|
+
for (const agent of this.readyAgents()) for (const task of agent.background.list(true)) if (task.kind === "agent" && task.agentId !== void 0) agentIds.add(task.agentId);
|
|
121893
|
+
return agentIds;
|
|
121894
|
+
}
|
|
121895
|
+
async cancelAgentTurnOnClose(agent) {
|
|
121896
|
+
if (!agent.turn.hasActiveTurn) return;
|
|
121897
|
+
let waitForTurn;
|
|
121898
|
+
try {
|
|
121899
|
+
waitForTurn = agent.turn.waitForCurrentTurn();
|
|
121900
|
+
} catch (error) {
|
|
121901
|
+
this.log.debug("active turn wait unavailable during session close", {
|
|
121902
|
+
agentType: agent.type,
|
|
121903
|
+
agentHomedir: agent.homedir,
|
|
121904
|
+
error
|
|
121905
|
+
});
|
|
121906
|
+
return;
|
|
121907
|
+
}
|
|
121908
|
+
agent.turn.cancel(void 0, abortError$1("Session closed"));
|
|
121909
|
+
if (!await waitForSettlementOrTimeout(waitForTurn, ACTIVE_TURN_CLOSE_TIMEOUT_MS)) this.log.warn("timed out waiting for active turn to cancel during session close", {
|
|
121910
|
+
agentType: agent.type,
|
|
121911
|
+
agentHomedir: agent.homedir,
|
|
121912
|
+
timeoutMs: ACTIVE_TURN_CLOSE_TIMEOUT_MS
|
|
121913
|
+
});
|
|
121914
|
+
}
|
|
121567
121915
|
async stopBackgroundTasksOnExit() {
|
|
121568
121916
|
if (resolveConfigValue({
|
|
121569
121917
|
env: process.env,
|
|
121570
121918
|
envKey: BACKGROUND_KEEP_ALIVE_ON_EXIT_ENV,
|
|
121571
121919
|
configValue: this.options.background?.keepAliveOnExit,
|
|
121572
|
-
defaultValue:
|
|
121920
|
+
defaultValue: false,
|
|
121573
121921
|
parseEnv: parseBooleanEnv
|
|
121574
121922
|
})) return;
|
|
121575
121923
|
await Promise.all(Array.from(this.readyAgents(), (agent) => agent.background.stopAll("Session closed")));
|
|
@@ -136951,6 +137299,7 @@ var ProviderManager = class {
|
|
|
136951
137299
|
providerName,
|
|
136952
137300
|
provider,
|
|
136953
137301
|
modelCapabilities: resolveModelCapabilities(alias, provider),
|
|
137302
|
+
alwaysThinking: (alias.capabilities ?? []).some((c) => c.trim().toLowerCase() === "always_thinking"),
|
|
136954
137303
|
maxOutputSize: alias.maxOutputSize
|
|
136955
137304
|
};
|
|
136956
137305
|
}
|
|
@@ -138335,9 +138684,11 @@ var LocalKaos = class LocalKaos {
|
|
|
138335
138684
|
name = "local";
|
|
138336
138685
|
osEnv;
|
|
138337
138686
|
_cwd;
|
|
138338
|
-
|
|
138687
|
+
_envLayers;
|
|
138688
|
+
constructor(osEnv, cwd, envLayers = []) {
|
|
138339
138689
|
this._cwd = normalize(cwd ?? process.cwd());
|
|
138340
138690
|
this.osEnv = osEnv;
|
|
138691
|
+
this._envLayers = envLayers;
|
|
138341
138692
|
}
|
|
138342
138693
|
/**
|
|
138343
138694
|
* Construct a fresh `LocalKaos` after probing the host environment.
|
|
@@ -138350,7 +138701,10 @@ var LocalKaos = class LocalKaos {
|
|
|
138350
138701
|
return new LocalKaos(await detectEnvironmentFromNode());
|
|
138351
138702
|
}
|
|
138352
138703
|
withCwd(cwd) {
|
|
138353
|
-
return new LocalKaos(this.osEnv, cwd);
|
|
138704
|
+
return new LocalKaos(this.osEnv, cwd, this._envLayers);
|
|
138705
|
+
}
|
|
138706
|
+
withEnv(env) {
|
|
138707
|
+
return new LocalKaos(this.osEnv, this._cwd, [...this._envLayers, env]);
|
|
138354
138708
|
}
|
|
138355
138709
|
_resolvePath(path) {
|
|
138356
138710
|
if (isAbsolute(path)) return normalize(path);
|
|
@@ -138543,7 +138897,8 @@ var LocalKaos = class LocalKaos {
|
|
|
138543
138897
|
"pipe",
|
|
138544
138898
|
"pipe"
|
|
138545
138899
|
],
|
|
138546
|
-
detached: !isWindows
|
|
138900
|
+
detached: !isWindows,
|
|
138901
|
+
env: this._buildExecEnv()
|
|
138547
138902
|
});
|
|
138548
138903
|
await waitForSpawn(child);
|
|
138549
138904
|
return new LocalProcess(child);
|
|
@@ -138559,11 +138914,20 @@ var LocalKaos = class LocalKaos {
|
|
|
138559
138914
|
"pipe"
|
|
138560
138915
|
],
|
|
138561
138916
|
detached: !isWindows,
|
|
138562
|
-
env
|
|
138917
|
+
env: this._buildExecEnv(env)
|
|
138563
138918
|
});
|
|
138564
138919
|
await waitForSpawn(child);
|
|
138565
138920
|
return new LocalProcess(child);
|
|
138566
138921
|
}
|
|
138922
|
+
_buildExecEnv(invocationEnv) {
|
|
138923
|
+
if (this._envLayers.length === 0) return invocationEnv;
|
|
138924
|
+
const merged = {
|
|
138925
|
+
...process.env,
|
|
138926
|
+
...invocationEnv
|
|
138927
|
+
};
|
|
138928
|
+
for (const layer of this._envLayers) Object.assign(merged, layer);
|
|
138929
|
+
return merged;
|
|
138930
|
+
}
|
|
138567
138931
|
};
|
|
138568
138932
|
function waitForSpawn(child) {
|
|
138569
138933
|
return new Promise((resolve, reject) => {
|
|
@@ -138596,6 +138960,7 @@ var KimiCore = class {
|
|
|
138596
138960
|
kaos;
|
|
138597
138961
|
runtime;
|
|
138598
138962
|
config;
|
|
138963
|
+
configWarnings = [];
|
|
138599
138964
|
runtimeOverride;
|
|
138600
138965
|
userHomeDir;
|
|
138601
138966
|
kimiRequestHeaders;
|
|
@@ -138623,7 +138988,11 @@ var KimiCore = class {
|
|
|
138623
138988
|
this.telemetry = options.telemetry ?? noopTelemetryClient;
|
|
138624
138989
|
this.appVersion = options.appVersion;
|
|
138625
138990
|
ensureKimiHome(this.homeDir);
|
|
138626
|
-
|
|
138991
|
+
const loaded = loadRuntimeConfigSafe(this.configPath);
|
|
138992
|
+
if (loaded.fileError !== void 0) throw loaded.fileError;
|
|
138993
|
+
this.config = loaded.config;
|
|
138994
|
+
this.configWarnings = [...loaded.fileWarnings, ...loaded.envWarnings];
|
|
138995
|
+
if (this.configWarnings.length > 0) log.warn("config load degraded", { warnings: this.configWarnings });
|
|
138627
138996
|
this.experimentalFlags = new FlagResolver(process.env, FLAG_DEFINITIONS, this.config.experimental);
|
|
138628
138997
|
this.sessionStore = new SessionStore(this.homeDir);
|
|
138629
138998
|
this.plugins = new PluginManager({ kimiHomeDir: this.homeDir });
|
|
@@ -138832,16 +139201,19 @@ var KimiCore = class {
|
|
|
138832
139201
|
});
|
|
138833
139202
|
}
|
|
138834
139203
|
async getKimiConfig(input) {
|
|
138835
|
-
if (input?.reload) this.
|
|
139204
|
+
if (input?.reload) this.reloadRuntimeConfig();
|
|
138836
139205
|
return this.config;
|
|
138837
139206
|
}
|
|
139207
|
+
async getConfigDiagnostics(_input) {
|
|
139208
|
+
return { warnings: this.configWarnings };
|
|
139209
|
+
}
|
|
138838
139210
|
async setKimiConfig(input) {
|
|
138839
|
-
const config = mergeConfigPatch(
|
|
139211
|
+
const config = mergeConfigPatch(this.readConfigForWrite(), input);
|
|
138840
139212
|
await writeConfigFile(this.configPath, config);
|
|
138841
|
-
return this.
|
|
139213
|
+
return this.reloadRuntimeConfig();
|
|
138842
139214
|
}
|
|
138843
139215
|
async removeKimiProvider(input) {
|
|
138844
|
-
const config =
|
|
139216
|
+
const config = this.readConfigForWrite();
|
|
138845
139217
|
delete config.providers[input.providerId];
|
|
138846
139218
|
let removedDefault = false;
|
|
138847
139219
|
const existingModels = config.models ?? {};
|
|
@@ -138853,7 +139225,7 @@ var KimiCore = class {
|
|
|
138853
139225
|
if (removedDefault) config.defaultModel = void 0;
|
|
138854
139226
|
if (config.defaultProvider === input.providerId) config.defaultProvider = void 0;
|
|
138855
139227
|
await writeConfigFile(this.configPath, config);
|
|
138856
|
-
return this.
|
|
139228
|
+
return this.reloadRuntimeConfig();
|
|
138857
139229
|
}
|
|
138858
139230
|
prompt({ sessionId, ...payload }) {
|
|
138859
139231
|
return this.sessionApi(sessionId).prompt(payload);
|
|
@@ -139113,7 +139485,24 @@ var KimiCore = class {
|
|
|
139113
139485
|
return new SessionAPIImpl(session);
|
|
139114
139486
|
}
|
|
139115
139487
|
reloadProviderManager() {
|
|
139116
|
-
return this.
|
|
139488
|
+
return this.reloadRuntimeConfig();
|
|
139489
|
+
}
|
|
139490
|
+
readConfigForWrite() {
|
|
139491
|
+
return readConfigFileForUpdate(this.configPath);
|
|
139492
|
+
}
|
|
139493
|
+
reloadRuntimeConfig() {
|
|
139494
|
+
const loaded = loadRuntimeConfigSafe(this.configPath);
|
|
139495
|
+
if (loaded.fileWarnings.length > 0) {
|
|
139496
|
+
this.configWarnings = [
|
|
139497
|
+
...loaded.fileWarnings,
|
|
139498
|
+
...loaded.envWarnings,
|
|
139499
|
+
"config.toml has errors; keeping the previously loaded configuration."
|
|
139500
|
+
];
|
|
139501
|
+
log.warn("config reload degraded; keeping previous config", { warnings: loaded.fileWarnings });
|
|
139502
|
+
return this.config;
|
|
139503
|
+
}
|
|
139504
|
+
this.configWarnings = loaded.envWarnings;
|
|
139505
|
+
return this.setRuntimeConfig(loaded.config);
|
|
139117
139506
|
}
|
|
139118
139507
|
setRuntimeConfig(config) {
|
|
139119
139508
|
this.config = config;
|
|
@@ -139649,8 +140038,8 @@ var KimiHarness = class {
|
|
|
139649
140038
|
get interactiveAgentId() {
|
|
139650
140039
|
return this.rpc.interactiveAgentId;
|
|
139651
140040
|
}
|
|
139652
|
-
|
|
139653
|
-
this.rpc.
|
|
140041
|
+
withInteractiveAgent(agentId, fn) {
|
|
140042
|
+
return this.rpc.withInteractiveAgent(agentId, fn);
|
|
139654
140043
|
}
|
|
139655
140044
|
track(event, properties) {
|
|
139656
140045
|
this.telemetry.track(event, properties);
|
|
@@ -139776,6 +140165,10 @@ var KimiHarness = class {
|
|
|
139776
140165
|
async getConfig(options = {}) {
|
|
139777
140166
|
return this.rpc.getConfig(options);
|
|
139778
140167
|
}
|
|
140168
|
+
/** Warnings from the most recent config.toml load; empty when the config is fully valid. */
|
|
140169
|
+
async getConfigDiagnostics() {
|
|
140170
|
+
return this.rpc.getConfigDiagnostics();
|
|
140171
|
+
}
|
|
139779
140172
|
async getExperimentalFeatures() {
|
|
139780
140173
|
return this.rpc.getExperimentalFeatures();
|
|
139781
140174
|
}
|
|
@@ -142102,7 +142495,19 @@ function managedModelKey(modelId) {
|
|
|
142102
142495
|
}
|
|
142103
142496
|
function capabilitiesForModel$1(model) {
|
|
142104
142497
|
const caps = /* @__PURE__ */ new Set();
|
|
142105
|
-
|
|
142498
|
+
switch (model.supportsThinkingType) {
|
|
142499
|
+
case "only":
|
|
142500
|
+
caps.add("thinking");
|
|
142501
|
+
caps.add("always_thinking");
|
|
142502
|
+
break;
|
|
142503
|
+
case "both":
|
|
142504
|
+
caps.add("thinking");
|
|
142505
|
+
break;
|
|
142506
|
+
case "no": break;
|
|
142507
|
+
case void 0:
|
|
142508
|
+
if (model.supportsReasoning) caps.add("thinking");
|
|
142509
|
+
break;
|
|
142510
|
+
}
|
|
142106
142511
|
if (model.supportsImageIn) caps.add("image_in");
|
|
142107
142512
|
if (model.supportsVideoIn) caps.add("video_in");
|
|
142108
142513
|
if (model.supportsToolUse ?? true) caps.add("tool_use");
|
|
@@ -142245,9 +142650,13 @@ function toModelInfo$1(item) {
|
|
|
142245
142650
|
supportsImageIn: Boolean(item["supports_image_in"]),
|
|
142246
142651
|
supportsVideoIn: Boolean(item["supports_video_in"]),
|
|
142247
142652
|
supportsToolUse,
|
|
142653
|
+
supportsThinkingType: parseSupportsThinkingType(item["supports_thinking_type"]),
|
|
142248
142654
|
displayName: normalizedDisplayName
|
|
142249
142655
|
};
|
|
142250
142656
|
}
|
|
142657
|
+
function parseSupportsThinkingType(value) {
|
|
142658
|
+
return value === "only" || value === "no" || value === "both" ? value : void 0;
|
|
142659
|
+
}
|
|
142251
142660
|
async function fetchManagedKimiCodeModels(options) {
|
|
142252
142661
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
142253
142662
|
const baseUrl = defaultBaseUrl(options.baseUrl);
|
|
@@ -142336,6 +142745,11 @@ function applyManagedKimiCodeLogoutConfig(config) {
|
|
|
142336
142745
|
if (Object.keys(config.services).length === 0) config.services = void 0;
|
|
142337
142746
|
}
|
|
142338
142747
|
}
|
|
142748
|
+
function forcedThinking(model, fallback) {
|
|
142749
|
+
if (model?.supportsThinkingType === "only") return true;
|
|
142750
|
+
if (model?.supportsThinkingType === "no") return false;
|
|
142751
|
+
return fallback;
|
|
142752
|
+
}
|
|
142339
142753
|
function selectDefaultModel(config, models, options) {
|
|
142340
142754
|
const firstModel = models[0];
|
|
142341
142755
|
if (firstModel === void 0) throw new Error("No models available for Kimi Code.");
|
|
@@ -142346,12 +142760,12 @@ function selectDefaultModel(config, models, options) {
|
|
|
142346
142760
|
const preservedModel = managedModels.get(currentDefault);
|
|
142347
142761
|
return {
|
|
142348
142762
|
modelKey: currentDefault,
|
|
142349
|
-
thinking: config.defaultThinking ?? preservedModel?.supportsReasoning ?? false
|
|
142763
|
+
thinking: forcedThinking(preservedModel, config.defaultThinking ?? preservedModel?.supportsReasoning ?? false)
|
|
142350
142764
|
};
|
|
142351
142765
|
}
|
|
142352
142766
|
return {
|
|
142353
142767
|
modelKey: managedModelKey(firstModel.id),
|
|
142354
|
-
thinking: config.defaultThinking ?? firstModel.supportsReasoning
|
|
142768
|
+
thinking: forcedThinking(firstModel, config.defaultThinking ?? firstModel.supportsReasoning)
|
|
142355
142769
|
};
|
|
142356
142770
|
}
|
|
142357
142771
|
function canPreserveDefaultModel(existingModels, defaultModel, managedModels) {
|
|
@@ -142463,12 +142877,25 @@ function toModelInfo(item) {
|
|
|
142463
142877
|
supportsImageIn: Boolean(item["supports_image_in"]),
|
|
142464
142878
|
supportsVideoIn: Boolean(item["supports_video_in"]),
|
|
142465
142879
|
supportsToolUse,
|
|
142880
|
+
supportsThinkingType: parseSupportsThinkingType(item["supports_thinking_type"]),
|
|
142466
142881
|
displayName: normalizedDisplayName
|
|
142467
142882
|
};
|
|
142468
142883
|
}
|
|
142469
142884
|
function capabilitiesForModel(model) {
|
|
142470
142885
|
const caps = /* @__PURE__ */ new Set();
|
|
142471
|
-
|
|
142886
|
+
switch (model.supportsThinkingType) {
|
|
142887
|
+
case "only":
|
|
142888
|
+
caps.add("thinking");
|
|
142889
|
+
caps.add("always_thinking");
|
|
142890
|
+
break;
|
|
142891
|
+
case "both":
|
|
142892
|
+
caps.add("thinking");
|
|
142893
|
+
break;
|
|
142894
|
+
case "no": break;
|
|
142895
|
+
case void 0:
|
|
142896
|
+
if (model.supportsReasoning) caps.add("thinking");
|
|
142897
|
+
break;
|
|
142898
|
+
}
|
|
142472
142899
|
if (model.supportsImageIn) caps.add("image_in");
|
|
142473
142900
|
if (model.supportsVideoIn) caps.add("video_in");
|
|
142474
142901
|
if (model.supportsToolUse ?? true) caps.add("tool_use");
|
|
@@ -142999,7 +143426,7 @@ var KimiAuthFacade = class {
|
|
|
142999
143426
|
onRefresh: options.onRefresh,
|
|
143000
143427
|
configAdapter: {
|
|
143001
143428
|
configPath: options.configPath,
|
|
143002
|
-
read: () =>
|
|
143429
|
+
read: () => readConfigFileForUpdate(options.configPath),
|
|
143003
143430
|
write: async (config) => {
|
|
143004
143431
|
await writeConfigFile(options.configPath, config);
|
|
143005
143432
|
},
|
|
@@ -143074,7 +143501,7 @@ var KimiAuthFacade = class {
|
|
|
143074
143501
|
};
|
|
143075
143502
|
resolveManagedAuth(providerName) {
|
|
143076
143503
|
const name = providerName ?? "managed:kimi-code";
|
|
143077
|
-
const provider =
|
|
143504
|
+
const provider = loadRuntimeConfigSafe(this.options.configPath).config.providers[name];
|
|
143078
143505
|
return {
|
|
143079
143506
|
oauthRef: provider?.oauth,
|
|
143080
143507
|
baseUrl: provider?.baseUrl
|
|
@@ -143100,10 +143527,16 @@ var KimiAuthFacade = class {
|
|
|
143100
143527
|
//#region ../../packages/node-sdk/src/rpc.ts
|
|
143101
143528
|
const MAIN_AGENT_ID$2 = "main";
|
|
143102
143529
|
var SDKRpcClientBase = class {
|
|
143103
|
-
|
|
143530
|
+
interactiveAgentScope = new AsyncLocalStorage();
|
|
143104
143531
|
eventListeners = /* @__PURE__ */ new Set();
|
|
143105
143532
|
approvalHandlers = /* @__PURE__ */ new Map();
|
|
143106
143533
|
questionHandlers = /* @__PURE__ */ new Map();
|
|
143534
|
+
get interactiveAgentId() {
|
|
143535
|
+
return this.interactiveAgentScope.getStore() ?? MAIN_AGENT_ID$2;
|
|
143536
|
+
}
|
|
143537
|
+
withInteractiveAgent(agentId, fn) {
|
|
143538
|
+
return this.interactiveAgentScope.run(agentId, fn);
|
|
143539
|
+
}
|
|
143107
143540
|
async createSession(input) {
|
|
143108
143541
|
const rpc = await this.getRpc();
|
|
143109
143542
|
const { planMode, ...coreInput } = input;
|
|
@@ -143157,6 +143590,9 @@ var SDKRpcClientBase = class {
|
|
|
143157
143590
|
async getConfig(input) {
|
|
143158
143591
|
return (await this.getRpc()).getKimiConfig(input ?? {});
|
|
143159
143592
|
}
|
|
143593
|
+
async getConfigDiagnostics() {
|
|
143594
|
+
return (await this.getRpc()).getConfigDiagnostics({});
|
|
143595
|
+
}
|
|
143160
143596
|
async getExperimentalFeatures() {
|
|
143161
143597
|
return (await this.getRpc()).getExperimentalFeatures({});
|
|
143162
143598
|
}
|
|
@@ -144401,6 +144837,7 @@ const FEEDBACK_VERSION_PREFIX = "kimi-code-";
|
|
|
144401
144837
|
const FEEDBACK_TELEMETRY_EVENT = "feedback_submitted";
|
|
144402
144838
|
const KIMI_CODE_CDN_BASE = "https://code.kimi.com/kimi-code";
|
|
144403
144839
|
const KIMI_CODE_CDN_LATEST_URL = `${KIMI_CODE_CDN_BASE}/latest`;
|
|
144840
|
+
const KIMI_CODE_TIPS_BANNER_URL = "https://cdn.kimi.com/kimi-code-tips/tips.json";
|
|
144404
144841
|
const KIMI_CODE_PLUGIN_MARKETPLACE_URL = `${KIMI_CODE_CDN_BASE}/plugins/marketplace.json`;
|
|
144405
144842
|
const KIMI_CODE_PLUGIN_MARKETPLACE_URL_ENV = "KIMI_CODE_PLUGIN_MARKETPLACE_URL";
|
|
144406
144843
|
const KIMI_CODE_INSTALL_SH_URL = `${KIMI_CODE_CDN_BASE}/install.sh`;
|
|
@@ -150542,6 +150979,9 @@ var AcpKaos = class AcpKaos {
|
|
|
150542
150979
|
withCwd(cwd) {
|
|
150543
150980
|
return new AcpKaos(this.conn, this.sessionId, this.inner.withCwd(cwd));
|
|
150544
150981
|
}
|
|
150982
|
+
withEnv(env) {
|
|
150983
|
+
return new AcpKaos(this.conn, this.sessionId, this.inner.withEnv(env));
|
|
150984
|
+
}
|
|
150545
150985
|
stat(path, options) {
|
|
150546
150986
|
return this.inner.stat(path, options);
|
|
150547
150987
|
}
|
|
@@ -150562,13 +151002,14 @@ var AcpKaos = class AcpKaos {
|
|
|
150562
151002
|
* should be routed through a non-ACP Kaos.
|
|
150563
151003
|
*/
|
|
150564
151004
|
async readText(path, _options) {
|
|
151005
|
+
const rpcPath = this.toClientPath(path);
|
|
150565
151006
|
try {
|
|
150566
151007
|
return (await this.conn.readTextFile({
|
|
150567
151008
|
sessionId: this.sessionId,
|
|
150568
|
-
path
|
|
151009
|
+
path: rpcPath
|
|
150569
151010
|
})).content;
|
|
150570
151011
|
} catch (err) {
|
|
150571
|
-
throw wrapKaosError(`acp: readTextFile failed for ${
|
|
151012
|
+
throw wrapKaosError(`acp: readTextFile failed for ${rpcPath}`, err);
|
|
150572
151013
|
}
|
|
150573
151014
|
}
|
|
150574
151015
|
/**
|
|
@@ -150646,16 +151087,21 @@ var AcpKaos = class AcpKaos {
|
|
|
150646
151087
|
return data.byteLength;
|
|
150647
151088
|
}
|
|
150648
151089
|
async acpWrite(path, content) {
|
|
151090
|
+
const rpcPath = this.toClientPath(path);
|
|
150649
151091
|
try {
|
|
150650
151092
|
await this.conn.writeTextFile({
|
|
150651
151093
|
sessionId: this.sessionId,
|
|
150652
|
-
path,
|
|
151094
|
+
path: rpcPath,
|
|
150653
151095
|
content
|
|
150654
151096
|
});
|
|
150655
151097
|
} catch (err) {
|
|
150656
|
-
throw wrapKaosError(`acp: writeTextFile failed for ${
|
|
151098
|
+
throw wrapKaosError(`acp: writeTextFile failed for ${rpcPath}`, err);
|
|
150657
151099
|
}
|
|
150658
151100
|
}
|
|
151101
|
+
toClientPath(path) {
|
|
151102
|
+
if (this.inner.pathClass() !== "win32") return path;
|
|
151103
|
+
return path.replaceAll("/", "\\");
|
|
151104
|
+
}
|
|
150659
151105
|
exec(...args) {
|
|
150660
151106
|
return this.inner.exec(...args);
|
|
150661
151107
|
}
|
|
@@ -151702,13 +152148,24 @@ function acpModeToToggles(id) {
|
|
|
151702
152148
|
*/
|
|
151703
152149
|
const TOGGLEABLE_THINKING_MODELS = new Set(["kimi-for-coding", "kimi-code"]);
|
|
151704
152150
|
function deriveThinkingSupported(alias) {
|
|
151705
|
-
|
|
152151
|
+
const declared = alias.capabilities ?? [];
|
|
152152
|
+
if (declared.includes("thinking") || declared.includes("always_thinking")) return true;
|
|
151706
152153
|
const lower = alias.model.toLowerCase();
|
|
151707
152154
|
if (lower.includes("thinking") || lower.includes("reason")) return true;
|
|
151708
152155
|
if (TOGGLEABLE_THINKING_MODELS.has(alias.model)) return true;
|
|
151709
152156
|
return false;
|
|
151710
152157
|
}
|
|
151711
152158
|
/**
|
|
152159
|
+
* Whether the alias declares the 'always_thinking' capability — the model
|
|
152160
|
+
* cannot run with thinking disabled, so the ACP toggle must lock to on.
|
|
152161
|
+
* Deliberately capability-only: the name heuristics above keep feeding
|
|
152162
|
+
* `thinkingSupported`, but only an explicit (server-derived) declaration
|
|
152163
|
+
* may remove the off option from the client.
|
|
152164
|
+
*/
|
|
152165
|
+
function deriveAlwaysThinking(alias) {
|
|
152166
|
+
return (alias.capabilities ?? []).includes("always_thinking");
|
|
152167
|
+
}
|
|
152168
|
+
/**
|
|
151712
152169
|
* Project `harness.getConfig().models` into a flat catalog. Returns an
|
|
151713
152170
|
* empty array when the harness has no models configured, when
|
|
151714
152171
|
* `getConfig` is missing on the harness (partial test stubs), or when
|
|
@@ -151729,7 +152186,8 @@ async function listModelsFromHarness(harness) {
|
|
|
151729
152186
|
for (const [id, alias] of Object.entries(models)) out.push({
|
|
151730
152187
|
id,
|
|
151731
152188
|
name: alias.displayName ?? alias.model ?? id,
|
|
151732
|
-
thinkingSupported: deriveThinkingSupported(alias)
|
|
152189
|
+
thinkingSupported: deriveThinkingSupported(alias),
|
|
152190
|
+
alwaysThinking: deriveAlwaysThinking(alias)
|
|
151733
152191
|
});
|
|
151734
152192
|
return out;
|
|
151735
152193
|
}
|
|
@@ -151788,8 +152246,26 @@ function buildModelOption(models, currentBaseModelId) {
|
|
|
151788
152246
|
* currently-selected model has `thinkingSupported === false`, the
|
|
151789
152247
|
* snapshot omits it entirely (dynamic visibility), so the client never
|
|
151790
152248
|
* shows a toggle that wouldn't do anything.
|
|
152249
|
+
*
|
|
152250
|
+
* `alwaysThinking` models (declared `always_thinking` capability — the
|
|
152251
|
+
* runtime cannot disable thinking) collapse the select to a single
|
|
152252
|
+
* locked `on` entry: the state stays visible to the client, but there
|
|
152253
|
+
* is no off option to pick. ACP has no "disabled entry" concept, so
|
|
152254
|
+
* omitting `off` is the wire-level equivalent of the TUI's greyed-out
|
|
152255
|
+
* `Off (Unsupported)` segment.
|
|
151791
152256
|
*/
|
|
151792
|
-
function buildThinkingOption(enabled) {
|
|
152257
|
+
function buildThinkingOption(enabled, alwaysThinking = false) {
|
|
152258
|
+
if (alwaysThinking) return {
|
|
152259
|
+
type: "select",
|
|
152260
|
+
id: "thinking",
|
|
152261
|
+
name: "Thinking",
|
|
152262
|
+
category: "thought_level",
|
|
152263
|
+
currentValue: "on",
|
|
152264
|
+
options: [{
|
|
152265
|
+
value: "on",
|
|
152266
|
+
name: "Thinking On"
|
|
152267
|
+
}]
|
|
152268
|
+
};
|
|
151793
152269
|
return {
|
|
151794
152270
|
type: "select",
|
|
151795
152271
|
id: "thinking",
|
|
@@ -151856,9 +152332,11 @@ function buildModeOption(currentModeId) {
|
|
|
151856
152332
|
*/
|
|
151857
152333
|
async function buildSessionConfigOptions(harness, currentBaseModelId, currentThinkingEnabled, currentModeId) {
|
|
151858
152334
|
const models = await listModelsFromHarness(harness);
|
|
151859
|
-
const
|
|
152335
|
+
const currentModelEntry = models.find((m) => m.id === currentBaseModelId);
|
|
152336
|
+
const showThinking = currentModelEntry?.thinkingSupported === true;
|
|
152337
|
+
const alwaysThinking = currentModelEntry?.alwaysThinking === true;
|
|
151860
152338
|
const out = [buildModelOption(models, currentBaseModelId)];
|
|
151861
|
-
if (showThinking) out.push(buildThinkingOption(currentThinkingEnabled));
|
|
152339
|
+
if (showThinking) out.push(buildThinkingOption(alwaysThinking || currentThinkingEnabled, alwaysThinking));
|
|
151862
152340
|
out.push(buildModeOption(currentModeId));
|
|
151863
152341
|
return out;
|
|
151864
152342
|
}
|
|
@@ -152204,11 +152682,25 @@ var AcpSession = class {
|
|
|
152204
152682
|
* carries a fresh snapshot.
|
|
152205
152683
|
*/
|
|
152206
152684
|
async setThinking(enabled) {
|
|
152685
|
+
if (!enabled && await this.currentModelAlwaysThinking()) {
|
|
152686
|
+
this.currentThinkingEnabledInternal = true;
|
|
152687
|
+
await this.emitConfigOptionUpdate();
|
|
152688
|
+
return;
|
|
152689
|
+
}
|
|
152207
152690
|
if (typeof this.session.setThinking === "function") await this.session.setThinking(enabled ? THINKING_ON_LEVEL : THINKING_OFF_LEVEL);
|
|
152208
152691
|
this.currentThinkingEnabledInternal = enabled;
|
|
152209
152692
|
await this.emitConfigOptionUpdate();
|
|
152210
152693
|
}
|
|
152211
152694
|
/**
|
|
152695
|
+
* Whether the currently-selected model declares 'always_thinking'.
|
|
152696
|
+
* Harness-less adapter unit tests resolve to false — the agent-core
|
|
152697
|
+
* runtime clamp still protects the actual request in that case.
|
|
152698
|
+
*/
|
|
152699
|
+
async currentModelAlwaysThinking() {
|
|
152700
|
+
if (!this.harness) return false;
|
|
152701
|
+
return (await listModelsFromHarness(this.harness)).find((m) => m.id === this.currentModelIdInternal)?.alwaysThinking === true;
|
|
152702
|
+
}
|
|
152703
|
+
/**
|
|
152212
152704
|
* Forward an ACP `session/set_mode` request to the underlying SDK
|
|
152213
152705
|
* session.
|
|
152214
152706
|
*
|
|
@@ -153909,7 +154401,7 @@ function buildSkillSlashCommands(skills) {
|
|
|
153909
154401
|
const commandMap = /* @__PURE__ */ new Map();
|
|
153910
154402
|
return {
|
|
153911
154403
|
commands: [...skills].toSorted(compareSkillSlashCommands).filter(isUserActivatableSkill).map((skill) => {
|
|
153912
|
-
const commandName = skill.source === "builtin" ? skill.name : `skill:${skill.name}`;
|
|
154404
|
+
const commandName = skill.source === "builtin" || skill.isSubSkill === true ? skill.name : `skill:${skill.name}`;
|
|
153913
154405
|
commandMap.set(commandName, skill.name);
|
|
153914
154406
|
return {
|
|
153915
154407
|
name: commandName,
|
|
@@ -154649,8 +155141,9 @@ function registerLoginCommand(parent) {
|
|
|
154649
155141
|
*
|
|
154650
155142
|
* `add` writes the same `source = { kind: 'apiJson', url, apiKey }` blob the
|
|
154651
155143
|
* TUI does; the next launch's `refreshAllProviderModels`
|
|
154652
|
-
* (apps/kimi-code/src/tui/utils/refresh-providers.ts) groups by
|
|
154653
|
-
* and re-fetches the model list, so periodic
|
|
155144
|
+
* (apps/kimi-code/src/tui/utils/refresh-providers.ts) groups by URL, retries
|
|
155145
|
+
* available API-key candidates, and re-fetches the model list, so periodic
|
|
155146
|
+
* refresh is automatic.
|
|
154654
155147
|
*/
|
|
154655
155148
|
async function handleProviderAdd$1(deps, url, opts) {
|
|
154656
155149
|
const apiKey = resolveApiKey(opts.apiKey, deps.env);
|
|
@@ -154874,29 +155367,42 @@ async function loadCatalogOrExit(deps, url) {
|
|
|
154874
155367
|
}
|
|
154875
155368
|
function registerProviderCommand(parent, deps) {
|
|
154876
155369
|
const provider = parent.command("provider").description("Manage LLM providers non-interactively.");
|
|
155370
|
+
const runAction = async (resolved, run) => {
|
|
155371
|
+
try {
|
|
155372
|
+
await run();
|
|
155373
|
+
} catch (error) {
|
|
155374
|
+
resolved.stderr.write(`${errorMessage(error)}\n`);
|
|
155375
|
+
resolved.exit(1);
|
|
155376
|
+
}
|
|
155377
|
+
};
|
|
154877
155378
|
provider.command("add <url>").description("Import every provider listed in a custom registry (api.json).").option("--api-key <key>", "Registry API key. Falls back to KIMI_REGISTRY_API_KEY.").action(async (url, options) => {
|
|
154878
|
-
|
|
155379
|
+
const resolved = resolveDeps(deps);
|
|
155380
|
+
await runAction(resolved, () => handleProviderAdd$1(resolved, url, { apiKey: options.apiKey }));
|
|
154879
155381
|
});
|
|
154880
155382
|
provider.command("remove <providerId>").description("Remove a provider and every model alias that referenced it.").action(async (providerId) => {
|
|
154881
|
-
|
|
155383
|
+
const resolved = resolveDeps(deps);
|
|
155384
|
+
await runAction(resolved, () => handleProviderRemove(resolved, providerId));
|
|
154882
155385
|
});
|
|
154883
155386
|
provider.command("list").description("Show configured providers and their model counts.").option("--json", "Emit the raw providers/models config as JSON.", false).action(async (options) => {
|
|
154884
|
-
|
|
155387
|
+
const resolved = resolveDeps(deps);
|
|
155388
|
+
await runAction(resolved, () => handleProviderList(resolved, { json: options.json === true }));
|
|
154885
155389
|
});
|
|
154886
155390
|
const catalog = provider.command("catalog").description("Discover and import providers from the public models.dev catalog.");
|
|
154887
155391
|
catalog.command("list [providerId]").description("List providers in the catalog, or models when a providerId is given.").option("--filter <substring>", "Case-insensitive id/name substring filter.").option("--url <url>", `Override catalog URL. Defaults to ${DEFAULT_CATALOG_URL}.`).option("--json", "Emit the matching catalog slice as JSON.", false).action(async (providerId, options) => {
|
|
154888
|
-
|
|
155392
|
+
const resolved = resolveDeps(deps);
|
|
155393
|
+
await runAction(resolved, () => handleCatalogList(resolved, providerId, {
|
|
154889
155394
|
json: options.json === true,
|
|
154890
155395
|
...options.filter === void 0 ? {} : { filter: options.filter },
|
|
154891
155396
|
...options.url === void 0 ? {} : { url: options.url }
|
|
154892
|
-
});
|
|
155397
|
+
}));
|
|
154893
155398
|
});
|
|
154894
155399
|
catalog.command("add <providerId>").description("Import a known provider from the catalog by id.").option("--api-key <key>", "API key for the provider. Falls back to KIMI_REGISTRY_API_KEY.").option("--default-model <modelId>", "Mark the imported model as default_model after import.").option("--url <url>", `Override catalog URL. Defaults to ${DEFAULT_CATALOG_URL}.`).action(async (providerId, options) => {
|
|
154895
|
-
|
|
155400
|
+
const resolved = resolveDeps(deps);
|
|
155401
|
+
await runAction(resolved, () => handleCatalogAdd(resolved, providerId, {
|
|
154896
155402
|
...options.apiKey === void 0 ? {} : { apiKey: options.apiKey },
|
|
154897
155403
|
...options.defaultModel === void 0 ? {} : { defaultModel: options.defaultModel },
|
|
154898
155404
|
...options.url === void 0 ? {} : { url: options.url }
|
|
154899
|
-
});
|
|
155405
|
+
}));
|
|
154900
155406
|
});
|
|
154901
155407
|
}
|
|
154902
155408
|
function resolveDeps(overrides = {}) {
|
|
@@ -154990,9 +155496,6 @@ function validateOptions(opts) {
|
|
|
154990
155496
|
if (promptMode && opts.session === "") throw new OptionConflictError("Cannot use --session without an id in prompt mode.");
|
|
154991
155497
|
if (opts.continue && opts.session !== void 0) throw new OptionConflictError("Cannot combine --continue, --session.");
|
|
154992
155498
|
if (opts.yolo && opts.auto) throw new OptionConflictError("Cannot combine --yolo with --auto.");
|
|
154993
|
-
if (!promptMode && (opts.continue || opts.session !== void 0) && opts.yolo) throw new OptionConflictError("Cannot combine --yolo with --continue or --session.");
|
|
154994
|
-
if (!promptMode && (opts.continue || opts.session !== void 0) && opts.auto) throw new OptionConflictError("Cannot combine --auto with --continue or --session.");
|
|
154995
|
-
if (!promptMode && (opts.continue || opts.session !== void 0) && opts.plan) throw new OptionConflictError("Cannot combine --plan with --continue or --session.");
|
|
154996
155499
|
return {
|
|
154997
155500
|
options: opts,
|
|
154998
155501
|
uiMode: promptMode ? "print" : "shell"
|
|
@@ -155413,7 +155916,6 @@ const LLM_NOT_SET_MESSAGE = "LLM not set, send \"/login\" to login";
|
|
|
155413
155916
|
const NO_ACTIVE_SESSION_MESSAGE = "No active session. Send /login to login.";
|
|
155414
155917
|
const CTRL_D_HINT = "Press Ctrl+D again to exit";
|
|
155415
155918
|
const CTRL_C_HINT = "Press Ctrl+C again to exit";
|
|
155416
|
-
const MAIN_AGENT_ID = "main";
|
|
155417
155919
|
const OAUTH_LOGIN_REQUIRED_STARTUP_NOTICE = "OAuth login expired. Send /login to login.";
|
|
155418
155920
|
const EXIT_CONFIRM_WINDOW_MS = 1500;
|
|
155419
155921
|
function isManagedUsageProvider(providerKey) {
|
|
@@ -155774,7 +156276,7 @@ var SearchableList = class {
|
|
|
155774
156276
|
* addChild(picker), setFocus(picker); the picker invokes `onSelect` or
|
|
155775
156277
|
* `onCancel`, and the host tears it down.
|
|
155776
156278
|
*/
|
|
155777
|
-
function wrapDescription(text, width) {
|
|
156279
|
+
function wrapDescription$1(text, width) {
|
|
155778
156280
|
const maxWidth = Math.max(1, width);
|
|
155779
156281
|
const words = text.trim().split(/\s+/).filter((word) => word.length > 0);
|
|
155780
156282
|
const lines = [];
|
|
@@ -155859,7 +156361,7 @@ var ChoicePickerComponent = class extends Container {
|
|
|
155859
156361
|
lines.push(line);
|
|
155860
156362
|
if (opt.description !== void 0 && opt.description.length > 0) {
|
|
155861
156363
|
const descriptionWidth = Math.max(1, width - 4);
|
|
155862
|
-
for (const descLine of wrapDescription(opt.description, descriptionWidth)) lines.push(currentTheme.fg("textMuted", ` ${descLine}`));
|
|
156364
|
+
for (const descLine of wrapDescription$1(opt.description, descriptionWidth)) lines.push(currentTheme.fg("textMuted", ` ${descLine}`));
|
|
155863
156365
|
}
|
|
155864
156366
|
}
|
|
155865
156367
|
lines.push("");
|
|
@@ -156130,9 +156632,10 @@ var ModelSelectorComponent = class extends Container {
|
|
|
156130
156632
|
}
|
|
156131
156633
|
renderThinkingControl(choice) {
|
|
156132
156634
|
const segment = (label, active) => active ? currentTheme.boldFg("primary", `[ ${label} ]`) : currentTheme.fg("text", ` ${label} `);
|
|
156635
|
+
const unavailable = (label) => currentTheme.fg("textMuted", ` ${label} (Unsupported) `);
|
|
156133
156636
|
const availability = thinkingAvailability(choice.model);
|
|
156134
|
-
if (availability === "always-on") return ` ${segment("
|
|
156135
|
-
if (availability === "unsupported") return ` ${
|
|
156637
|
+
if (availability === "always-on") return ` ${segment("On", true)} ${unavailable("Off")}`;
|
|
156638
|
+
if (availability === "unsupported") return ` ${unavailable("On")} ${segment("Off", true)}`;
|
|
156136
156639
|
const draft = this.draftFor(choice);
|
|
156137
156640
|
return ` ${segment("On", draft)} ${segment("Off", !draft)}`;
|
|
156138
156641
|
}
|
|
@@ -156651,7 +157154,7 @@ var EditorSelectorComponent = class extends ChoicePickerComponent {
|
|
|
156651
157154
|
};
|
|
156652
157155
|
//#endregion
|
|
156653
157156
|
//#region src/tui/components/dialogs/experiments-selector.ts
|
|
156654
|
-
const ELLIPSIS$
|
|
157157
|
+
const ELLIPSIS$8 = "…";
|
|
156655
157158
|
var ExperimentsSelectorComponent = class extends Container {
|
|
156656
157159
|
focused = false;
|
|
156657
157160
|
opts;
|
|
@@ -156710,7 +157213,7 @@ var ExperimentsSelectorComponent = class extends Container {
|
|
|
156710
157213
|
else if (view.page.end < view.items.length) lines.push(currentTheme.fg("textMuted", ` ▼ ${String(view.items.length - view.page.end)} more`));
|
|
156711
157214
|
lines.push(this.renderApplyButton());
|
|
156712
157215
|
lines.push(currentTheme.fg("primary", "─".repeat(width)));
|
|
156713
|
-
return lines.map((line) => truncateToWidth(line, width, ELLIPSIS$
|
|
157216
|
+
return lines.map((line) => truncateToWidth(line, width, ELLIPSIS$8));
|
|
156714
157217
|
}
|
|
156715
157218
|
toggleDraft(feature) {
|
|
156716
157219
|
if (isLocked(feature)) return;
|
|
@@ -156783,7 +157286,7 @@ function wrapText(text, width) {
|
|
|
156783
157286
|
continue;
|
|
156784
157287
|
}
|
|
156785
157288
|
if (current.length > 0) lines.push(current);
|
|
156786
|
-
current = visibleWidth(word) <= maxWidth ? word : truncateToWidth(word, maxWidth, ELLIPSIS$
|
|
157289
|
+
current = visibleWidth(word) <= maxWidth ? word : truncateToWidth(word, maxWidth, ELLIPSIS$8);
|
|
156787
157290
|
}
|
|
156788
157291
|
if (current.length > 0) lines.push(current);
|
|
156789
157292
|
return lines;
|
|
@@ -158154,7 +158657,7 @@ var GoalStartPermissionPromptComponent = class extends StartPermissionPromptComp
|
|
|
158154
158657
|
//#region src/tui/components/dialogs/goal-queue-manager.ts
|
|
158155
158658
|
const MAX_GOAL_OBJECTIVE_LENGTH$2 = 4e3;
|
|
158156
158659
|
const MAX_EDIT_INPUT_LINES = 8;
|
|
158157
|
-
const ELLIPSIS$
|
|
158660
|
+
const ELLIPSIS$7 = "…";
|
|
158158
158661
|
const BRACKET_PASTE_START$1 = "\x1B[200~";
|
|
158159
158662
|
const BRACKET_PASTE_END$1 = "\x1B[201~";
|
|
158160
158663
|
const SHIFT_ENTER_LEGACY = "\x1B\r";
|
|
@@ -158244,7 +158747,7 @@ var GoalQueueManagerComponent = class extends Container {
|
|
|
158244
158747
|
}
|
|
158245
158748
|
lines.push("");
|
|
158246
158749
|
lines.push(currentTheme.fg("primary", "─".repeat(width)));
|
|
158247
|
-
return lines.map((line) => truncateToWidth(line, width, ELLIPSIS$
|
|
158750
|
+
return lines.map((line) => truncateToWidth(line, width, ELLIPSIS$7));
|
|
158248
158751
|
}
|
|
158249
158752
|
renderGoal(goal, index, selected, width) {
|
|
158250
158753
|
const moving = goal.id === this.movingGoalId;
|
|
@@ -158255,7 +158758,7 @@ var GoalQueueManagerComponent = class extends Container {
|
|
|
158255
158758
|
const labelWidth = visibleWidth(labelPrefix);
|
|
158256
158759
|
const stateWidth = visibleWidth(stateLabel);
|
|
158257
158760
|
const objectiveWidth = Math.max(1, width - 5 - labelWidth - stateWidth);
|
|
158258
|
-
const objective = truncateToWidth(formatListObjective(goal.objective), objectiveWidth, ELLIPSIS$
|
|
158761
|
+
const objective = truncateToWidth(formatListObjective(goal.objective), objectiveWidth, ELLIPSIS$7);
|
|
158259
158762
|
let line = prefix + (selected ? (text) => currentTheme.boldFg("primary", text) : (text) => currentTheme.fg("text", text))(labelPrefix + objective);
|
|
158260
158763
|
if (moving) line += currentTheme.fg("success", stateLabel);
|
|
158261
158764
|
return line;
|
|
@@ -158326,10 +158829,10 @@ var GoalQueueEditDialogComponent = class extends Container {
|
|
|
158326
158829
|
const innerWidth = Math.max(10, safeWidth - 4);
|
|
158327
158830
|
const pad = " ";
|
|
158328
158831
|
const border = (s) => currentTheme.fg("primary", s);
|
|
158329
|
-
const title = truncateToWidth(currentTheme.boldFg("textStrong", "Edit upcoming goal"), innerWidth, ELLIPSIS$
|
|
158330
|
-
const subtitle = truncateToWidth(currentTheme.fg(this.error === void 0 ? "textDim" : "warning", this.error ?? "Update the queued objective."), innerWidth, ELLIPSIS$
|
|
158832
|
+
const title = truncateToWidth(currentTheme.boldFg("textStrong", "Edit upcoming goal"), innerWidth, ELLIPSIS$7);
|
|
158833
|
+
const subtitle = truncateToWidth(currentTheme.fg(this.error === void 0 ? "textDim" : "warning", this.error ?? "Update the queued objective."), innerWidth, ELLIPSIS$7);
|
|
158331
158834
|
const inputLines = this.input.render(innerWidth);
|
|
158332
|
-
const footer = truncateToWidth(currentTheme.fg("textDim", "Enter submit · Shift-Enter/Ctrl-J newline · Esc cancel"), innerWidth, ELLIPSIS$
|
|
158835
|
+
const footer = truncateToWidth(currentTheme.fg("textDim", "Enter submit · Shift-Enter/Ctrl-J newline · Esc cancel"), innerWidth, ELLIPSIS$7);
|
|
158333
158836
|
const contentLines = [
|
|
158334
158837
|
title,
|
|
158335
158838
|
"",
|
|
@@ -158435,14 +158938,14 @@ var MultilineGoalInput = class {
|
|
|
158435
158938
|
const cursor = this.cursorLocation();
|
|
158436
158939
|
const range = visibleLineRange(logicalLines.length, cursor.line);
|
|
158437
158940
|
const rendered = [];
|
|
158438
|
-
if (range.start > 0) rendered.push(padInputLine(` ${ELLIPSIS$
|
|
158941
|
+
if (range.start > 0) rendered.push(padInputLine(` ${ELLIPSIS$7} ${String(range.start)} previous`, safeWidth));
|
|
158439
158942
|
for (let lineIndex = range.start; lineIndex < range.end; lineIndex++) {
|
|
158440
158943
|
const line = logicalLines[lineIndex] ?? "";
|
|
158441
158944
|
const prefix = lineIndex === 0 ? "> " : " ";
|
|
158442
158945
|
rendered.push(lineIndex === cursor.line ? renderCursorLine(line, cursor.column, prefix, safeWidth, this.focused) : renderTextLine(line, prefix, safeWidth));
|
|
158443
158946
|
}
|
|
158444
158947
|
const remaining = logicalLines.length - range.end;
|
|
158445
|
-
if (remaining > 0) rendered.push(padInputLine(` ${ELLIPSIS$
|
|
158948
|
+
if (remaining > 0) rendered.push(padInputLine(` ${ELLIPSIS$7} ${String(remaining)} more`, safeWidth));
|
|
158446
158949
|
return rendered;
|
|
158447
158950
|
}
|
|
158448
158951
|
insert(text) {
|
|
@@ -158582,7 +159085,7 @@ function visibleLineRange(totalLines, cursorLine) {
|
|
|
158582
159085
|
}
|
|
158583
159086
|
function renderTextLine(line, prefix, width) {
|
|
158584
159087
|
const prefixWidth = visibleWidth(prefix);
|
|
158585
|
-
return padInputLine(prefix + truncateToWidth(line, Math.max(1, width - prefixWidth), ELLIPSIS$
|
|
159088
|
+
return padInputLine(prefix + truncateToWidth(line, Math.max(1, width - prefixWidth), ELLIPSIS$7), width);
|
|
158586
159089
|
}
|
|
158587
159090
|
function renderCursorLine(line, column, prefix, width, focused) {
|
|
158588
159091
|
const prefixWidth = visibleWidth(prefix);
|
|
@@ -159737,10 +160240,14 @@ function buildProviderManagerOptions(host) {
|
|
|
159737
160240
|
providers: host.state.appState.availableProviders,
|
|
159738
160241
|
activeProviderId,
|
|
159739
160242
|
onAdd: () => {
|
|
159740
|
-
handleProviderAdd(host)
|
|
160243
|
+
handleProviderAdd(host).catch((error) => {
|
|
160244
|
+
host.showError(`Add provider failed: ${formatErrorMessage$2(error)}`);
|
|
160245
|
+
});
|
|
159741
160246
|
},
|
|
159742
160247
|
onDeleteSource: (providerIds) => {
|
|
159743
|
-
handleProviderManagerDeleteSource(host, providerIds)
|
|
160248
|
+
handleProviderManagerDeleteSource(host, providerIds).catch((error) => {
|
|
160249
|
+
host.showError(`Remove provider failed: ${formatErrorMessage$2(error)}`);
|
|
160250
|
+
});
|
|
159744
160251
|
},
|
|
159745
160252
|
onClose: () => {
|
|
159746
160253
|
host.restoreEditor();
|
|
@@ -159890,7 +160397,9 @@ async function handleCatalogProviderAdd(host) {
|
|
|
159890
160397
|
initialTabId: providerId,
|
|
159891
160398
|
onSelect: ({ alias, thinking }) => {
|
|
159892
160399
|
host.restoreEditor();
|
|
159893
|
-
setDefaultModel(host, alias, thinking)
|
|
160400
|
+
setDefaultModel(host, alias, thinking).catch((error) => {
|
|
160401
|
+
host.showError(`Set default model failed: ${formatErrorMessage$2(error)}`);
|
|
160402
|
+
});
|
|
159894
160403
|
},
|
|
159895
160404
|
onCancel: () => {
|
|
159896
160405
|
host.restoreEditor();
|
|
@@ -159918,8 +160427,8 @@ async function handleCustomRegistryAddViaDialog(host) {
|
|
|
159918
160427
|
let entries;
|
|
159919
160428
|
try {
|
|
159920
160429
|
entries = await fetchCustomRegistry(source);
|
|
159921
|
-
} catch (
|
|
159922
|
-
host.showError(`Failed to import registry: ${formatErrorMessage$2(
|
|
160430
|
+
} catch (error) {
|
|
160431
|
+
host.showError(`Failed to import registry: ${formatErrorMessage$2(error)}`);
|
|
159923
160432
|
return false;
|
|
159924
160433
|
}
|
|
159925
160434
|
const addedProviderIds = Object.values(entries).map((entry) => entry.id);
|
|
@@ -159931,8 +160440,8 @@ async function handleCustomRegistryAddViaDialog(host) {
|
|
|
159931
160440
|
models: config.models
|
|
159932
160441
|
});
|
|
159933
160442
|
await host.authFlow.refreshConfigAfterLogin();
|
|
159934
|
-
} catch (
|
|
159935
|
-
host.showError(`Failed to apply registry: ${formatErrorMessage$2(
|
|
160443
|
+
} catch (error) {
|
|
160444
|
+
host.showError(`Failed to apply registry: ${formatErrorMessage$2(error)}`);
|
|
159936
160445
|
return false;
|
|
159937
160446
|
}
|
|
159938
160447
|
const count = addedProviderIds.length;
|
|
@@ -159952,7 +160461,9 @@ async function handleCustomRegistryAddViaDialog(host) {
|
|
|
159952
160461
|
initialTabId: firstNewProvider,
|
|
159953
160462
|
onSelect: ({ alias, thinking }) => {
|
|
159954
160463
|
host.restoreEditor();
|
|
159955
|
-
setDefaultModel(host, alias, thinking)
|
|
160464
|
+
setDefaultModel(host, alias, thinking).catch((error) => {
|
|
160465
|
+
host.showError(`Set default model failed: ${formatErrorMessage$2(error)}`);
|
|
160466
|
+
});
|
|
159956
160467
|
},
|
|
159957
160468
|
onCancel: () => {
|
|
159958
160469
|
host.restoreEditor();
|
|
@@ -160150,7 +160661,7 @@ const OVERVIEW_PLUGIN_PREFIX = "plugin:";
|
|
|
160150
160661
|
const MCP_SERVER_PREFIX = "mcp:";
|
|
160151
160662
|
const REMOVE_CONFIRM_CANCEL = "cancel";
|
|
160152
160663
|
const REMOVE_CONFIRM_REMOVE = "remove";
|
|
160153
|
-
const ELLIPSIS$
|
|
160664
|
+
const ELLIPSIS$6 = "…";
|
|
160154
160665
|
var PluginsOverviewSelectorComponent = class extends Container {
|
|
160155
160666
|
focused = false;
|
|
160156
160667
|
opts;
|
|
@@ -160243,7 +160754,7 @@ var PluginsOverviewSelectorComponent = class extends Container {
|
|
|
160243
160754
|
for (let i = 0; i < actionItems.length; i++) lines.push(...this.renderItem(actionItems[i], pluginItems.length + i, width));
|
|
160244
160755
|
lines.push("");
|
|
160245
160756
|
lines.push(currentTheme.fg("primary", "─".repeat(width)));
|
|
160246
|
-
return lines.map((line) => truncateToWidth(line, width, ELLIPSIS$
|
|
160757
|
+
return lines.map((line) => truncateToWidth(line, width, ELLIPSIS$6));
|
|
160247
160758
|
}
|
|
160248
160759
|
renderItem(item, index, width) {
|
|
160249
160760
|
const selected = index === this.selectedIndex;
|
|
@@ -160315,7 +160826,7 @@ var PluginMarketplaceSelectorComponent = class extends Container {
|
|
|
160315
160826
|
for (let i = 0; i < actions.length; i++) lines.push(...this.renderItem(actions[i], entries.length + i, width));
|
|
160316
160827
|
lines.push("");
|
|
160317
160828
|
lines.push(currentTheme.fg("primary", "─".repeat(width)));
|
|
160318
|
-
return lines.map((line) => truncateToWidth(line, width, ELLIPSIS$
|
|
160829
|
+
return lines.map((line) => truncateToWidth(line, width, ELLIPSIS$6));
|
|
160319
160830
|
}
|
|
160320
160831
|
renderItem(item, index, width) {
|
|
160321
160832
|
const selected = index === this.selectedIndex;
|
|
@@ -160394,7 +160905,7 @@ var PluginMcpSelectorComponent = class extends Container {
|
|
|
160394
160905
|
for (let i = 0; i < actionItems.length; i++) lines.push(...this.renderItem(actionItems[i], serverItems.length + i, width));
|
|
160395
160906
|
lines.push("");
|
|
160396
160907
|
lines.push(currentTheme.fg("primary", "─".repeat(width)));
|
|
160397
|
-
return lines.map((line) => truncateToWidth(line, width, ELLIPSIS$
|
|
160908
|
+
return lines.map((line) => truncateToWidth(line, width, ELLIPSIS$6));
|
|
160398
160909
|
}
|
|
160399
160910
|
renderItem(item, index, width) {
|
|
160400
160911
|
const selected = index === this.selectedIndex;
|
|
@@ -160574,7 +161085,7 @@ function wrapOverviewDescription(text, width) {
|
|
|
160574
161085
|
continue;
|
|
160575
161086
|
}
|
|
160576
161087
|
if (current.length > 0) lines.push(current);
|
|
160577
|
-
current = visibleWidth(word) <= maxWidth ? word : truncateToWidth(word, maxWidth, ELLIPSIS$
|
|
161088
|
+
current = visibleWidth(word) <= maxWidth ? word : truncateToWidth(word, maxWidth, ELLIPSIS$6);
|
|
160578
161089
|
}
|
|
160579
161090
|
if (current.length > 0) lines.push(current);
|
|
160580
161091
|
return lines;
|
|
@@ -161065,15 +161576,23 @@ function applyRuntimeConfig(host, config) {
|
|
|
161065
161576
|
}
|
|
161066
161577
|
//#endregion
|
|
161067
161578
|
//#region src/tui/components/dialogs/swarm-start-permission-prompt.ts
|
|
161068
|
-
const OPTIONS = [
|
|
161069
|
-
|
|
161070
|
-
|
|
161071
|
-
|
|
161072
|
-
|
|
161073
|
-
|
|
161074
|
-
|
|
161075
|
-
|
|
161076
|
-
|
|
161579
|
+
const OPTIONS = [
|
|
161580
|
+
{
|
|
161581
|
+
value: "auto",
|
|
161582
|
+
label: "Switch to Auto and start",
|
|
161583
|
+
description: "Best for swarm tasks. Tools are approved automatically, and questions are skipped."
|
|
161584
|
+
},
|
|
161585
|
+
{
|
|
161586
|
+
value: "yolo",
|
|
161587
|
+
label: "Switch to YOLO and start",
|
|
161588
|
+
description: "Tools and plan changes are approved automatically. Kimi Code may still ask you questions."
|
|
161589
|
+
},
|
|
161590
|
+
{
|
|
161591
|
+
value: "manual",
|
|
161592
|
+
label: "Start in Manual",
|
|
161593
|
+
description: "Keep approvals on. Kimi Code may stop and wait for you during the swarm task."
|
|
161594
|
+
}
|
|
161595
|
+
];
|
|
161077
161596
|
const NOTICE_LINES = [
|
|
161078
161597
|
"Manual mode asks you before Kimi Code runs commands, edits files, or takes other risky actions.",
|
|
161079
161598
|
"Manual mode can block swarm work while agents are running.",
|
|
@@ -161151,7 +161670,7 @@ function showSwarmStartPermissionPrompt(host, commandText, cancelStatus, onSelec
|
|
|
161151
161670
|
}));
|
|
161152
161671
|
}
|
|
161153
161672
|
async function startSwarmWithPermission(host, prompt, choice) {
|
|
161154
|
-
if (choice === "auto") {
|
|
161673
|
+
if (choice === "auto" || choice === "yolo") {
|
|
161155
161674
|
if (!await setPermissionForSwarm(host, choice)) return;
|
|
161156
161675
|
}
|
|
161157
161676
|
await startSwarmTask(host, prompt);
|
|
@@ -161182,7 +161701,7 @@ async function applySwarmMode(host, enabled, commandText) {
|
|
|
161182
161701
|
}
|
|
161183
161702
|
if (enabled && host.state.appState.permissionMode === "manual") {
|
|
161184
161703
|
showSwarmStartPermissionPrompt(host, commandText, "Swarm mode not enabled.", async (choice) => {
|
|
161185
|
-
if (choice === "auto" && !await setPermissionForSwarm(host, choice)) return;
|
|
161704
|
+
if ((choice === "auto" || choice === "yolo") && !await setPermissionForSwarm(host, choice)) return;
|
|
161186
161705
|
if (!await setSwarmMode(host, true, "manual")) return;
|
|
161187
161706
|
renderSwarmModeMarker(host, "active");
|
|
161188
161707
|
});
|
|
@@ -164236,11 +164755,13 @@ var TruncatedOutputComponent = class {
|
|
|
164236
164755
|
maxLines;
|
|
164237
164756
|
indent;
|
|
164238
164757
|
expandHint;
|
|
164758
|
+
tail;
|
|
164239
164759
|
constructor(output, options) {
|
|
164240
164760
|
this.expanded = options.expanded;
|
|
164241
164761
|
this.maxLines = options.maxLines ?? PREVIEW_LINES;
|
|
164242
164762
|
this.indent = options.indent ?? DEFAULT_INDENT;
|
|
164243
164763
|
this.expandHint = options.expandHint ?? true;
|
|
164764
|
+
this.tail = options.tail ?? false;
|
|
164244
164765
|
const cleaned = trimTrailingEmptyLines(output.split("\n")).join("\n");
|
|
164245
164766
|
this.textComponent = new Text(options.isError ? currentTheme.fg("error", cleaned) : currentTheme.dim(cleaned), this.indent, 0);
|
|
164246
164767
|
}
|
|
@@ -164250,8 +164771,12 @@ var TruncatedOutputComponent = class {
|
|
|
164250
164771
|
render(width) {
|
|
164251
164772
|
const contentLines = this.textComponent.render(width);
|
|
164252
164773
|
if (this.expanded || contentLines.length <= this.maxLines) return contentLines;
|
|
164253
|
-
const shown = contentLines.slice(0, this.maxLines);
|
|
164254
164774
|
const remaining = contentLines.length - this.maxLines;
|
|
164775
|
+
if (this.tail) {
|
|
164776
|
+
const shown = contentLines.slice(contentLines.length - this.maxLines);
|
|
164777
|
+
return [" ".repeat(this.indent) + currentTheme.dim(`... (${String(remaining)} earlier lines)`), ...shown];
|
|
164778
|
+
}
|
|
164779
|
+
const shown = contentLines.slice(0, this.maxLines);
|
|
164255
164780
|
const hint = this.expandHint ? `... (${String(remaining)} more lines, ctrl+o to expand)` : `... (${String(remaining)} more lines)`;
|
|
164256
164781
|
return [...shown, " ".repeat(this.indent) + currentTheme.dim(hint)];
|
|
164257
164782
|
}
|
|
@@ -164269,7 +164794,7 @@ var ShellExecutionComponent = class extends Container {
|
|
|
164269
164794
|
constructor(options) {
|
|
164270
164795
|
super();
|
|
164271
164796
|
if (options.showCommand === true) this.addCommandPreview(options.command ?? "", options.commandPreviewLines);
|
|
164272
|
-
if (options.result !== void 0) this.addResultPreview(options.result, options.expanded ?? false, options.resultPreviewLines ?? PREVIEW_LINES);
|
|
164797
|
+
if (options.result !== void 0) this.addResultPreview(options.result, options.expanded ?? false, options.resultPreviewLines ?? PREVIEW_LINES, options.tailOutput ?? false, options.expandHint ?? true);
|
|
164273
164798
|
}
|
|
164274
164799
|
addCommandPreview(command, previewLines) {
|
|
164275
164800
|
if (command.length === 0) return;
|
|
@@ -164280,12 +164805,14 @@ var ShellExecutionComponent = class extends Container {
|
|
|
164280
164805
|
this.addChild(new Text(currentTheme.dim(prefix + line), 2, 0));
|
|
164281
164806
|
}
|
|
164282
164807
|
}
|
|
164283
|
-
addResultPreview(result, expanded, previewLines) {
|
|
164808
|
+
addResultPreview(result, expanded, previewLines, tailOutput, expandHint) {
|
|
164284
164809
|
if (!result.output) return;
|
|
164285
164810
|
this.addChild(new TruncatedOutputComponent(result.output, {
|
|
164286
164811
|
expanded,
|
|
164287
164812
|
isError: result.is_error ?? false,
|
|
164288
|
-
maxLines: previewLines
|
|
164813
|
+
maxLines: previewLines,
|
|
164814
|
+
tail: tailOutput,
|
|
164815
|
+
expandHint
|
|
164289
164816
|
}));
|
|
164290
164817
|
}
|
|
164291
164818
|
};
|
|
@@ -164735,6 +165262,7 @@ const STREAMING_PROGRESS_INTERVAL_MS = 1e3;
|
|
|
164735
165262
|
const SUBAGENT_ELAPSED_INTERVAL_MS = 1e3;
|
|
164736
165263
|
const PROGRESS_URL_RE = /https?:\/\/\S+/g;
|
|
164737
165264
|
const ABORTED_MARK = "⊘";
|
|
165265
|
+
const MAX_LIVE_OUTPUT_CHARS = 5e4;
|
|
164738
165266
|
function backgroundFailureMessage(status) {
|
|
164739
165267
|
switch (status) {
|
|
164740
165268
|
case "lost": return "Background agent lost (session restarted before completion)";
|
|
@@ -165050,6 +165578,7 @@ var ToolCallComponent = class ToolCallComponent extends Container {
|
|
|
165050
165578
|
subagentEndedAtMs;
|
|
165051
165579
|
progressLines = [];
|
|
165052
165580
|
static MAX_PROGRESS_LINES = 24;
|
|
165581
|
+
liveOutput = "";
|
|
165053
165582
|
/**
|
|
165054
165583
|
* Registered by a group container (`AgentGroupComponent` or
|
|
165055
165584
|
* `ReadGroupComponent`) when this component is borrowed as a hidden state
|
|
@@ -165072,6 +165601,7 @@ var ToolCallComponent = class ToolCallComponent extends Container {
|
|
|
165072
165601
|
this.buildCallPreview();
|
|
165073
165602
|
this.callPreviewEndIndex = this.children.length;
|
|
165074
165603
|
this.buildProgressBlock();
|
|
165604
|
+
this.buildLiveOutputBlock();
|
|
165075
165605
|
this.buildContent();
|
|
165076
165606
|
this.buildSubagentBlock();
|
|
165077
165607
|
this.syncStreamingProgressTimer();
|
|
@@ -165090,6 +165620,7 @@ var ToolCallComponent = class ToolCallComponent extends Container {
|
|
|
165090
165620
|
setResult(result) {
|
|
165091
165621
|
this.result = result;
|
|
165092
165622
|
this.progressLines = [];
|
|
165623
|
+
this.liveOutput = "";
|
|
165093
165624
|
this.finalizeSubagentElapsedIfNeeded();
|
|
165094
165625
|
this.syncStreamingProgressTimer();
|
|
165095
165626
|
this.syncSubagentElapsedTimer();
|
|
@@ -165120,6 +165651,14 @@ var ToolCallComponent = class ToolCallComponent extends Container {
|
|
|
165120
165651
|
this.notifySnapshotChange();
|
|
165121
165652
|
this.ui?.requestRender();
|
|
165122
165653
|
}
|
|
165654
|
+
appendLiveOutput(text) {
|
|
165655
|
+
if (this.result !== void 0 || text.length === 0) return;
|
|
165656
|
+
this.liveOutput += text;
|
|
165657
|
+
if (this.liveOutput.length > MAX_LIVE_OUTPUT_CHARS) this.liveOutput = `[...truncated]\n${this.liveOutput.slice(this.liveOutput.length - MAX_LIVE_OUTPUT_CHARS)}`;
|
|
165658
|
+
this.rebuildContent();
|
|
165659
|
+
this.notifySnapshotChange();
|
|
165660
|
+
this.ui?.requestRender();
|
|
165661
|
+
}
|
|
165123
165662
|
dispose() {
|
|
165124
165663
|
this.stopStreamingProgressTimer();
|
|
165125
165664
|
this.stopSubagentElapsedTimer();
|
|
@@ -165490,6 +166029,20 @@ var ToolCallComponent = class ToolCallComponent extends Container {
|
|
|
165490
166029
|
this.notifySnapshotChange();
|
|
165491
166030
|
this.ui?.requestRender();
|
|
165492
166031
|
}
|
|
166032
|
+
appendSubToolLiveOutput(id, text) {
|
|
166033
|
+
if (text.length === 0) return;
|
|
166034
|
+
const activity = this.subToolActivities.get(id);
|
|
166035
|
+
const ongoing = this.ongoingSubCalls.get(id);
|
|
166036
|
+
if (activity === void 0 && ongoing === void 0) return;
|
|
166037
|
+
const name = activity?.name ?? ongoing?.name ?? "Tool";
|
|
166038
|
+
const args = activity?.args ?? ongoing?.args ?? {};
|
|
166039
|
+
let output = (activity?.output ?? "") + text;
|
|
166040
|
+
if (output.length > MAX_LIVE_OUTPUT_CHARS) output = `[...truncated]\n${output.slice(output.length - MAX_LIVE_OUTPUT_CHARS)}`;
|
|
166041
|
+
this.upsertSubToolActivity(id, name, args, activity?.phase ?? "ongoing", output);
|
|
166042
|
+
this.rebuildContent();
|
|
166043
|
+
this.notifySnapshotChange();
|
|
166044
|
+
this.ui?.requestRender();
|
|
166045
|
+
}
|
|
165493
166046
|
finishSubToolCall(result) {
|
|
165494
166047
|
const ongoing = this.ongoingSubCalls.get(result.tool_call_id);
|
|
165495
166048
|
if (ongoing === void 0) return;
|
|
@@ -165564,6 +166117,7 @@ var ToolCallComponent = class ToolCallComponent extends Container {
|
|
|
165564
166117
|
rebuildContent() {
|
|
165565
166118
|
while (this.children.length > this.callPreviewEndIndex) this.children.pop();
|
|
165566
166119
|
this.buildProgressBlock();
|
|
166120
|
+
this.buildLiveOutputBlock();
|
|
165567
166121
|
this.buildContent();
|
|
165568
166122
|
this.buildSubagentBlock();
|
|
165569
166123
|
}
|
|
@@ -165572,6 +166126,7 @@ var ToolCallComponent = class ToolCallComponent extends Container {
|
|
|
165572
166126
|
this.buildCallPreview();
|
|
165573
166127
|
this.callPreviewEndIndex = this.children.length;
|
|
165574
166128
|
this.buildProgressBlock();
|
|
166129
|
+
this.buildLiveOutputBlock();
|
|
165575
166130
|
this.buildContent();
|
|
165576
166131
|
this.buildSubagentBlock();
|
|
165577
166132
|
}
|
|
@@ -165601,6 +166156,21 @@ var ToolCallComponent = class ToolCallComponent extends Container {
|
|
|
165601
166156
|
this.addChild(new Text(styled, 2, 0));
|
|
165602
166157
|
}
|
|
165603
166158
|
}
|
|
166159
|
+
buildLiveOutputBlock() {
|
|
166160
|
+
if (this.result !== void 0) return;
|
|
166161
|
+
if (this.liveOutput.length === 0) return;
|
|
166162
|
+
this.addChild(new ShellExecutionComponent({
|
|
166163
|
+
result: {
|
|
166164
|
+
tool_call_id: this.toolCall.id,
|
|
166165
|
+
output: this.liveOutput,
|
|
166166
|
+
is_error: false
|
|
166167
|
+
},
|
|
166168
|
+
expanded: this.expanded,
|
|
166169
|
+
resultPreviewLines: 3,
|
|
166170
|
+
tailOutput: true,
|
|
166171
|
+
expandHint: false
|
|
166172
|
+
}));
|
|
166173
|
+
}
|
|
165604
166174
|
buildSubagentBlock() {
|
|
165605
166175
|
if (this.subagentAgentId === void 0 && this.ongoingSubCalls.size === 0 && this.finishedSubCalls.length === 0 && this.subagentText.length === 0 && this.subagentPhase === void 0 && this.backgroundTaskTerminalPhase === void 0) return;
|
|
165606
166176
|
if (this.isSingleSubagentView()) {
|
|
@@ -165750,7 +166320,6 @@ var ToolCallComponent = class ToolCallComponent extends Container {
|
|
|
165750
166320
|
if (outputLine !== void 0) this.addChild(new PrefixedWrappedLine(` ${currentTheme.fg("text", "└")} `, " ", currentTheme.fg("text", outputLine)));
|
|
165751
166321
|
}
|
|
165752
166322
|
addSubToolOutputPreview(activity) {
|
|
165753
|
-
if (activity.phase === "ongoing") return;
|
|
165754
166323
|
const output = activity.output;
|
|
165755
166324
|
if (output === void 0 || output.trim().length === 0) return;
|
|
165756
166325
|
if (activity.name !== "Bash" && !isGenericToolResult(activity.name)) return;
|
|
@@ -165759,7 +166328,8 @@ var ToolCallComponent = class ToolCallComponent extends Container {
|
|
|
165759
166328
|
expandHint: false,
|
|
165760
166329
|
isError: activity.phase === "failed",
|
|
165761
166330
|
maxLines: 3,
|
|
165762
|
-
indent: SUBAGENT_SUBTOOL_OUTPUT_INDENT
|
|
166331
|
+
indent: SUBAGENT_SUBTOOL_OUTPUT_INDENT,
|
|
166332
|
+
tail: activity.phase === "ongoing"
|
|
165763
166333
|
}));
|
|
165764
166334
|
}
|
|
165765
166335
|
getRecentSubToolActivities() {
|
|
@@ -166665,6 +167235,7 @@ async function runPrompt(opts, version, io = {}) {
|
|
|
166665
167235
|
try {
|
|
166666
167236
|
await harness.ensureConfigFile();
|
|
166667
167237
|
const config = await harness.getConfig();
|
|
167238
|
+
for (const warning of (await harness.getConfigDiagnostics()).warnings) stderr.write(`Warning: ${warning}\n`);
|
|
166668
167239
|
const { session, resumed, restorePermission, telemetryModel, goalModel } = await resolvePromptSession(harness, opts, workDir, config.defaultModel, stderr, (restorePermission) => {
|
|
166669
167240
|
restorePromptSessionPermission = restorePermission;
|
|
166670
167241
|
});
|
|
@@ -166809,15 +167380,20 @@ function installPromptTerminationCleanup(promptProcess, cleanup) {
|
|
|
166809
167380
|
};
|
|
166810
167381
|
const onSigint = () => exitAfterCleanup("SIGINT");
|
|
166811
167382
|
const onSigterm = () => exitAfterCleanup("SIGTERM");
|
|
167383
|
+
const onSighup = () => exitAfterCleanup("SIGHUP");
|
|
166812
167384
|
promptProcess.once("SIGINT", onSigint);
|
|
166813
167385
|
promptProcess.once("SIGTERM", onSigterm);
|
|
167386
|
+
promptProcess.once("SIGHUP", onSighup);
|
|
166814
167387
|
return () => {
|
|
166815
167388
|
promptProcess.off("SIGINT", onSigint);
|
|
166816
167389
|
promptProcess.off("SIGTERM", onSigterm);
|
|
167390
|
+
promptProcess.off("SIGHUP", onSighup);
|
|
166817
167391
|
};
|
|
166818
167392
|
}
|
|
166819
167393
|
function signalExitCode(signal) {
|
|
166820
|
-
|
|
167394
|
+
if (signal === "SIGINT") return 130;
|
|
167395
|
+
if (signal === "SIGHUP") return 129;
|
|
167396
|
+
return 143;
|
|
166821
167397
|
}
|
|
166822
167398
|
function runPromptTurn(session, prompt, outputFormat, stdout, stderr) {
|
|
166823
167399
|
let activeTurnId;
|
|
@@ -167373,6 +167949,144 @@ function findBinaryRecursively(rootDir, binaryName) {
|
|
|
167373
167949
|
return null;
|
|
167374
167950
|
}
|
|
167375
167951
|
//#endregion
|
|
167952
|
+
//#region src/tui/banner/banner-provider.ts
|
|
167953
|
+
function normalizeTag(value) {
|
|
167954
|
+
if (typeof value !== "string") return null;
|
|
167955
|
+
const trimmed = value.trim();
|
|
167956
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
167957
|
+
}
|
|
167958
|
+
function normalizeText(value) {
|
|
167959
|
+
if (typeof value !== "string") return null;
|
|
167960
|
+
const trimmed = value.trim();
|
|
167961
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
167962
|
+
}
|
|
167963
|
+
function normalizeUtcDate(value) {
|
|
167964
|
+
if (value.endsWith("Z")) return value;
|
|
167965
|
+
if (/[+-]\d{2}:\d{2}$/.test(value)) return value;
|
|
167966
|
+
return `${value}Z`;
|
|
167967
|
+
}
|
|
167968
|
+
function parseDate(value) {
|
|
167969
|
+
if (typeof value !== "string" || value.length === 0) return null;
|
|
167970
|
+
const normalized = normalizeUtcDate(value);
|
|
167971
|
+
const date = new Date(normalized);
|
|
167972
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
167973
|
+
}
|
|
167974
|
+
function isWithinWindow(start, end, now) {
|
|
167975
|
+
if (start !== null && now < start) return false;
|
|
167976
|
+
if (end !== null && now > end) return false;
|
|
167977
|
+
return true;
|
|
167978
|
+
}
|
|
167979
|
+
function meetsMinVersion(minVersion, clientVersion) {
|
|
167980
|
+
if (minVersion === void 0 || minVersion === null) return true;
|
|
167981
|
+
if (typeof minVersion !== "string" || minVersion.length === 0) return true;
|
|
167982
|
+
const min = valid(minVersion);
|
|
167983
|
+
const current = valid(clientVersion);
|
|
167984
|
+
if (min === null || current === null) return false;
|
|
167985
|
+
return gte(current, min);
|
|
167986
|
+
}
|
|
167987
|
+
function pickActiveBanner(json, clientVersion, now) {
|
|
167988
|
+
if (json.banner_enabled !== true) return null;
|
|
167989
|
+
if (!meetsMinVersion(json.banner_min_version, clientVersion)) return null;
|
|
167990
|
+
if (!isWithinWindow(parseDate(json.banner_start_time), parseDate(json.banner_end_time), now)) return null;
|
|
167991
|
+
const mainText = normalizeText(json.banner_maintext);
|
|
167992
|
+
if (mainText === null) return null;
|
|
167993
|
+
return {
|
|
167994
|
+
tag: normalizeTag(json.banner_title),
|
|
167995
|
+
mainText,
|
|
167996
|
+
subText: normalizeText(json.banner_subtext)
|
|
167997
|
+
};
|
|
167998
|
+
}
|
|
167999
|
+
function pickFallbackBanner(json, clientVersion, now, random) {
|
|
168000
|
+
if (json.banner_fallback_enabled !== true) return null;
|
|
168001
|
+
const list = Array.isArray(json.banner_fallback_list) ? json.banner_fallback_list : [];
|
|
168002
|
+
const candidates = [];
|
|
168003
|
+
for (const raw of list) {
|
|
168004
|
+
if (typeof raw !== "object" || raw === null) continue;
|
|
168005
|
+
const item = raw;
|
|
168006
|
+
if (item.enabled !== true) continue;
|
|
168007
|
+
if (!meetsMinVersion(item.banner_min_version, clientVersion)) continue;
|
|
168008
|
+
const mainText = normalizeText(item.banner_maintext);
|
|
168009
|
+
if (mainText === null) continue;
|
|
168010
|
+
candidates.push({
|
|
168011
|
+
tag: normalizeTag(item.banner_title),
|
|
168012
|
+
mainText,
|
|
168013
|
+
subText: normalizeText(item.banner_subtext)
|
|
168014
|
+
});
|
|
168015
|
+
}
|
|
168016
|
+
if (candidates.length === 0) return null;
|
|
168017
|
+
return candidates[Math.floor(random() * candidates.length)];
|
|
168018
|
+
}
|
|
168019
|
+
function selectBannerState(json, clientVersion, now, random) {
|
|
168020
|
+
const typed = typeof json === "object" && json !== null ? json : {};
|
|
168021
|
+
return pickActiveBanner(typed, clientVersion, now) ?? pickFallbackBanner(typed, clientVersion, now, random);
|
|
168022
|
+
}
|
|
168023
|
+
var BannerProvider = class {
|
|
168024
|
+
clientVersion;
|
|
168025
|
+
url;
|
|
168026
|
+
constructor(clientVersion, url = KIMI_CODE_TIPS_BANNER_URL) {
|
|
168027
|
+
this.clientVersion = clientVersion;
|
|
168028
|
+
this.url = url;
|
|
168029
|
+
}
|
|
168030
|
+
async load(fetchImpl = fetch) {
|
|
168031
|
+
try {
|
|
168032
|
+
const controller = new AbortController();
|
|
168033
|
+
const timeout = setTimeout(() => {
|
|
168034
|
+
controller.abort();
|
|
168035
|
+
}, 3e3);
|
|
168036
|
+
const response = await fetchImpl(this.url, { signal: controller.signal });
|
|
168037
|
+
clearTimeout(timeout);
|
|
168038
|
+
if (!response.ok) return null;
|
|
168039
|
+
return selectBannerState(await response.json(), this.clientVersion, /* @__PURE__ */ new Date(), Math.random);
|
|
168040
|
+
} catch {
|
|
168041
|
+
return null;
|
|
168042
|
+
}
|
|
168043
|
+
}
|
|
168044
|
+
};
|
|
168045
|
+
//#endregion
|
|
168046
|
+
//#region src/tui/components/chrome/banner.ts
|
|
168047
|
+
const PREFIX_STAR = "✦";
|
|
168048
|
+
const PADDING = " ";
|
|
168049
|
+
var BannerComponent = class {
|
|
168050
|
+
state;
|
|
168051
|
+
constructor(state) {
|
|
168052
|
+
this.state = state;
|
|
168053
|
+
}
|
|
168054
|
+
invalidate() {}
|
|
168055
|
+
render(width) {
|
|
168056
|
+
const main = (s) => currentTheme.boldFg("textStrong", s);
|
|
168057
|
+
const dim = (s) => currentTheme.fg("textDim", s);
|
|
168058
|
+
if (width < 1) return [""];
|
|
168059
|
+
const tagText = this.state.tag ?? "";
|
|
168060
|
+
const tagLabel = tagText.length > 0 ? `${PREFIX_STAR} ${tagText}` : "";
|
|
168061
|
+
const tagStyled = tagLabel.length > 0 ? currentTheme.boldFg("primary", tagLabel) : "";
|
|
168062
|
+
const tagDisplay = tagStyled.length > 0 ? tagStyled + PADDING : "";
|
|
168063
|
+
const tagWidth = visibleWidth(tagDisplay);
|
|
168064
|
+
const showTag = tagWidth > 0 && tagWidth < width;
|
|
168065
|
+
const bodyIndent = showTag ? " ".repeat(tagWidth) : "";
|
|
168066
|
+
const descIndent = showTag ? " ".repeat(visibleWidth(PREFIX_STAR + PADDING)) : "";
|
|
168067
|
+
const bodyContentWidth = width - (showTag ? tagWidth : 0);
|
|
168068
|
+
const descContentWidth = width - (showTag ? visibleWidth(PREFIX_STAR + PADDING) : 0);
|
|
168069
|
+
if (bodyContentWidth <= 0) return [""];
|
|
168070
|
+
const mainSegments = this.state.mainText.split("\n");
|
|
168071
|
+
const subSegments = this.state.subText ? this.state.subText.split("\n") : [];
|
|
168072
|
+
const result = [];
|
|
168073
|
+
for (let i = 0; i < mainSegments.length; i++) {
|
|
168074
|
+
const wrapped = wrapTextWithAnsi(mainSegments[i], bodyContentWidth);
|
|
168075
|
+
for (let j = 0; j < wrapped.length; j++) {
|
|
168076
|
+
const boldLine = main(wrapped[j]);
|
|
168077
|
+
if (i === 0 && j === 0 && showTag) result.push(tagDisplay + boldLine);
|
|
168078
|
+
else result.push(bodyIndent + boldLine);
|
|
168079
|
+
}
|
|
168080
|
+
}
|
|
168081
|
+
for (const sub of subSegments) {
|
|
168082
|
+
const wrapped = wrapTextWithAnsi(sub, descContentWidth <= 0 ? bodyContentWidth : descContentWidth);
|
|
168083
|
+
for (const line of wrapped) result.push(descIndent + dim(line));
|
|
168084
|
+
}
|
|
168085
|
+
result.push("");
|
|
168086
|
+
return result;
|
|
168087
|
+
}
|
|
168088
|
+
};
|
|
168089
|
+
//#endregion
|
|
167376
168090
|
//#region src/tui/components/chrome/device-code-box.ts
|
|
167377
168091
|
var DeviceCodeBoxComponent = class {
|
|
167378
168092
|
params;
|
|
@@ -167783,16 +168497,16 @@ function buildNumericHint(count) {
|
|
|
167783
168497
|
* emulator's "snap to bottom on stdout" reflex, causing flicker and an
|
|
167784
168498
|
* unscrollable history pane.
|
|
167785
168499
|
*/
|
|
167786
|
-
const ELLIPSIS$
|
|
168500
|
+
const ELLIPSIS$5 = "…";
|
|
167787
168501
|
function padToWidth$2(line, width) {
|
|
167788
168502
|
const w = visibleWidth(line);
|
|
167789
168503
|
if (w === width) return line;
|
|
167790
|
-
if (w > width) return truncateToWidth(line, width, ELLIPSIS$
|
|
168504
|
+
if (w > width) return truncateToWidth(line, width, ELLIPSIS$5);
|
|
167791
168505
|
return line + " ".repeat(width - w);
|
|
167792
168506
|
}
|
|
167793
168507
|
function fitExactly$2(line, width) {
|
|
167794
168508
|
let s = line;
|
|
167795
|
-
if (visibleWidth(s) > width) s = truncateToWidth(s, width, ELLIPSIS$
|
|
168509
|
+
if (visibleWidth(s) > width) s = truncateToWidth(s, width, ELLIPSIS$5);
|
|
167796
168510
|
return padToWidth$2(s, width);
|
|
167797
168511
|
}
|
|
167798
168512
|
var ApprovalPreviewViewer = class extends Container {
|
|
@@ -168649,7 +169363,7 @@ var QuestionDialogComponent = class extends Container {
|
|
|
168649
169363
|
/**
|
|
168650
169364
|
* SessionPicker — pi-tui version of the session selection dialog.
|
|
168651
169365
|
*/
|
|
168652
|
-
const ELLIPSIS$
|
|
169366
|
+
const ELLIPSIS$4 = "…";
|
|
168653
169367
|
function formatRelativeTime$1(ts) {
|
|
168654
169368
|
if (!Number.isFinite(ts) || ts <= 0) return "";
|
|
168655
169369
|
const diffSec = Math.floor(Math.max(0, Date.now() - ts) / 1e3);
|
|
@@ -168669,7 +169383,7 @@ function homeAlias(path) {
|
|
|
168669
169383
|
function truncatePathLeft(path, maxWidth) {
|
|
168670
169384
|
if (maxWidth <= 0) return "";
|
|
168671
169385
|
if (visibleWidth(path) <= maxWidth) return path;
|
|
168672
|
-
if (maxWidth === 1) return ELLIPSIS$
|
|
169386
|
+
if (maxWidth === 1) return ELLIPSIS$4;
|
|
168673
169387
|
const segments = [...new Intl.Segmenter(void 0, { granularity: "grapheme" }).segment(path)].map((s) => s.segment);
|
|
168674
169388
|
let used = 0;
|
|
168675
169389
|
const budget = maxWidth - 1;
|
|
@@ -168682,7 +169396,7 @@ function truncatePathLeft(path, maxWidth) {
|
|
|
168682
169396
|
used += w;
|
|
168683
169397
|
i--;
|
|
168684
169398
|
}
|
|
168685
|
-
return ELLIPSIS$
|
|
169399
|
+
return ELLIPSIS$4 + segments.slice(i + 1).join("");
|
|
168686
169400
|
}
|
|
168687
169401
|
function singleLine$1(text) {
|
|
168688
169402
|
return text.replaceAll(/\s+/g, " ").trim();
|
|
@@ -168734,26 +169448,26 @@ var SessionPickerComponent = class extends Container {
|
|
|
168734
169448
|
if (matchesKey(data, Key.down)) this.selectedIndex = Math.min(this.sessions.length - 1, this.selectedIndex + 1);
|
|
168735
169449
|
}
|
|
168736
169450
|
render(width) {
|
|
168737
|
-
return this.renderLines(width).map((line) => truncateToWidth(line, width, ELLIPSIS$
|
|
169451
|
+
return this.renderLines(width).map((line) => truncateToWidth(line, width, ELLIPSIS$4));
|
|
168738
169452
|
}
|
|
168739
169453
|
renderLines(width) {
|
|
168740
169454
|
const lines = [currentTheme.fg("primary", "─".repeat(width))];
|
|
168741
169455
|
if (this.loading) {
|
|
168742
|
-
lines.push(currentTheme.boldFg("primary", truncateToWidth("Sessions", width, ELLIPSIS$
|
|
168743
|
-
lines.push(currentTheme.fg("textMuted", truncateToWidth("Loading sessions...", width, ELLIPSIS$
|
|
169456
|
+
lines.push(currentTheme.boldFg("primary", truncateToWidth("Sessions", width, ELLIPSIS$4)));
|
|
169457
|
+
lines.push(currentTheme.fg("textMuted", truncateToWidth("Loading sessions...", width, ELLIPSIS$4)));
|
|
168744
169458
|
lines.push(currentTheme.fg("primary", "─".repeat(width)));
|
|
168745
169459
|
return lines;
|
|
168746
169460
|
}
|
|
168747
169461
|
if (this.sessions.length === 0) {
|
|
168748
|
-
lines.push(currentTheme.boldFg("primary", truncateToWidth("Sessions", width, ELLIPSIS$
|
|
168749
|
-
lines.push(currentTheme.fg("textMuted", truncateToWidth("No sessions found. Press Escape to close.", width, ELLIPSIS$
|
|
169462
|
+
lines.push(currentTheme.boldFg("primary", truncateToWidth("Sessions", width, ELLIPSIS$4)));
|
|
169463
|
+
lines.push(currentTheme.fg("textMuted", truncateToWidth("No sessions found. Press Escape to close.", width, ELLIPSIS$4)));
|
|
168750
169464
|
lines.push(currentTheme.fg("primary", "─".repeat(width)));
|
|
168751
169465
|
return lines;
|
|
168752
169466
|
}
|
|
168753
169467
|
const headerLabel = "Sessions ";
|
|
168754
169468
|
const headerHint = "↑↓ navigate · Enter select · Esc cancel";
|
|
168755
169469
|
const labelWidth = visibleWidth(headerLabel);
|
|
168756
|
-
const shownHint = truncateToWidth(headerHint, Math.max(0, width - labelWidth), ELLIPSIS$
|
|
169470
|
+
const shownHint = truncateToWidth(headerHint, Math.max(0, width - labelWidth), ELLIPSIS$4);
|
|
168757
169471
|
lines.push(currentTheme.boldFg("primary", headerLabel) + currentTheme.fg("textMuted", shownHint));
|
|
168758
169472
|
lines.push("");
|
|
168759
169473
|
const visibleStart = Math.max(0, Math.min(this.selectedIndex - Math.floor(this.maxVisibleSessions / 2), Math.max(0, this.sessions.length - this.maxVisibleSessions)));
|
|
@@ -168768,7 +169482,7 @@ var SessionPickerComponent = class extends Container {
|
|
|
168768
169482
|
if (this.sessions.length > visibleSessions.length) {
|
|
168769
169483
|
lines.push("");
|
|
168770
169484
|
const footer = `Showing ${String(visibleStart + 1)}-${String(visibleStart + visibleSessions.length)} of ${String(this.sessions.length)} sessions`;
|
|
168771
|
-
lines.push(currentTheme.fg("textMuted", truncateToWidth(footer, width, ELLIPSIS$
|
|
169485
|
+
lines.push(currentTheme.fg("textMuted", truncateToWidth(footer, width, ELLIPSIS$4)));
|
|
168772
169486
|
}
|
|
168773
169487
|
lines.push(currentTheme.fg("primary", "─".repeat(width)));
|
|
168774
169488
|
return lines;
|
|
@@ -168789,7 +169503,7 @@ var SessionPickerComponent = class extends Container {
|
|
|
168789
169503
|
const trailingWidth = visibleWidth(trailingParts.length > 0 ? " " + trailingParts.join(" ") : "");
|
|
168790
169504
|
const headerPrefixWidth = visibleWidth(pointer) + 1;
|
|
168791
169505
|
const titleBudget = Math.max(8, width - headerPrefixWidth - trailingWidth);
|
|
168792
|
-
const shownTitle = truncateToWidth(singleLine$1(titleSource), titleBudget, ELLIPSIS$
|
|
169506
|
+
const shownTitle = truncateToWidth(singleLine$1(titleSource), titleBudget, ELLIPSIS$4);
|
|
168793
169507
|
let header = currentTheme.fg(isSelected ? "primary" : "textDim", pointer + " ");
|
|
168794
169508
|
header += titleStyle(shownTitle);
|
|
168795
169509
|
if (time.length > 0) header += " " + currentTheme.fg("textDim", time);
|
|
@@ -168804,7 +169518,7 @@ var SessionPickerComponent = class extends Container {
|
|
|
168804
169518
|
const dirWidth = visibleWidth(aliasedDir);
|
|
168805
169519
|
if (idLineWidth + metaGapWidth + dirWidth <= width) card.push(indent + currentTheme.fg("textMuted", fullId) + currentTheme.fg("textDim", metaGap) + currentTheme.fg("textMuted", aliasedDir));
|
|
168806
169520
|
else {
|
|
168807
|
-
card.push(indent + currentTheme.fg("textMuted", truncateToWidth(fullId, Math.max(idWidth, width - indentWidth), ELLIPSIS$
|
|
169521
|
+
card.push(indent + currentTheme.fg("textMuted", truncateToWidth(fullId, Math.max(idWidth, width - indentWidth), ELLIPSIS$4)));
|
|
168808
169522
|
const dir = truncatePathLeft(aliasedDir, Math.max(8, width - indentWidth));
|
|
168809
169523
|
card.push(indent + currentTheme.fg("textMuted", dir));
|
|
168810
169524
|
}
|
|
@@ -168813,7 +169527,7 @@ var SessionPickerComponent = class extends Container {
|
|
|
168813
169527
|
const promptMarker = "› ";
|
|
168814
169528
|
const promptMarkerWidth = visibleWidth(promptMarker);
|
|
168815
169529
|
const promptBudget = Math.max(8, width - indentWidth - promptMarkerWidth);
|
|
168816
|
-
const promptText = truncateToWidth(singleLine$1(rawPrompt), promptBudget, ELLIPSIS$
|
|
169530
|
+
const promptText = truncateToWidth(singleLine$1(rawPrompt), promptBudget, ELLIPSIS$4);
|
|
168817
169531
|
const promptLine = indent + currentTheme.fg("textDim", promptMarker + promptText);
|
|
168818
169532
|
card.push(promptLine);
|
|
168819
169533
|
}
|
|
@@ -168821,6 +169535,447 @@ var SessionPickerComponent = class extends Container {
|
|
|
168821
169535
|
}
|
|
168822
169536
|
};
|
|
168823
169537
|
//#endregion
|
|
169538
|
+
//#region src/tui/components/editor/file-mention-provider.ts
|
|
169539
|
+
const PATH_DELIMITERS = new Set([
|
|
169540
|
+
" ",
|
|
169541
|
+
" ",
|
|
169542
|
+
"\"",
|
|
169543
|
+
"'",
|
|
169544
|
+
"="
|
|
169545
|
+
]);
|
|
169546
|
+
const MAX_FALLBACK_SCAN = 2e3;
|
|
169547
|
+
const MAX_FALLBACK_SUGGESTIONS = 50;
|
|
169548
|
+
/**
|
|
169549
|
+
* Kimi wrapper around pi-tui's combined autocomplete provider.
|
|
169550
|
+
*
|
|
169551
|
+
* File / folder mention behavior uses pi-tui's fd-backed provider when fd is
|
|
169552
|
+
* available. While managed fd is downloading (or when it is unavailable), a
|
|
169553
|
+
* small filesystem fallback keeps basic `@` file and folder completion usable.
|
|
169554
|
+
* Ordinary path completion is still handled by pi-tui's readdir-backed path
|
|
169555
|
+
* completer. This wrapper also keeps Kimi-specific slash-command guards.
|
|
169556
|
+
*/
|
|
169557
|
+
var FileMentionProvider = class {
|
|
169558
|
+
slashCommands;
|
|
169559
|
+
workDir;
|
|
169560
|
+
fdPath;
|
|
169561
|
+
inner;
|
|
169562
|
+
constructor(slashCommands, workDir, fdPath) {
|
|
169563
|
+
this.slashCommands = slashCommands;
|
|
169564
|
+
this.workDir = workDir;
|
|
169565
|
+
this.fdPath = fdPath;
|
|
169566
|
+
const expanded = [];
|
|
169567
|
+
for (const cmd of slashCommands) {
|
|
169568
|
+
expanded.push(cmd);
|
|
169569
|
+
for (const alias of cmd.aliases ?? []) expanded.push({
|
|
169570
|
+
...cmd,
|
|
169571
|
+
name: alias
|
|
169572
|
+
});
|
|
169573
|
+
}
|
|
169574
|
+
this.inner = new CombinedAutocompleteProvider(expanded, workDir, fdPath);
|
|
169575
|
+
}
|
|
169576
|
+
async getSuggestions(lines, cursorLine, cursorCol, options) {
|
|
169577
|
+
const currentLine = lines[cursorLine] ?? "";
|
|
169578
|
+
const textBeforeCursor = currentLine.slice(0, cursorCol);
|
|
169579
|
+
if (shouldSuppressLeadingWhitespaceSlashPath(textBeforeCursor, options.force)) return null;
|
|
169580
|
+
if (shouldSuppressSlashArgumentCompletion(textBeforeCursor, currentLine.slice(cursorCol), options.force)) return null;
|
|
169581
|
+
const atPrefix = extractAtPrefix(textBeforeCursor);
|
|
169582
|
+
if (atPrefix !== null) {
|
|
169583
|
+
if (this.fdPath === null) return getFsMentionSuggestions(this.workDir, atPrefix, options.signal);
|
|
169584
|
+
try {
|
|
169585
|
+
return await this.inner.getSuggestions(lines, cursorLine, cursorCol, options);
|
|
169586
|
+
} catch {
|
|
169587
|
+
return getFsMentionSuggestions(this.workDir, atPrefix, options.signal);
|
|
169588
|
+
}
|
|
169589
|
+
}
|
|
169590
|
+
if (!options.force && textBeforeCursor.startsWith("/")) {
|
|
169591
|
+
if (textBeforeCursor.indexOf(" ") === -1) {
|
|
169592
|
+
const tokens = textBeforeCursor.slice(1).trim().split(/\s+/).filter((t) => t.length > 0);
|
|
169593
|
+
const matches = [];
|
|
169594
|
+
for (const cmd of this.slashCommands) {
|
|
169595
|
+
const nameScore = scoreTokens(tokens, cmd.name);
|
|
169596
|
+
if (nameScore !== null) {
|
|
169597
|
+
matches.push({
|
|
169598
|
+
cmd,
|
|
169599
|
+
score: nameScore,
|
|
169600
|
+
viaAlias: false,
|
|
169601
|
+
label: cmd.name
|
|
169602
|
+
});
|
|
169603
|
+
continue;
|
|
169604
|
+
}
|
|
169605
|
+
const aliases = cmd.aliases ?? [];
|
|
169606
|
+
let bestAliasScore = null;
|
|
169607
|
+
for (const alias of aliases) {
|
|
169608
|
+
const aliasScore = scoreTokens(tokens, alias);
|
|
169609
|
+
if (aliasScore !== null && (bestAliasScore === null || aliasScore < bestAliasScore)) bestAliasScore = aliasScore;
|
|
169610
|
+
}
|
|
169611
|
+
if (bestAliasScore !== null) matches.push({
|
|
169612
|
+
cmd,
|
|
169613
|
+
score: bestAliasScore,
|
|
169614
|
+
viaAlias: true,
|
|
169615
|
+
label: `${cmd.name} (${aliases.join(", ")})`
|
|
169616
|
+
});
|
|
169617
|
+
}
|
|
169618
|
+
matches.sort((a, b) => a.score - b.score || Number(a.viaAlias) - Number(b.viaAlias));
|
|
169619
|
+
if (matches.length === 0) return null;
|
|
169620
|
+
return {
|
|
169621
|
+
items: matches.map((m) => ({
|
|
169622
|
+
value: m.cmd.name,
|
|
169623
|
+
label: m.label,
|
|
169624
|
+
description: formatSlashCommandDescription(m.cmd)
|
|
169625
|
+
})),
|
|
169626
|
+
prefix: textBeforeCursor
|
|
169627
|
+
};
|
|
169628
|
+
}
|
|
169629
|
+
}
|
|
169630
|
+
try {
|
|
169631
|
+
return await this.inner.getSuggestions(lines, cursorLine, cursorCol, options);
|
|
169632
|
+
} catch {
|
|
169633
|
+
return null;
|
|
169634
|
+
}
|
|
169635
|
+
}
|
|
169636
|
+
applyCompletion(lines, cursorLine, cursorCol, item, prefix) {
|
|
169637
|
+
return this.inner.applyCompletion(lines, cursorLine, cursorCol, item, prefix);
|
|
169638
|
+
}
|
|
169639
|
+
};
|
|
169640
|
+
function extractAtPrefix(text) {
|
|
169641
|
+
let tokenStart = 0;
|
|
169642
|
+
for (let i = text.length - 1; i >= 0; i -= 1) if (PATH_DELIMITERS.has(text[i] ?? "")) {
|
|
169643
|
+
tokenStart = i + 1;
|
|
169644
|
+
break;
|
|
169645
|
+
}
|
|
169646
|
+
if (text[tokenStart] !== "@") return null;
|
|
169647
|
+
return text.slice(tokenStart);
|
|
169648
|
+
}
|
|
169649
|
+
function getFsMentionSuggestions(workDir, atPrefix, signal) {
|
|
169650
|
+
if (signal.aborted) return null;
|
|
169651
|
+
const query = atPrefix.slice(1);
|
|
169652
|
+
const candidates = collectFsMentionCandidates(workDir, signal);
|
|
169653
|
+
if (candidates.length === 0 || signal.aborted) return null;
|
|
169654
|
+
const ranked = rankFsMentionCandidates(candidates, query).slice(0, MAX_FALLBACK_SUGGESTIONS);
|
|
169655
|
+
if (ranked.length === 0) return null;
|
|
169656
|
+
return {
|
|
169657
|
+
prefix: atPrefix,
|
|
169658
|
+
items: ranked.map(toMentionItem)
|
|
169659
|
+
};
|
|
169660
|
+
}
|
|
169661
|
+
function collectFsMentionCandidates(workDir, signal) {
|
|
169662
|
+
const result = [];
|
|
169663
|
+
const stack = [""];
|
|
169664
|
+
while (stack.length > 0 && result.length < MAX_FALLBACK_SCAN) {
|
|
169665
|
+
if (signal.aborted) break;
|
|
169666
|
+
const relativeDir = stack.pop() ?? "";
|
|
169667
|
+
const absoluteDir = relativeDir.length === 0 ? workDir : join$1(workDir, relativeDir);
|
|
169668
|
+
let entries;
|
|
169669
|
+
try {
|
|
169670
|
+
entries = readdirSync(absoluteDir, { withFileTypes: true });
|
|
169671
|
+
} catch {
|
|
169672
|
+
continue;
|
|
169673
|
+
}
|
|
169674
|
+
for (const entry of entries) {
|
|
169675
|
+
if (signal.aborted || result.length >= MAX_FALLBACK_SCAN) break;
|
|
169676
|
+
if (entry.name === ".git") continue;
|
|
169677
|
+
const relativePath = normalizePath(relativeDir.length === 0 ? entry.name : join$1(relativeDir, entry.name));
|
|
169678
|
+
const isSymlink = entry.isSymbolicLink();
|
|
169679
|
+
let isDirectory = entry.isDirectory();
|
|
169680
|
+
if (!isDirectory && isSymlink) try {
|
|
169681
|
+
isDirectory = statSync(join$1(workDir, relativePath)).isDirectory();
|
|
169682
|
+
} catch {}
|
|
169683
|
+
result.push({
|
|
169684
|
+
path: relativePath,
|
|
169685
|
+
isDirectory
|
|
169686
|
+
});
|
|
169687
|
+
if (isDirectory && !isSymlink) stack.push(relativePath);
|
|
169688
|
+
}
|
|
169689
|
+
}
|
|
169690
|
+
return result;
|
|
169691
|
+
}
|
|
169692
|
+
function rankFsMentionCandidates(candidates, query) {
|
|
169693
|
+
const lowerQuery = query.toLowerCase();
|
|
169694
|
+
const scored = [];
|
|
169695
|
+
for (const candidate of candidates) {
|
|
169696
|
+
const score = scoreCandidate(candidate, lowerQuery);
|
|
169697
|
+
if (score > 0) scored.push({
|
|
169698
|
+
candidate,
|
|
169699
|
+
score
|
|
169700
|
+
});
|
|
169701
|
+
}
|
|
169702
|
+
scored.sort((a, b) => {
|
|
169703
|
+
if (a.score !== b.score) return b.score - a.score;
|
|
169704
|
+
if (a.candidate.isDirectory !== b.candidate.isDirectory) return a.candidate.isDirectory ? -1 : 1;
|
|
169705
|
+
return a.candidate.path.localeCompare(b.candidate.path);
|
|
169706
|
+
});
|
|
169707
|
+
return scored.map((entry) => entry.candidate);
|
|
169708
|
+
}
|
|
169709
|
+
function scoreCandidate(candidate, lowerQuery) {
|
|
169710
|
+
if (lowerQuery.length === 0) {
|
|
169711
|
+
const depthPenalty = candidate.path.split("/").length - 1;
|
|
169712
|
+
return (candidate.isDirectory ? 120 : 100) - depthPenalty;
|
|
169713
|
+
}
|
|
169714
|
+
const lowerPath = candidate.path.toLowerCase();
|
|
169715
|
+
const lowerBase = basename$1(candidate.path).toLowerCase();
|
|
169716
|
+
let score = 0;
|
|
169717
|
+
if (lowerBase === lowerQuery) score = 100;
|
|
169718
|
+
else if (lowerBase.startsWith(lowerQuery)) score = 80;
|
|
169719
|
+
else if (lowerBase.includes(lowerQuery)) score = 50;
|
|
169720
|
+
else if (lowerPath.includes(lowerQuery)) score = 30;
|
|
169721
|
+
if (candidate.isDirectory && score > 0) score += 10;
|
|
169722
|
+
return score;
|
|
169723
|
+
}
|
|
169724
|
+
function toMentionItem(candidate) {
|
|
169725
|
+
const valuePath = candidate.isDirectory ? `${candidate.path}/` : candidate.path;
|
|
169726
|
+
return {
|
|
169727
|
+
value: valuePath.includes(" ") ? `@"${valuePath}"` : `@${valuePath}`,
|
|
169728
|
+
label: `${basename$1(candidate.path)}${candidate.isDirectory ? "/" : ""}`,
|
|
169729
|
+
description: valuePath
|
|
169730
|
+
};
|
|
169731
|
+
}
|
|
169732
|
+
function normalizePath(path) {
|
|
169733
|
+
return path.replaceAll("\\", "/");
|
|
169734
|
+
}
|
|
169735
|
+
function shouldSuppressLeadingWhitespaceSlashPath(textBeforeCursor, force) {
|
|
169736
|
+
if (force === true) return false;
|
|
169737
|
+
if (textBeforeCursor.startsWith("/")) return false;
|
|
169738
|
+
return textBeforeCursor.trimStart().startsWith("/");
|
|
169739
|
+
}
|
|
169740
|
+
function shouldSuppressSlashArgumentCompletion(textBeforeCursor, textAfterCursor, force) {
|
|
169741
|
+
if (force === true) return false;
|
|
169742
|
+
if (!textBeforeCursor.startsWith("/")) return false;
|
|
169743
|
+
if (!textBeforeCursor.includes(" ")) return false;
|
|
169744
|
+
return textAfterCursor.trimStart().length > 0;
|
|
169745
|
+
}
|
|
169746
|
+
/**
|
|
169747
|
+
* All tokens must fuzzy-match `text`; returns the summed score, or null when
|
|
169748
|
+
* any token misses. An empty token list matches everything with score 0.
|
|
169749
|
+
* Mirrors pi-tui fuzzyFilter's token semantics — keep in sync if it changes.
|
|
169750
|
+
*/
|
|
169751
|
+
function scoreTokens(tokens, text) {
|
|
169752
|
+
let score = 0;
|
|
169753
|
+
for (const token of tokens) {
|
|
169754
|
+
const m = fuzzyMatch(token, text);
|
|
169755
|
+
if (!m.matches) return null;
|
|
169756
|
+
score += m.score;
|
|
169757
|
+
}
|
|
169758
|
+
return score;
|
|
169759
|
+
}
|
|
169760
|
+
/**
|
|
169761
|
+
* Mirrors CombinedAutocompleteProvider's description rendering so the
|
|
169762
|
+
* intercepted name completion keeps showing the argument hint.
|
|
169763
|
+
*/
|
|
169764
|
+
function formatSlashCommandDescription(cmd) {
|
|
169765
|
+
const desc = cmd.description ?? "";
|
|
169766
|
+
return (cmd.argumentHint ? desc ? `${cmd.argumentHint} — ${desc}` : cmd.argumentHint : desc) || void 0;
|
|
169767
|
+
}
|
|
169768
|
+
//#endregion
|
|
169769
|
+
//#region src/tui/components/messages/goal-markers.ts
|
|
169770
|
+
/**
|
|
169771
|
+
* Low-profile transcript markers for the autonomous goal loop.
|
|
169772
|
+
*
|
|
169773
|
+
* Lifecycle changes (paused / resumed / cancelled) and `no_progress` verdicts
|
|
169774
|
+
* render as a single dim line — `◦ Goal paused` — that expands (ctrl+o, shared
|
|
169775
|
+
* with tool output) to show the reason when there is one. Terminal outcomes use
|
|
169776
|
+
* the richer completion card (the `/goal` box), not this marker.
|
|
169777
|
+
*/
|
|
169778
|
+
const HEAD_INDENT = " ";
|
|
169779
|
+
const DETAIL_INDENT = " ";
|
|
169780
|
+
var GoalMarkerComponent = class {
|
|
169781
|
+
headline;
|
|
169782
|
+
detail;
|
|
169783
|
+
accentToken;
|
|
169784
|
+
expanded = false;
|
|
169785
|
+
marker;
|
|
169786
|
+
textToken;
|
|
169787
|
+
expandable;
|
|
169788
|
+
indent;
|
|
169789
|
+
leadingBlank;
|
|
169790
|
+
constructor(headline, detail, accentToken, options = {}) {
|
|
169791
|
+
this.headline = headline;
|
|
169792
|
+
this.detail = detail;
|
|
169793
|
+
this.accentToken = accentToken;
|
|
169794
|
+
this.marker = options.marker ?? "◦";
|
|
169795
|
+
this.textToken = options.textToken ?? "textDim";
|
|
169796
|
+
this.expandable = options.expandable ?? true;
|
|
169797
|
+
this.indent = options.indent ?? HEAD_INDENT;
|
|
169798
|
+
this.leadingBlank = options.leadingBlank ?? false;
|
|
169799
|
+
}
|
|
169800
|
+
invalidate() {}
|
|
169801
|
+
setExpanded(expanded) {
|
|
169802
|
+
this.expanded = expanded;
|
|
169803
|
+
}
|
|
169804
|
+
render(width) {
|
|
169805
|
+
const dot = currentTheme.fg(this.accentToken, this.marker);
|
|
169806
|
+
const head = currentTheme.fg(this.textToken, this.headline);
|
|
169807
|
+
if (!(this.detail !== void 0 && this.detail.length > 0)) return this.clampToWidth([`${this.indent}${dot} ${head}`], width);
|
|
169808
|
+
if (!this.expandable) return this.clampToWidth([`${this.indent}${dot} ${head}`], width);
|
|
169809
|
+
if (!this.expanded) return this.clampToWidth([`${this.indent}${dot} ${head} ${currentTheme.fg("textMuted", "(ctrl+o)")}`], width);
|
|
169810
|
+
const out = [`${this.indent}${dot} ${head}`];
|
|
169811
|
+
const wrapWidth = Math.max(20, width - 4);
|
|
169812
|
+
for (const line of wrap(this.detail, wrapWidth)) out.push(DETAIL_INDENT + currentTheme.fg("textDim", line));
|
|
169813
|
+
return this.clampToWidth(out, width);
|
|
169814
|
+
}
|
|
169815
|
+
clampToWidth(lines, width) {
|
|
169816
|
+
const withBlank = this.withLeadingBlank(lines);
|
|
169817
|
+
if (width <= 0) return withBlank.map(() => "");
|
|
169818
|
+
return withBlank.map((line) => truncateToWidth(line, width));
|
|
169819
|
+
}
|
|
169820
|
+
withLeadingBlank(lines) {
|
|
169821
|
+
return this.leadingBlank ? ["", ...lines] : lines;
|
|
169822
|
+
}
|
|
169823
|
+
};
|
|
169824
|
+
/**
|
|
169825
|
+
* Builds a marker for a lifecycle change (paused / resumed / blocked), or `null`
|
|
169826
|
+
* when the change should be silent (a `completion` change posts its own message,
|
|
169827
|
+
* not a marker). `expanded` seeds the initial ctrl+o state.
|
|
169828
|
+
*/
|
|
169829
|
+
function buildGoalMarker(change, expanded, actor) {
|
|
169830
|
+
const spec = markerSpec(change, actor);
|
|
169831
|
+
if (spec === null) return null;
|
|
169832
|
+
const marker = new GoalMarkerComponent(spec.headline, spec.detail ?? change.reason, spec.accentToken, spec.options);
|
|
169833
|
+
marker.setExpanded(expanded);
|
|
169834
|
+
return marker;
|
|
169835
|
+
}
|
|
169836
|
+
function markerSpec(change, actor) {
|
|
169837
|
+
if (change.kind === "lifecycle") switch (change.status) {
|
|
169838
|
+
case "paused": return prominentMarker(pausedHeadline(change.reason, actor), "warning");
|
|
169839
|
+
case "active": return prominentMarker(resumedHeadline(actor), "primary");
|
|
169840
|
+
case "blocked": return {
|
|
169841
|
+
headline: "Goal blocked",
|
|
169842
|
+
accentToken: "warning"
|
|
169843
|
+
};
|
|
169844
|
+
default: return null;
|
|
169845
|
+
}
|
|
169846
|
+
return null;
|
|
169847
|
+
}
|
|
169848
|
+
function prominentMarker(headline, accentToken) {
|
|
169849
|
+
return {
|
|
169850
|
+
headline,
|
|
169851
|
+
accentToken,
|
|
169852
|
+
detail: void 0,
|
|
169853
|
+
options: {
|
|
169854
|
+
marker: STATUS_BULLET.trimEnd(),
|
|
169855
|
+
textToken: accentToken,
|
|
169856
|
+
expandable: false,
|
|
169857
|
+
indent: "",
|
|
169858
|
+
leadingBlank: true
|
|
169859
|
+
}
|
|
169860
|
+
};
|
|
169861
|
+
}
|
|
169862
|
+
function pausedHeadline(reason, actor) {
|
|
169863
|
+
if (reason === "Paused after interruption") return "Goal paused due to user's interruption";
|
|
169864
|
+
if (actor === "user") return "Goal paused by the user.";
|
|
169865
|
+
if (reason?.startsWith("Paused ") === true) return `Goal ${lowercaseFirst(reason)}`;
|
|
169866
|
+
if (reason !== void 0 && reason.length > 0) return `Goal paused: ${reason}`;
|
|
169867
|
+
if (actor === "model") return "Goal paused by the agent.";
|
|
169868
|
+
return "Goal paused";
|
|
169869
|
+
}
|
|
169870
|
+
function resumedHeadline(actor) {
|
|
169871
|
+
if (actor === "user") return "Goal resumed by the user.";
|
|
169872
|
+
if (actor === "model") return "Goal resumed by the agent.";
|
|
169873
|
+
return "Goal resumed";
|
|
169874
|
+
}
|
|
169875
|
+
function lowercaseFirst(text) {
|
|
169876
|
+
return text.length === 0 ? text : `${text[0].toLowerCase()}${text.slice(1)}`;
|
|
169877
|
+
}
|
|
169878
|
+
function wrap(text, width) {
|
|
169879
|
+
const words = text.replaceAll(/\s+/g, " ").trim().split(" ");
|
|
169880
|
+
const lines = [];
|
|
169881
|
+
let current = "";
|
|
169882
|
+
for (const word of words) {
|
|
169883
|
+
const candidate = current.length === 0 ? word : `${current} ${word}`;
|
|
169884
|
+
if (candidate.length > width && current.length > 0) {
|
|
169885
|
+
lines.push(current);
|
|
169886
|
+
current = word;
|
|
169887
|
+
} else current = candidate;
|
|
169888
|
+
}
|
|
169889
|
+
if (current.length > 0) lines.push(current);
|
|
169890
|
+
return lines.length > 0 ? lines : [""];
|
|
169891
|
+
}
|
|
169892
|
+
//#endregion
|
|
169893
|
+
//#region src/tui/components/messages/status-message.ts
|
|
169894
|
+
var StatusMessageComponent = class extends Container {
|
|
169895
|
+
textComponent;
|
|
169896
|
+
content;
|
|
169897
|
+
color;
|
|
169898
|
+
constructor(content, color) {
|
|
169899
|
+
super();
|
|
169900
|
+
this.content = content;
|
|
169901
|
+
this.color = color;
|
|
169902
|
+
const text = color === void 0 ? currentTheme.fg("textDim", content) : currentTheme.fg(color, content);
|
|
169903
|
+
this.textComponent = new Text(` ${text}`, 0, 0);
|
|
169904
|
+
this.addChild(this.textComponent);
|
|
169905
|
+
}
|
|
169906
|
+
invalidate() {
|
|
169907
|
+
const text = this.color === void 0 ? currentTheme.fg("textDim", this.content) : currentTheme.fg(this.color, this.content);
|
|
169908
|
+
this.textComponent.setText(` ${text}`);
|
|
169909
|
+
super.invalidate();
|
|
169910
|
+
}
|
|
169911
|
+
};
|
|
169912
|
+
var NoticeMessageComponent = class extends Container {
|
|
169913
|
+
titleText;
|
|
169914
|
+
detailText;
|
|
169915
|
+
title;
|
|
169916
|
+
detail;
|
|
169917
|
+
constructor(title, detail) {
|
|
169918
|
+
super();
|
|
169919
|
+
this.title = title;
|
|
169920
|
+
this.detail = detail;
|
|
169921
|
+
this.addChild(new Spacer(1));
|
|
169922
|
+
this.titleText = new Text(` ${currentTheme.fg("textStrong", title)}`, 0, 0);
|
|
169923
|
+
this.addChild(this.titleText);
|
|
169924
|
+
if (detail !== void 0 && detail.length > 0) {
|
|
169925
|
+
this.detailText = new Text(` ${currentTheme.fg("textDim", detail)}`, 0, 0);
|
|
169926
|
+
this.addChild(this.detailText);
|
|
169927
|
+
}
|
|
169928
|
+
}
|
|
169929
|
+
invalidate() {
|
|
169930
|
+
this.titleText.setText(` ${currentTheme.fg("textStrong", this.title)}`);
|
|
169931
|
+
if (this.detailText !== void 0 && this.detail !== void 0) this.detailText.setText(` ${currentTheme.fg("textDim", this.detail)}`);
|
|
169932
|
+
super.invalidate();
|
|
169933
|
+
}
|
|
169934
|
+
};
|
|
169935
|
+
//#endregion
|
|
169936
|
+
//#region src/tui/components/panes/activity-pane.ts
|
|
169937
|
+
var ActivityPaneComponent = class extends Container {
|
|
169938
|
+
constructor(options) {
|
|
169939
|
+
super();
|
|
169940
|
+
if (options.mode === "waiting" || options.mode === "tool") {
|
|
169941
|
+
if (options.spinner !== void 0) {
|
|
169942
|
+
this.addChild(new Spacer(1));
|
|
169943
|
+
this.addChild(options.spinner);
|
|
169944
|
+
}
|
|
169945
|
+
return;
|
|
169946
|
+
}
|
|
169947
|
+
if (options.mode === "composing" && options.spinner !== void 0) {
|
|
169948
|
+
this.addChild(new Spacer(1));
|
|
169949
|
+
this.addChild(options.spinner);
|
|
169950
|
+
}
|
|
169951
|
+
}
|
|
169952
|
+
};
|
|
169953
|
+
//#endregion
|
|
169954
|
+
//#region src/tui/components/panes/queue-pane.ts
|
|
169955
|
+
const ELLIPSIS$3 = "…";
|
|
169956
|
+
var QueuePaneComponent = class extends Container {
|
|
169957
|
+
messages;
|
|
169958
|
+
hint;
|
|
169959
|
+
constructor(options) {
|
|
169960
|
+
super();
|
|
169961
|
+
this.messages = options.messages;
|
|
169962
|
+
if (options.messages.length > 0) this.hint = options.isCompacting && !options.isStreaming ? " ↑ to edit · will send after compaction" : !options.canSteerImmediately ? " ↑ to edit · will send after current task" : " ↑ to edit · ctrl-s to steer immediately";
|
|
169963
|
+
}
|
|
169964
|
+
render(width) {
|
|
169965
|
+
const accent = (text) => currentTheme.fg("accent", text);
|
|
169966
|
+
const dim = (text) => currentTheme.fg("textDim", text);
|
|
169967
|
+
const lines = [];
|
|
169968
|
+
for (const item of this.messages) {
|
|
169969
|
+
const singleLine = item.text.replaceAll(/\s+/g, " ").trim();
|
|
169970
|
+
const prefix = ` ❯ `;
|
|
169971
|
+
const truncated = truncateToWidth(singleLine, Math.max(1, width - visibleWidth(prefix)), ELLIPSIS$3);
|
|
169972
|
+
lines.push(accent(prefix + truncated));
|
|
169973
|
+
}
|
|
169974
|
+
if (this.hint !== void 0) lines.push(dim(truncateToWidth(this.hint, width, ELLIPSIS$3)));
|
|
169975
|
+
return lines;
|
|
169976
|
+
}
|
|
169977
|
+
};
|
|
169978
|
+
//#endregion
|
|
168824
169979
|
//#region src/tui/utils/refresh-providers.ts
|
|
168825
169980
|
function readCustomRegistrySource(provider) {
|
|
168826
169981
|
const source = provider.source;
|
|
@@ -168837,6 +169992,26 @@ function readCustomRegistrySource(provider) {
|
|
|
168837
169992
|
apiKey
|
|
168838
169993
|
};
|
|
168839
169994
|
}
|
|
169995
|
+
function customRegistrySourceKey(source) {
|
|
169996
|
+
return JSON.stringify([source.url]);
|
|
169997
|
+
}
|
|
169998
|
+
function customRegistrySourceCredentialKey(source) {
|
|
169999
|
+
return JSON.stringify([source.url, source.apiKey]);
|
|
170000
|
+
}
|
|
170001
|
+
async function fetchCustomRegistryFromSources(sources) {
|
|
170002
|
+
let lastError;
|
|
170003
|
+
for (const source of sources) try {
|
|
170004
|
+
return {
|
|
170005
|
+
entries: await fetchCustomRegistry(source),
|
|
170006
|
+
source
|
|
170007
|
+
};
|
|
170008
|
+
} catch (error) {
|
|
170009
|
+
lastError = error;
|
|
170010
|
+
}
|
|
170011
|
+
if (lastError instanceof Error) throw lastError;
|
|
170012
|
+
if (typeof lastError === "string") throw new Error(lastError);
|
|
170013
|
+
throw new Error("No custom registry sources configured.");
|
|
170014
|
+
}
|
|
168840
170015
|
function asManaged(config) {
|
|
168841
170016
|
return config;
|
|
168842
170017
|
}
|
|
@@ -168887,6 +170062,12 @@ function providerModelSnapshot(config, providerId, aliasKeys) {
|
|
|
168887
170062
|
function providerModelsEqual(config, nextConfig, providerId, aliasKeys) {
|
|
168888
170063
|
return providerModelSnapshot(config, providerId, aliasKeys) === providerModelSnapshot(nextConfig, providerId, aliasKeys);
|
|
168889
170064
|
}
|
|
170065
|
+
function providerConfigSnapshot(config, providerId) {
|
|
170066
|
+
return JSON.stringify(config.providers[providerId] ?? null);
|
|
170067
|
+
}
|
|
170068
|
+
function providerConfigEqual(config, nextConfig, providerId) {
|
|
170069
|
+
return providerConfigSnapshot(config, providerId) === providerConfigSnapshot(nextConfig, providerId);
|
|
170070
|
+
}
|
|
168890
170071
|
function providerRefreshAliasKeys(config, nextConfig, providerId, aliasPrefix) {
|
|
168891
170072
|
const keys = generatedProviderAliasKeys(config, providerId, aliasPrefix);
|
|
168892
170073
|
for (const key of providerAliasKeys(nextConfig, providerId)) keys.add(key);
|
|
@@ -168910,7 +170091,7 @@ function restoreProviderAliases(config, aliases) {
|
|
|
168910
170091
|
function restoreDefaultSelection(config, defaultModel, defaultThinking) {
|
|
168911
170092
|
if (defaultModel === void 0 || config.models?.[defaultModel] === void 0) return;
|
|
168912
170093
|
config.defaultModel = defaultModel;
|
|
168913
|
-
config.defaultThinking = defaultThinking;
|
|
170094
|
+
config.defaultThinking = (config.models[defaultModel]?.capabilities ?? []).includes("always_thinking") ? true : defaultThinking;
|
|
168914
170095
|
}
|
|
168915
170096
|
function clampDanglingDefault(config) {
|
|
168916
170097
|
if (config.defaultModel !== void 0 && config.models?.[config.defaultModel] === void 0) {
|
|
@@ -168918,6 +170099,9 @@ function clampDanglingDefault(config) {
|
|
|
168918
170099
|
config.defaultThinking = void 0;
|
|
168919
170100
|
}
|
|
168920
170101
|
}
|
|
170102
|
+
function clearDefaultThinkingWhenDefaultRemoved(config, previousDefaultModel) {
|
|
170103
|
+
if (previousDefaultModel !== void 0 && config.defaultModel === void 0) config.defaultThinking = void 0;
|
|
170104
|
+
}
|
|
168921
170105
|
function pickDefaultModel(config, providerId, models) {
|
|
168922
170106
|
const firstModel = models[0];
|
|
168923
170107
|
if (firstModel === void 0) return "";
|
|
@@ -168959,6 +170143,7 @@ async function refreshAllProviderModels(host) {
|
|
|
168959
170143
|
restoreProviderAliases(next, preserveUserProviderAliases(config, KIMI_CODE_PROVIDER_NAME, refreshedAliasKeys));
|
|
168960
170144
|
restoreDefaultSelection(next, config.defaultModel, config.defaultThinking);
|
|
168961
170145
|
clampDanglingDefault(next);
|
|
170146
|
+
clearDefaultThinkingWhenDefaultRemoved(next, config.defaultModel);
|
|
168962
170147
|
if (providerModelsEqual(config, next, "managed:kimi-code", refreshedAliasKeys)) unchanged.push(KIMI_CODE_PROVIDER_NAME);
|
|
168963
170148
|
else {
|
|
168964
170149
|
const { added, removed } = computeChanges(collectModelIdsForAliases(config, refreshedAliasKeys), collectModelIdsForAliases(next, refreshedAliasKeys));
|
|
@@ -169010,6 +170195,7 @@ async function refreshAllProviderModels(host) {
|
|
|
169010
170195
|
restoreProviderAliases(next, preserveUserProviderAliases(config, providerId, refreshedAliasKeys));
|
|
169011
170196
|
restoreDefaultSelection(next, config.defaultModel, config.defaultThinking);
|
|
169012
170197
|
clampDanglingDefault(next);
|
|
170198
|
+
clearDefaultThinkingWhenDefaultRemoved(next, config.defaultModel);
|
|
169013
170199
|
if (providerModelsEqual(config, next, providerId, refreshedAliasKeys)) unchanged.push(providerId);
|
|
169014
170200
|
else {
|
|
169015
170201
|
const { added, removed } = computeChanges(collectModelIdsForAliases(config, refreshedAliasKeys), collectModelIdsForAliases(next, refreshedAliasKeys));
|
|
@@ -169040,26 +170226,55 @@ async function refreshAllProviderModels(host) {
|
|
|
169040
170226
|
if (isOpenPlatformId(providerId)) continue;
|
|
169041
170227
|
const source = readCustomRegistrySource(providerConfig);
|
|
169042
170228
|
if (source === void 0) continue;
|
|
169043
|
-
const key =
|
|
170229
|
+
const key = customRegistrySourceKey(source);
|
|
170230
|
+
const sourceKey = customRegistrySourceCredentialKey(source);
|
|
169044
170231
|
const entry = customSources.get(key);
|
|
169045
|
-
if (entry !== void 0)
|
|
169046
|
-
|
|
169047
|
-
|
|
170232
|
+
if (entry !== void 0) {
|
|
170233
|
+
if (!entry.sourceKeys.has(sourceKey)) {
|
|
170234
|
+
entry.sources.push(source);
|
|
170235
|
+
entry.sourceKeys.add(sourceKey);
|
|
170236
|
+
}
|
|
170237
|
+
entry.providerIds.push(providerId);
|
|
170238
|
+
} else customSources.set(key, {
|
|
170239
|
+
sources: [source],
|
|
170240
|
+
sourceKeys: new Set([sourceKey]),
|
|
169048
170241
|
providerIds: [providerId]
|
|
169049
170242
|
});
|
|
169050
170243
|
}
|
|
169051
|
-
for (const {
|
|
169052
|
-
const entries = await
|
|
170244
|
+
for (const { sources, providerIds } of customSources.values()) try {
|
|
170245
|
+
const { entries, source } = await fetchCustomRegistryFromSources(sources);
|
|
169053
170246
|
const next = structuredClone(config);
|
|
169054
170247
|
const changedProviders = [];
|
|
169055
|
-
|
|
169056
|
-
|
|
169057
|
-
|
|
170248
|
+
const providersToRemoveBeforeSet = /* @__PURE__ */ new Set();
|
|
170249
|
+
let hasUnreportedConfigChange = false;
|
|
170250
|
+
const remoteEntries = Object.values(entries);
|
|
170251
|
+
const remoteEntriesByProviderId = new Map(remoteEntries.map((entry) => [entry.id, entry]));
|
|
170252
|
+
const providerIdsToSync = new Set(providerIds);
|
|
170253
|
+
for (const entry of remoteEntries) providerIdsToSync.add(entry.id);
|
|
170254
|
+
for (const providerId of providerIdsToSync) {
|
|
170255
|
+
const entry = remoteEntriesByProviderId.get(providerId);
|
|
170256
|
+
if (entry === void 0) {
|
|
170257
|
+
const oldIds = collectModelIdsForAliases(config, providerAliasKeys(config, providerId));
|
|
170258
|
+
removeCustomRegistryProvider(asManaged(next), providerId);
|
|
170259
|
+
changedProviders.push({
|
|
170260
|
+
providerId,
|
|
170261
|
+
providerName: providerId,
|
|
170262
|
+
added: 0,
|
|
170263
|
+
removed: oldIds.size
|
|
170264
|
+
});
|
|
170265
|
+
providersToRemoveBeforeSet.add(providerId);
|
|
170266
|
+
continue;
|
|
170267
|
+
}
|
|
170268
|
+
const existed = config.providers[providerId] !== void 0;
|
|
169058
170269
|
applyCustomRegistryProvider(asManaged(next), entry, source);
|
|
169059
170270
|
const refreshedAliasKeys = providerRefreshAliasKeys(config, next, providerId, `${providerId}/`);
|
|
169060
|
-
restoreProviderAliases(next, preserveUserProviderAliases(config, providerId, refreshedAliasKeys));
|
|
169061
|
-
if (providerModelsEqual(config, next, providerId, refreshedAliasKeys)) unchanged.push(providerId);
|
|
169062
|
-
else {
|
|
170271
|
+
if (existed) restoreProviderAliases(next, preserveUserProviderAliases(config, providerId, refreshedAliasKeys));
|
|
170272
|
+
if (existed && providerModelsEqual(config, next, providerId, refreshedAliasKeys) && providerConfigEqual(config, next, providerId)) unchanged.push(providerId);
|
|
170273
|
+
else if (existed && providerModelsEqual(config, next, providerId, refreshedAliasKeys)) {
|
|
170274
|
+
unchanged.push(providerId);
|
|
170275
|
+
providersToRemoveBeforeSet.add(providerId);
|
|
170276
|
+
hasUnreportedConfigChange = true;
|
|
170277
|
+
} else {
|
|
169063
170278
|
const { added, removed } = computeChanges(collectModelIdsForAliases(config, refreshedAliasKeys), collectModelIdsForAliases(next, refreshedAliasKeys));
|
|
169064
170279
|
changedProviders.push({
|
|
169065
170280
|
providerId,
|
|
@@ -169067,19 +170282,26 @@ async function refreshAllProviderModels(host) {
|
|
|
169067
170282
|
added,
|
|
169068
170283
|
removed
|
|
169069
170284
|
});
|
|
170285
|
+
if (existed) providersToRemoveBeforeSet.add(providerId);
|
|
169070
170286
|
}
|
|
169071
170287
|
}
|
|
169072
|
-
if (changedProviders.length > 0) {
|
|
170288
|
+
if (changedProviders.length > 0 || hasUnreportedConfigChange) {
|
|
169073
170289
|
restoreDefaultSelection(next, config.defaultModel, config.defaultThinking);
|
|
169074
170290
|
clampDanglingDefault(next);
|
|
169075
|
-
|
|
170291
|
+
clearDefaultThinkingWhenDefaultRemoved(next, config.defaultModel);
|
|
170292
|
+
for (const providerId of providersToRemoveBeforeSet) await host.removeProvider(providerId);
|
|
169076
170293
|
config = await host.setConfig({
|
|
169077
170294
|
providers: next.providers,
|
|
169078
170295
|
models: next.models,
|
|
169079
170296
|
defaultModel: next.defaultModel,
|
|
169080
170297
|
defaultThinking: next.defaultThinking
|
|
169081
170298
|
});
|
|
169082
|
-
for (const change of changedProviders) changed.push(
|
|
170299
|
+
for (const change of changedProviders) changed.push({
|
|
170300
|
+
providerId: change.providerId,
|
|
170301
|
+
providerName: change.providerName,
|
|
170302
|
+
added: change.added,
|
|
170303
|
+
removed: change.removed
|
|
170304
|
+
});
|
|
169083
170305
|
}
|
|
169084
170306
|
} catch (error) {
|
|
169085
170307
|
for (const providerId of providerIds) failed.push({
|
|
@@ -169539,13 +170761,7 @@ var BtwPanelController = class {
|
|
|
169539
170761
|
return panel.isRunning() || panel.isEmpty();
|
|
169540
170762
|
}
|
|
169541
170763
|
withInteractiveAgent(agentId, fn) {
|
|
169542
|
-
|
|
169543
|
-
this.host.harness.interactiveAgentId = agentId;
|
|
169544
|
-
try {
|
|
169545
|
-
return fn();
|
|
169546
|
-
} finally {
|
|
169547
|
-
this.host.harness.interactiveAgentId = previousAgentId;
|
|
169548
|
-
}
|
|
170764
|
+
return this.host.harness.withInteractiveAgent(agentId, fn);
|
|
169549
170765
|
}
|
|
169550
170766
|
};
|
|
169551
170767
|
function formatBtwTurnEnd(event) {
|
|
@@ -170682,173 +171898,6 @@ var EditorKeyboardController = class {
|
|
|
170682
171898
|
}
|
|
170683
171899
|
};
|
|
170684
171900
|
//#endregion
|
|
170685
|
-
//#region src/tui/components/messages/goal-markers.ts
|
|
170686
|
-
/**
|
|
170687
|
-
* Low-profile transcript markers for the autonomous goal loop.
|
|
170688
|
-
*
|
|
170689
|
-
* Lifecycle changes (paused / resumed / cancelled) and `no_progress` verdicts
|
|
170690
|
-
* render as a single dim line — `◦ Goal paused` — that expands (ctrl+o, shared
|
|
170691
|
-
* with tool output) to show the reason when there is one. Terminal outcomes use
|
|
170692
|
-
* the richer completion card (the `/goal` box), not this marker.
|
|
170693
|
-
*/
|
|
170694
|
-
const HEAD_INDENT = " ";
|
|
170695
|
-
const DETAIL_INDENT = " ";
|
|
170696
|
-
var GoalMarkerComponent = class {
|
|
170697
|
-
headline;
|
|
170698
|
-
detail;
|
|
170699
|
-
accentToken;
|
|
170700
|
-
expanded = false;
|
|
170701
|
-
marker;
|
|
170702
|
-
textToken;
|
|
170703
|
-
expandable;
|
|
170704
|
-
indent;
|
|
170705
|
-
leadingBlank;
|
|
170706
|
-
constructor(headline, detail, accentToken, options = {}) {
|
|
170707
|
-
this.headline = headline;
|
|
170708
|
-
this.detail = detail;
|
|
170709
|
-
this.accentToken = accentToken;
|
|
170710
|
-
this.marker = options.marker ?? "◦";
|
|
170711
|
-
this.textToken = options.textToken ?? "textDim";
|
|
170712
|
-
this.expandable = options.expandable ?? true;
|
|
170713
|
-
this.indent = options.indent ?? HEAD_INDENT;
|
|
170714
|
-
this.leadingBlank = options.leadingBlank ?? false;
|
|
170715
|
-
}
|
|
170716
|
-
invalidate() {}
|
|
170717
|
-
setExpanded(expanded) {
|
|
170718
|
-
this.expanded = expanded;
|
|
170719
|
-
}
|
|
170720
|
-
render(width) {
|
|
170721
|
-
const dot = currentTheme.fg(this.accentToken, this.marker);
|
|
170722
|
-
const head = currentTheme.fg(this.textToken, this.headline);
|
|
170723
|
-
if (!(this.detail !== void 0 && this.detail.length > 0)) return this.clampToWidth([`${this.indent}${dot} ${head}`], width);
|
|
170724
|
-
if (!this.expandable) return this.clampToWidth([`${this.indent}${dot} ${head}`], width);
|
|
170725
|
-
if (!this.expanded) return this.clampToWidth([`${this.indent}${dot} ${head} ${currentTheme.fg("textMuted", "(ctrl+o)")}`], width);
|
|
170726
|
-
const out = [`${this.indent}${dot} ${head}`];
|
|
170727
|
-
const wrapWidth = Math.max(20, width - 4);
|
|
170728
|
-
for (const line of wrap(this.detail, wrapWidth)) out.push(DETAIL_INDENT + currentTheme.fg("textDim", line));
|
|
170729
|
-
return this.clampToWidth(out, width);
|
|
170730
|
-
}
|
|
170731
|
-
clampToWidth(lines, width) {
|
|
170732
|
-
const withBlank = this.withLeadingBlank(lines);
|
|
170733
|
-
if (width <= 0) return withBlank.map(() => "");
|
|
170734
|
-
return withBlank.map((line) => truncateToWidth(line, width));
|
|
170735
|
-
}
|
|
170736
|
-
withLeadingBlank(lines) {
|
|
170737
|
-
return this.leadingBlank ? ["", ...lines] : lines;
|
|
170738
|
-
}
|
|
170739
|
-
};
|
|
170740
|
-
/**
|
|
170741
|
-
* Builds a marker for a lifecycle change (paused / resumed / blocked), or `null`
|
|
170742
|
-
* when the change should be silent (a `completion` change posts its own message,
|
|
170743
|
-
* not a marker). `expanded` seeds the initial ctrl+o state.
|
|
170744
|
-
*/
|
|
170745
|
-
function buildGoalMarker(change, expanded, actor) {
|
|
170746
|
-
const spec = markerSpec(change, actor);
|
|
170747
|
-
if (spec === null) return null;
|
|
170748
|
-
const marker = new GoalMarkerComponent(spec.headline, spec.detail ?? change.reason, spec.accentToken, spec.options);
|
|
170749
|
-
marker.setExpanded(expanded);
|
|
170750
|
-
return marker;
|
|
170751
|
-
}
|
|
170752
|
-
function markerSpec(change, actor) {
|
|
170753
|
-
if (change.kind === "lifecycle") switch (change.status) {
|
|
170754
|
-
case "paused": return prominentMarker(pausedHeadline(change.reason, actor), "warning");
|
|
170755
|
-
case "active": return prominentMarker(resumedHeadline(actor), "primary");
|
|
170756
|
-
case "blocked": return {
|
|
170757
|
-
headline: "Goal blocked",
|
|
170758
|
-
accentToken: "warning"
|
|
170759
|
-
};
|
|
170760
|
-
default: return null;
|
|
170761
|
-
}
|
|
170762
|
-
return null;
|
|
170763
|
-
}
|
|
170764
|
-
function prominentMarker(headline, accentToken) {
|
|
170765
|
-
return {
|
|
170766
|
-
headline,
|
|
170767
|
-
accentToken,
|
|
170768
|
-
detail: void 0,
|
|
170769
|
-
options: {
|
|
170770
|
-
marker: STATUS_BULLET.trimEnd(),
|
|
170771
|
-
textToken: accentToken,
|
|
170772
|
-
expandable: false,
|
|
170773
|
-
indent: "",
|
|
170774
|
-
leadingBlank: true
|
|
170775
|
-
}
|
|
170776
|
-
};
|
|
170777
|
-
}
|
|
170778
|
-
function pausedHeadline(reason, actor) {
|
|
170779
|
-
if (reason === "Paused after interruption") return "Goal paused due to user's interruption";
|
|
170780
|
-
if (actor === "user") return "Goal paused by the user.";
|
|
170781
|
-
if (reason?.startsWith("Paused ") === true) return `Goal ${lowercaseFirst(reason)}`;
|
|
170782
|
-
if (reason !== void 0 && reason.length > 0) return `Goal paused: ${reason}`;
|
|
170783
|
-
if (actor === "model") return "Goal paused by the agent.";
|
|
170784
|
-
return "Goal paused";
|
|
170785
|
-
}
|
|
170786
|
-
function resumedHeadline(actor) {
|
|
170787
|
-
if (actor === "user") return "Goal resumed by the user.";
|
|
170788
|
-
if (actor === "model") return "Goal resumed by the agent.";
|
|
170789
|
-
return "Goal resumed";
|
|
170790
|
-
}
|
|
170791
|
-
function lowercaseFirst(text) {
|
|
170792
|
-
return text.length === 0 ? text : `${text[0].toLowerCase()}${text.slice(1)}`;
|
|
170793
|
-
}
|
|
170794
|
-
function wrap(text, width) {
|
|
170795
|
-
const words = text.replaceAll(/\s+/g, " ").trim().split(" ");
|
|
170796
|
-
const lines = [];
|
|
170797
|
-
let current = "";
|
|
170798
|
-
for (const word of words) {
|
|
170799
|
-
const candidate = current.length === 0 ? word : `${current} ${word}`;
|
|
170800
|
-
if (candidate.length > width && current.length > 0) {
|
|
170801
|
-
lines.push(current);
|
|
170802
|
-
current = word;
|
|
170803
|
-
} else current = candidate;
|
|
170804
|
-
}
|
|
170805
|
-
if (current.length > 0) lines.push(current);
|
|
170806
|
-
return lines.length > 0 ? lines : [""];
|
|
170807
|
-
}
|
|
170808
|
-
//#endregion
|
|
170809
|
-
//#region src/tui/components/messages/status-message.ts
|
|
170810
|
-
var StatusMessageComponent = class extends Container {
|
|
170811
|
-
textComponent;
|
|
170812
|
-
content;
|
|
170813
|
-
color;
|
|
170814
|
-
constructor(content, color) {
|
|
170815
|
-
super();
|
|
170816
|
-
this.content = content;
|
|
170817
|
-
this.color = color;
|
|
170818
|
-
const text = color === void 0 ? currentTheme.fg("textDim", content) : currentTheme.fg(color, content);
|
|
170819
|
-
this.textComponent = new Text(` ${text}`, 0, 0);
|
|
170820
|
-
this.addChild(this.textComponent);
|
|
170821
|
-
}
|
|
170822
|
-
invalidate() {
|
|
170823
|
-
const text = this.color === void 0 ? currentTheme.fg("textDim", this.content) : currentTheme.fg(this.color, this.content);
|
|
170824
|
-
this.textComponent.setText(` ${text}`);
|
|
170825
|
-
super.invalidate();
|
|
170826
|
-
}
|
|
170827
|
-
};
|
|
170828
|
-
var NoticeMessageComponent = class extends Container {
|
|
170829
|
-
titleText;
|
|
170830
|
-
detailText;
|
|
170831
|
-
title;
|
|
170832
|
-
detail;
|
|
170833
|
-
constructor(title, detail) {
|
|
170834
|
-
super();
|
|
170835
|
-
this.title = title;
|
|
170836
|
-
this.detail = detail;
|
|
170837
|
-
this.addChild(new Spacer(1));
|
|
170838
|
-
this.titleText = new Text(` ${currentTheme.fg("textStrong", title)}`, 0, 0);
|
|
170839
|
-
this.addChild(this.titleText);
|
|
170840
|
-
if (detail !== void 0 && detail.length > 0) {
|
|
170841
|
-
this.detailText = new Text(` ${currentTheme.fg("textDim", detail)}`, 0, 0);
|
|
170842
|
-
this.addChild(this.detailText);
|
|
170843
|
-
}
|
|
170844
|
-
}
|
|
170845
|
-
invalidate() {
|
|
170846
|
-
this.titleText.setText(` ${currentTheme.fg("textStrong", this.title)}`);
|
|
170847
|
-
if (this.detailText !== void 0 && this.detail !== void 0) this.detailText.setText(` ${currentTheme.fg("textDim", this.detail)}`);
|
|
170848
|
-
super.invalidate();
|
|
170849
|
-
}
|
|
170850
|
-
};
|
|
170851
|
-
//#endregion
|
|
170852
171901
|
//#region src/tui/utils/goal-completion.ts
|
|
170853
171902
|
/**
|
|
170854
171903
|
* Deterministic goal-completion text rendered by the TUI when the model marks a
|
|
@@ -171128,6 +172177,7 @@ var SubAgentEventHandler = class {
|
|
|
171128
172177
|
name: event.name,
|
|
171129
172178
|
argumentsPart: event.argumentsPart ?? null
|
|
171130
172179
|
});
|
|
172180
|
+
else if (event.type === "tool.progress" && (event.update.kind === "stdout" || event.update.kind === "stderr") && event.update.text !== void 0) toolCall.appendSubToolLiveOutput(`${childAgentId}:${event.toolCallId}`, event.update.text);
|
|
171131
172181
|
else if (event.type === "tool.result") toolCall.finishSubToolCall({
|
|
171132
172182
|
tool_call_id: `${childAgentId}:${event.toolCallId}`,
|
|
171133
172183
|
output: serializeToolResultOutput(event.output),
|
|
@@ -171865,12 +172915,15 @@ var SessionEventHandler = class {
|
|
|
171865
172915
|
streamingUI.scheduleFlush();
|
|
171866
172916
|
}
|
|
171867
172917
|
handleToolProgress(event) {
|
|
171868
|
-
if (event.update.kind !== "status") return;
|
|
171869
172918
|
const text = event.update.text;
|
|
171870
172919
|
if (text === void 0 || text.length === 0) return;
|
|
171871
172920
|
const tc = this.host.streamingUI.getToolComponent(event.toolCallId);
|
|
171872
172921
|
if (tc === void 0) return;
|
|
171873
|
-
|
|
172922
|
+
if (event.update.kind === "status") {
|
|
172923
|
+
tc.appendProgress(text);
|
|
172924
|
+
return;
|
|
172925
|
+
}
|
|
172926
|
+
if (event.update.kind === "stdout" || event.update.kind === "stderr") tc.appendLiveOutput(text);
|
|
171874
172927
|
}
|
|
171875
172928
|
handleToolResult(event) {
|
|
171876
172929
|
const { streamingUI } = this.host;
|
|
@@ -172579,6 +173632,9 @@ var SessionReplayRenderer = class {
|
|
|
172579
173632
|
case "message":
|
|
172580
173633
|
this.renderMessage(context, record.message);
|
|
172581
173634
|
return;
|
|
173635
|
+
case "compaction":
|
|
173636
|
+
this.renderCompaction(context, record);
|
|
173637
|
+
return;
|
|
172582
173638
|
case "goal_updated":
|
|
172583
173639
|
this.renderGoalReplayRecord(context, record);
|
|
172584
173640
|
return;
|
|
@@ -172741,6 +173797,28 @@ var SessionReplayRenderer = class {
|
|
|
172741
173797
|
skillTrigger: skill.trigger
|
|
172742
173798
|
});
|
|
172743
173799
|
}
|
|
173800
|
+
renderCompaction(context, record) {
|
|
173801
|
+
this.flushAssistant(context);
|
|
173802
|
+
if (record.result === void 0) return;
|
|
173803
|
+
if (record.result === "cancelled") {
|
|
173804
|
+
this.host.appendTranscriptEntry({
|
|
173805
|
+
...replayEntry(context, "status", "Compaction cancelled", "plain"),
|
|
173806
|
+
compactionData: {
|
|
173807
|
+
result: "cancelled",
|
|
173808
|
+
instruction: record.instruction
|
|
173809
|
+
}
|
|
173810
|
+
});
|
|
173811
|
+
return;
|
|
173812
|
+
}
|
|
173813
|
+
this.host.appendTranscriptEntry({
|
|
173814
|
+
...replayEntry(context, "status", "Compaction complete", "plain"),
|
|
173815
|
+
compactionData: {
|
|
173816
|
+
tokensBefore: record.result.tokensBefore,
|
|
173817
|
+
tokensAfter: record.result.tokensAfter,
|
|
173818
|
+
instruction: record.instruction
|
|
173819
|
+
}
|
|
173820
|
+
});
|
|
173821
|
+
}
|
|
172744
173822
|
renderGoalReplayRecord(context, record) {
|
|
172745
173823
|
this.flushAssistant(context);
|
|
172746
173824
|
const { change } = record;
|
|
@@ -173011,6 +174089,23 @@ function supportsOsc9Notification(env = process.env) {
|
|
|
173011
174089
|
if (term === "xterm-kitty" || term === "xterm-ghostty") return true;
|
|
173012
174090
|
return false;
|
|
173013
174091
|
}
|
|
174092
|
+
/**
|
|
174093
|
+
* Best-effort detection of ConEmu-style OSC 9;4 progress support, driven
|
|
174094
|
+
* off well-known environment variables like `supportsOsc9Notification`.
|
|
174095
|
+
* The two allow-lists must stay separate: iTerm2 posts a desktop
|
|
174096
|
+
* notification for ANY `OSC 9;<payload>` it receives, so sending the 9;4
|
|
174097
|
+
* progress sequence there pops a "4;3" notification every keepalive tick.
|
|
174098
|
+
* Terminals outside this list simply get no progress reporting, which is
|
|
174099
|
+
* always safe.
|
|
174100
|
+
*/
|
|
174101
|
+
function supportsTerminalProgress(env = process.env) {
|
|
174102
|
+
if ((env["WT_SESSION"] ?? "").length > 0) return true;
|
|
174103
|
+
if (env["ConEmuANSI"] === "ON") return true;
|
|
174104
|
+
const termProgram = env["TERM_PROGRAM"] ?? "";
|
|
174105
|
+
if (termProgram === "ghostty" || termProgram === "WezTerm") return true;
|
|
174106
|
+
if ((env["TERM"] ?? "") === "xterm-ghostty") return true;
|
|
174107
|
+
return false;
|
|
174108
|
+
}
|
|
173014
174109
|
function isInsideTmux(env = process.env) {
|
|
173015
174110
|
return (env["TMUX"] ?? "").length > 0;
|
|
173016
174111
|
}
|
|
@@ -174536,217 +175631,6 @@ var TasksBrowserController = class {
|
|
|
174536
175631
|
}
|
|
174537
175632
|
};
|
|
174538
175633
|
//#endregion
|
|
174539
|
-
//#region src/tui/components/editor/file-mention-provider.ts
|
|
174540
|
-
const PATH_DELIMITERS = new Set([
|
|
174541
|
-
" ",
|
|
174542
|
-
" ",
|
|
174543
|
-
"\"",
|
|
174544
|
-
"'",
|
|
174545
|
-
"="
|
|
174546
|
-
]);
|
|
174547
|
-
const MAX_FALLBACK_SCAN = 2e3;
|
|
174548
|
-
const MAX_FALLBACK_SUGGESTIONS = 50;
|
|
174549
|
-
/**
|
|
174550
|
-
* Kimi wrapper around pi-tui's combined autocomplete provider.
|
|
174551
|
-
*
|
|
174552
|
-
* File / folder mention behavior uses pi-tui's fd-backed provider when fd is
|
|
174553
|
-
* available. While managed fd is downloading (or when it is unavailable), a
|
|
174554
|
-
* small filesystem fallback keeps basic `@` file and folder completion usable.
|
|
174555
|
-
* Ordinary path completion is still handled by pi-tui's readdir-backed path
|
|
174556
|
-
* completer. This wrapper also keeps Kimi-specific slash-command guards.
|
|
174557
|
-
*/
|
|
174558
|
-
var FileMentionProvider = class {
|
|
174559
|
-
workDir;
|
|
174560
|
-
fdPath;
|
|
174561
|
-
inner;
|
|
174562
|
-
constructor(slashCommands, workDir, fdPath) {
|
|
174563
|
-
this.workDir = workDir;
|
|
174564
|
-
this.fdPath = fdPath;
|
|
174565
|
-
this.inner = new CombinedAutocompleteProvider(slashCommands, workDir, fdPath);
|
|
174566
|
-
}
|
|
174567
|
-
async getSuggestions(lines, cursorLine, cursorCol, options) {
|
|
174568
|
-
const currentLine = lines[cursorLine] ?? "";
|
|
174569
|
-
const textBeforeCursor = currentLine.slice(0, cursorCol);
|
|
174570
|
-
if (shouldSuppressLeadingWhitespaceSlashPath(textBeforeCursor, options.force)) return null;
|
|
174571
|
-
if (shouldSuppressSlashArgumentCompletion(textBeforeCursor, currentLine.slice(cursorCol), options.force)) return null;
|
|
174572
|
-
const atPrefix = extractAtPrefix(textBeforeCursor);
|
|
174573
|
-
if (atPrefix !== null) {
|
|
174574
|
-
if (this.fdPath === null) return getFsMentionSuggestions(this.workDir, atPrefix, options.signal);
|
|
174575
|
-
try {
|
|
174576
|
-
return await this.inner.getSuggestions(lines, cursorLine, cursorCol, options);
|
|
174577
|
-
} catch {
|
|
174578
|
-
return getFsMentionSuggestions(this.workDir, atPrefix, options.signal);
|
|
174579
|
-
}
|
|
174580
|
-
}
|
|
174581
|
-
try {
|
|
174582
|
-
return await this.inner.getSuggestions(lines, cursorLine, cursorCol, options);
|
|
174583
|
-
} catch {
|
|
174584
|
-
return null;
|
|
174585
|
-
}
|
|
174586
|
-
}
|
|
174587
|
-
applyCompletion(lines, cursorLine, cursorCol, item, prefix) {
|
|
174588
|
-
return this.inner.applyCompletion(lines, cursorLine, cursorCol, item, prefix);
|
|
174589
|
-
}
|
|
174590
|
-
};
|
|
174591
|
-
function extractAtPrefix(text) {
|
|
174592
|
-
let tokenStart = 0;
|
|
174593
|
-
for (let i = text.length - 1; i >= 0; i -= 1) if (PATH_DELIMITERS.has(text[i] ?? "")) {
|
|
174594
|
-
tokenStart = i + 1;
|
|
174595
|
-
break;
|
|
174596
|
-
}
|
|
174597
|
-
if (text[tokenStart] !== "@") return null;
|
|
174598
|
-
return text.slice(tokenStart);
|
|
174599
|
-
}
|
|
174600
|
-
function getFsMentionSuggestions(workDir, atPrefix, signal) {
|
|
174601
|
-
if (signal.aborted) return null;
|
|
174602
|
-
const query = atPrefix.slice(1);
|
|
174603
|
-
const candidates = collectFsMentionCandidates(workDir, signal);
|
|
174604
|
-
if (candidates.length === 0 || signal.aborted) return null;
|
|
174605
|
-
const ranked = rankFsMentionCandidates(candidates, query).slice(0, MAX_FALLBACK_SUGGESTIONS);
|
|
174606
|
-
if (ranked.length === 0) return null;
|
|
174607
|
-
return {
|
|
174608
|
-
prefix: atPrefix,
|
|
174609
|
-
items: ranked.map(toMentionItem)
|
|
174610
|
-
};
|
|
174611
|
-
}
|
|
174612
|
-
function collectFsMentionCandidates(workDir, signal) {
|
|
174613
|
-
const result = [];
|
|
174614
|
-
const stack = [""];
|
|
174615
|
-
while (stack.length > 0 && result.length < MAX_FALLBACK_SCAN) {
|
|
174616
|
-
if (signal.aborted) break;
|
|
174617
|
-
const relativeDir = stack.pop() ?? "";
|
|
174618
|
-
const absoluteDir = relativeDir.length === 0 ? workDir : join$1(workDir, relativeDir);
|
|
174619
|
-
let entries;
|
|
174620
|
-
try {
|
|
174621
|
-
entries = readdirSync(absoluteDir, { withFileTypes: true });
|
|
174622
|
-
} catch {
|
|
174623
|
-
continue;
|
|
174624
|
-
}
|
|
174625
|
-
for (const entry of entries) {
|
|
174626
|
-
if (signal.aborted || result.length >= MAX_FALLBACK_SCAN) break;
|
|
174627
|
-
if (entry.name === ".git") continue;
|
|
174628
|
-
const relativePath = normalizePath(relativeDir.length === 0 ? entry.name : join$1(relativeDir, entry.name));
|
|
174629
|
-
const isSymlink = entry.isSymbolicLink();
|
|
174630
|
-
let isDirectory = entry.isDirectory();
|
|
174631
|
-
if (!isDirectory && isSymlink) try {
|
|
174632
|
-
isDirectory = statSync(join$1(workDir, relativePath)).isDirectory();
|
|
174633
|
-
} catch {}
|
|
174634
|
-
result.push({
|
|
174635
|
-
path: relativePath,
|
|
174636
|
-
isDirectory
|
|
174637
|
-
});
|
|
174638
|
-
if (isDirectory && !isSymlink) stack.push(relativePath);
|
|
174639
|
-
}
|
|
174640
|
-
}
|
|
174641
|
-
return result;
|
|
174642
|
-
}
|
|
174643
|
-
function rankFsMentionCandidates(candidates, query) {
|
|
174644
|
-
const lowerQuery = query.toLowerCase();
|
|
174645
|
-
const scored = [];
|
|
174646
|
-
for (const candidate of candidates) {
|
|
174647
|
-
const score = scoreCandidate(candidate, lowerQuery);
|
|
174648
|
-
if (score > 0) scored.push({
|
|
174649
|
-
candidate,
|
|
174650
|
-
score
|
|
174651
|
-
});
|
|
174652
|
-
}
|
|
174653
|
-
scored.sort((a, b) => {
|
|
174654
|
-
if (a.score !== b.score) return b.score - a.score;
|
|
174655
|
-
if (a.candidate.isDirectory !== b.candidate.isDirectory) return a.candidate.isDirectory ? -1 : 1;
|
|
174656
|
-
return a.candidate.path.localeCompare(b.candidate.path);
|
|
174657
|
-
});
|
|
174658
|
-
return scored.map((entry) => entry.candidate);
|
|
174659
|
-
}
|
|
174660
|
-
function scoreCandidate(candidate, lowerQuery) {
|
|
174661
|
-
if (lowerQuery.length === 0) {
|
|
174662
|
-
const depthPenalty = candidate.path.split("/").length - 1;
|
|
174663
|
-
return (candidate.isDirectory ? 120 : 100) - depthPenalty;
|
|
174664
|
-
}
|
|
174665
|
-
const lowerPath = candidate.path.toLowerCase();
|
|
174666
|
-
const lowerBase = basename$1(candidate.path).toLowerCase();
|
|
174667
|
-
let score = 0;
|
|
174668
|
-
if (lowerBase === lowerQuery) score = 100;
|
|
174669
|
-
else if (lowerBase.startsWith(lowerQuery)) score = 80;
|
|
174670
|
-
else if (lowerBase.includes(lowerQuery)) score = 50;
|
|
174671
|
-
else if (lowerPath.includes(lowerQuery)) score = 30;
|
|
174672
|
-
if (candidate.isDirectory && score > 0) score += 10;
|
|
174673
|
-
return score;
|
|
174674
|
-
}
|
|
174675
|
-
function toMentionItem(candidate) {
|
|
174676
|
-
const valuePath = candidate.isDirectory ? `${candidate.path}/` : candidate.path;
|
|
174677
|
-
return {
|
|
174678
|
-
value: valuePath.includes(" ") ? `@"${valuePath}"` : `@${valuePath}`,
|
|
174679
|
-
label: `${basename$1(candidate.path)}${candidate.isDirectory ? "/" : ""}`,
|
|
174680
|
-
description: valuePath
|
|
174681
|
-
};
|
|
174682
|
-
}
|
|
174683
|
-
function normalizePath(path) {
|
|
174684
|
-
return path.replaceAll("\\", "/");
|
|
174685
|
-
}
|
|
174686
|
-
function shouldSuppressLeadingWhitespaceSlashPath(textBeforeCursor, force) {
|
|
174687
|
-
if (force === true) return false;
|
|
174688
|
-
if (textBeforeCursor.startsWith("/")) return false;
|
|
174689
|
-
return textBeforeCursor.trimStart().startsWith("/");
|
|
174690
|
-
}
|
|
174691
|
-
function shouldSuppressSlashArgumentCompletion(textBeforeCursor, textAfterCursor, force) {
|
|
174692
|
-
if (force === true) return false;
|
|
174693
|
-
if (!textBeforeCursor.startsWith("/")) return false;
|
|
174694
|
-
if (!textBeforeCursor.includes(" ")) return false;
|
|
174695
|
-
return textAfterCursor.trimStart().length > 0;
|
|
174696
|
-
}
|
|
174697
|
-
//#endregion
|
|
174698
|
-
//#region src/tui/components/panes/activity-pane.ts
|
|
174699
|
-
var ActivityPaneComponent = class extends Container {
|
|
174700
|
-
constructor(options) {
|
|
174701
|
-
super();
|
|
174702
|
-
if (options.mode === "waiting" || options.mode === "tool") {
|
|
174703
|
-
if (options.spinner !== void 0) {
|
|
174704
|
-
this.addChild(new Spacer(1));
|
|
174705
|
-
this.addChild(options.spinner);
|
|
174706
|
-
}
|
|
174707
|
-
return;
|
|
174708
|
-
}
|
|
174709
|
-
if (options.mode === "composing" && options.spinner !== void 0) {
|
|
174710
|
-
this.addChild(new Spacer(1));
|
|
174711
|
-
this.addChild(options.spinner);
|
|
174712
|
-
}
|
|
174713
|
-
}
|
|
174714
|
-
};
|
|
174715
|
-
//#endregion
|
|
174716
|
-
//#region src/tui/components/panes/queue-pane.ts
|
|
174717
|
-
const ELLIPSIS = "…";
|
|
174718
|
-
var QueuePaneComponent = class extends Container {
|
|
174719
|
-
messages;
|
|
174720
|
-
hint;
|
|
174721
|
-
constructor(options) {
|
|
174722
|
-
super();
|
|
174723
|
-
this.messages = options.messages;
|
|
174724
|
-
if (options.messages.length > 0) this.hint = options.isCompacting && !options.isStreaming ? " ↑ to edit · will send after compaction" : !options.canSteerImmediately ? " ↑ to edit · will send after current task" : " ↑ to edit · ctrl-s to steer immediately";
|
|
174725
|
-
}
|
|
174726
|
-
render(width) {
|
|
174727
|
-
const accent = (text) => currentTheme.fg("accent", text);
|
|
174728
|
-
const dim = (text) => currentTheme.fg("textDim", text);
|
|
174729
|
-
const lines = [];
|
|
174730
|
-
for (const item of this.messages) {
|
|
174731
|
-
const singleLine = item.text.replaceAll(/\s+/g, " ").trim();
|
|
174732
|
-
const prefix = ` ❯ `;
|
|
174733
|
-
const truncated = truncateToWidth(singleLine, Math.max(1, width - visibleWidth(prefix)), ELLIPSIS);
|
|
174734
|
-
lines.push(accent(prefix + truncated));
|
|
174735
|
-
}
|
|
174736
|
-
if (this.hint !== void 0) lines.push(dim(truncateToWidth(this.hint, width, ELLIPSIS)));
|
|
174737
|
-
return lines;
|
|
174738
|
-
}
|
|
174739
|
-
};
|
|
174740
|
-
//#endregion
|
|
174741
|
-
//#region src/tui/utils/startup.ts
|
|
174742
|
-
function combineStartupNotice(existing, next) {
|
|
174743
|
-
if (existing !== void 0 && next !== void 0) return `${existing}\n${next}`;
|
|
174744
|
-
return existing ?? next;
|
|
174745
|
-
}
|
|
174746
|
-
function isOAuthLoginRequiredError(error) {
|
|
174747
|
-
return error.code === OAUTH_LOGIN_REQUIRED_CODE;
|
|
174748
|
-
}
|
|
174749
|
-
//#endregion
|
|
174750
175634
|
//#region src/tui/reverse-rpc/approval/adapter.ts
|
|
174751
175635
|
const DEFAULT_APPROVAL_CHOICES = [
|
|
174752
175636
|
{
|
|
@@ -175305,13 +176189,6 @@ function adaptQuestionAnswers(event, response) {
|
|
|
175305
176189
|
} : null;
|
|
175306
176190
|
}
|
|
175307
176191
|
//#endregion
|
|
175308
|
-
//#region src/tui/types.ts
|
|
175309
|
-
const INITIAL_LIVE_PANE = {
|
|
175310
|
-
mode: "idle",
|
|
175311
|
-
pendingApproval: null,
|
|
175312
|
-
pendingQuestion: null
|
|
175313
|
-
};
|
|
175314
|
-
//#endregion
|
|
175315
176192
|
//#region src/utils/git/git-status.ts
|
|
175316
176193
|
/**
|
|
175317
176194
|
* Cached git branch + working-tree status for the footer/statusline.
|
|
@@ -176028,6 +176905,107 @@ function styleTitle(title, status, colors) {
|
|
|
176028
176905
|
}
|
|
176029
176906
|
}
|
|
176030
176907
|
//#endregion
|
|
176908
|
+
//#region src/tui/components/editor/wrapping-select-list.ts
|
|
176909
|
+
const DEFAULT_PRIMARY_COLUMN_WIDTH = 32;
|
|
176910
|
+
const PRIMARY_COLUMN_GAP = 2;
|
|
176911
|
+
const MIN_DESCRIPTION_WIDTH = 10;
|
|
176912
|
+
const DESCRIPTION_MAX_LINES = 2;
|
|
176913
|
+
const ELLIPSIS = "…";
|
|
176914
|
+
const ELLIPSIS_WIDTH = visibleWidth(ELLIPSIS);
|
|
176915
|
+
const TRAILING_ANSI_RESET = /(?:\u001B\[0m)+$/;
|
|
176916
|
+
function truncatePlainToWidth(text, maxWidth) {
|
|
176917
|
+
return truncateToWidth(text, maxWidth, "").replace(TRAILING_ANSI_RESET, "");
|
|
176918
|
+
}
|
|
176919
|
+
/**
|
|
176920
|
+
* SelectList that wraps item descriptions onto up to two lines instead of
|
|
176921
|
+
* truncating them to one. Long command / skill descriptions stay readable;
|
|
176922
|
+
* anything past the second line is ellipsized.
|
|
176923
|
+
*
|
|
176924
|
+
* Only `render` is replaced — selection, filtering, and key handling stay in
|
|
176925
|
+
* pi-tui. pi-tui keeps the row state private, so the renderer reads it
|
|
176926
|
+
* through a cast, the same idiom CustomEditor uses for autocomplete
|
|
176927
|
+
* internals.
|
|
176928
|
+
*/
|
|
176929
|
+
var WrappingSelectList = class extends SelectList {
|
|
176930
|
+
render(width) {
|
|
176931
|
+
const { filteredItems, selectedIndex, maxVisible, theme } = this.internals();
|
|
176932
|
+
if (filteredItems.length === 0) return [theme.noMatch(" No matching commands")];
|
|
176933
|
+
const primaryColumnWidth = this.primaryColumnWidth();
|
|
176934
|
+
const startIndex = Math.max(0, Math.min(selectedIndex - Math.floor(maxVisible / 2), filteredItems.length - maxVisible));
|
|
176935
|
+
const endIndex = Math.min(startIndex + maxVisible, filteredItems.length);
|
|
176936
|
+
const lines = [];
|
|
176937
|
+
for (let i = startIndex; i < endIndex; i++) {
|
|
176938
|
+
const item = filteredItems[i];
|
|
176939
|
+
if (!item) continue;
|
|
176940
|
+
lines.push(...this.renderItemLines(item, i === selectedIndex, width, primaryColumnWidth));
|
|
176941
|
+
}
|
|
176942
|
+
if (startIndex > 0 || endIndex < filteredItems.length) {
|
|
176943
|
+
const scrollText = ` (${selectedIndex + 1}/${filteredItems.length})`;
|
|
176944
|
+
lines.push(theme.scrollInfo(truncatePlainToWidth(scrollText, width - 2)));
|
|
176945
|
+
}
|
|
176946
|
+
return lines;
|
|
176947
|
+
}
|
|
176948
|
+
renderItemLines(item, isSelected, width, primaryColumnWidth) {
|
|
176949
|
+
const { theme } = this.internals();
|
|
176950
|
+
const prefix = isSelected ? "→ " : " ";
|
|
176951
|
+
const prefixWidth = visibleWidth(prefix);
|
|
176952
|
+
const description = item.description ? item.description.replaceAll(/[\r\n]+/g, " ").trim() : void 0;
|
|
176953
|
+
if (description && width > 40) {
|
|
176954
|
+
const effectivePrimaryColumnWidth = Math.max(1, Math.min(primaryColumnWidth, width - prefixWidth - 4));
|
|
176955
|
+
const maxPrimaryWidth = Math.max(1, effectivePrimaryColumnWidth - PRIMARY_COLUMN_GAP);
|
|
176956
|
+
const truncatedValue = this.truncatePrimaryValue(item, isSelected, maxPrimaryWidth, effectivePrimaryColumnWidth);
|
|
176957
|
+
const truncatedValueWidth = visibleWidth(truncatedValue);
|
|
176958
|
+
const spacing = " ".repeat(Math.max(1, effectivePrimaryColumnWidth - truncatedValueWidth));
|
|
176959
|
+
const descriptionStart = prefixWidth + truncatedValueWidth + spacing.length;
|
|
176960
|
+
const remainingWidth = width - descriptionStart - 2;
|
|
176961
|
+
if (remainingWidth > MIN_DESCRIPTION_WIDTH) {
|
|
176962
|
+
const descriptionLines = wrapDescription(description, remainingWidth);
|
|
176963
|
+
const indent = " ".repeat(descriptionStart);
|
|
176964
|
+
if (isSelected) return descriptionLines.map((line, index) => theme.selectedText(index === 0 ? `${prefix}${truncatedValue}${spacing}${line}` : indent + line));
|
|
176965
|
+
return descriptionLines.map((line, index) => index === 0 ? prefix + truncatedValue + theme.description(spacing + line) : theme.description(indent + line));
|
|
176966
|
+
}
|
|
176967
|
+
}
|
|
176968
|
+
const maxWidth = width - prefixWidth - 2;
|
|
176969
|
+
const truncatedValue = this.truncatePrimaryValue(item, isSelected, maxWidth, maxWidth);
|
|
176970
|
+
return [isSelected ? theme.selectedText(`${prefix}${truncatedValue}`) : prefix + truncatedValue];
|
|
176971
|
+
}
|
|
176972
|
+
truncatePrimaryValue(item, isSelected, maxWidth, columnWidth) {
|
|
176973
|
+
const { layout } = this.internals();
|
|
176974
|
+
const displayValue = item.label || item.value;
|
|
176975
|
+
return truncatePlainToWidth(layout.truncatePrimary ? layout.truncatePrimary({
|
|
176976
|
+
text: displayValue,
|
|
176977
|
+
maxWidth,
|
|
176978
|
+
columnWidth,
|
|
176979
|
+
item,
|
|
176980
|
+
isSelected
|
|
176981
|
+
}) : displayValue, maxWidth);
|
|
176982
|
+
}
|
|
176983
|
+
primaryColumnWidth() {
|
|
176984
|
+
const { filteredItems, layout } = this.internals();
|
|
176985
|
+
const rawMin = layout.minPrimaryColumnWidth ?? layout.maxPrimaryColumnWidth ?? DEFAULT_PRIMARY_COLUMN_WIDTH;
|
|
176986
|
+
const rawMax = layout.maxPrimaryColumnWidth ?? layout.minPrimaryColumnWidth ?? DEFAULT_PRIMARY_COLUMN_WIDTH;
|
|
176987
|
+
const min = Math.max(1, Math.min(rawMin, rawMax));
|
|
176988
|
+
const max = Math.max(1, Math.max(rawMin, rawMax));
|
|
176989
|
+
const widest = filteredItems.reduce((acc, item) => Math.max(acc, visibleWidth(item.label || item.value) + PRIMARY_COLUMN_GAP), 0);
|
|
176990
|
+
return Math.max(min, Math.min(widest, max));
|
|
176991
|
+
}
|
|
176992
|
+
internals() {
|
|
176993
|
+
return this;
|
|
176994
|
+
}
|
|
176995
|
+
};
|
|
176996
|
+
/**
|
|
176997
|
+
* Wrap `text` to at most DESCRIPTION_MAX_LINES lines of `width` columns.
|
|
176998
|
+
* When the text needs more lines, the last visible line is rebuilt from the
|
|
176999
|
+
* remaining text and ellipsized.
|
|
177000
|
+
*/
|
|
177001
|
+
function wrapDescription(text, width) {
|
|
177002
|
+
const wrapped = wrapTextWithAnsi(text, width);
|
|
177003
|
+
if (wrapped.length <= DESCRIPTION_MAX_LINES) return wrapped;
|
|
177004
|
+
const kept = wrapped.slice(0, DESCRIPTION_MAX_LINES - 1);
|
|
177005
|
+
const clipped = truncatePlainToWidth(wrapped.slice(DESCRIPTION_MAX_LINES - 1).join(" "), width - ELLIPSIS_WIDTH).trimEnd();
|
|
177006
|
+
return [...kept, `${clipped}${ELLIPSIS}`];
|
|
177007
|
+
}
|
|
177008
|
+
//#endregion
|
|
176031
177009
|
//#region src/tui/components/editor/custom-editor.ts
|
|
176032
177010
|
/**
|
|
176033
177011
|
* Custom editor extending pi-tui Editor with app-level keybindings.
|
|
@@ -176040,6 +177018,10 @@ const KITTY_CSI_U = /^\u001B\[(\d+);(\d+)((?::\d+)*)u$/;
|
|
|
176040
177018
|
const CAPS_LOCK_BIT = 64;
|
|
176041
177019
|
const CTRL_BIT = 4;
|
|
176042
177020
|
const SHIFT_BIT = 1;
|
|
177021
|
+
const SLASH_COMMAND_SELECT_LIST_LAYOUT = {
|
|
177022
|
+
minPrimaryColumnWidth: 12,
|
|
177023
|
+
maxPrimaryColumnWidth: 32
|
|
177024
|
+
};
|
|
176043
177025
|
/**
|
|
176044
177026
|
* Workaround for a pi-tui bug that surfaces when Kitty keyboard protocol
|
|
176045
177027
|
* is active AND caps_lock is on. In that state terminals emit, e.g.,
|
|
@@ -176125,7 +177107,12 @@ var CustomEditor = class extends Editor {
|
|
|
176125
177107
|
consumingPaste = false;
|
|
176126
177108
|
consumeBuffer = "";
|
|
176127
177109
|
constructor(tui) {
|
|
176128
|
-
|
|
177110
|
+
const theme = createEditorTheme();
|
|
177111
|
+
super(tui, theme, { paddingX: 4 });
|
|
177112
|
+
this.createAutocompleteList = (prefix, items) => {
|
|
177113
|
+
if (prefix.startsWith("/")) return new WrappingSelectList(items, this.getAutocompleteMaxVisible(), theme.selectList, SLASH_COMMAND_SELECT_LIST_LAYOUT);
|
|
177114
|
+
return new SelectList(items, this.getAutocompleteMaxVisible(), theme.selectList);
|
|
177115
|
+
};
|
|
176129
177116
|
}
|
|
176130
177117
|
expandPasteMarkerAtCursor() {
|
|
176131
177118
|
const { line, col } = this.getCursor();
|
|
@@ -176368,11 +177355,19 @@ function createTerminalState() {
|
|
|
176368
177355
|
notificationKeys: /* @__PURE__ */ new Set(),
|
|
176369
177356
|
focused: true,
|
|
176370
177357
|
supportsOsc9: supportsOsc9Notification(),
|
|
177358
|
+
supportsProgress: supportsTerminalProgress(),
|
|
176371
177359
|
insideTmux: isInsideTmux(),
|
|
176372
177360
|
progressActive: false
|
|
176373
177361
|
};
|
|
176374
177362
|
}
|
|
176375
177363
|
//#endregion
|
|
177364
|
+
//#region src/tui/types.ts
|
|
177365
|
+
const INITIAL_LIVE_PANE = {
|
|
177366
|
+
mode: "idle",
|
|
177367
|
+
pendingApproval: null,
|
|
177368
|
+
pendingQuestion: null
|
|
177369
|
+
};
|
|
177370
|
+
//#endregion
|
|
176376
177371
|
//#region src/tui/tui-state.ts
|
|
176377
177372
|
function createTUIState(options) {
|
|
176378
177373
|
const initialAppState = options.initialAppState;
|
|
@@ -176586,6 +177581,15 @@ function sessionRowsForPicker(sessions, currentSessionId, currentSessionHasConte
|
|
|
176586
177581
|
}));
|
|
176587
177582
|
}
|
|
176588
177583
|
//#endregion
|
|
177584
|
+
//#region src/tui/utils/startup.ts
|
|
177585
|
+
function combineStartupNotice(existing, next) {
|
|
177586
|
+
if (existing !== void 0 && next !== void 0) return `${existing}\n${next}`;
|
|
177587
|
+
return existing ?? next;
|
|
177588
|
+
}
|
|
177589
|
+
function isOAuthLoginRequiredError(error) {
|
|
177590
|
+
return error.code === OAUTH_LOGIN_REQUIRED_CODE;
|
|
177591
|
+
}
|
|
177592
|
+
//#endregion
|
|
176589
177593
|
//#region src/tui/utils/terminal-focus.ts
|
|
176590
177594
|
function installTerminalFocusTracking(state) {
|
|
176591
177595
|
state.terminalState.focused = true;
|
|
@@ -176756,7 +177760,8 @@ function createInitialAppState(input) {
|
|
|
176756
177760
|
availableProviders: {},
|
|
176757
177761
|
sessionTitle: null,
|
|
176758
177762
|
goal: null,
|
|
176759
|
-
mcpServersSummary: null
|
|
177763
|
+
mcpServersSummary: null,
|
|
177764
|
+
banner: void 0
|
|
176760
177765
|
};
|
|
176761
177766
|
}
|
|
176762
177767
|
var KimiTUI = class {
|
|
@@ -176853,6 +177858,7 @@ var KimiTUI = class {
|
|
|
176853
177858
|
const completer = cmd.completeArgs;
|
|
176854
177859
|
return {
|
|
176855
177860
|
name: cmd.name,
|
|
177861
|
+
aliases: cmd.aliases,
|
|
176856
177862
|
description: cmd.description,
|
|
176857
177863
|
...cmd.argumentHint !== void 0 ? { argumentHint: cmd.argumentHint } : {},
|
|
176858
177864
|
...completer !== void 0 ? { getArgumentCompletions: (prefix) => completer(prefix) } : {}
|
|
@@ -176921,10 +177927,28 @@ var KimiTUI = class {
|
|
|
176921
177927
|
throw error;
|
|
176922
177928
|
}
|
|
176923
177929
|
}
|
|
177930
|
+
async loadBanner() {
|
|
177931
|
+
const provider = new BannerProvider(this.state.appState.version);
|
|
177932
|
+
this.state.appState.banner = await provider.load();
|
|
177933
|
+
if (this.state.appState.banner !== null) {
|
|
177934
|
+
this.renderBanner();
|
|
177935
|
+
this.state.ui.requestRender();
|
|
177936
|
+
}
|
|
177937
|
+
}
|
|
177938
|
+
renderBanner() {
|
|
177939
|
+
if (this.state.appState.banner === null || this.state.appState.banner === void 0) return;
|
|
177940
|
+
if (this.state.transcriptContainer.children.some((child) => child instanceof BannerComponent)) return;
|
|
177941
|
+
const welcomeIndex = this.state.transcriptContainer.children.findIndex((child) => child instanceof WelcomeComponent);
|
|
177942
|
+
const banner = new BannerComponent(this.state.appState.banner);
|
|
177943
|
+
if (welcomeIndex >= 0) this.state.transcriptContainer.children.splice(welcomeIndex + 1, 0, banner);
|
|
177944
|
+
else this.state.transcriptContainer.children.unshift(banner);
|
|
177945
|
+
this.state.transcriptContainer.invalidate();
|
|
177946
|
+
}
|
|
176924
177947
|
async initMainTui() {
|
|
176925
177948
|
const shouldReplayHistory = await this.init();
|
|
176926
177949
|
this.mountFooter();
|
|
176927
177950
|
this.renderWelcome();
|
|
177951
|
+
this.loadBanner();
|
|
176928
177952
|
this.setupAutocomplete();
|
|
176929
177953
|
this.loadPersistedInputHistory();
|
|
176930
177954
|
this.state.editorContainer.clear();
|
|
@@ -176950,10 +177974,8 @@ var KimiTUI = class {
|
|
|
176950
177974
|
try {
|
|
176951
177975
|
const result = await this.authFlow.refreshProviderModels();
|
|
176952
177976
|
for (const c of result.changed) {
|
|
176953
|
-
|
|
176954
|
-
|
|
176955
|
-
if (c.removed > 0) parts.push(`-${String(c.removed)} model${c.removed > 1 ? "s" : ""}`);
|
|
176956
|
-
this.showStatus(parts.join(" · ") + ".");
|
|
177977
|
+
if (c.added <= 0) continue;
|
|
177978
|
+
this.showStatus(`${c.providerName} · +${String(c.added)} model${c.added > 1 ? "s" : ""}.`);
|
|
176957
177979
|
}
|
|
176958
177980
|
for (const f of result.failed) this.showStatus(`Skipped refreshing ${f.provider}: ${f.reason}`, "warning");
|
|
176959
177981
|
} catch {}
|
|
@@ -176968,7 +177990,10 @@ var KimiTUI = class {
|
|
|
176968
177990
|
this.bootstrapFromPicker();
|
|
176969
177991
|
return;
|
|
176970
177992
|
}
|
|
176971
|
-
if (shouldReplayHistory)
|
|
177993
|
+
if (shouldReplayHistory) {
|
|
177994
|
+
await this.sessionReplay.hydrateFromReplay(this.requireSession());
|
|
177995
|
+
this.applyStartupPermissionAndPlanToAppState();
|
|
177996
|
+
}
|
|
176972
177997
|
const resumeState = this.session?.getResumeState();
|
|
176973
177998
|
if (resumeState?.warning !== void 0) this.showStatus(`Warning: ${resumeState.warning}`, "warning");
|
|
176974
177999
|
if (this.session !== void 0) this.sessionEventHandler.startSubscription();
|
|
@@ -177026,7 +178051,10 @@ var KimiTUI = class {
|
|
|
177026
178051
|
}
|
|
177027
178052
|
}
|
|
177028
178053
|
} else session = await this.harness.createSession(createSessionOptions);
|
|
177029
|
-
if (session !== void 0 &&
|
|
178054
|
+
if (session !== void 0 && shouldReplayHistory) {
|
|
178055
|
+
await this.applyStartupModesToResumedSession(session);
|
|
178056
|
+
if (startup.model !== void 0) await session.setModel(startup.model);
|
|
178057
|
+
}
|
|
177030
178058
|
} catch (error) {
|
|
177031
178059
|
if (!isOAuthLoginRequiredError(error)) throw error;
|
|
177032
178060
|
this.authFlow.enterLoginRequiredStartupState();
|
|
@@ -177035,6 +178063,7 @@ var KimiTUI = class {
|
|
|
177035
178063
|
if (session === void 0) throw new Error("Startup session was not initialized.");
|
|
177036
178064
|
await this.setSession(session);
|
|
177037
178065
|
await this.syncRuntimeState(session);
|
|
178066
|
+
this.applyStartupPermissionAndPlanToAppState();
|
|
177038
178067
|
this.state.startupState = "ready";
|
|
177039
178068
|
return shouldReplayHistory;
|
|
177040
178069
|
}
|
|
@@ -177224,10 +178253,11 @@ var KimiTUI = class {
|
|
|
177224
178253
|
this.showError(message);
|
|
177225
178254
|
}
|
|
177226
178255
|
sendQueuedMessage(session, item) {
|
|
177227
|
-
this.harness.
|
|
177228
|
-
|
|
177229
|
-
|
|
177230
|
-
|
|
178256
|
+
this.harness.withInteractiveAgent(item.agentId ?? "main", () => {
|
|
178257
|
+
this.sendMessageInternal(session, item.text, {
|
|
178258
|
+
parts: item.parts,
|
|
178259
|
+
imageAttachmentIds: item.imageAttachmentIds
|
|
178260
|
+
});
|
|
177231
178261
|
});
|
|
177232
178262
|
}
|
|
177233
178263
|
requestQueuedGoalPromotion() {
|
|
@@ -177388,6 +178418,20 @@ var KimiTUI = class {
|
|
|
177388
178418
|
goal: goalResult.goal
|
|
177389
178419
|
});
|
|
177390
178420
|
}
|
|
178421
|
+
async applyStartupModesToResumedSession(session) {
|
|
178422
|
+
const { startup } = this.options;
|
|
178423
|
+
if (startup.auto) await session.setPermission("auto");
|
|
178424
|
+
else if (startup.yolo) await session.setPermission("yolo");
|
|
178425
|
+
if (startup.plan) {
|
|
178426
|
+
if (!(await session.getStatus()).planMode) await session.setPlanMode(true);
|
|
178427
|
+
}
|
|
178428
|
+
}
|
|
178429
|
+
applyStartupPermissionAndPlanToAppState() {
|
|
178430
|
+
const { startup } = this.options;
|
|
178431
|
+
if (startup.auto) this.setAppState({ permissionMode: "auto" });
|
|
178432
|
+
else if (startup.yolo) this.setAppState({ permissionMode: "yolo" });
|
|
178433
|
+
if (startup.plan) this.setAppState({ planMode: true });
|
|
178434
|
+
}
|
|
177391
178435
|
async activateRuntime() {
|
|
177392
178436
|
const session = this.requireSession();
|
|
177393
178437
|
await session.setPermission(this.state.appState.permissionMode);
|
|
@@ -177439,7 +178483,6 @@ var KimiTUI = class {
|
|
|
177439
178483
|
this.streamingUI.discardPending();
|
|
177440
178484
|
this.state.queuedMessages = [];
|
|
177441
178485
|
this.state.swarmModeEntry = void 0;
|
|
177442
|
-
this.harness.interactiveAgentId = MAIN_AGENT_ID;
|
|
177443
178486
|
this.streamingUI.resetToolCallState();
|
|
177444
178487
|
this.streamingUI.resetToolUi();
|
|
177445
178488
|
this.sessionEventHandler.resetRuntimeState();
|
|
@@ -177554,12 +178597,21 @@ var KimiTUI = class {
|
|
|
177554
178597
|
this.sessionEventHandler.startSubscription();
|
|
177555
178598
|
this.clearTranscriptAndRedraw();
|
|
177556
178599
|
this.showStatus(`Started a new session (${session.id}).`);
|
|
178600
|
+
this.showConfigWarningsIfAny();
|
|
178601
|
+
}
|
|
178602
|
+
/** Surface config.toml load warnings (degraded or kept-previous config) in the status bar. */
|
|
178603
|
+
async showConfigWarningsIfAny() {
|
|
178604
|
+
try {
|
|
178605
|
+
const { warnings } = await this.harness.getConfigDiagnostics();
|
|
178606
|
+
for (const warning of warnings) this.showStatus(warning, "warning");
|
|
178607
|
+
} catch {}
|
|
177557
178608
|
}
|
|
177558
178609
|
createTranscriptComponent(entry) {
|
|
177559
178610
|
if (entry.compactionData !== void 0) {
|
|
177560
178611
|
const data = entry.compactionData;
|
|
177561
178612
|
const block = new CompactionComponent(this.state.ui, data.instruction);
|
|
177562
|
-
|
|
178613
|
+
if (data.result === "cancelled") block.markCanceled();
|
|
178614
|
+
else block.markDone(data.tokensBefore, data.tokensAfter);
|
|
177563
178615
|
return block;
|
|
177564
178616
|
}
|
|
177565
178617
|
switch (entry.kind) {
|
|
@@ -177826,6 +178878,7 @@ var KimiTUI = class {
|
|
|
177826
178878
|
this.sessionEventHandler.syncAgentSwarmActivitySpinner(spinner);
|
|
177827
178879
|
}
|
|
177828
178880
|
syncTerminalProgress(active) {
|
|
178881
|
+
if (!this.state.terminalState.supportsProgress) return;
|
|
177829
178882
|
if (this.state.terminalState.progressActive === active) return;
|
|
177830
178883
|
this.state.terminal.setProgress(active);
|
|
177831
178884
|
this.state.terminalState.progressActive = active;
|
|
@@ -177905,16 +178958,18 @@ var KimiTUI = class {
|
|
|
177905
178958
|
}
|
|
177906
178959
|
async showSessionPicker() {
|
|
177907
178960
|
await this.fetchSessions();
|
|
177908
|
-
this.mountSessionPicker(() => {
|
|
178961
|
+
this.mountSessionPicker({ onCancel: () => {
|
|
177909
178962
|
this.hideSessionPicker();
|
|
177910
|
-
});
|
|
178963
|
+
} });
|
|
177911
178964
|
}
|
|
177912
178965
|
async bootstrapFromPicker() {
|
|
177913
178966
|
await this.fetchSessions();
|
|
177914
|
-
this.mountSessionPicker(
|
|
177915
|
-
|
|
177916
|
-
|
|
177917
|
-
|
|
178967
|
+
this.mountSessionPicker({
|
|
178968
|
+
applyStartupModes: true,
|
|
178969
|
+
onCancel: () => {
|
|
178970
|
+
this.hideSessionPicker();
|
|
178971
|
+
this.stop();
|
|
178972
|
+
},
|
|
177918
178973
|
onCtrlC: () => {
|
|
177919
178974
|
this.state.editor.onCtrlC?.();
|
|
177920
178975
|
},
|
|
@@ -177928,20 +178983,27 @@ var KimiTUI = class {
|
|
|
177928
178983
|
this.state.activeDialog = null;
|
|
177929
178984
|
this.restoreEditor();
|
|
177930
178985
|
}
|
|
177931
|
-
mountSessionPicker(
|
|
178986
|
+
mountSessionPicker(options) {
|
|
177932
178987
|
this.state.activeDialog = "session-picker";
|
|
177933
178988
|
this.mountEditorReplacement(new SessionPickerComponent({
|
|
177934
178989
|
sessions: this.state.sessions,
|
|
177935
178990
|
loading: this.state.loadingSessions,
|
|
177936
178991
|
currentSessionId: this.state.appState.sessionId,
|
|
177937
178992
|
onSelect: (sessionId) => {
|
|
177938
|
-
this.resumeSession(sessionId).then((switched) => {
|
|
177939
|
-
if (switched)
|
|
178993
|
+
this.resumeSession(sessionId).then(async (switched) => {
|
|
178994
|
+
if (!switched) return;
|
|
178995
|
+
if (options.applyStartupModes === true) {
|
|
178996
|
+
await this.applyStartupModesToResumedSession(this.requireSession());
|
|
178997
|
+
this.applyStartupPermissionAndPlanToAppState();
|
|
178998
|
+
}
|
|
178999
|
+
this.hideSessionPicker();
|
|
179000
|
+
}).catch((error) => {
|
|
179001
|
+
this.showError(`Failed to apply startup flags: ${formatErrorMessage$2(error)}`);
|
|
177940
179002
|
});
|
|
177941
179003
|
},
|
|
177942
|
-
onCancel,
|
|
177943
|
-
onCtrlC:
|
|
177944
|
-
onCtrlD:
|
|
179004
|
+
onCancel: options.onCancel,
|
|
179005
|
+
onCtrlC: options.onCtrlC,
|
|
179006
|
+
onCtrlD: options.onCtrlD
|
|
177945
179007
|
}));
|
|
177946
179008
|
}
|
|
177947
179009
|
showApprovalPanel(payload) {
|
|
@@ -178069,6 +179131,7 @@ async function runShell(opts, version, runOptions = {}) {
|
|
|
178069
179131
|
return;
|
|
178070
179132
|
}
|
|
178071
179133
|
const config = await harness.getConfig();
|
|
179134
|
+
for (const warning of (await harness.getConfigDiagnostics()).warnings) configWarning = combineStartupNotice(configWarning, warning);
|
|
178072
179135
|
const configMs = Date.now() - configStartedAt;
|
|
178073
179136
|
const tui = new KimiTUI(harness, {
|
|
178074
179137
|
cliOptions: opts,
|