@moonshot-ai/kimi-code 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.mjs +927 -281
- package/package.json +5 -5
package/dist/main.mjs
CHANGED
|
@@ -40,9 +40,9 @@ import * as z4mini from "zod/v4-mini";
|
|
|
40
40
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
41
41
|
import process$1 from "node:process";
|
|
42
42
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
43
|
-
import {
|
|
44
|
-
import { CombinedAutocompleteProvider, Container, Editor, Image, Input, Key, Markdown, ProcessTerminal, Spacer, TUI, Text, decodeKittyPrintable, deleteAllKittyImages, fuzzyFilter, fuzzyMatch, getCapabilities, isKeyRelease, matchesKey, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
|
|
43
|
+
import { CURSOR_MARKER, CombinedAutocompleteProvider, Container, Editor, Image, Input, Key, Markdown, ProcessTerminal, Spacer, TUI, Text, decodeKittyPrintable, deleteAllKittyImages, fuzzyFilter, fuzzyMatch, getCapabilities, isKeyRelease, matchesKey, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
|
|
45
44
|
import chalk, { chalkStderr } from "chalk";
|
|
45
|
+
import { Command, Option } from "commander";
|
|
46
46
|
import { Buffer as Buffer$2 } from "node:buffer";
|
|
47
47
|
import { createInterface } from "node:readline/promises";
|
|
48
48
|
import { highlight, supportsLanguage } from "cli-highlight";
|
|
@@ -1089,9 +1089,13 @@ var APIContextOverflowError = class extends APIStatusError {
|
|
|
1089
1089
|
* The API returned an empty response (no content, no tool calls).
|
|
1090
1090
|
*/
|
|
1091
1091
|
var APIEmptyResponseError = class extends ChatProviderError {
|
|
1092
|
-
|
|
1092
|
+
finishReason;
|
|
1093
|
+
rawFinishReason;
|
|
1094
|
+
constructor(message, options = {}) {
|
|
1093
1095
|
super(message);
|
|
1094
1096
|
this.name = "APIEmptyResponseError";
|
|
1097
|
+
this.finishReason = options.finishReason ?? null;
|
|
1098
|
+
this.rawFinishReason = options.rawFinishReason ?? null;
|
|
1095
1099
|
}
|
|
1096
1100
|
};
|
|
1097
1101
|
function isRetryableGenerateError(error) {
|
|
@@ -8609,6 +8613,11 @@ const OPENAI_RESPONSES_DEVELOPER_ROLE_MODELS = new Set([
|
|
|
8609
8613
|
"o3-pro",
|
|
8610
8614
|
"o4-mini"
|
|
8611
8615
|
]);
|
|
8616
|
+
const OPENAI_CHAT_COMPLETIONS_XHIGH_REASONING_MODELS = new Set([
|
|
8617
|
+
"gpt-5.2",
|
|
8618
|
+
"gpt-5.4",
|
|
8619
|
+
"gpt-5.5"
|
|
8620
|
+
]);
|
|
8612
8621
|
const OPENAI_VISION_TOOL_PREFIXES = [
|
|
8613
8622
|
"gpt-4o",
|
|
8614
8623
|
"gpt-4-turbo",
|
|
@@ -8720,6 +8729,9 @@ const ANTHROPIC_CAPABILITY_CATALOG = [{
|
|
|
8720
8729
|
function normalizeModelName(modelName) {
|
|
8721
8730
|
return modelName.toLowerCase();
|
|
8722
8731
|
}
|
|
8732
|
+
function modelIdLeaf(modelName) {
|
|
8733
|
+
return normalizeModelName(modelName).trim().split("/").at(-1) ?? "";
|
|
8734
|
+
}
|
|
8723
8735
|
function hasPrefix(modelName, prefixes) {
|
|
8724
8736
|
return prefixes.some((prefix) => modelName.startsWith(prefix));
|
|
8725
8737
|
}
|
|
@@ -8747,6 +8759,9 @@ function getGoogleGenAIModelCapability(modelName) {
|
|
|
8747
8759
|
if (normalized.startsWith("gemini-2.5-") || normalized.includes("thinking")) return GEMINI_THINKING_MULTIMODAL_TOOL_CAPABILITY;
|
|
8748
8760
|
return GEMINI_MULTIMODAL_TOOL_CAPABILITY;
|
|
8749
8761
|
}
|
|
8762
|
+
function supportsOpenAIChatCompletionsXHighReasoning(modelName) {
|
|
8763
|
+
return OPENAI_CHAT_COMPLETIONS_XHIGH_REASONING_MODELS.has(modelIdLeaf(modelName));
|
|
8764
|
+
}
|
|
8750
8765
|
function usesOpenAIResponsesDeveloperRole(modelName) {
|
|
8751
8766
|
const normalized = normalizeModelName(modelName);
|
|
8752
8767
|
if (OPENAI_RESPONSES_DEVELOPER_ROLE_MODELS.has(normalized)) return true;
|
|
@@ -46253,6 +46268,10 @@ function normalizeGenerationKwargs(model, source) {
|
|
|
46253
46268
|
}
|
|
46254
46269
|
return kwargs;
|
|
46255
46270
|
}
|
|
46271
|
+
function clampChatCompletionsReasoningEffort(reasoningEffort, model) {
|
|
46272
|
+
if (reasoningEffort !== "xhigh") return reasoningEffort;
|
|
46273
|
+
return supportsOpenAIChatCompletionsXHighReasoning(model) ? "xhigh" : "high";
|
|
46274
|
+
}
|
|
46256
46275
|
function convertMessage$1(message, reasoningKey, toolMessageConversion) {
|
|
46257
46276
|
let reasoningContent = "";
|
|
46258
46277
|
const nonThinkParts = [];
|
|
@@ -46443,7 +46462,7 @@ var OpenAILegacyChatProvider = class {
|
|
|
46443
46462
|
}
|
|
46444
46463
|
}
|
|
46445
46464
|
withThinking(effort) {
|
|
46446
|
-
const reasoningEffort = thinkingEffortToReasoningEffort(effort);
|
|
46465
|
+
const reasoningEffort = clampChatCompletionsReasoningEffort(thinkingEffortToReasoningEffort(effort), this._model);
|
|
46447
46466
|
const clone = this._clone();
|
|
46448
46467
|
clone._reasoningEffort = reasoningEffort;
|
|
46449
46468
|
return clone;
|
|
@@ -47322,11 +47341,17 @@ async function generate(provider, systemPrompt, tools, history, callbacks, optio
|
|
|
47322
47341
|
await throwIfAborted(options?.signal, stream);
|
|
47323
47342
|
options?.onStreamEnd?.();
|
|
47324
47343
|
if (pendingPart !== null) flushPart(message, pendingPart, toolCallIndexMap);
|
|
47325
|
-
if (message.content.length === 0 && message.toolCalls.length === 0) throw new APIEmptyResponseError(
|
|
47344
|
+
if (message.content.length === 0 && message.toolCalls.length === 0) throw new APIEmptyResponseError("The API returned an empty response (no content, no tool calls)." + formatFinishReasonHint(stream) + ` Provider: ${provider.name}, model: ${provider.modelName}`, {
|
|
47345
|
+
finishReason: stream.finishReason,
|
|
47346
|
+
rawFinishReason: stream.rawFinishReason
|
|
47347
|
+
});
|
|
47326
47348
|
const hasThink = message.content.some((p) => p.type === "think");
|
|
47327
47349
|
const hasText = message.content.some((p) => p.type === "text" && p.text.trim().length > 0);
|
|
47328
47350
|
const hasToolCalls = message.toolCalls.length > 0;
|
|
47329
|
-
if (hasThink && !hasText && !hasToolCalls) throw new APIEmptyResponseError(
|
|
47351
|
+
if (hasThink && !hasText && !hasToolCalls) throw new APIEmptyResponseError("The API returned a response containing only thinking content without any text or tool calls. This usually indicates the stream was interrupted or the output token budget was exhausted during reasoning." + formatFinishReasonHint(stream) + ` Provider: ${provider.name}, model: ${provider.modelName}`, {
|
|
47352
|
+
finishReason: stream.finishReason,
|
|
47353
|
+
rawFinishReason: stream.rawFinishReason
|
|
47354
|
+
});
|
|
47330
47355
|
if (callbacks?.onToolCall !== void 0) for (const toolCall of message.toolCalls) {
|
|
47331
47356
|
await throwIfAborted(options?.signal, stream);
|
|
47332
47357
|
await callbacks.onToolCall(toolCall);
|
|
@@ -47387,6 +47412,12 @@ function flushPart(message, part, toolCallIndexMap) {
|
|
|
47387
47412
|
if (streamIndex !== void 0) toolCallIndexMap.set(streamIndex, ordinal);
|
|
47388
47413
|
}
|
|
47389
47414
|
}
|
|
47415
|
+
function formatFinishReasonHint(stream) {
|
|
47416
|
+
if (stream.finishReason === null && stream.rawFinishReason === null) return "";
|
|
47417
|
+
const raw = stream.rawFinishReason === null ? "" : `, rawFinishReason=${stream.rawFinishReason}`;
|
|
47418
|
+
const filteredHint = stream.finishReason === "filtered" ? " The provider filtered the response before visible output was emitted." : "";
|
|
47419
|
+
return ` Provider stop details: finishReason=${stream.finishReason ?? "unknown"}${raw}.${filteredHint}`;
|
|
47420
|
+
}
|
|
47390
47421
|
/**
|
|
47391
47422
|
* Produce a shallow-ish copy of a StreamedMessagePart.
|
|
47392
47423
|
*
|
|
@@ -47500,6 +47531,16 @@ function toKimiErrorPayload(error) {
|
|
|
47500
47531
|
name: error.name,
|
|
47501
47532
|
retryable: KIMI_ERROR_INFO[ErrorCodes.PROVIDER_CONNECTION_ERROR].retryable
|
|
47502
47533
|
};
|
|
47534
|
+
if (error instanceof APIEmptyResponseError) return {
|
|
47535
|
+
code: ErrorCodes.PROVIDER_API_ERROR,
|
|
47536
|
+
message: error.message,
|
|
47537
|
+
name: error.name,
|
|
47538
|
+
details: {
|
|
47539
|
+
finishReason: error.finishReason,
|
|
47540
|
+
rawFinishReason: error.rawFinishReason
|
|
47541
|
+
},
|
|
47542
|
+
retryable: KIMI_ERROR_INFO[ErrorCodes.PROVIDER_API_ERROR].retryable
|
|
47543
|
+
};
|
|
47503
47544
|
if (error instanceof ChatProviderError) return {
|
|
47504
47545
|
code: ErrorCodes.PROVIDER_API_ERROR,
|
|
47505
47546
|
message: error.message,
|
|
@@ -48298,6 +48339,14 @@ const FLAG_DEFINITIONS = [
|
|
|
48298
48339
|
env: "KIMI_CODE_EXPERIMENTAL_BACKGROUND_ASK",
|
|
48299
48340
|
default: false,
|
|
48300
48341
|
surface: "core"
|
|
48342
|
+
},
|
|
48343
|
+
{
|
|
48344
|
+
id: "sub_skill",
|
|
48345
|
+
title: "Sub-skill",
|
|
48346
|
+
description: "Enable discovery of nested skills inside skill bundles that declare has-sub-skill.",
|
|
48347
|
+
env: "KIMI_CODE_EXPERIMENTAL_SUB_SKILL",
|
|
48348
|
+
default: false,
|
|
48349
|
+
surface: "core"
|
|
48301
48350
|
}
|
|
48302
48351
|
];
|
|
48303
48352
|
//#endregion
|
|
@@ -48324,6 +48373,19 @@ function parseBooleanEnv(value) {
|
|
|
48324
48373
|
if (FALSE_BOOLEAN_ENV_VALUES.has(normalized)) return false;
|
|
48325
48374
|
}
|
|
48326
48375
|
/**
|
|
48376
|
+
* Parse a floating-point environment value (e.g. `KIMI_MODEL_TEMPERATURE`).
|
|
48377
|
+
* Returns `undefined` when unset/blank; throws `KimiError(CONFIG_INVALID)` on a
|
|
48378
|
+
* non-numeric value so a typo fails fast like the other `KIMI_MODEL_*` vars.
|
|
48379
|
+
* No range validation — callers pass values the upstream API accepts.
|
|
48380
|
+
*/
|
|
48381
|
+
function parseFloatEnv(value, varName) {
|
|
48382
|
+
const trimmed = value?.trim();
|
|
48383
|
+
if (trimmed === void 0 || trimmed.length === 0) return void 0;
|
|
48384
|
+
const parsed = Number(trimmed);
|
|
48385
|
+
if (!Number.isFinite(parsed)) throw new KimiError(ErrorCodes.CONFIG_INVALID, `${varName} must be a number, got "${value}".`);
|
|
48386
|
+
return parsed;
|
|
48387
|
+
}
|
|
48388
|
+
/**
|
|
48327
48389
|
* Pure, synchronous flag resolver. State comes entirely from (env, registry) and nothing is
|
|
48328
48390
|
* cached: env is read live on every call, so a single shared instance always reflects the current
|
|
48329
48391
|
* process env. Defaults to process.env + FLAG_DEFINITIONS; tests can inject a custom env / defs.
|
|
@@ -48384,7 +48446,12 @@ var FlagResolver = class {
|
|
|
48384
48446
|
};
|
|
48385
48447
|
}
|
|
48386
48448
|
};
|
|
48387
|
-
|
|
48449
|
+
/**
|
|
48450
|
+
* Compatibility accessor for callers that only need process-global env behavior.
|
|
48451
|
+
* Runtime code that belongs to a KimiCore/Session/Agent should use the scoped
|
|
48452
|
+
* resolver on that owner instead.
|
|
48453
|
+
*/
|
|
48454
|
+
const flags = new FlagResolver();
|
|
48388
48455
|
//#endregion
|
|
48389
48456
|
//#region ../../packages/agent-core/src/telemetry.ts
|
|
48390
48457
|
const noopTelemetryClient = {
|
|
@@ -48396,56 +48463,6 @@ function withTelemetryContext$1(telemetry, patch) {
|
|
|
48396
48463
|
return telemetry.withContext?.(patch) ?? telemetry;
|
|
48397
48464
|
}
|
|
48398
48465
|
//#endregion
|
|
48399
|
-
//#region ../../packages/agent-core/src/utils/tokens.ts
|
|
48400
|
-
/**
|
|
48401
|
-
* Estimate token count from text using a character-based heuristic.
|
|
48402
|
-
* - ASCII (~4 chars per token)
|
|
48403
|
-
* - CJK and other non-ASCII (~1 char per token)
|
|
48404
|
-
* The estimate is transient — the next LLM call returns the real count
|
|
48405
|
-
* and supersedes this value. Used to keep `tokenCountWithPending`
|
|
48406
|
-
* monotonic between LLM round-trips without paying for a tokenizer.
|
|
48407
|
-
*/
|
|
48408
|
-
function estimateTokens(text) {
|
|
48409
|
-
let asciiCount = 0;
|
|
48410
|
-
let nonAsciiCount = 0;
|
|
48411
|
-
for (const char of text) if (char.codePointAt(0) <= 127) asciiCount++;
|
|
48412
|
-
else nonAsciiCount++;
|
|
48413
|
-
return Math.ceil(asciiCount / 4) + nonAsciiCount;
|
|
48414
|
-
}
|
|
48415
|
-
function estimateTokensForMessages(messages) {
|
|
48416
|
-
let total = 0;
|
|
48417
|
-
for (const message of messages) total += estimateTokensForMessage(message);
|
|
48418
|
-
return total;
|
|
48419
|
-
}
|
|
48420
|
-
function estimateTokensForTools(tools) {
|
|
48421
|
-
let total = 0;
|
|
48422
|
-
for (const tool of tools) {
|
|
48423
|
-
total += estimateTokens(tool.name);
|
|
48424
|
-
total += estimateTokens(tool.description);
|
|
48425
|
-
total += estimateTokens(JSON.stringify(tool.parameters));
|
|
48426
|
-
}
|
|
48427
|
-
return total;
|
|
48428
|
-
}
|
|
48429
|
-
function estimateTokensForMessage(message) {
|
|
48430
|
-
let total = estimateTokens(message.role);
|
|
48431
|
-
total += estimateTokensForContentParts(message.content);
|
|
48432
|
-
if (message.toolCalls !== void 0) for (const call of message.toolCalls) {
|
|
48433
|
-
total += estimateTokens(call.name);
|
|
48434
|
-
total += estimateTokens(JSON.stringify(call.arguments));
|
|
48435
|
-
}
|
|
48436
|
-
return total;
|
|
48437
|
-
}
|
|
48438
|
-
function estimateTokensForContentParts(parts) {
|
|
48439
|
-
let total = 0;
|
|
48440
|
-
for (const part of parts) total += estimateTokensForContentPart(part);
|
|
48441
|
-
return total;
|
|
48442
|
-
}
|
|
48443
|
-
function estimateTokensForContentPart(part) {
|
|
48444
|
-
if (part.type === "text") return estimateTokens(part.text);
|
|
48445
|
-
else if (part.type === "think") return estimateTokens(part.think);
|
|
48446
|
-
return 0;
|
|
48447
|
-
}
|
|
48448
|
-
//#endregion
|
|
48449
48466
|
//#region ../../packages/agent-core/src/loop/errors.ts
|
|
48450
48467
|
/**
|
|
48451
48468
|
* Loop-local error helpers.
|
|
@@ -54575,6 +54592,47 @@ function renderPrompt(template, vars) {
|
|
|
54575
54592
|
return env.renderString(template, vars);
|
|
54576
54593
|
}
|
|
54577
54594
|
//#endregion
|
|
54595
|
+
//#region ../../packages/agent-core/src/utils/tokens.ts
|
|
54596
|
+
/**
|
|
54597
|
+
* Estimate token count from text using a character-based heuristic.
|
|
54598
|
+
* - ASCII (~4 chars per token)
|
|
54599
|
+
* - CJK and other non-ASCII (~1 char per token)
|
|
54600
|
+
* The estimate is transient — the next LLM call returns the real count
|
|
54601
|
+
* and supersedes this value. Used to keep `tokenCountWithPending`
|
|
54602
|
+
* monotonic between LLM round-trips without paying for a tokenizer.
|
|
54603
|
+
*/
|
|
54604
|
+
function estimateTokens(text) {
|
|
54605
|
+
let asciiCount = 0;
|
|
54606
|
+
let nonAsciiCount = 0;
|
|
54607
|
+
for (const char of text) if (char.codePointAt(0) <= 127) asciiCount++;
|
|
54608
|
+
else nonAsciiCount++;
|
|
54609
|
+
return Math.ceil(asciiCount / 4) + nonAsciiCount;
|
|
54610
|
+
}
|
|
54611
|
+
function estimateTokensForMessages(messages) {
|
|
54612
|
+
let total = 0;
|
|
54613
|
+
for (const message of messages) total += estimateTokensForMessage(message);
|
|
54614
|
+
return total;
|
|
54615
|
+
}
|
|
54616
|
+
function estimateTokensForMessage(message) {
|
|
54617
|
+
let total = estimateTokens(message.role);
|
|
54618
|
+
total += estimateTokensForContentParts(message.content);
|
|
54619
|
+
if (message.toolCalls !== void 0) for (const call of message.toolCalls) {
|
|
54620
|
+
total += estimateTokens(call.name);
|
|
54621
|
+
total += estimateTokens(JSON.stringify(call.arguments));
|
|
54622
|
+
}
|
|
54623
|
+
return total;
|
|
54624
|
+
}
|
|
54625
|
+
function estimateTokensForContentParts(parts) {
|
|
54626
|
+
let total = 0;
|
|
54627
|
+
for (const part of parts) total += estimateTokensForContentPart(part);
|
|
54628
|
+
return total;
|
|
54629
|
+
}
|
|
54630
|
+
function estimateTokensForContentPart(part) {
|
|
54631
|
+
if (part.type === "text") return estimateTokens(part.text);
|
|
54632
|
+
else if (part.type === "think") return estimateTokens(part.think);
|
|
54633
|
+
return 0;
|
|
54634
|
+
}
|
|
54635
|
+
//#endregion
|
|
54578
54636
|
//#region ../../packages/agent-core/src/utils/completion-budget.ts
|
|
54579
54637
|
const MIN_FLOOR = 1;
|
|
54580
54638
|
const DEFAULT_UNKNOWN_CONTEXT_FALLBACK = 32e3;
|
|
@@ -56570,6 +56628,44 @@ var CronManager = class {
|
|
|
56570
56628
|
}
|
|
56571
56629
|
};
|
|
56572
56630
|
//#endregion
|
|
56631
|
+
//#region ../../packages/agent-core/src/agent/kimi-env-params.ts
|
|
56632
|
+
/**
|
|
56633
|
+
* Apply Kimi sampling params (`KIMI_MODEL_TEMPERATURE`, `KIMI_MODEL_TOP_P`) from
|
|
56634
|
+
* the environment to a chat provider. Applied at provider construction
|
|
56635
|
+
* (`ConfigState.provider`) so every request built from `config.provider` — the
|
|
56636
|
+
* main loop AND full-history compaction — carries them, matching kimi-cli where
|
|
56637
|
+
* these live on the shared `create_llm` provider. Applies globally to any Kimi
|
|
56638
|
+
* provider (not tied to `KIMI_MODEL_NAME`).
|
|
56639
|
+
*
|
|
56640
|
+
* Non-Kimi providers — and Kimi providers with neither var set — are returned
|
|
56641
|
+
* unchanged. `max_tokens` is intentionally NOT handled here: `KIMI_MODEL_MAX_TOKENS`
|
|
56642
|
+
* already flows through the completion-budget path (`resolveCompletionBudget`).
|
|
56643
|
+
*/
|
|
56644
|
+
function applyKimiEnvSamplingParams(provider, env = process.env) {
|
|
56645
|
+
if (!(provider instanceof KimiChatProvider)) return provider;
|
|
56646
|
+
const kwargs = {};
|
|
56647
|
+
const temperature = parseFloatEnv(env["KIMI_MODEL_TEMPERATURE"], "KIMI_MODEL_TEMPERATURE");
|
|
56648
|
+
if (temperature !== void 0) kwargs.temperature = temperature;
|
|
56649
|
+
const topP = parseFloatEnv(env["KIMI_MODEL_TOP_P"], "KIMI_MODEL_TOP_P");
|
|
56650
|
+
if (topP !== void 0) kwargs.top_p = topP;
|
|
56651
|
+
return Object.keys(kwargs).length > 0 ? provider.withGenerationKwargs(kwargs) : provider;
|
|
56652
|
+
}
|
|
56653
|
+
/**
|
|
56654
|
+
* Apply the Moonshot preserved-thinking passthrough (`KIMI_MODEL_THINKING_KEEP`
|
|
56655
|
+
* -> `thinking.keep`) to a chat provider. Applied in `Agent.llm` after
|
|
56656
|
+
* `withThinking`, and only while thinking is on — otherwise the API would
|
|
56657
|
+
* receive a `thinking.keep` with no accompanying `thinking.type` it honors.
|
|
56658
|
+
* (Compaction uses a raw provider with thinking off, so it correctly skips this.)
|
|
56659
|
+
*
|
|
56660
|
+
* Non-Kimi providers — and an unset/blank value — are returned unchanged.
|
|
56661
|
+
*/
|
|
56662
|
+
function applyKimiEnvThinkingKeep(provider, thinkingLevel, env = process.env) {
|
|
56663
|
+
if (!(provider instanceof KimiChatProvider)) return provider;
|
|
56664
|
+
const keep = env["KIMI_MODEL_THINKING_KEEP"]?.trim();
|
|
56665
|
+
if (keep === void 0 || keep.length === 0 || thinkingLevel === "off") return provider;
|
|
56666
|
+
return provider.withExtraBody({ thinking: { keep } });
|
|
56667
|
+
}
|
|
56668
|
+
//#endregion
|
|
56573
56669
|
//#region ../../packages/agent-core/src/agent/config/thinking.ts
|
|
56574
56670
|
const DEFAULT_THINKING_EFFORT = "high";
|
|
56575
56671
|
const THINKING_EFFORTS = new Set([
|
|
@@ -56659,7 +56755,7 @@ var ConfigState = class {
|
|
|
56659
56755
|
return provider;
|
|
56660
56756
|
}
|
|
56661
56757
|
get provider() {
|
|
56662
|
-
return createProvider(this.providerConfig);
|
|
56758
|
+
return applyKimiEnvThinkingKeep(applyKimiEnvSamplingParams(createProvider(this.providerConfig).withThinking(this.thinkingLevel)), this.thinkingLevel);
|
|
56663
56759
|
}
|
|
56664
56760
|
get model() {
|
|
56665
56761
|
if (this._modelAlias === void 0) throw new KimiError(ErrorCodes.MODEL_NOT_CONFIGURED, "Model not set");
|
|
@@ -65445,6 +65541,41 @@ const MCP_CONFIG_SKILL = {
|
|
|
65445
65541
|
}
|
|
65446
65542
|
};
|
|
65447
65543
|
//#endregion
|
|
65544
|
+
//#region ../../packages/agent-core/src/skill/builtin/sub-skill/consolidate/SKILL.md
|
|
65545
|
+
var SKILL_default$2 = "---\nname: sub-skill.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. **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`).\n6. **Report the change.** Summarize what was moved, the new structure, 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 create deeply nested hierarchies** (3+ levels) unless the user explicitly requests it.\n";
|
|
65546
|
+
//#endregion
|
|
65547
|
+
//#region ../../packages/agent-core/src/skill/builtin/sub-skill/review/SKILL.md
|
|
65548
|
+
var SKILL_default$1 = "---\nname: sub-skill.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 - 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 - Rationale: Both deal with online information retrieval and are often chained together.\n```\n";
|
|
65549
|
+
//#endregion
|
|
65550
|
+
//#region ../../packages/agent-core/src/skill/builtin/sub-skill/SKILL.md
|
|
65551
|
+
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";
|
|
65552
|
+
//#endregion
|
|
65553
|
+
//#region ../../packages/agent-core/src/skill/builtin/sub-skill.ts
|
|
65554
|
+
function makeBuiltin(body, dirName, pseudoPath, extraMetadata = {}) {
|
|
65555
|
+
const parsed = parseSkillText({
|
|
65556
|
+
skillMdPath: `/builtin/skills/${dirName}/SKILL.md`,
|
|
65557
|
+
skillDirName: dirName,
|
|
65558
|
+
source: "builtin",
|
|
65559
|
+
text: body
|
|
65560
|
+
});
|
|
65561
|
+
return {
|
|
65562
|
+
...parsed,
|
|
65563
|
+
path: pseudoPath,
|
|
65564
|
+
dir: pseudoPath,
|
|
65565
|
+
metadata: {
|
|
65566
|
+
...parsed.metadata,
|
|
65567
|
+
type: parsed.metadata.type ?? "inline",
|
|
65568
|
+
...extraMetadata
|
|
65569
|
+
}
|
|
65570
|
+
};
|
|
65571
|
+
}
|
|
65572
|
+
const SUB_SKILL_PARENT = makeBuiltin(SKILL_default, "sub-skill", "builtin://sub-skill", {
|
|
65573
|
+
disableModelInvocation: true,
|
|
65574
|
+
"has-sub-skill": true
|
|
65575
|
+
});
|
|
65576
|
+
const SUB_SKILL_REVIEW = makeBuiltin(SKILL_default$1, "sub-skill.review", "builtin://sub-skill/review", { disableModelInvocation: true });
|
|
65577
|
+
const SUB_SKILL_CONSOLIDATE = makeBuiltin(SKILL_default$2, "sub-skill.consolidate", "builtin://sub-skill/consolidate", { disableModelInvocation: true });
|
|
65578
|
+
//#endregion
|
|
65448
65579
|
//#region ../../packages/agent-core/src/skill/builtin/update-config.md
|
|
65449
65580
|
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/` (or under `KIMI_CODE_HOME` when set), both snake_case, but with different ownership — decide which one the user means before doing anything:\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/config.toml` or `~/.kimi-code/tui.toml` (under `$KIMI_CODE_HOME/` when set). 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/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";
|
|
65450
65581
|
//#endregion
|
|
@@ -65467,9 +65598,15 @@ const UPDATE_CONFIG_SKILL = {
|
|
|
65467
65598
|
};
|
|
65468
65599
|
//#endregion
|
|
65469
65600
|
//#region ../../packages/agent-core/src/skill/builtin/index.ts
|
|
65470
|
-
function registerBuiltinSkills(registry) {
|
|
65601
|
+
function registerBuiltinSkills(registry, options = {}) {
|
|
65602
|
+
const experimentalFlags = options.experimentalFlags ?? flags;
|
|
65471
65603
|
registry.registerBuiltinSkill(MCP_CONFIG_SKILL);
|
|
65472
65604
|
registry.registerBuiltinSkill(UPDATE_CONFIG_SKILL);
|
|
65605
|
+
if (experimentalFlags.enabled("sub_skill")) {
|
|
65606
|
+
registry.registerBuiltinSkill(SUB_SKILL_PARENT);
|
|
65607
|
+
registry.registerBuiltinSkill(SUB_SKILL_REVIEW);
|
|
65608
|
+
registry.registerBuiltinSkill(SUB_SKILL_CONSOLIDATE);
|
|
65609
|
+
}
|
|
65473
65610
|
}
|
|
65474
65611
|
//#endregion
|
|
65475
65612
|
//#region ../../packages/agent-core/src/skill/scanner.ts
|
|
@@ -65502,6 +65639,7 @@ async function discoverSkills(options) {
|
|
|
65502
65639
|
const isFile = options.isFile ?? defaultIsFile;
|
|
65503
65640
|
const isDir = options.isDir ?? defaultIsDir;
|
|
65504
65641
|
const parse = options.parse ?? parseSkillFromFile;
|
|
65642
|
+
const subSkillFlags = options.experimentalFlags ?? flags;
|
|
65505
65643
|
const warn = options.onWarning ?? (() => {});
|
|
65506
65644
|
const skip = options.onSkippedByPolicy ?? (() => {});
|
|
65507
65645
|
const byName = /* @__PURE__ */ new Map();
|
|
@@ -65517,23 +65655,25 @@ async function discoverSkills(options) {
|
|
|
65517
65655
|
const directorySkills = /* @__PURE__ */ new Set();
|
|
65518
65656
|
const subdirs = [];
|
|
65519
65657
|
for (const entry of entries) {
|
|
65520
|
-
|
|
65521
|
-
|
|
65522
|
-
continue;
|
|
65523
|
-
}
|
|
65658
|
+
const entryPath = posix$1.join(dirPath, entry);
|
|
65659
|
+
if (await isFile(posix$1.join(entryPath, "SKILL.md"))) directorySkills.add(entry);
|
|
65524
65660
|
if (entry === "node_modules" || entry.startsWith(".")) continue;
|
|
65525
|
-
if (await isDir(
|
|
65661
|
+
if (await isDir(entryPath)) subdirs.push(entry);
|
|
65662
|
+
}
|
|
65663
|
+
const allowedSubSkillBundles = /* @__PURE__ */ new Set();
|
|
65664
|
+
for (const entry of directorySkills) {
|
|
65665
|
+
const skill = await parseAndRegister({
|
|
65666
|
+
parse,
|
|
65667
|
+
byName,
|
|
65668
|
+
skillMdPath: posix$1.join(dirPath, entry, "SKILL.md"),
|
|
65669
|
+
skillDirName: entry,
|
|
65670
|
+
root,
|
|
65671
|
+
onDiscoveredSkill: options.onDiscoveredSkill,
|
|
65672
|
+
warn,
|
|
65673
|
+
skip
|
|
65674
|
+
});
|
|
65675
|
+
if (skill !== void 0 && hasSubSkillEnabled(skill, subSkillFlags)) allowedSubSkillBundles.add(entry);
|
|
65526
65676
|
}
|
|
65527
|
-
for (const entry of directorySkills) await parseAndRegister({
|
|
65528
|
-
parse,
|
|
65529
|
-
byName,
|
|
65530
|
-
skillMdPath: posix$1.join(dirPath, entry, "SKILL.md"),
|
|
65531
|
-
skillDirName: entry,
|
|
65532
|
-
root,
|
|
65533
|
-
onDiscoveredSkill: options.onDiscoveredSkill,
|
|
65534
|
-
warn,
|
|
65535
|
-
skip
|
|
65536
|
-
});
|
|
65537
65677
|
if (isTopLevel) {
|
|
65538
65678
|
if (root.plugin !== void 0) {
|
|
65539
65679
|
const rootSkillMd = posix$1.join(dirPath, "SKILL.md");
|
|
@@ -65570,7 +65710,10 @@ async function discoverSkills(options) {
|
|
|
65570
65710
|
});
|
|
65571
65711
|
}
|
|
65572
65712
|
}
|
|
65573
|
-
for (const entry of subdirs)
|
|
65713
|
+
for (const entry of subdirs) {
|
|
65714
|
+
if (directorySkills.has(entry) && !allowedSubSkillBundles.has(entry)) continue;
|
|
65715
|
+
await walkSkillDir(posix$1.join(dirPath, entry), root, false, depth + 1);
|
|
65716
|
+
}
|
|
65574
65717
|
}
|
|
65575
65718
|
for (const root of options.roots) await walkSkillDir(root.path, root, true, 0);
|
|
65576
65719
|
return sortSkills([...byName.values()]);
|
|
@@ -65645,6 +65788,7 @@ async function parseAndRegister(input) {
|
|
|
65645
65788
|
input.onDiscoveredSkill?.(discovered);
|
|
65646
65789
|
const key = normalizeSkillName(discovered.name);
|
|
65647
65790
|
if (!input.byName.has(key)) input.byName.set(key, discovered);
|
|
65791
|
+
return skill;
|
|
65648
65792
|
} catch (error) {
|
|
65649
65793
|
if (error instanceof UnsupportedSkillTypeError) input.skip({
|
|
65650
65794
|
path: input.skillMdPath,
|
|
@@ -65653,8 +65797,15 @@ async function parseAndRegister(input) {
|
|
|
65653
65797
|
});
|
|
65654
65798
|
else if (error instanceof SkillParseError) input.warn(`Skipping invalid skill at ${input.skillMdPath}: ${error.message}`, error);
|
|
65655
65799
|
else input.warn(`Skipping skill at ${input.skillMdPath} due to unexpected error`, error);
|
|
65800
|
+
return;
|
|
65656
65801
|
}
|
|
65657
65802
|
}
|
|
65803
|
+
function hasSubSkillEnabled(skill, experimentalFlags) {
|
|
65804
|
+
if (!experimentalFlags.enabled("sub_skill")) return false;
|
|
65805
|
+
const nested = skill.metadata["metadata"];
|
|
65806
|
+
const nestedFlag = typeof nested === "object" && nested !== null ? nested["has-sub-skill"] === true || nested["hasSubSkill"] === true : false;
|
|
65807
|
+
return skill.metadata["has-sub-skill"] === true || skill.metadata["hasSubSkill"] === true || nestedFlag;
|
|
65808
|
+
}
|
|
65658
65809
|
async function defaultIsDir(p) {
|
|
65659
65810
|
try {
|
|
65660
65811
|
return (await promises.stat(p)).isDirectory();
|
|
@@ -65706,10 +65857,12 @@ var SkillRegistry = class {
|
|
|
65706
65857
|
roots = [];
|
|
65707
65858
|
skipped = [];
|
|
65708
65859
|
discoverImpl;
|
|
65860
|
+
experimentalFlags;
|
|
65709
65861
|
onWarning;
|
|
65710
65862
|
sessionId;
|
|
65711
65863
|
constructor(options = {}) {
|
|
65712
65864
|
this.discoverImpl = options.discover ?? discoverSkills;
|
|
65865
|
+
this.experimentalFlags = options.experimentalFlags ?? flags;
|
|
65713
65866
|
this.onWarning = options.onWarning ?? (() => {});
|
|
65714
65867
|
this.sessionId = options.sessionId;
|
|
65715
65868
|
}
|
|
@@ -65717,6 +65870,7 @@ var SkillRegistry = class {
|
|
|
65717
65870
|
for (const root of roots) if (!this.roots.includes(root.path)) this.roots.push(root.path);
|
|
65718
65871
|
const skills = await this.discoverImpl({
|
|
65719
65872
|
roots,
|
|
65873
|
+
experimentalFlags: this.experimentalFlags,
|
|
65720
65874
|
onWarning: this.onWarning,
|
|
65721
65875
|
onSkippedByPolicy: (skill) => this.skipped.push(skill),
|
|
65722
65876
|
onDiscoveredSkill: (skill) => {
|
|
@@ -78894,10 +79048,10 @@ var CronListTool = class {
|
|
|
78894
79048
|
var agent_background_disabled_default = "Background agent execution is disabled for this agent. Do not set `run_in_background=true`.";
|
|
78895
79049
|
//#endregion
|
|
78896
79050
|
//#region ../../packages/agent-core/src/tools/builtin/collaboration/agent-background-enabled.md
|
|
78897
|
-
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
|
|
79051
|
+
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";
|
|
78898
79052
|
//#endregion
|
|
78899
79053
|
//#region ../../packages/agent-core/src/tools/builtin/collaboration/agent.md
|
|
78900
|
-
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\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
|
|
79054
|
+
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";
|
|
78901
79055
|
//#endregion
|
|
78902
79056
|
//#region ../../packages/agent-core/src/tools/builtin/collaboration/agent.ts
|
|
78903
79057
|
/**
|
|
@@ -78930,8 +79084,7 @@ const AgentToolInputSchema = z.preprocess((input) => {
|
|
|
78930
79084
|
description: z.string().describe("Short task description (3-5 words) for UI display"),
|
|
78931
79085
|
subagent_type: z.string().optional().describe("One of the available agent types (see \"Available agent types\" in this tool description). Defaults to \"coder\" when omitted."),
|
|
78932
79086
|
resume: z.string().optional().describe("Optional agent ID to resume instead of creating a new instance"),
|
|
78933
|
-
run_in_background: z.boolean().optional().describe("If true, return immediately without waiting for completion. Prefer false unless the task can run independently and there is a clear benefit to not waiting.")
|
|
78934
|
-
timeout: z.number().int().min(30).max(3600).optional().describe("Timeout in seconds for the agent task (min 30s, max 3600s / 1hr). When omitted, a foreground task runs until completion with no timeout. The agent is stopped if it exceeds this limit.")
|
|
79087
|
+
run_in_background: z.boolean().optional().describe("If true, return immediately without waiting for completion. Prefer false unless the task can run independently and there is a clear benefit to not waiting.")
|
|
78935
79088
|
}));
|
|
78936
79089
|
z.object({
|
|
78937
79090
|
result: z.string().describe("Aggregated text output from the subagent"),
|
|
@@ -78943,6 +79096,8 @@ z.object({
|
|
|
78943
79096
|
}).describe("Cumulative token usage")
|
|
78944
79097
|
});
|
|
78945
79098
|
const BACKGROUND_AGENT_UNAVAILABLE = "Background agent execution is not available for this agent because TaskList, TaskOutput, and TaskStop are not enabled.";
|
|
79099
|
+
const AGENT_TIMEOUT_MS = 1800 * 1e3;
|
|
79100
|
+
const AGENT_TIMEOUT_DESCRIPTION = "30 minutes";
|
|
78946
79101
|
var AgentTool = class {
|
|
78947
79102
|
subagentHost;
|
|
78948
79103
|
backgroundManager;
|
|
@@ -78995,8 +79150,7 @@ var AgentTool = class {
|
|
|
78995
79150
|
};
|
|
78996
79151
|
}
|
|
78997
79152
|
const backgroundController = runInBackground ? new AbortController() : void 0;
|
|
78998
|
-
|
|
78999
|
-
foregroundDeadline = !runInBackground && timeoutMs !== void 0 ? createDeadlineAbortSignal(signal, timeoutMs) : void 0;
|
|
79153
|
+
foregroundDeadline = !runInBackground ? createDeadlineAbortSignal(signal, AGENT_TIMEOUT_MS) : void 0;
|
|
79000
79154
|
const options = {
|
|
79001
79155
|
parentToolCallId: toolCallId,
|
|
79002
79156
|
prompt: args.prompt,
|
|
@@ -79027,7 +79181,7 @@ var AgentTool = class {
|
|
|
79027
79181
|
let taskId;
|
|
79028
79182
|
try {
|
|
79029
79183
|
taskId = this.backgroundManager.registerTask(new AgentBackgroundTask(handle.completion, args.description, {
|
|
79030
|
-
timeoutMs:
|
|
79184
|
+
timeoutMs: AGENT_TIMEOUT_MS,
|
|
79031
79185
|
agentId: handle.agentId,
|
|
79032
79186
|
subagentType: handle.profileName,
|
|
79033
79187
|
abort: () => {
|
|
@@ -79073,24 +79227,27 @@ var AgentTool = class {
|
|
|
79073
79227
|
].join("\n") };
|
|
79074
79228
|
} catch (error) {
|
|
79075
79229
|
let message;
|
|
79076
|
-
|
|
79230
|
+
const timedOut = foregroundDeadline?.timedOut() === true;
|
|
79231
|
+
if (timedOut) message = `Agent timed out after ${AGENT_TIMEOUT_DESCRIPTION}.`;
|
|
79077
79232
|
else if (isUserCancellation(signal.reason)) message = "The user manually interrupted this subagent (and any sibling agents launched alongside it). This was a deliberate user action, not a system error, a timeout, or a capacity/concurrency limit. Do not retry automatically or speculate about why it failed — wait for the user's next instruction.";
|
|
79078
79233
|
else if (isAbortError$3(error)) message = "The subagent was stopped before it finished.";
|
|
79079
79234
|
else message = error instanceof Error ? error.message : String(error);
|
|
79235
|
+
const lines = [
|
|
79236
|
+
`agent_id: ${handle.agentId}`,
|
|
79237
|
+
`actual_subagent_type: ${handle.profileName}`,
|
|
79238
|
+
"status: failed",
|
|
79239
|
+
"",
|
|
79240
|
+
`subagent error: ${message}`
|
|
79241
|
+
];
|
|
79242
|
+
if (timedOut) lines.push(`resume_hint: Continue with Agent(resume="${handle.agentId}", prompt="continue"). Use agent_id only; do not set subagent_type. The subagent retains its prior context; redo any unfinished tool call if its result was lost.`);
|
|
79080
79243
|
return {
|
|
79081
|
-
output:
|
|
79082
|
-
`agent_id: ${handle.agentId}`,
|
|
79083
|
-
`actual_subagent_type: ${handle.profileName}`,
|
|
79084
|
-
"status: failed",
|
|
79085
|
-
"",
|
|
79086
|
-
`subagent error: ${message}`
|
|
79087
|
-
].join("\n"),
|
|
79244
|
+
output: lines.join("\n"),
|
|
79088
79245
|
isError: true
|
|
79089
79246
|
};
|
|
79090
79247
|
}
|
|
79091
79248
|
} catch (error) {
|
|
79092
79249
|
let message;
|
|
79093
|
-
if (foregroundDeadline?.timedOut() === true
|
|
79250
|
+
if (foregroundDeadline?.timedOut() === true) message = `Agent timed out after ${AGENT_TIMEOUT_DESCRIPTION}.`;
|
|
79094
79251
|
else if (isUserCancellation(signal.reason)) message = "The user manually interrupted this subagent (and any sibling agents launched alongside it). This was a deliberate user action, not a system error, a timeout, or a capacity/concurrency limit. Do not retry automatically or speculate about why it failed — wait for the user's next instruction.";
|
|
79095
79252
|
else if (isAbortError$3(error)) message = "The subagent was stopped before it finished.";
|
|
79096
79253
|
else message = error instanceof Error ? error.message : String(error);
|
|
@@ -88328,7 +88485,7 @@ var Agent = class {
|
|
|
88328
88485
|
}
|
|
88329
88486
|
get llm() {
|
|
88330
88487
|
const model = this.config.model;
|
|
88331
|
-
const provider = this.config.provider
|
|
88488
|
+
const provider = this.config.provider;
|
|
88332
88489
|
const loopControl = this.kimiConfig?.loopControl;
|
|
88333
88490
|
const completionBudgetConfig = resolveCompletionBudget({
|
|
88334
88491
|
maxOutputSize: this.config.maxOutputSize,
|
|
@@ -88349,7 +88506,7 @@ var Agent = class {
|
|
|
88349
88506
|
this.logLlmConfigIfChanged(context, configMetadata, buildLlmConfigSignature(configMetadata, systemPrompt, tools));
|
|
88350
88507
|
let partialMessageCount = 0;
|
|
88351
88508
|
for (const message of history) if (message.partial === true) partialMessageCount += 1;
|
|
88352
|
-
const requestMetadata = {
|
|
88509
|
+
const requestMetadata = {};
|
|
88353
88510
|
if (partialMessageCount > 0) requestMetadata.partialMessageCount = partialMessageCount;
|
|
88354
88511
|
this.log.info("llm request", {
|
|
88355
88512
|
...context,
|
|
@@ -89101,7 +89258,6 @@ const BackgroundConfigSchema = z.object({
|
|
|
89101
89258
|
maxRunningTasks: z.number().int().min(1).optional(),
|
|
89102
89259
|
keepAliveOnExit: z.boolean().optional(),
|
|
89103
89260
|
killGracePeriodMs: z.number().int().min(0).optional(),
|
|
89104
|
-
agentTaskTimeoutS: z.number().int().min(1).optional(),
|
|
89105
89261
|
printWaitCeilingS: z.number().int().min(1).optional()
|
|
89106
89262
|
});
|
|
89107
89263
|
const ExperimentalFlagIdSet = new Set(FLAG_DEFINITIONS.map((def) => def.id));
|
|
@@ -93248,19 +93404,19 @@ async function readMcpJson(filePath, options = {}) {
|
|
|
93248
93404
|
text = await readFile(filePath, "utf-8");
|
|
93249
93405
|
} catch (error) {
|
|
93250
93406
|
if (isFileNotFound(error)) return {};
|
|
93251
|
-
throw new KimiError(ErrorCodes.CONFIG_INVALID, `Failed to read ${filePath}: ${describeError(error)}`, { cause: error });
|
|
93407
|
+
throw new KimiError(ErrorCodes.CONFIG_INVALID, `Failed to read ${filePath}: ${describeError$1(error)}`, { cause: error });
|
|
93252
93408
|
}
|
|
93253
93409
|
if (text.trim().length === 0) return {};
|
|
93254
93410
|
let data;
|
|
93255
93411
|
try {
|
|
93256
93412
|
data = JSON.parse(text);
|
|
93257
93413
|
} catch (error) {
|
|
93258
|
-
throw new KimiError(ErrorCodes.CONFIG_INVALID, `Invalid JSON in ${filePath}: ${describeError(error)}`, { cause: error });
|
|
93414
|
+
throw new KimiError(ErrorCodes.CONFIG_INVALID, `Invalid JSON in ${filePath}: ${describeError$1(error)}`, { cause: error });
|
|
93259
93415
|
}
|
|
93260
93416
|
try {
|
|
93261
93417
|
return normalizeMcpServers(McpJsonFileSchema.parse(data).mcpServers, options);
|
|
93262
93418
|
} catch (error) {
|
|
93263
|
-
throw new KimiError(ErrorCodes.CONFIG_INVALID, `Invalid MCP server config in ${filePath}: ${describeError(error)}`, { cause: error });
|
|
93419
|
+
throw new KimiError(ErrorCodes.CONFIG_INVALID, `Invalid MCP server config in ${filePath}: ${describeError$1(error)}`, { cause: error });
|
|
93264
93420
|
}
|
|
93265
93421
|
}
|
|
93266
93422
|
function normalizeMcpServers(servers, options) {
|
|
@@ -93290,7 +93446,7 @@ function getErrorCode(error) {
|
|
|
93290
93446
|
if (typeof error !== "object" || error === null || !("code" in error)) return void 0;
|
|
93291
93447
|
return error.code;
|
|
93292
93448
|
}
|
|
93293
|
-
function describeError(error) {
|
|
93449
|
+
function describeError$1(error) {
|
|
93294
93450
|
return error instanceof Error ? error.message : String(error);
|
|
93295
93451
|
}
|
|
93296
93452
|
//#endregion
|
|
@@ -93500,12 +93656,10 @@ IMPORTANT:
|
|
|
93500
93656
|
var SessionSubagentHost = class {
|
|
93501
93657
|
session;
|
|
93502
93658
|
ownerAgentId;
|
|
93503
|
-
backgroundTaskTimeoutMs;
|
|
93504
93659
|
activeChildren = /* @__PURE__ */ new Map();
|
|
93505
|
-
constructor(session, ownerAgentId
|
|
93660
|
+
constructor(session, ownerAgentId) {
|
|
93506
93661
|
this.session = session;
|
|
93507
93662
|
this.ownerAgentId = ownerAgentId;
|
|
93508
|
-
this.backgroundTaskTimeoutMs = backgroundTaskTimeoutMs;
|
|
93509
93663
|
}
|
|
93510
93664
|
async spawn(profileName, options) {
|
|
93511
93665
|
options.signal.throwIfAborted();
|
|
@@ -93785,7 +93939,10 @@ var Session$1 = class {
|
|
|
93785
93939
|
},
|
|
93786
93940
|
telemetry: this.telemetry
|
|
93787
93941
|
});
|
|
93788
|
-
this.skills = new SkillRegistry({
|
|
93942
|
+
this.skills = new SkillRegistry({
|
|
93943
|
+
sessionId: options.id,
|
|
93944
|
+
experimentalFlags: this.experimentalFlags
|
|
93945
|
+
});
|
|
93789
93946
|
this.mcp = new McpConnectionManager({
|
|
93790
93947
|
oauthService: new McpOAuthService({ kimiHomeDir: options.kimiHomeDir }),
|
|
93791
93948
|
log: this.log
|
|
@@ -93965,7 +94122,7 @@ var Session$1 = class {
|
|
|
93965
94122
|
builtinDir: this.options.skills?.builtinDir
|
|
93966
94123
|
});
|
|
93967
94124
|
await this.skills.loadRoots(roots);
|
|
93968
|
-
registerBuiltinSkills(this.skills);
|
|
94125
|
+
registerBuiltinSkills(this.skills, { experimentalFlags: this.experimentalFlags });
|
|
93969
94126
|
}
|
|
93970
94127
|
async loadMcpServers() {
|
|
93971
94128
|
const servers = this.options.mcpConfig?.servers;
|
|
@@ -94007,10 +94164,6 @@ var Session$1 = class {
|
|
|
94007
94164
|
}
|
|
94008
94165
|
});
|
|
94009
94166
|
}
|
|
94010
|
-
backgroundTaskTimeoutMs() {
|
|
94011
|
-
const timeoutS = this.options.background?.agentTaskTimeoutS;
|
|
94012
|
-
return timeoutS === void 0 ? void 0 : timeoutS * 1e3;
|
|
94013
|
-
}
|
|
94014
94167
|
refreshAgentBuiltinTools() {
|
|
94015
94168
|
for (const agent of this.readyAgents()) {
|
|
94016
94169
|
if (!agent.config.hasProvider) continue;
|
|
@@ -94030,7 +94183,7 @@ var Session$1 = class {
|
|
|
94030
94183
|
rpc: proxyWithExtraPayload(this.rpc, { agentId: id }),
|
|
94031
94184
|
modelProvider: this.options.providerManager,
|
|
94032
94185
|
hookEngine: config.hookEngine ?? this.hookEngine,
|
|
94033
|
-
subagentHost: config.subagentHost ?? new SessionSubagentHost(this, id
|
|
94186
|
+
subagentHost: config.subagentHost ?? new SessionSubagentHost(this, id),
|
|
94034
94187
|
mcp: this.mcp,
|
|
94035
94188
|
goals: this.goals,
|
|
94036
94189
|
permission: this.permissionOptions(parentAgentId, config.permission),
|
|
@@ -114550,39 +114703,6 @@ function canPreserveDefaultModel(existingModels, defaultModel, managedModels) {
|
|
|
114550
114703
|
const existing = existingModels[defaultModel];
|
|
114551
114704
|
return isRecord$8(existing) && existing["provider"] !== "managed:kimi-code";
|
|
114552
114705
|
}
|
|
114553
|
-
function clearManagedKimiCodeConfig(config) {
|
|
114554
|
-
const removedProvider = Object.hasOwn(config.providers, KIMI_CODE_PROVIDER_NAME);
|
|
114555
|
-
delete config.providers[KIMI_CODE_PROVIDER_NAME];
|
|
114556
|
-
const removedModels = [];
|
|
114557
|
-
const models = config.models;
|
|
114558
|
-
if (models !== void 0) for (const [key, model] of Object.entries(models)) {
|
|
114559
|
-
if (!isRecord$8(model) || model["provider"] !== "managed:kimi-code") continue;
|
|
114560
|
-
delete models[key];
|
|
114561
|
-
removedModels.push(key);
|
|
114562
|
-
}
|
|
114563
|
-
let defaultModelCleared = false;
|
|
114564
|
-
if (typeof config.defaultModel === "string" && removedModels.includes(config.defaultModel)) {
|
|
114565
|
-
config.defaultModel = void 0;
|
|
114566
|
-
defaultModelCleared = true;
|
|
114567
|
-
}
|
|
114568
|
-
const removedServices = [];
|
|
114569
|
-
if (config.services?.moonshotSearch !== void 0) {
|
|
114570
|
-
delete config.services.moonshotSearch;
|
|
114571
|
-
removedServices.push("moonshotSearch");
|
|
114572
|
-
}
|
|
114573
|
-
if (config.services?.moonshotFetch !== void 0) {
|
|
114574
|
-
delete config.services.moonshotFetch;
|
|
114575
|
-
removedServices.push("moonshotFetch");
|
|
114576
|
-
}
|
|
114577
|
-
if (config.services !== void 0 && Object.keys(config.services).length === 0) config.services = void 0;
|
|
114578
|
-
return {
|
|
114579
|
-
providerName: KIMI_CODE_PROVIDER_NAME,
|
|
114580
|
-
removedProvider,
|
|
114581
|
-
removedModels,
|
|
114582
|
-
defaultModelCleared,
|
|
114583
|
-
removedServices
|
|
114584
|
-
};
|
|
114585
|
-
}
|
|
114586
114706
|
function assertPositiveContextLength(model) {
|
|
114587
114707
|
if (!Number.isInteger(model.contextLength) || model.contextLength <= 0) throw new Error(`Kimi Code model "${model.id}" must include a positive context_length.`);
|
|
114588
114708
|
}
|
|
@@ -114751,19 +114871,6 @@ function applyOpenPlatformConfig(config, options) {
|
|
|
114751
114871
|
defaultThinking: options.thinking
|
|
114752
114872
|
};
|
|
114753
114873
|
}
|
|
114754
|
-
function removeOpenPlatformConfig(config, platformId) {
|
|
114755
|
-
delete config.providers[platformId];
|
|
114756
|
-
let removedDefault = false;
|
|
114757
|
-
const existingModels = config.models ?? {};
|
|
114758
|
-
for (const [key, model] of Object.entries(existingModels)) {
|
|
114759
|
-
if (!isRecord$8(model) || model["provider"] !== platformId) continue;
|
|
114760
|
-
delete existingModels[key];
|
|
114761
|
-
if (config.defaultModel === key) removedDefault = true;
|
|
114762
|
-
}
|
|
114763
|
-
config.models = existingModels;
|
|
114764
|
-
if (removedDefault) config.defaultModel = void 0;
|
|
114765
|
-
if (config["defaultProvider"] === platformId) config["defaultProvider"] = void 0;
|
|
114766
|
-
}
|
|
114767
114874
|
//#endregion
|
|
114768
114875
|
//#region ../../packages/oauth/src/custom-registry.ts
|
|
114769
114876
|
/**
|
|
@@ -126347,7 +126454,7 @@ function errorMessage(error) {
|
|
|
126347
126454
|
//#endregion
|
|
126348
126455
|
//#region src/cli/commands.ts
|
|
126349
126456
|
function createProgram(version, onMain, onMigrate, onPluginNodeRunner = () => {}, onUpgrade = () => {}) {
|
|
126350
|
-
const program = new Command(CLI_COMMAND_NAME).description("The Starting Point for Next-Gen Agents").version(version, "-V, --version").allowUnknownOption(false).configureHelp({ helpWidth: 100 }).helpOption("-h, --help", "Show help.").addHelpText("after", "\nDocumentation: https://moonshotai.github.io/kimi-code/\n");
|
|
126457
|
+
const program = new Command(CLI_COMMAND_NAME).description("The Starting Point for Next-Gen Agents").version(version, "-V, --version").allowUnknownOption(false).configureHelp({ helpWidth: 100 }).helpOption("-h, --help", "Show help.").usage("[options] [command]").addHelpText("after", "\nDocumentation: https://moonshotai.github.io/kimi-code/\n");
|
|
126351
126458
|
program.addOption(new Option("-S, --session [id]", "Resume a session. With ID: resume that session. Without ID: interactively pick.").argParser((val) => val === true ? "" : val)).addOption(new Option("-r, --resume [id]").hideHelp().argParser((val) => val === true ? "" : val)).option("-C, --continue", "Continue the previous session for the working directory.", false).option("-y, --yolo", "Automatically approve all actions.", false).option("--auto", "Start in auto permission mode.", false).addOption(new Option("-m, --model <model>", "LLM model alias to use for this invocation. Defaults to default_model in config.toml.")).addOption(new Option("-p, --prompt <prompt>", "Run one prompt non-interactively and print the response.")).addOption(new Option("--output-format <format>", "Output format for prompt mode. Defaults to text.").choices(["text", "stream-json"])).addOption(new Option("--skills-dir <dir>", "Load skills from this directory instead of auto-discovered user and project directories. Can be repeated.").argParser((value, previous) => [...previous ?? [], value]).default([])).addOption(new Option("--yes").hideHelp().default(false)).addOption(new Option("--auto-approve").hideHelp().default(false)).option("--plan", "Start in plan mode.", false);
|
|
126352
126459
|
registerExportCommand(program);
|
|
126353
126460
|
registerProviderCommand(program);
|
|
@@ -126361,7 +126468,8 @@ function createProgram(version, onMain, onMigrate, onPluginNodeRunner = () => {}
|
|
|
126361
126468
|
program.command("__plugin_run_node", { hidden: true }).argument("<entry>").argument("[args...]").allowUnknownOption(true).action((entry, args) => {
|
|
126362
126469
|
onPluginNodeRunner(entry, args);
|
|
126363
126470
|
});
|
|
126364
|
-
program.action(() => {
|
|
126471
|
+
program.argument("[args...]").action((args) => {
|
|
126472
|
+
if (args.length > 0) program.error(`unknown command '${args[0]}'. See '${CLI_COMMAND_NAME} --help'.`);
|
|
126365
126473
|
const raw = program.opts();
|
|
126366
126474
|
const rawSession = raw["session"] ?? raw["resume"];
|
|
126367
126475
|
const sessionValue = rawSession === true ? "" : rawSession;
|
|
@@ -126805,11 +126913,17 @@ function slashBusyMessage(commandName, reason) {
|
|
|
126805
126913
|
function isUserActivatableSkill(skill) {
|
|
126806
126914
|
return skill.type === void 0 || skill.type === "prompt" || skill.type === "inline" || skill.type === "flow";
|
|
126807
126915
|
}
|
|
126916
|
+
function compareSkillSlashCommands(a, b) {
|
|
126917
|
+
return getSkillSlashCommandGroup(a.source) - getSkillSlashCommandGroup(b.source) || a.name.localeCompare(b.name);
|
|
126918
|
+
}
|
|
126919
|
+
function getSkillSlashCommandGroup(source) {
|
|
126920
|
+
return source === "builtin" ? 0 : 1;
|
|
126921
|
+
}
|
|
126808
126922
|
function buildSkillSlashCommands(skills) {
|
|
126809
126923
|
const commandMap = /* @__PURE__ */ new Map();
|
|
126810
126924
|
return {
|
|
126811
|
-
commands: skills.filter(isUserActivatableSkill).map((skill) => {
|
|
126812
|
-
const commandName = `skill:${skill.name}`;
|
|
126925
|
+
commands: [...skills].toSorted(compareSkillSlashCommands).filter(isUserActivatableSkill).map((skill) => {
|
|
126926
|
+
const commandName = skill.source === "builtin" ? skill.name : `skill:${skill.name}`;
|
|
126813
126927
|
commandMap.set(commandName, skill.name);
|
|
126814
126928
|
return {
|
|
126815
126929
|
name: commandName,
|
|
@@ -126890,9 +127004,28 @@ function isTodoItemShape(value) {
|
|
|
126890
127004
|
return rec.status === "pending" || rec.status === "in_progress" || rec.status === "done";
|
|
126891
127005
|
}
|
|
126892
127006
|
function formatErrorMessage$2(error) {
|
|
126893
|
-
if (isKimiError(error)) return
|
|
127007
|
+
if (isKimiError(error)) return formatErrorPayload({
|
|
127008
|
+
code: error.code,
|
|
127009
|
+
message: error.message,
|
|
127010
|
+
details: error.details
|
|
127011
|
+
});
|
|
126894
127012
|
return error instanceof Error ? error.message : String(error);
|
|
126895
127013
|
}
|
|
127014
|
+
function formatErrorPayload(error) {
|
|
127015
|
+
const filteredMessage = formatProviderFilteredMessage(error.details);
|
|
127016
|
+
if (filteredMessage !== void 0) return `[${error.code}] ${filteredMessage}`;
|
|
127017
|
+
return `[${error.code}] ${error.message}`;
|
|
127018
|
+
}
|
|
127019
|
+
function formatProviderFilteredMessage(details) {
|
|
127020
|
+
const finishReason = stringDetail(details, "finishReason");
|
|
127021
|
+
const rawFinishReason = stringDetail(details, "rawFinishReason");
|
|
127022
|
+
if (finishReason !== "filtered" && rawFinishReason !== "content_filter") return void 0;
|
|
127023
|
+
return `Provider filtered the response before visible output (finishReason=${finishReason ?? "filtered"}${rawFinishReason === void 0 ? "" : `, rawFinishReason=${rawFinishReason}`}).`;
|
|
127024
|
+
}
|
|
127025
|
+
function stringDetail(details, key) {
|
|
127026
|
+
const value = details?.[key];
|
|
127027
|
+
return typeof value === "string" ? value : void 0;
|
|
127028
|
+
}
|
|
126896
127029
|
function stringValue(value) {
|
|
126897
127030
|
return typeof value === "string" ? value : void 0;
|
|
126898
127031
|
}
|
|
@@ -129740,7 +129873,7 @@ function handleSettingsSelection(host, value) {
|
|
|
129740
129873
|
}
|
|
129741
129874
|
//#endregion
|
|
129742
129875
|
//#region src/tui/components/dialogs/goal-start-permission-prompt.ts
|
|
129743
|
-
const
|
|
129876
|
+
const MANUAL_OPTIONS = [
|
|
129744
129877
|
{
|
|
129745
129878
|
value: "auto",
|
|
129746
129879
|
label: "Switch to Auto and start",
|
|
@@ -129762,11 +129895,33 @@ const OPTIONS = [
|
|
|
129762
129895
|
description: "Return to the input box with your goal command."
|
|
129763
129896
|
}
|
|
129764
129897
|
];
|
|
129765
|
-
const
|
|
129898
|
+
const YOLO_OPTIONS = [
|
|
129899
|
+
{
|
|
129900
|
+
value: "auto",
|
|
129901
|
+
label: "Switch to Auto and start",
|
|
129902
|
+
description: "Best if you want Kimi Code to keep working while you are away. Tools are approved automatically, and questions are skipped."
|
|
129903
|
+
},
|
|
129904
|
+
{
|
|
129905
|
+
value: "yolo",
|
|
129906
|
+
label: "Keep YOLO and start",
|
|
129907
|
+
description: "Tools and plan changes stay approved automatically. Kimi Code may still ask you questions."
|
|
129908
|
+
},
|
|
129909
|
+
{
|
|
129910
|
+
value: "cancel",
|
|
129911
|
+
label: "Do not start",
|
|
129912
|
+
description: "Return to the input box with your goal command."
|
|
129913
|
+
}
|
|
129914
|
+
];
|
|
129915
|
+
const MANUAL_NOTICE_LINES = [
|
|
129766
129916
|
"Manual mode asks you before Kimi Code runs commands, edits files, or takes other risky actions.",
|
|
129767
129917
|
"Manual mode is not suitable for unattended goal work.",
|
|
129768
129918
|
"You can go back without losing your command."
|
|
129769
129919
|
];
|
|
129920
|
+
const YOLO_NOTICE_LINES = [
|
|
129921
|
+
"YOLO mode approves tools and plan changes automatically.",
|
|
129922
|
+
"YOLO mode can still stop for questions.",
|
|
129923
|
+
"Switch to Auto if you want questions skipped during goal work."
|
|
129924
|
+
];
|
|
129770
129925
|
var GoalStartPermissionPromptComponent = class {
|
|
129771
129926
|
opts;
|
|
129772
129927
|
focused = false;
|
|
@@ -129785,27 +129940,27 @@ var GoalStartPermissionPromptComponent = class {
|
|
|
129785
129940
|
return;
|
|
129786
129941
|
}
|
|
129787
129942
|
if (matchesKey(data, Key.down)) {
|
|
129788
|
-
this.selectedIndex = Math.min(
|
|
129943
|
+
this.selectedIndex = Math.min(this.options.length - 1, this.selectedIndex + 1);
|
|
129789
129944
|
return;
|
|
129790
129945
|
}
|
|
129791
|
-
if (matchesKey(data, Key.enter) || matchesKey(data, Key.space)) this.opts.onSelect(
|
|
129946
|
+
if (matchesKey(data, Key.enter) || matchesKey(data, Key.space)) this.opts.onSelect(this.options[this.selectedIndex].value);
|
|
129792
129947
|
}
|
|
129793
129948
|
render(width) {
|
|
129794
129949
|
const { colors } = this.opts;
|
|
129795
129950
|
const rule = chalk.hex(colors.primary)("─".repeat(width));
|
|
129796
129951
|
const lines = [
|
|
129797
129952
|
rule,
|
|
129798
|
-
chalk.hex(colors.primary).bold(
|
|
129799
|
-
chalk.hex(colors.textMuted)(" ↑↓ navigate · Enter select · Esc
|
|
129953
|
+
chalk.hex(colors.primary).bold(` ${this.title}`),
|
|
129954
|
+
chalk.hex(colors.textMuted)(" ↑↓ navigate · Enter select · Esc cancel"),
|
|
129800
129955
|
""
|
|
129801
129956
|
];
|
|
129802
129957
|
const textWidth = Math.max(20, width - 2);
|
|
129803
|
-
for (const paragraph of
|
|
129958
|
+
for (const paragraph of this.noticeLines) {
|
|
129804
129959
|
for (const line of wrapPlain(paragraph, textWidth)) lines.push(` ${styleModeNames(line, colors, colors.textMuted)}`);
|
|
129805
129960
|
lines.push("");
|
|
129806
129961
|
}
|
|
129807
|
-
for (let i = 0; i <
|
|
129808
|
-
const option =
|
|
129962
|
+
for (let i = 0; i < this.options.length; i += 1) {
|
|
129963
|
+
const option = this.options[i];
|
|
129809
129964
|
const selected = i === this.selectedIndex;
|
|
129810
129965
|
const pointer = selected ? "❯" : " ";
|
|
129811
129966
|
lines.push(chalk.hex(selected ? colors.primary : colors.textDim)(` ${pointer} `) + styleLabel(option.label, selected, colors));
|
|
@@ -129815,6 +129970,15 @@ var GoalStartPermissionPromptComponent = class {
|
|
|
129815
129970
|
lines.push(rule);
|
|
129816
129971
|
return lines.map((line) => truncateToWidth(line, width));
|
|
129817
129972
|
}
|
|
129973
|
+
get options() {
|
|
129974
|
+
return this.opts.mode === "yolo" ? YOLO_OPTIONS : MANUAL_OPTIONS;
|
|
129975
|
+
}
|
|
129976
|
+
get noticeLines() {
|
|
129977
|
+
return this.opts.mode === "yolo" ? YOLO_NOTICE_LINES : MANUAL_NOTICE_LINES;
|
|
129978
|
+
}
|
|
129979
|
+
get title() {
|
|
129980
|
+
return this.opts.mode === "yolo" ? "Start a goal in YOLO mode?" : "Start a goal with approvals on?";
|
|
129981
|
+
}
|
|
129818
129982
|
};
|
|
129819
129983
|
function styleLabel(label, selected, colors) {
|
|
129820
129984
|
if (selected) return chalk.hex(colors.primary).bold(label);
|
|
@@ -129847,8 +130011,14 @@ function wrapPlain(text, width) {
|
|
|
129847
130011
|
//#endregion
|
|
129848
130012
|
//#region src/tui/components/dialogs/goal-queue-manager.ts
|
|
129849
130013
|
const MAX_GOAL_OBJECTIVE_LENGTH$2 = 4e3;
|
|
130014
|
+
const MAX_EDIT_INPUT_LINES = 8;
|
|
129850
130015
|
const ELLIPSIS$5 = "…";
|
|
129851
|
-
const
|
|
130016
|
+
const BRACKET_PASTE_START$1 = "\x1B[200~";
|
|
130017
|
+
const BRACKET_PASTE_END$1 = "\x1B[201~";
|
|
130018
|
+
const SHIFT_ENTER_LEGACY = "\x1B\r";
|
|
130019
|
+
const SHIFT_ENTER_CSI = "\x1B[13;2~";
|
|
130020
|
+
const SEGMENTER = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
130021
|
+
const ANSI_CSI = /\u001B\[[0-?]*[ -/]*[@-~]/g;
|
|
129852
130022
|
var GoalQueueManagerComponent = class extends Container {
|
|
129853
130023
|
focused = false;
|
|
129854
130024
|
opts;
|
|
@@ -129945,7 +130115,7 @@ var GoalQueueManagerComponent = class extends Container {
|
|
|
129945
130115
|
const labelWidth = visibleWidth(labelPrefix);
|
|
129946
130116
|
const stateWidth = visibleWidth(stateLabel);
|
|
129947
130117
|
const objectiveWidth = Math.max(1, width - 5 - labelWidth - stateWidth);
|
|
129948
|
-
const objective = truncateToWidth(goal.objective, objectiveWidth, ELLIPSIS$5);
|
|
130118
|
+
const objective = truncateToWidth(formatListObjective(goal.objective), objectiveWidth, ELLIPSIS$5);
|
|
129949
130119
|
let line = prefix + (selected ? chalk.hex(colors.primary).bold : chalk.hex(colors.text))(labelPrefix + objective);
|
|
129950
130120
|
if (moving) line += chalk.hex(colors.success)(stateLabel);
|
|
129951
130121
|
return line;
|
|
@@ -129981,7 +130151,7 @@ var GoalQueueManagerComponent = class extends Container {
|
|
|
129981
130151
|
};
|
|
129982
130152
|
var GoalQueueEditDialogComponent = class extends Container {
|
|
129983
130153
|
focused = false;
|
|
129984
|
-
input = new
|
|
130154
|
+
input = new MultilineGoalInput();
|
|
129985
130155
|
opts;
|
|
129986
130156
|
done = false;
|
|
129987
130157
|
error;
|
|
@@ -129989,7 +130159,6 @@ var GoalQueueEditDialogComponent = class extends Container {
|
|
|
129989
130159
|
super();
|
|
129990
130160
|
this.opts = opts;
|
|
129991
130161
|
this.input.setValue(opts.goal.objective);
|
|
129992
|
-
this.input.handleInput(END_KEY);
|
|
129993
130162
|
this.input.onSubmit = (value) => {
|
|
129994
130163
|
this.submit(value);
|
|
129995
130164
|
};
|
|
@@ -130018,14 +130187,18 @@ var GoalQueueEditDialogComponent = class extends Container {
|
|
|
130018
130187
|
const pad = " ";
|
|
130019
130188
|
const { colors } = this.opts;
|
|
130020
130189
|
const border = (s) => chalk.hex(colors.primary)(s);
|
|
130190
|
+
const title = truncateToWidth(chalk.hex(colors.textStrong).bold("Edit upcoming goal"), innerWidth, ELLIPSIS$5);
|
|
130191
|
+
const subtitle = truncateToWidth(chalk.hex(this.error === void 0 ? colors.textDim : colors.warning)(this.error ?? "Update the queued objective."), innerWidth, ELLIPSIS$5);
|
|
130192
|
+
const inputLines = this.input.render(innerWidth);
|
|
130193
|
+
const footer = truncateToWidth(chalk.hex(colors.textDim)("Enter submit · Shift-Enter/Ctrl-J newline · Esc cancel"), innerWidth, ELLIPSIS$5);
|
|
130021
130194
|
const contentLines = [
|
|
130022
|
-
|
|
130195
|
+
title,
|
|
130023
130196
|
"",
|
|
130024
|
-
|
|
130197
|
+
subtitle,
|
|
130025
130198
|
"",
|
|
130026
|
-
|
|
130199
|
+
...inputLines,
|
|
130027
130200
|
"",
|
|
130028
|
-
|
|
130201
|
+
footer
|
|
130029
130202
|
];
|
|
130030
130203
|
const lines = [
|
|
130031
130204
|
"",
|
|
@@ -130058,6 +130231,261 @@ var GoalQueueEditDialogComponent = class extends Container {
|
|
|
130058
130231
|
});
|
|
130059
130232
|
}
|
|
130060
130233
|
};
|
|
130234
|
+
var MultilineGoalInput = class {
|
|
130235
|
+
focused = false;
|
|
130236
|
+
onSubmit;
|
|
130237
|
+
value = "";
|
|
130238
|
+
cursor = 0;
|
|
130239
|
+
pasteBuffer;
|
|
130240
|
+
getValue() {
|
|
130241
|
+
return this.value;
|
|
130242
|
+
}
|
|
130243
|
+
setValue(value) {
|
|
130244
|
+
this.value = normalizeNewlines(value);
|
|
130245
|
+
this.cursor = this.value.length;
|
|
130246
|
+
}
|
|
130247
|
+
handleInput(data) {
|
|
130248
|
+
if (this.handleBracketedPaste(data)) return;
|
|
130249
|
+
if (isNewlineInput(data)) {
|
|
130250
|
+
this.insert("\n");
|
|
130251
|
+
return;
|
|
130252
|
+
}
|
|
130253
|
+
if (matchesKey(data, Key.enter) || matchesKey(data, Key.return)) {
|
|
130254
|
+
this.onSubmit?.(this.value);
|
|
130255
|
+
return;
|
|
130256
|
+
}
|
|
130257
|
+
if (matchesKey(data, Key.backspace)) {
|
|
130258
|
+
this.deleteBeforeCursor();
|
|
130259
|
+
return;
|
|
130260
|
+
}
|
|
130261
|
+
if (matchesKey(data, Key.delete)) {
|
|
130262
|
+
this.deleteAfterCursor();
|
|
130263
|
+
return;
|
|
130264
|
+
}
|
|
130265
|
+
if (matchesKey(data, Key.left)) {
|
|
130266
|
+
this.cursor = previousGraphemeStart(this.value, this.cursor);
|
|
130267
|
+
return;
|
|
130268
|
+
}
|
|
130269
|
+
if (matchesKey(data, Key.right)) {
|
|
130270
|
+
this.cursor = nextGraphemeEnd(this.value, this.cursor);
|
|
130271
|
+
return;
|
|
130272
|
+
}
|
|
130273
|
+
if (matchesKey(data, Key.up)) {
|
|
130274
|
+
this.moveVertical(-1);
|
|
130275
|
+
return;
|
|
130276
|
+
}
|
|
130277
|
+
if (matchesKey(data, Key.down)) {
|
|
130278
|
+
this.moveVertical(1);
|
|
130279
|
+
return;
|
|
130280
|
+
}
|
|
130281
|
+
if (matchesKey(data, Key.home) || matchesKey(data, Key.ctrl("a"))) {
|
|
130282
|
+
this.cursor = this.currentLineStart();
|
|
130283
|
+
return;
|
|
130284
|
+
}
|
|
130285
|
+
if (matchesKey(data, Key.end) || matchesKey(data, Key.ctrl("e"))) {
|
|
130286
|
+
this.cursor = this.currentLineEnd();
|
|
130287
|
+
return;
|
|
130288
|
+
}
|
|
130289
|
+
const decoded = printableChar(data);
|
|
130290
|
+
if (isPrintableText(decoded)) this.insert(decoded);
|
|
130291
|
+
}
|
|
130292
|
+
invalidate() {}
|
|
130293
|
+
render(width) {
|
|
130294
|
+
const safeWidth = Math.max(4, width);
|
|
130295
|
+
const logicalLines = this.value.split("\n");
|
|
130296
|
+
const cursor = this.cursorLocation();
|
|
130297
|
+
const range = visibleLineRange(logicalLines.length, cursor.line);
|
|
130298
|
+
const rendered = [];
|
|
130299
|
+
if (range.start > 0) rendered.push(padInputLine(` ${ELLIPSIS$5} ${String(range.start)} previous`, safeWidth));
|
|
130300
|
+
for (let lineIndex = range.start; lineIndex < range.end; lineIndex++) {
|
|
130301
|
+
const line = logicalLines[lineIndex] ?? "";
|
|
130302
|
+
const prefix = lineIndex === 0 ? "> " : " ";
|
|
130303
|
+
rendered.push(lineIndex === cursor.line ? renderCursorLine(line, cursor.column, prefix, safeWidth, this.focused) : renderTextLine(line, prefix, safeWidth));
|
|
130304
|
+
}
|
|
130305
|
+
const remaining = logicalLines.length - range.end;
|
|
130306
|
+
if (remaining > 0) rendered.push(padInputLine(` ${ELLIPSIS$5} ${String(remaining)} more`, safeWidth));
|
|
130307
|
+
return rendered;
|
|
130308
|
+
}
|
|
130309
|
+
insert(text) {
|
|
130310
|
+
const normalized = normalizeNewlines(text);
|
|
130311
|
+
this.value = this.value.slice(0, this.cursor) + normalized + this.value.slice(this.cursor);
|
|
130312
|
+
this.cursor += normalized.length;
|
|
130313
|
+
}
|
|
130314
|
+
deleteBeforeCursor() {
|
|
130315
|
+
if (this.cursor === 0) return;
|
|
130316
|
+
const start = previousGraphemeStart(this.value, this.cursor);
|
|
130317
|
+
this.value = this.value.slice(0, start) + this.value.slice(this.cursor);
|
|
130318
|
+
this.cursor = start;
|
|
130319
|
+
}
|
|
130320
|
+
deleteAfterCursor() {
|
|
130321
|
+
if (this.cursor >= this.value.length) return;
|
|
130322
|
+
const end = nextGraphemeEnd(this.value, this.cursor);
|
|
130323
|
+
this.value = this.value.slice(0, this.cursor) + this.value.slice(end);
|
|
130324
|
+
}
|
|
130325
|
+
moveVertical(delta) {
|
|
130326
|
+
const starts = lineStarts(this.value);
|
|
130327
|
+
const location = this.cursorLocation(starts);
|
|
130328
|
+
const targetLine = location.line + delta;
|
|
130329
|
+
if (targetLine < 0 || targetLine >= starts.length) return;
|
|
130330
|
+
const targetStart = starts[targetLine] ?? 0;
|
|
130331
|
+
const targetEnd = lineEndForStart(this.value, starts, targetLine);
|
|
130332
|
+
this.cursor = Math.min(targetStart + location.column, targetEnd);
|
|
130333
|
+
}
|
|
130334
|
+
currentLineStart() {
|
|
130335
|
+
return this.value.lastIndexOf("\n", Math.max(0, this.cursor - 1)) + 1;
|
|
130336
|
+
}
|
|
130337
|
+
currentLineEnd() {
|
|
130338
|
+
return lineEndAt(this.value, this.cursor);
|
|
130339
|
+
}
|
|
130340
|
+
cursorLocation(starts = lineStarts(this.value)) {
|
|
130341
|
+
let line = 0;
|
|
130342
|
+
for (let i = 0; i < starts.length; i++) {
|
|
130343
|
+
if ((starts[i] ?? 0) > this.cursor) break;
|
|
130344
|
+
line = i;
|
|
130345
|
+
}
|
|
130346
|
+
const lineStart = starts[line] ?? 0;
|
|
130347
|
+
return {
|
|
130348
|
+
line,
|
|
130349
|
+
column: this.cursor - lineStart
|
|
130350
|
+
};
|
|
130351
|
+
}
|
|
130352
|
+
handleBracketedPaste(data) {
|
|
130353
|
+
if (this.pasteBuffer !== void 0) {
|
|
130354
|
+
this.appendPasteChunk(data);
|
|
130355
|
+
return true;
|
|
130356
|
+
}
|
|
130357
|
+
const start = data.indexOf(BRACKET_PASTE_START$1);
|
|
130358
|
+
if (start === -1) return false;
|
|
130359
|
+
this.pasteBuffer = "";
|
|
130360
|
+
const before = data.slice(0, start);
|
|
130361
|
+
if (isPrintableText(before)) this.insert(before);
|
|
130362
|
+
this.appendPasteChunk(data.slice(start + 6));
|
|
130363
|
+
return true;
|
|
130364
|
+
}
|
|
130365
|
+
appendPasteChunk(data) {
|
|
130366
|
+
if (this.pasteBuffer === void 0) return;
|
|
130367
|
+
this.pasteBuffer += data;
|
|
130368
|
+
const end = this.pasteBuffer.indexOf(BRACKET_PASTE_END$1);
|
|
130369
|
+
if (end === -1) return;
|
|
130370
|
+
const pasted = this.pasteBuffer.slice(0, end);
|
|
130371
|
+
const remaining = this.pasteBuffer.slice(end + 6);
|
|
130372
|
+
this.pasteBuffer = void 0;
|
|
130373
|
+
this.insert(sanitizePastedText(pasted));
|
|
130374
|
+
if (remaining.length > 0) this.handleInput(remaining);
|
|
130375
|
+
}
|
|
130376
|
+
};
|
|
130377
|
+
function isNewlineInput(data) {
|
|
130378
|
+
return data === "\n" || data === SHIFT_ENTER_LEGACY || data === SHIFT_ENTER_CSI || matchesKey(data, Key.ctrl("j"));
|
|
130379
|
+
}
|
|
130380
|
+
function normalizeNewlines(text) {
|
|
130381
|
+
return text.replaceAll("\r\n", "\n").replaceAll("\r", "\n");
|
|
130382
|
+
}
|
|
130383
|
+
function formatListObjective(objective) {
|
|
130384
|
+
return objective.replaceAll(/\s+/g, " ").trim();
|
|
130385
|
+
}
|
|
130386
|
+
function sanitizePastedText(text) {
|
|
130387
|
+
const normalized = normalizeNewlines(text).replaceAll(ANSI_CSI, "");
|
|
130388
|
+
let out = "";
|
|
130389
|
+
for (let i = 0; i < normalized.length;) {
|
|
130390
|
+
const code = normalized.codePointAt(i);
|
|
130391
|
+
if (code === void 0) break;
|
|
130392
|
+
const char = String.fromCodePoint(code);
|
|
130393
|
+
if (char === "\n" || isPrintableText(char)) out += char;
|
|
130394
|
+
i += code > 65535 ? 2 : 1;
|
|
130395
|
+
}
|
|
130396
|
+
return out;
|
|
130397
|
+
}
|
|
130398
|
+
function isPrintableText(text) {
|
|
130399
|
+
if (text.length === 0) return false;
|
|
130400
|
+
for (let i = 0; i < text.length;) {
|
|
130401
|
+
const code = text.codePointAt(i);
|
|
130402
|
+
if (code === void 0) return false;
|
|
130403
|
+
if (code < 32 || code === 127 || code >= 128 && code <= 159) return false;
|
|
130404
|
+
i += code > 65535 ? 2 : 1;
|
|
130405
|
+
}
|
|
130406
|
+
return true;
|
|
130407
|
+
}
|
|
130408
|
+
function lineStarts(text) {
|
|
130409
|
+
const starts = [0];
|
|
130410
|
+
for (let i = 0; i < text.length; i++) if (text[i] === "\n") starts.push(i + 1);
|
|
130411
|
+
return starts;
|
|
130412
|
+
}
|
|
130413
|
+
function lineEndAt(text, offset) {
|
|
130414
|
+
const end = text.indexOf("\n", offset);
|
|
130415
|
+
return end === -1 ? text.length : end;
|
|
130416
|
+
}
|
|
130417
|
+
function lineEndForStart(text, starts, line) {
|
|
130418
|
+
const nextStart = starts[line + 1];
|
|
130419
|
+
return nextStart === void 0 ? text.length : nextStart - 1;
|
|
130420
|
+
}
|
|
130421
|
+
function previousGraphemeStart(text, offset) {
|
|
130422
|
+
if (offset <= 0) return 0;
|
|
130423
|
+
let previous = 0;
|
|
130424
|
+
for (const segment of SEGMENTER.segment(text.slice(0, offset))) previous = segment.index;
|
|
130425
|
+
return previous;
|
|
130426
|
+
}
|
|
130427
|
+
function nextGraphemeEnd(text, offset) {
|
|
130428
|
+
if (offset >= text.length) return text.length;
|
|
130429
|
+
const segment = SEGMENTER.segment(text.slice(offset))[Symbol.iterator]().next().value;
|
|
130430
|
+
return segment === void 0 ? text.length : offset + segment.segment.length;
|
|
130431
|
+
}
|
|
130432
|
+
function visibleLineRange(totalLines, cursorLine) {
|
|
130433
|
+
if (totalLines <= MAX_EDIT_INPUT_LINES) return {
|
|
130434
|
+
start: 0,
|
|
130435
|
+
end: totalLines
|
|
130436
|
+
};
|
|
130437
|
+
const half = Math.floor(MAX_EDIT_INPUT_LINES / 2);
|
|
130438
|
+
const start = Math.min(Math.max(0, cursorLine - half), Math.max(0, totalLines - MAX_EDIT_INPUT_LINES));
|
|
130439
|
+
return {
|
|
130440
|
+
start,
|
|
130441
|
+
end: start + MAX_EDIT_INPUT_LINES
|
|
130442
|
+
};
|
|
130443
|
+
}
|
|
130444
|
+
function renderTextLine(line, prefix, width) {
|
|
130445
|
+
const prefixWidth = visibleWidth(prefix);
|
|
130446
|
+
return padInputLine(prefix + truncateToWidth(line, Math.max(1, width - prefixWidth), ELLIPSIS$5), width);
|
|
130447
|
+
}
|
|
130448
|
+
function renderCursorLine(line, column, prefix, width, focused) {
|
|
130449
|
+
const prefixWidth = visibleWidth(prefix);
|
|
130450
|
+
const textWidth = Math.max(1, width - prefixWidth);
|
|
130451
|
+
const cursorEnd = nextGraphemeEnd(line, column);
|
|
130452
|
+
const before = line.slice(0, column);
|
|
130453
|
+
const cursorText = line.slice(column, cursorEnd) || " ";
|
|
130454
|
+
const after = line.slice(cursorEnd);
|
|
130455
|
+
const cursorWidth = Math.max(1, visibleWidth(cursorText));
|
|
130456
|
+
const beforeView = takeEndByWidth(before, Math.max(0, textWidth - cursorWidth));
|
|
130457
|
+
const afterView = takeStartByWidth(after, Math.max(0, textWidth - visibleWidth(beforeView) - cursorWidth));
|
|
130458
|
+
const marker = focused ? CURSOR_MARKER : "";
|
|
130459
|
+
return padInputLine(prefix + beforeView + marker + chalk.inverse(cursorText) + afterView, width);
|
|
130460
|
+
}
|
|
130461
|
+
function takeStartByWidth(text, width) {
|
|
130462
|
+
let out = "";
|
|
130463
|
+
let used = 0;
|
|
130464
|
+
for (const segment of SEGMENTER.segment(text)) {
|
|
130465
|
+
const segmentWidth = visibleWidth(segment.segment);
|
|
130466
|
+
if (used + segmentWidth > width) break;
|
|
130467
|
+
out += segment.segment;
|
|
130468
|
+
used += segmentWidth;
|
|
130469
|
+
}
|
|
130470
|
+
return out;
|
|
130471
|
+
}
|
|
130472
|
+
function takeEndByWidth(text, width) {
|
|
130473
|
+
let out = "";
|
|
130474
|
+
let used = 0;
|
|
130475
|
+
const segments = [...SEGMENTER.segment(text)];
|
|
130476
|
+
for (let i = segments.length - 1; i >= 0; i--) {
|
|
130477
|
+
const segment = segments[i];
|
|
130478
|
+
if (segment === void 0) continue;
|
|
130479
|
+
const segmentWidth = visibleWidth(segment.segment);
|
|
130480
|
+
if (used + segmentWidth > width) break;
|
|
130481
|
+
out = segment.segment + out;
|
|
130482
|
+
used += segmentWidth;
|
|
130483
|
+
}
|
|
130484
|
+
return out;
|
|
130485
|
+
}
|
|
130486
|
+
function padInputLine(line, width) {
|
|
130487
|
+
return line + " ".repeat(Math.max(0, width - visibleWidth(line)));
|
|
130488
|
+
}
|
|
130061
130489
|
//#endregion
|
|
130062
130490
|
//#region src/tui/constant/rendering.ts
|
|
130063
130491
|
const BRAILLE_SPINNER_FRAMES = [
|
|
@@ -130088,6 +130516,9 @@ const WRAP_WIDTH = 72;
|
|
|
130088
130516
|
const MAX_OBJECTIVE_LINES = 6;
|
|
130089
130517
|
const MAX_CRITERION_LINES = 3;
|
|
130090
130518
|
const LABEL_WIDTH = 11;
|
|
130519
|
+
function renderLifecycleLine(label, colors) {
|
|
130520
|
+
return ["", chalk.hex(colors.primary).bold(STATUS_BULLET) + chalk.hex(colors.primary).bold(label)];
|
|
130521
|
+
}
|
|
130091
130522
|
/**
|
|
130092
130523
|
* The "Goal set" confirmation shown after `/goal <objective>`. The objective is
|
|
130093
130524
|
* rendered as the following user prompt, so this message only marks the state
|
|
@@ -130100,7 +130531,17 @@ var GoalSetMessageComponent = class {
|
|
|
130100
130531
|
}
|
|
130101
130532
|
invalidate() {}
|
|
130102
130533
|
render(_width) {
|
|
130103
|
-
return
|
|
130534
|
+
return renderLifecycleLine("Goal set", this.colors);
|
|
130535
|
+
}
|
|
130536
|
+
};
|
|
130537
|
+
var UpcomingGoalAddedMessageComponent = class {
|
|
130538
|
+
colors;
|
|
130539
|
+
constructor(colors) {
|
|
130540
|
+
this.colors = colors;
|
|
130541
|
+
}
|
|
130542
|
+
invalidate() {}
|
|
130543
|
+
render(_width) {
|
|
130544
|
+
return renderLifecycleLine("Upcoming goal added. It will start after the current goal is complete.", this.colors);
|
|
130104
130545
|
}
|
|
130105
130546
|
};
|
|
130106
130547
|
var GoalCompletionMessageComponent = class {
|
|
@@ -130184,7 +130625,7 @@ function statusHex(status, colors) {
|
|
|
130184
130625
|
case "active": return colors.primary;
|
|
130185
130626
|
case "complete": return colors.success;
|
|
130186
130627
|
case "blocked": return colors.warning;
|
|
130187
|
-
|
|
130628
|
+
case "paused": return colors.textDim;
|
|
130188
130629
|
}
|
|
130189
130630
|
}
|
|
130190
130631
|
function formatElapsed$1(ms) {
|
|
@@ -130197,7 +130638,7 @@ function formatElapsed$1(ms) {
|
|
|
130197
130638
|
}
|
|
130198
130639
|
/** Word-wrap to `width`, capped at `maxLines` (last line gets an ellipsis when clipped). */
|
|
130199
130640
|
function wrap$1(text, width, maxLines) {
|
|
130200
|
-
const words = text.
|
|
130641
|
+
const words = text.replaceAll(/\s+/g, " ").trim().split(" ");
|
|
130201
130642
|
const lines = [];
|
|
130202
130643
|
let current = "";
|
|
130203
130644
|
for (const word of words) {
|
|
@@ -130319,10 +130760,8 @@ async function readQueueFile(session) {
|
|
|
130319
130760
|
let parsed;
|
|
130320
130761
|
try {
|
|
130321
130762
|
parsed = JSON.parse(raw);
|
|
130322
|
-
} catch {
|
|
130323
|
-
|
|
130324
|
-
await writeQueueFile(session, empty);
|
|
130325
|
-
return empty;
|
|
130763
|
+
} catch (error) {
|
|
130764
|
+
throw new KimiError(ErrorCodes.CONFIG_INVALID, `Invalid JSON in goal queue: ${describeError(error)}`);
|
|
130326
130765
|
}
|
|
130327
130766
|
if (!isGoalQueueFile(parsed)) {
|
|
130328
130767
|
const empty = emptyQueueFile();
|
|
@@ -130390,10 +130829,14 @@ function timestampAfter(previous) {
|
|
|
130390
130829
|
function isErrno(error, code) {
|
|
130391
130830
|
return isRecord$4(error) && error["code"] === code;
|
|
130392
130831
|
}
|
|
130832
|
+
function describeError(error) {
|
|
130833
|
+
return error instanceof Error ? error.message : String(error);
|
|
130834
|
+
}
|
|
130393
130835
|
//#endregion
|
|
130394
130836
|
//#region src/tui/commands/goal.ts
|
|
130395
130837
|
const MAX_GOAL_OBJECTIVE_LENGTH = 4e3;
|
|
130396
130838
|
const RESUME_GOAL_INPUT = "Resume the active goal.";
|
|
130839
|
+
const START_NEXT_GOAL_NOW_MESSAGE = "No active goal. Starting this goal now.";
|
|
130397
130840
|
const CONTROL_SUBCOMMANDS = new Set([
|
|
130398
130841
|
"pause",
|
|
130399
130842
|
"resume",
|
|
@@ -130488,14 +130931,34 @@ function parseNextGoalCommand(tokens) {
|
|
|
130488
130931
|
};
|
|
130489
130932
|
}
|
|
130490
130933
|
async function queueNextGoal(host, parsed) {
|
|
130934
|
+
const session = host.requireSession();
|
|
130935
|
+
let hasCurrentGoal;
|
|
130491
130936
|
try {
|
|
130492
|
-
|
|
130937
|
+
const { goal } = await session.getGoal();
|
|
130938
|
+
hasCurrentGoal = goal !== null;
|
|
130939
|
+
} catch (error) {
|
|
130940
|
+
host.showError(`Failed to inspect current goal: ${formatErrorMessage$2(error)}`);
|
|
130941
|
+
return;
|
|
130942
|
+
}
|
|
130943
|
+
if (!hasCurrentGoal && !isBusy(host)) {
|
|
130944
|
+
host.showStatus(START_NEXT_GOAL_NOW_MESSAGE);
|
|
130945
|
+
await createGoal(host, {
|
|
130946
|
+
kind: "create",
|
|
130947
|
+
objective: parsed.objective,
|
|
130948
|
+
replace: false
|
|
130949
|
+
}, `next ${parsed.objective}`);
|
|
130950
|
+
return;
|
|
130951
|
+
}
|
|
130952
|
+
try {
|
|
130953
|
+
await appendGoalQueueItem(session, { objective: parsed.objective });
|
|
130493
130954
|
} catch (error) {
|
|
130494
130955
|
host.showError(formatErrorMessage$2(error));
|
|
130495
130956
|
return;
|
|
130496
130957
|
}
|
|
130497
130958
|
host.track("goal_queue_append");
|
|
130498
|
-
host.
|
|
130959
|
+
if (!hasCurrentGoal) host.requestQueuedGoalPromotion?.();
|
|
130960
|
+
host.state.transcriptContainer.addChild(new UpcomingGoalAddedMessageComponent(host.state.theme.colors));
|
|
130961
|
+
host.state.ui.requestRender();
|
|
130499
130962
|
}
|
|
130500
130963
|
async function showGoalQueueManager(host, selectedGoalId) {
|
|
130501
130964
|
let snapshot;
|
|
@@ -130585,7 +131048,7 @@ async function createGoal(host, parsed, rawArgs, options = {}) {
|
|
|
130585
131048
|
host.showError(LLM_NOT_SET_MESSAGE);
|
|
130586
131049
|
return false;
|
|
130587
131050
|
}
|
|
130588
|
-
if (host.state.appState.permissionMode === "manual") {
|
|
131051
|
+
if (host.state.appState.permissionMode === "manual" || host.state.appState.permissionMode === "yolo") {
|
|
130589
131052
|
showGoalStartPermissionPrompt(host, parsed, rawArgs ?? parsed.objective, options);
|
|
130590
131053
|
return false;
|
|
130591
131054
|
}
|
|
@@ -130599,6 +131062,7 @@ function showGoalStartPermissionPrompt(host, parsed, rawArgs, options) {
|
|
|
130599
131062
|
};
|
|
130600
131063
|
host.mountEditorReplacement(new GoalStartPermissionPromptComponent({
|
|
130601
131064
|
colors: host.state.theme.colors,
|
|
131065
|
+
mode: host.state.appState.permissionMode === "yolo" ? "yolo" : "manual",
|
|
130602
131066
|
onSelect: (choice) => {
|
|
130603
131067
|
if (choice === "cancel") {
|
|
130604
131068
|
cancelStart();
|
|
@@ -130611,7 +131075,7 @@ function showGoalStartPermissionPrompt(host, parsed, rawArgs, options) {
|
|
|
130611
131075
|
}));
|
|
130612
131076
|
}
|
|
130613
131077
|
async function startGoalWithPermission(host, parsed, choice, options) {
|
|
130614
|
-
if (choice === "auto" || choice === "yolo") {
|
|
131078
|
+
if (choice !== host.state.appState.permissionMode && (choice === "auto" || choice === "yolo")) {
|
|
130615
131079
|
if (!await setPermissionForGoal(host, choice)) return;
|
|
130616
131080
|
}
|
|
130617
131081
|
await startGoal(host, parsed, options);
|
|
@@ -130644,7 +131108,8 @@ async function startGoal(host, parsed, options) {
|
|
|
130644
131108
|
host.track("goal_create", { replace: parsed.replace });
|
|
130645
131109
|
host.state.transcriptContainer.addChild(new GoalSetMessageComponent(host.state.theme.colors));
|
|
130646
131110
|
host.state.ui.requestRender();
|
|
130647
|
-
(options.sendInput
|
|
131111
|
+
if (options.sendInput !== void 0) options.sendInput(parsed.objective);
|
|
131112
|
+
else host.sendNormalUserInput(parsed.objective);
|
|
130648
131113
|
return true;
|
|
130649
131114
|
}
|
|
130650
131115
|
async function pauseGoal(host) {
|
|
@@ -130711,6 +131176,9 @@ async function showGoalStatus(host) {
|
|
|
130711
131176
|
function isStreaming(host) {
|
|
130712
131177
|
return host.state.appState.streamingPhase !== "idle";
|
|
130713
131178
|
}
|
|
131179
|
+
function isBusy(host) {
|
|
131180
|
+
return isStreaming(host) || host.state.appState.isCompacting;
|
|
131181
|
+
}
|
|
130714
131182
|
//#endregion
|
|
130715
131183
|
//#region src/tui/components/dialogs/custom-registry-import.ts
|
|
130716
131184
|
/**
|
|
@@ -137226,7 +137694,7 @@ var HelpPanelComponent = class extends Container {
|
|
|
137226
137694
|
const slashColor = chalk.hex(colors.primary);
|
|
137227
137695
|
const shortcuts = this.opts.shortcuts ?? DEFAULT_KEYBOARD_SHORTCUTS;
|
|
137228
137696
|
const kbdWidth = Math.max(8, ...shortcuts.map((s) => s.keys.length));
|
|
137229
|
-
const sortedCmds = [...this.opts.commands].toSorted(
|
|
137697
|
+
const sortedCmds = [...this.opts.commands].toSorted(compareSlashCommandsForDisplay);
|
|
137230
137698
|
const cmdLabels = sortedCmds.map((c) => {
|
|
137231
137699
|
const aliases = c.aliases.length > 0 ? ` (${c.aliases.map((a) => "/" + a).join(", ")})` : "";
|
|
137232
137700
|
return `/${c.name}${aliases}`;
|
|
@@ -137265,6 +137733,12 @@ var HelpPanelComponent = class extends Container {
|
|
|
137265
137733
|
return lines.map((line) => truncateToWidth(line, width));
|
|
137266
137734
|
}
|
|
137267
137735
|
};
|
|
137736
|
+
function compareSlashCommandsForDisplay(a, b) {
|
|
137737
|
+
return getSlashCommandDisplayGroup(a.name) - getSlashCommandDisplayGroup(b.name) || a.name.localeCompare(b.name);
|
|
137738
|
+
}
|
|
137739
|
+
function getSlashCommandDisplayGroup(name) {
|
|
137740
|
+
return name.startsWith("skill:") ? 1 : 0;
|
|
137741
|
+
}
|
|
137268
137742
|
//#endregion
|
|
137269
137743
|
//#region src/tui/components/dialogs/question-dialog.ts
|
|
137270
137744
|
/**
|
|
@@ -138039,15 +138513,23 @@ function readCustomRegistrySource(provider) {
|
|
|
138039
138513
|
function asManaged(config) {
|
|
138040
138514
|
return config;
|
|
138041
138515
|
}
|
|
138042
|
-
function
|
|
138516
|
+
function collectModelIdsForAliases(config, aliasKeys) {
|
|
138043
138517
|
const ids = /* @__PURE__ */ new Set();
|
|
138044
|
-
for (const
|
|
138518
|
+
for (const aliasKey of aliasKeys) {
|
|
138519
|
+
const alias = config.models?.[aliasKey];
|
|
138520
|
+
if (alias !== void 0 && alias.model.length > 0) ids.add(alias.model);
|
|
138521
|
+
}
|
|
138045
138522
|
return ids;
|
|
138046
138523
|
}
|
|
138047
|
-
function
|
|
138048
|
-
|
|
138049
|
-
for (const
|
|
138050
|
-
return
|
|
138524
|
+
function providerAliasKeys(config, providerId) {
|
|
138525
|
+
const keys = /* @__PURE__ */ new Set();
|
|
138526
|
+
for (const [alias, model] of Object.entries(config.models ?? {})) if (model.provider === providerId) keys.add(alias);
|
|
138527
|
+
return keys;
|
|
138528
|
+
}
|
|
138529
|
+
function generatedProviderAliasKeys(config, providerId, aliasPrefix) {
|
|
138530
|
+
const keys = /* @__PURE__ */ new Set();
|
|
138531
|
+
for (const [alias, model] of Object.entries(config.models ?? {})) if (model.provider === providerId && alias.startsWith(aliasPrefix)) keys.add(alias);
|
|
138532
|
+
return keys;
|
|
138051
138533
|
}
|
|
138052
138534
|
function computeChanges(oldIds, newIds) {
|
|
138053
138535
|
let added = 0;
|
|
@@ -138059,6 +138541,56 @@ function computeChanges(oldIds, newIds) {
|
|
|
138059
138541
|
removed
|
|
138060
138542
|
};
|
|
138061
138543
|
}
|
|
138544
|
+
function providerModelSnapshot(config, providerId, aliasKeys) {
|
|
138545
|
+
const snapshots = [];
|
|
138546
|
+
for (const alias of aliasKeys) {
|
|
138547
|
+
const model = config.models?.[alias];
|
|
138548
|
+
if (model === void 0 || model.provider !== providerId) continue;
|
|
138549
|
+
snapshots.push({
|
|
138550
|
+
alias,
|
|
138551
|
+
model: {
|
|
138552
|
+
...model,
|
|
138553
|
+
capabilities: model.capabilities === void 0 ? void 0 : model.capabilities.toSorted()
|
|
138554
|
+
}
|
|
138555
|
+
});
|
|
138556
|
+
}
|
|
138557
|
+
snapshots.sort((a, b) => a.alias.localeCompare(b.alias));
|
|
138558
|
+
return JSON.stringify(snapshots);
|
|
138559
|
+
}
|
|
138560
|
+
function providerModelsEqual(config, nextConfig, providerId, aliasKeys) {
|
|
138561
|
+
return providerModelSnapshot(config, providerId, aliasKeys) === providerModelSnapshot(nextConfig, providerId, aliasKeys);
|
|
138562
|
+
}
|
|
138563
|
+
function providerRefreshAliasKeys(config, nextConfig, providerId, aliasPrefix) {
|
|
138564
|
+
const keys = generatedProviderAliasKeys(config, providerId, aliasPrefix);
|
|
138565
|
+
for (const key of providerAliasKeys(nextConfig, providerId)) keys.add(key);
|
|
138566
|
+
return keys;
|
|
138567
|
+
}
|
|
138568
|
+
function preserveUserProviderAliases(config, providerId, refreshedAliasKeys) {
|
|
138569
|
+
const preserved = {};
|
|
138570
|
+
for (const [alias, model] of Object.entries(config.models ?? {})) {
|
|
138571
|
+
if (model.provider !== providerId || refreshedAliasKeys.has(alias)) continue;
|
|
138572
|
+
preserved[alias] = structuredClone(model);
|
|
138573
|
+
}
|
|
138574
|
+
return preserved;
|
|
138575
|
+
}
|
|
138576
|
+
function restoreProviderAliases(config, aliases) {
|
|
138577
|
+
if (Object.keys(aliases).length === 0) return;
|
|
138578
|
+
config.models = {
|
|
138579
|
+
...config.models,
|
|
138580
|
+
...aliases
|
|
138581
|
+
};
|
|
138582
|
+
}
|
|
138583
|
+
function restoreDefaultSelection(config, defaultModel, defaultThinking) {
|
|
138584
|
+
if (defaultModel === void 0 || config.models?.[defaultModel] === void 0) return;
|
|
138585
|
+
config.defaultModel = defaultModel;
|
|
138586
|
+
config.defaultThinking = defaultThinking;
|
|
138587
|
+
}
|
|
138588
|
+
function clampDanglingDefault(config) {
|
|
138589
|
+
if (config.defaultModel !== void 0 && config.models?.[config.defaultModel] === void 0) {
|
|
138590
|
+
config.defaultModel = void 0;
|
|
138591
|
+
config.defaultThinking = void 0;
|
|
138592
|
+
}
|
|
138593
|
+
}
|
|
138062
138594
|
function pickDefaultModel(config, providerId, models) {
|
|
138063
138595
|
const firstModel = models[0];
|
|
138064
138596
|
if (firstModel === void 0) return "";
|
|
@@ -138088,25 +138620,27 @@ async function refreshAllProviderModels(host) {
|
|
|
138088
138620
|
baseUrl: auth.baseUrl
|
|
138089
138621
|
});
|
|
138090
138622
|
if (models.length > 0) {
|
|
138091
|
-
const
|
|
138092
|
-
|
|
138093
|
-
|
|
138623
|
+
const next = structuredClone(config);
|
|
138624
|
+
applyManagedKimiCodeConfig(asManaged(next), {
|
|
138625
|
+
models,
|
|
138626
|
+
baseUrl: auth.baseUrl,
|
|
138627
|
+
oauthKey: auth.oauthRef.key,
|
|
138628
|
+
oauthHost: auth.oauthRef.oauthHost,
|
|
138629
|
+
preserveDefaultModel: true
|
|
138630
|
+
});
|
|
138631
|
+
const refreshedAliasKeys = providerRefreshAliasKeys(config, next, KIMI_CODE_PROVIDER_NAME, `${KIMI_CODE_PLATFORM_ID}/`);
|
|
138632
|
+
restoreProviderAliases(next, preserveUserProviderAliases(config, KIMI_CODE_PROVIDER_NAME, refreshedAliasKeys));
|
|
138633
|
+
restoreDefaultSelection(next, config.defaultModel, config.defaultThinking);
|
|
138634
|
+
clampDanglingDefault(next);
|
|
138635
|
+
if (providerModelsEqual(config, next, "managed:kimi-code", refreshedAliasKeys)) unchanged.push(KIMI_CODE_PROVIDER_NAME);
|
|
138094
138636
|
else {
|
|
138095
|
-
const { added, removed } = computeChanges(
|
|
138096
|
-
|
|
138097
|
-
|
|
138098
|
-
|
|
138099
|
-
models,
|
|
138100
|
-
|
|
138101
|
-
|
|
138102
|
-
oauthHost: auth.oauthRef.oauthHost,
|
|
138103
|
-
preserveDefaultModel: true
|
|
138104
|
-
});
|
|
138105
|
-
await host.setConfig({
|
|
138106
|
-
providers: config.providers,
|
|
138107
|
-
models: config.models,
|
|
138108
|
-
defaultModel: config.defaultModel,
|
|
138109
|
-
defaultThinking: config.defaultThinking
|
|
138637
|
+
const { added, removed } = computeChanges(collectModelIdsForAliases(config, refreshedAliasKeys), collectModelIdsForAliases(next, refreshedAliasKeys));
|
|
138638
|
+
await host.removeProvider(KIMI_CODE_PROVIDER_NAME);
|
|
138639
|
+
config = await host.setConfig({
|
|
138640
|
+
providers: next.providers,
|
|
138641
|
+
models: next.models,
|
|
138642
|
+
defaultModel: next.defaultModel,
|
|
138643
|
+
defaultThinking: next.defaultThinking
|
|
138110
138644
|
});
|
|
138111
138645
|
changed.push({
|
|
138112
138646
|
providerId: KIMI_CODE_PROVIDER_NAME,
|
|
@@ -138134,28 +138668,30 @@ async function refreshAllProviderModels(host) {
|
|
|
138134
138668
|
let models = await fetchOpenPlatformModels(platform, apiKey);
|
|
138135
138669
|
models = filterModelsByPrefix(models, platform);
|
|
138136
138670
|
if (models.length === 0) continue;
|
|
138137
|
-
const
|
|
138138
|
-
const
|
|
138139
|
-
if (
|
|
138671
|
+
const selectedModelId = pickDefaultModel(config, providerId, models);
|
|
138672
|
+
const selectedModel = models.find((m) => m.id === selectedModelId);
|
|
138673
|
+
if (selectedModel === void 0) continue;
|
|
138674
|
+
const next = structuredClone(config);
|
|
138675
|
+
applyOpenPlatformConfig(asManaged(next), {
|
|
138676
|
+
platform,
|
|
138677
|
+
models,
|
|
138678
|
+
selectedModel,
|
|
138679
|
+
thinking: false,
|
|
138680
|
+
apiKey
|
|
138681
|
+
});
|
|
138682
|
+
const refreshedAliasKeys = providerRefreshAliasKeys(config, next, providerId, `${providerId}/`);
|
|
138683
|
+
restoreProviderAliases(next, preserveUserProviderAliases(config, providerId, refreshedAliasKeys));
|
|
138684
|
+
restoreDefaultSelection(next, config.defaultModel, config.defaultThinking);
|
|
138685
|
+
clampDanglingDefault(next);
|
|
138686
|
+
if (providerModelsEqual(config, next, providerId, refreshedAliasKeys)) unchanged.push(providerId);
|
|
138140
138687
|
else {
|
|
138141
|
-
const { added, removed } = computeChanges(
|
|
138142
|
-
|
|
138143
|
-
|
|
138144
|
-
|
|
138145
|
-
|
|
138146
|
-
|
|
138147
|
-
|
|
138148
|
-
platform,
|
|
138149
|
-
models,
|
|
138150
|
-
selectedModel,
|
|
138151
|
-
thinking: false,
|
|
138152
|
-
apiKey
|
|
138153
|
-
});
|
|
138154
|
-
await host.setConfig({
|
|
138155
|
-
providers: config.providers,
|
|
138156
|
-
models: config.models,
|
|
138157
|
-
defaultModel: config.defaultModel,
|
|
138158
|
-
defaultThinking: config.defaultThinking
|
|
138688
|
+
const { added, removed } = computeChanges(collectModelIdsForAliases(config, refreshedAliasKeys), collectModelIdsForAliases(next, refreshedAliasKeys));
|
|
138689
|
+
await host.removeProvider(providerId);
|
|
138690
|
+
config = await host.setConfig({
|
|
138691
|
+
providers: next.providers,
|
|
138692
|
+
models: next.models,
|
|
138693
|
+
defaultModel: next.defaultModel,
|
|
138694
|
+
defaultThinking: next.defaultThinking
|
|
138159
138695
|
});
|
|
138160
138696
|
changed.push({
|
|
138161
138697
|
providerId,
|
|
@@ -138187,20 +138723,18 @@ async function refreshAllProviderModels(host) {
|
|
|
138187
138723
|
}
|
|
138188
138724
|
for (const { source, providerIds } of customSources.values()) try {
|
|
138189
138725
|
const entries = await fetchCustomRegistry(source);
|
|
138190
|
-
|
|
138726
|
+
const next = structuredClone(config);
|
|
138727
|
+
const changedProviders = [];
|
|
138191
138728
|
for (const providerId of providerIds) {
|
|
138192
138729
|
const entry = entries[providerId];
|
|
138193
138730
|
if (entry === void 0) continue;
|
|
138194
|
-
|
|
138195
|
-
const
|
|
138196
|
-
|
|
138731
|
+
applyCustomRegistryProvider(asManaged(next), entry, source);
|
|
138732
|
+
const refreshedAliasKeys = providerRefreshAliasKeys(config, next, providerId, `${providerId}/`);
|
|
138733
|
+
restoreProviderAliases(next, preserveUserProviderAliases(config, providerId, refreshedAliasKeys));
|
|
138734
|
+
if (providerModelsEqual(config, next, providerId, refreshedAliasKeys)) unchanged.push(providerId);
|
|
138197
138735
|
else {
|
|
138198
|
-
const { added, removed } = computeChanges(
|
|
138199
|
-
|
|
138200
|
-
removeCustomRegistryProvider(asManaged(config), providerId);
|
|
138201
|
-
applyCustomRegistryProvider(asManaged(config), entry, source);
|
|
138202
|
-
changedAny = true;
|
|
138203
|
-
changed.push({
|
|
138736
|
+
const { added, removed } = computeChanges(collectModelIdsForAliases(config, refreshedAliasKeys), collectModelIdsForAliases(next, refreshedAliasKeys));
|
|
138737
|
+
changedProviders.push({
|
|
138204
138738
|
providerId,
|
|
138205
138739
|
providerName: entry.name || providerId,
|
|
138206
138740
|
added,
|
|
@@ -138208,10 +138742,18 @@ async function refreshAllProviderModels(host) {
|
|
|
138208
138742
|
});
|
|
138209
138743
|
}
|
|
138210
138744
|
}
|
|
138211
|
-
if (
|
|
138212
|
-
|
|
138213
|
-
|
|
138214
|
-
|
|
138745
|
+
if (changedProviders.length > 0) {
|
|
138746
|
+
restoreDefaultSelection(next, config.defaultModel, config.defaultThinking);
|
|
138747
|
+
clampDanglingDefault(next);
|
|
138748
|
+
for (const { providerId } of changedProviders) await host.removeProvider(providerId);
|
|
138749
|
+
config = await host.setConfig({
|
|
138750
|
+
providers: next.providers,
|
|
138751
|
+
models: next.models,
|
|
138752
|
+
defaultModel: next.defaultModel,
|
|
138753
|
+
defaultThinking: next.defaultThinking
|
|
138754
|
+
});
|
|
138755
|
+
for (const change of changedProviders) changed.push(change);
|
|
138756
|
+
}
|
|
138215
138757
|
} catch (error) {
|
|
138216
138758
|
for (const providerId of providerIds) failed.push({
|
|
138217
138759
|
provider: providerId,
|
|
@@ -140159,6 +140701,7 @@ var SessionEventHandler = class {
|
|
|
140159
140701
|
goalCompletionAwaitingClear = false;
|
|
140160
140702
|
goalCompletionTurnEnded = false;
|
|
140161
140703
|
queuedGoalPromotionPending = false;
|
|
140704
|
+
queuedGoalPromotionInFlight = false;
|
|
140162
140705
|
queuedGoalPromotionTimer;
|
|
140163
140706
|
resetRuntimeState() {
|
|
140164
140707
|
this.backgroundAgentMetadata.clear();
|
|
@@ -140171,6 +140714,7 @@ var SessionEventHandler = class {
|
|
|
140171
140714
|
this.goalCompletionAwaitingClear = false;
|
|
140172
140715
|
this.goalCompletionTurnEnded = false;
|
|
140173
140716
|
this.queuedGoalPromotionPending = false;
|
|
140717
|
+
this.queuedGoalPromotionInFlight = false;
|
|
140174
140718
|
this.clearQueuedGoalPromotionTimer();
|
|
140175
140719
|
this.stopAllMcpServerStatusSpinners();
|
|
140176
140720
|
}
|
|
@@ -140630,14 +141174,25 @@ var SessionEventHandler = class {
|
|
|
140630
141174
|
}
|
|
140631
141175
|
scheduleQueuedGoalPromotion() {
|
|
140632
141176
|
if (!this.queuedGoalPromotionPending || !this.goalCompletionTurnEnded) return;
|
|
141177
|
+
if (this.queuedGoalPromotionInFlight) return;
|
|
140633
141178
|
if (this.queuedGoalPromotionTimer !== void 0) return;
|
|
140634
141179
|
this.queuedGoalPromotionTimer = setTimeout(() => {
|
|
140635
141180
|
this.queuedGoalPromotionTimer = void 0;
|
|
140636
141181
|
if (!this.queuedGoalPromotionPending || !this.goalCompletionTurnEnded) return;
|
|
140637
|
-
if (this.
|
|
140638
|
-
this.
|
|
140639
|
-
this.
|
|
140640
|
-
this.promoteNextQueuedGoal()
|
|
141182
|
+
if (this.queuedGoalPromotionInFlight) return;
|
|
141183
|
+
if (!this.isReadyForQueuedGoalPromotion()) return;
|
|
141184
|
+
this.queuedGoalPromotionInFlight = true;
|
|
141185
|
+
this.promoteNextQueuedGoal().then((complete) => {
|
|
141186
|
+
if (complete) {
|
|
141187
|
+
this.queuedGoalPromotionPending = false;
|
|
141188
|
+
this.goalCompletionTurnEnded = false;
|
|
141189
|
+
return;
|
|
141190
|
+
}
|
|
141191
|
+
this.goalCompletionTurnEnded = false;
|
|
141192
|
+
}).finally(() => {
|
|
141193
|
+
this.queuedGoalPromotionInFlight = false;
|
|
141194
|
+
this.scheduleQueuedGoalPromotion();
|
|
141195
|
+
});
|
|
140641
141196
|
}, 0);
|
|
140642
141197
|
}
|
|
140643
141198
|
clearQueuedGoalPromotionTimer() {
|
|
@@ -140645,50 +141200,72 @@ var SessionEventHandler = class {
|
|
|
140645
141200
|
clearTimeout(this.queuedGoalPromotionTimer);
|
|
140646
141201
|
this.queuedGoalPromotionTimer = void 0;
|
|
140647
141202
|
}
|
|
141203
|
+
requestQueuedGoalPromotion() {
|
|
141204
|
+
this.queuedGoalPromotionPending = true;
|
|
141205
|
+
this.goalCompletionTurnEnded = true;
|
|
141206
|
+
this.scheduleQueuedGoalPromotion();
|
|
141207
|
+
}
|
|
141208
|
+
retryQueuedGoalPromotion() {
|
|
141209
|
+
this.scheduleQueuedGoalPromotion();
|
|
141210
|
+
}
|
|
141211
|
+
isReadyForQueuedGoalPromotion(session) {
|
|
141212
|
+
return (session === void 0 || this.host.session === session) && !this.host.aborted && this.host.state.appState.streamingPhase === "idle" && this.host.state.queuedMessages.length === 0;
|
|
141213
|
+
}
|
|
140648
141214
|
async promoteNextQueuedGoal() {
|
|
140649
141215
|
const { host } = this;
|
|
140650
141216
|
const session = host.session;
|
|
140651
|
-
if (session === void 0 || host.aborted) return;
|
|
141217
|
+
if (session === void 0 || host.aborted) return true;
|
|
140652
141218
|
let queue;
|
|
140653
141219
|
try {
|
|
140654
141220
|
queue = await readGoalQueue(session);
|
|
140655
141221
|
} catch (error) {
|
|
140656
141222
|
host.showError(`Failed to read upcoming goals: ${formatErrorMessage$2(error)}`);
|
|
140657
|
-
return;
|
|
141223
|
+
return false;
|
|
140658
141224
|
}
|
|
140659
|
-
if (host.session !== session || host.aborted) return;
|
|
141225
|
+
if (host.session !== session || host.aborted) return true;
|
|
140660
141226
|
const next = queue.goals[0];
|
|
140661
|
-
if (next === void 0) return;
|
|
140662
|
-
|
|
141227
|
+
if (next === void 0) return true;
|
|
141228
|
+
if (!this.isReadyForQueuedGoalPromotion(session)) return false;
|
|
141229
|
+
return await createGoal(host, {
|
|
140663
141230
|
kind: "create",
|
|
140664
141231
|
objective: next.objective,
|
|
140665
141232
|
replace: false
|
|
140666
141233
|
}, next.objective, {
|
|
140667
141234
|
beforeSend: async () => {
|
|
140668
|
-
if (
|
|
141235
|
+
if (!this.isReadyForQueuedGoalPromotion(session)) {
|
|
141236
|
+
await this.cancelStartedQueuedGoal(session);
|
|
141237
|
+
return false;
|
|
141238
|
+
}
|
|
140669
141239
|
try {
|
|
140670
141240
|
await removeGoalQueueItem(session, { goalId: next.id });
|
|
140671
141241
|
} catch (error) {
|
|
140672
141242
|
host.showError(`Queued goal started, but could not be removed from the queue: ${formatErrorMessage$2(error)}`);
|
|
141243
|
+
await this.cancelStartedQueuedGoal(session);
|
|
140673
141244
|
return false;
|
|
140674
141245
|
}
|
|
140675
|
-
if (
|
|
140676
|
-
|
|
140677
|
-
await restoreGoalQueueItem(session, next);
|
|
140678
|
-
} catch (error) {
|
|
140679
|
-
host.showError(`Queued goal could not be restored: ${formatErrorMessage$2(error)}`);
|
|
140680
|
-
}
|
|
140681
|
-
try {
|
|
140682
|
-
await session.cancelGoal();
|
|
140683
|
-
} catch (error) {
|
|
140684
|
-
host.showError(`Queued goal could not be cancelled: ${formatErrorMessage$2(error)}`);
|
|
140685
|
-
}
|
|
141246
|
+
if (this.isReadyForQueuedGoalPromotion(session)) return true;
|
|
141247
|
+
await this.restoreAndCancelStartedQueuedGoal(session, next);
|
|
140686
141248
|
return false;
|
|
140687
141249
|
},
|
|
140688
141250
|
sendInput: (objective) => {
|
|
140689
141251
|
host.sendQueuedMessage(session, { text: objective });
|
|
140690
141252
|
}
|
|
140691
|
-
});
|
|
141253
|
+
}) || host.session !== session || host.aborted;
|
|
141254
|
+
}
|
|
141255
|
+
async restoreAndCancelStartedQueuedGoal(session, goal) {
|
|
141256
|
+
try {
|
|
141257
|
+
await restoreGoalQueueItem(session, goal);
|
|
141258
|
+
} catch (error) {
|
|
141259
|
+
this.host.showError(`Queued goal could not be restored: ${formatErrorMessage$2(error)}`);
|
|
141260
|
+
}
|
|
141261
|
+
await this.cancelStartedQueuedGoal(session);
|
|
141262
|
+
}
|
|
141263
|
+
async cancelStartedQueuedGoal(session) {
|
|
141264
|
+
try {
|
|
141265
|
+
await session.cancelGoal();
|
|
141266
|
+
} catch (error) {
|
|
141267
|
+
this.host.showError(`Queued goal could not be cancelled: ${formatErrorMessage$2(error)}`);
|
|
141268
|
+
}
|
|
140692
141269
|
}
|
|
140693
141270
|
async notifyQueuedGoalWaitingOnBlocked() {
|
|
140694
141271
|
const { host } = this;
|
|
@@ -140718,7 +141295,7 @@ var SessionEventHandler = class {
|
|
|
140718
141295
|
this.host.showError(OAUTH_LOGIN_REQUIRED_STARTUP_NOTICE);
|
|
140719
141296
|
return;
|
|
140720
141297
|
}
|
|
140721
|
-
this.host.showError(
|
|
141298
|
+
this.host.showError(formatErrorPayload(event));
|
|
140722
141299
|
if (this.host.state.appState.sessionId.length > 0) this.host.showStatus(errorReportHintLine());
|
|
140723
141300
|
}
|
|
140724
141301
|
handleSessionWarning(event) {
|
|
@@ -143303,8 +143880,13 @@ var FileMentionProvider = class {
|
|
|
143303
143880
|
this.inner = new CombinedAutocompleteProvider(slashCommands, workDir, fdPath);
|
|
143304
143881
|
}
|
|
143305
143882
|
async getSuggestions(lines, cursorLine, cursorCol, options) {
|
|
143306
|
-
const
|
|
143307
|
-
|
|
143883
|
+
const currentLine = lines[cursorLine] ?? "";
|
|
143884
|
+
const textBeforeCursor = currentLine.slice(0, cursorCol);
|
|
143885
|
+
const atPrefix = extractAtPrefix(textBeforeCursor);
|
|
143886
|
+
if (atPrefix === null) {
|
|
143887
|
+
if (shouldSuppressSlashArgumentCompletion(textBeforeCursor, currentLine.slice(cursorCol), options.force)) return null;
|
|
143888
|
+
return this.inner.getSuggestions(lines, cursorLine, cursorCol, options);
|
|
143889
|
+
}
|
|
143308
143890
|
if (this.fdPath !== null) return this.inner.getSuggestions(lines, cursorLine, cursorCol, options);
|
|
143309
143891
|
const snapshot = this.gitCache.getSnapshot();
|
|
143310
143892
|
if (snapshot === null || snapshot.files.length === 0) return this.inner.getSuggestions(lines, cursorLine, cursorCol, options);
|
|
@@ -143336,6 +143918,12 @@ function extractAtPrefix(text) {
|
|
|
143336
143918
|
if (text[tokenStart] !== "@") return null;
|
|
143337
143919
|
return text.slice(tokenStart);
|
|
143338
143920
|
}
|
|
143921
|
+
function shouldSuppressSlashArgumentCompletion(textBeforeCursor, textAfterCursor, force) {
|
|
143922
|
+
if (force === true) return false;
|
|
143923
|
+
if (!textBeforeCursor.startsWith("/")) return false;
|
|
143924
|
+
if (!textBeforeCursor.includes(" ")) return false;
|
|
143925
|
+
return textAfterCursor.trimStart().length > 0;
|
|
143926
|
+
}
|
|
143339
143927
|
/** True when any path segment starts with a dot (e.g. `.github/x.yml`). */
|
|
143340
143928
|
function containsDotSegment(path) {
|
|
143341
143929
|
for (const segment of path.split("/")) if (segment.startsWith(".")) return true;
|
|
@@ -145027,6 +145615,7 @@ var CustomEditor = class extends Editor {
|
|
|
145027
145615
|
};
|
|
145028
145616
|
/**
|
|
145029
145617
|
* Return a copy of `line` with the first `/token` coloured using `hex`.
|
|
145618
|
+
* For `/goal next manage`, also colour the command-path tokens.
|
|
145030
145619
|
* `line` may already contain SGR escapes (cursor inverse, etc.); we
|
|
145031
145620
|
* locate `/` via visible-index math so ANSI pass-through survives.
|
|
145032
145621
|
* Returns `undefined` if no token is found.
|
|
@@ -145042,13 +145631,48 @@ function highlightFirstSlashToken(line, hex) {
|
|
|
145042
145631
|
if (ch === " " || ch === " ") break;
|
|
145043
145632
|
endVisible++;
|
|
145044
145633
|
}
|
|
145045
|
-
|
|
145046
|
-
|
|
145047
|
-
const
|
|
145048
|
-
|
|
145049
|
-
|
|
145050
|
-
|
|
145051
|
-
|
|
145634
|
+
const visibleToken = visible.slice(slashIdx, endVisible);
|
|
145635
|
+
if (visibleToken.slice(1).includes("/")) return void 0;
|
|
145636
|
+
const ranges = [{
|
|
145637
|
+
start: slashIdx,
|
|
145638
|
+
end: endVisible
|
|
145639
|
+
}];
|
|
145640
|
+
if (visibleToken === "/goal") ranges.push(...goalCommandPathRanges(visible, endVisible));
|
|
145641
|
+
return highlightVisibleRanges(line, ranges, hex);
|
|
145642
|
+
}
|
|
145643
|
+
function goalCommandPathRanges(visible, commandEnd) {
|
|
145644
|
+
const nextRange = readTokenRange(visible, commandEnd);
|
|
145645
|
+
if (nextRange === null || visible.slice(nextRange.start, nextRange.end) !== "next") return [];
|
|
145646
|
+
const ranges = [nextRange];
|
|
145647
|
+
const manageRange = readTokenRange(visible, nextRange.end);
|
|
145648
|
+
if (manageRange !== null && visible.slice(manageRange.start, manageRange.end) === "manage") ranges.push(manageRange);
|
|
145649
|
+
return ranges;
|
|
145650
|
+
}
|
|
145651
|
+
function readTokenRange(visible, start) {
|
|
145652
|
+
let tokenStart = start;
|
|
145653
|
+
while (tokenStart < visible.length && isTokenSpace(visible[tokenStart])) tokenStart++;
|
|
145654
|
+
if (tokenStart >= visible.length) return null;
|
|
145655
|
+
let tokenEnd = tokenStart;
|
|
145656
|
+
while (tokenEnd < visible.length && !isTokenSpace(visible[tokenEnd])) tokenEnd++;
|
|
145657
|
+
return {
|
|
145658
|
+
start: tokenStart,
|
|
145659
|
+
end: tokenEnd
|
|
145660
|
+
};
|
|
145661
|
+
}
|
|
145662
|
+
function isTokenSpace(ch) {
|
|
145663
|
+
return ch === " " || ch === " ";
|
|
145664
|
+
}
|
|
145665
|
+
function highlightVisibleRanges(line, ranges, hex) {
|
|
145666
|
+
let out = "";
|
|
145667
|
+
let rawCursor = 0;
|
|
145668
|
+
for (const range of ranges) {
|
|
145669
|
+
const rawStart = mapVisibleIdxToRaw(line, range.start);
|
|
145670
|
+
const rawEnd = mapVisibleIdxToRaw(line, range.end);
|
|
145671
|
+
out += line.slice(rawCursor, rawStart);
|
|
145672
|
+
out += chalk.hex(hex).bold(line.slice(rawStart, rawEnd));
|
|
145673
|
+
rawCursor = rawEnd;
|
|
145674
|
+
}
|
|
145675
|
+
return out + line.slice(rawCursor);
|
|
145052
145676
|
}
|
|
145053
145677
|
/**
|
|
145054
145678
|
* Overlay a terminal-style `> ` prompt symbol on the first content line.
|
|
@@ -145964,6 +146588,9 @@ var KimiTUI = class {
|
|
|
145964
146588
|
imageAttachmentIds: item.imageAttachmentIds
|
|
145965
146589
|
});
|
|
145966
146590
|
}
|
|
146591
|
+
requestQueuedGoalPromotion() {
|
|
146592
|
+
this.sessionEventHandler.requestQueuedGoalPromotion();
|
|
146593
|
+
}
|
|
145967
146594
|
sendMessageInternal(session, input, options) {
|
|
145968
146595
|
const imageAttachmentIds = options?.imageAttachmentIds !== void 0 && options.imageAttachmentIds.length > 0 ? options.imageAttachmentIds : void 0;
|
|
145969
146596
|
this.appendTranscriptEntry({
|
|
@@ -146065,7 +146692,10 @@ var KimiTUI = class {
|
|
|
146065
146692
|
if ("planMode" in patch) this.updateEditorBorderHighlight();
|
|
146066
146693
|
this.state.footer.setState(this.state.appState);
|
|
146067
146694
|
this.updateActivityPane();
|
|
146068
|
-
if (busyChanged)
|
|
146695
|
+
if (busyChanged) {
|
|
146696
|
+
this.updateQueueDisplay();
|
|
146697
|
+
this.sessionEventHandler.retryQueuedGoalPromotion();
|
|
146698
|
+
}
|
|
146069
146699
|
this.state.ui.requestRender();
|
|
146070
146700
|
}
|
|
146071
146701
|
patchLivePane(patch) {
|
|
@@ -147355,6 +147985,21 @@ async function showPendingBackgroundInstallNotice(state, currentVersion, stdout,
|
|
|
147355
147985
|
await writeUpdateInstallState(nextState).catch(() => {});
|
|
147356
147986
|
return nextState;
|
|
147357
147987
|
}
|
|
147988
|
+
/**
|
|
147989
|
+
* `KIMI_CODE_NO_AUTO_UPDATE` (or the legacy `KIMI_CLI_NO_AUTO_UPDATE` alias)
|
|
147990
|
+
* fully disables the update preflight — no check, no background install, no
|
|
147991
|
+
* prompt. Migrated from kimi-cli, where the variable gated all auto-update
|
|
147992
|
+
* behavior. Accepts the usual truthy values (`1`/`true`/`yes`/`on`).
|
|
147993
|
+
*/
|
|
147994
|
+
function isAutoUpdateDisabledByEnv(env = process.env) {
|
|
147995
|
+
const truthy = (value) => [
|
|
147996
|
+
"1",
|
|
147997
|
+
"true",
|
|
147998
|
+
"yes",
|
|
147999
|
+
"on"
|
|
148000
|
+
].includes((value ?? "").trim().toLowerCase());
|
|
148001
|
+
return truthy(env["KIMI_CODE_NO_AUTO_UPDATE"]) || truthy(env["KIMI_CLI_NO_AUTO_UPDATE"]);
|
|
148002
|
+
}
|
|
147358
148003
|
async function shouldAutoInstallUpdates() {
|
|
147359
148004
|
try {
|
|
147360
148005
|
return (await loadTuiConfig()).upgrade.autoInstall;
|
|
@@ -147512,6 +148157,7 @@ async function runUpdatePreflight(currentVersion, options = {}) {
|
|
|
147512
148157
|
const stderr = options.stderr ?? process.stderr;
|
|
147513
148158
|
const logger = options.logger ?? log;
|
|
147514
148159
|
const platform = process.platform;
|
|
148160
|
+
if (isAutoUpdateDisabledByEnv()) return "continue";
|
|
147515
148161
|
try {
|
|
147516
148162
|
const isInteractive = options.isTTY ?? (process.stdin.isTTY && process.stdout.isTTY);
|
|
147517
148163
|
let installState = await readUpdateInstallState().catch(() => emptyUpdateInstallState());
|