@moonshot-ai/kimi-code 0.17.0 → 0.18.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 +281 -131
- package/dist-web/assets/{CodeBlockNode-xopu-OEb.js → CodeBlockNode-BBTPBNlr.js} +1 -1
- package/dist-web/assets/{CodeBlockShell.vue_vue_type_style_index_0_lang-DmARNWLd.js → CodeBlockShell.vue_vue_type_style_index_0_lang-DW-0ZP66.js} +1 -1
- package/dist-web/assets/{Tooltip-DzPFYPha.js → Tooltip-BEPNqHjy.js} +1 -1
- package/dist-web/assets/{arc-D9ISmG8O.js → arc-DsEMn4wL.js} +1 -1
- package/dist-web/assets/{architectureDiagram-3BPJPVTR-Bde5KvUn.js → architectureDiagram-3BPJPVTR-CRMgytTq.js} +1 -1
- package/dist-web/assets/{blockDiagram-GPEHLZMM-JCl1lMhx.js → blockDiagram-GPEHLZMM-DZjTWP93.js} +1 -1
- package/dist-web/assets/{c4Diagram-AAUBKEIU-CbJhvcRt.js → c4Diagram-AAUBKEIU-XN05Flkv.js} +1 -1
- package/dist-web/assets/channel-Dyiajwlv.js +1 -0
- package/dist-web/assets/{chunk-2J33WTMH-L9nQnfKd.js → chunk-2J33WTMH-DB2YVfPY.js} +1 -1
- package/dist-web/assets/{chunk-4BX2VUAB-zohve9Ok.js → chunk-4BX2VUAB-Bed6jJZo.js} +1 -1
- package/dist-web/assets/{chunk-55IACEB6-DR3E48TL.js → chunk-55IACEB6-CHhaYL59.js} +1 -1
- package/dist-web/assets/{chunk-727SXJPM-C18LQHi4.js → chunk-727SXJPM-BOJiU2Eb.js} +1 -1
- package/dist-web/assets/{chunk-AQP2D5EJ-BsjNQvhe.js → chunk-AQP2D5EJ-C8k6MI_Z.js} +1 -1
- package/dist-web/assets/{chunk-FMBD7UC4-774mj8wI.js → chunk-FMBD7UC4-C-MvWtbr.js} +1 -1
- package/dist-web/assets/{chunk-ND2GUHAM-BahAcenP.js → chunk-ND2GUHAM-CEqD9cw0.js} +1 -1
- package/dist-web/assets/{chunk-QZHKN3VN-Dc2ML4_y.js → chunk-QZHKN3VN-BcJHlqi-.js} +1 -1
- package/dist-web/assets/classDiagram-4FO5ZUOK-Cq15LdMD.js +1 -0
- package/dist-web/assets/classDiagram-v2-Q7XG4LA2-Cq15LdMD.js +1 -0
- package/dist-web/assets/{cose-bilkent-S5V4N54A-BHhvV2M3.js → cose-bilkent-S5V4N54A-DJ8zjD1S.js} +1 -1
- package/dist-web/assets/{dagre-BM42HDAG-CCUkqn3c.js → dagre-BM42HDAG-BrTwtLB1.js} +1 -1
- package/dist-web/assets/{diagram-2AECGRRQ-CJAIuD9v.js → diagram-2AECGRRQ-Y7FcZPzP.js} +1 -1
- package/dist-web/assets/{diagram-5GNKFQAL-CIzOyklY.js → diagram-5GNKFQAL-DKHdXG1y.js} +1 -1
- package/dist-web/assets/{diagram-KO2AKTUF-Dy0TSkF9.js → diagram-KO2AKTUF-VCCXGLOR.js} +1 -1
- package/dist-web/assets/{diagram-LMA3HP47-D0VZv9QJ.js → diagram-LMA3HP47-CYLE3Fzr.js} +1 -1
- package/dist-web/assets/{diagram-OG6HWLK6-BOmRuoa3.js → diagram-OG6HWLK6-DoP7AdmG.js} +1 -1
- package/dist-web/assets/{erDiagram-TEJ5UH35-XD82Xp5G.js → erDiagram-TEJ5UH35-BMcb04Oc.js} +1 -1
- package/dist-web/assets/{flowDiagram-I6XJVG4X-Cjx82rYf.js → flowDiagram-I6XJVG4X-C6UZeyqx.js} +1 -1
- package/dist-web/assets/{ganttDiagram-6RSMTGT7-uApHfVFI.js → ganttDiagram-6RSMTGT7-ejmlce9Q.js} +1 -1
- package/dist-web/assets/{gitGraphDiagram-PVQCEYII-pCJa6Sqh.js → gitGraphDiagram-PVQCEYII-0oVWkTiE.js} +1 -1
- package/dist-web/assets/{index-ruKp3ITH.js → index-Bj6xsK-Y.js} +1 -1
- package/dist-web/assets/index-CNwU-esk.js +268 -0
- package/dist-web/assets/index-D6vWyrW-.css +1 -0
- package/dist-web/assets/{index-DSJEhgK2.js → index-DrcjPgrD.js} +3 -3
- package/dist-web/assets/{index10-BU_fP3cF.js → index10-BIb6yLoQ.js} +1 -1
- package/dist-web/assets/{index11-4vKmecHt.js → index11-BcLwmlar.js} +2 -2
- package/dist-web/assets/{index5-B_Zm1CXv.js → index5-BOBUDie_.js} +1 -1
- package/dist-web/assets/{index6-Bcj2CUc2.js → index6-B1AecMuA.js} +1 -1
- package/dist-web/assets/{index7-CktYDBgt.js → index7-B1vZsaF7.js} +1 -1
- package/dist-web/assets/{index8-Dv0bVWi6.js → index8-jsIBLdbS.js} +2 -2
- package/dist-web/assets/{infoDiagram-5YYISTIA-ntWeW9KZ.js → infoDiagram-5YYISTIA-C3E_KFZS.js} +1 -1
- package/dist-web/assets/{ishikawaDiagram-YF4QCWOH-LIB-i9cU.js → ishikawaDiagram-YF4QCWOH-DTMAsXar.js} +1 -1
- package/dist-web/assets/{journeyDiagram-JHISSGLW-BlfBWGGp.js → journeyDiagram-JHISSGLW-DlMqknWB.js} +1 -1
- package/dist-web/assets/{kanban-definition-UN3LZRKU-D5dIR3XR.js → kanban-definition-UN3LZRKU-D8W-yZwQ.js} +1 -1
- package/dist-web/assets/{linear-DModnwwD.js → linear-CXvIR_Cz.js} +1 -1
- package/dist-web/assets/{mermaid.core-vCZSrzF3.js → mermaid.core-Cm0scdl_.js} +4 -4
- package/dist-web/assets/{mindmap-definition-RKZ34NQL-DtXX70f6.js → mindmap-definition-RKZ34NQL-BTR5HSvV.js} +1 -1
- package/dist-web/assets/{pieDiagram-4H26LBE5-BTWE5xhz.js → pieDiagram-4H26LBE5-DgBdBron.js} +1 -1
- package/dist-web/assets/{quadrantDiagram-W4KKPZXB-BIf4h40K.js → quadrantDiagram-W4KKPZXB-DlJDz6Co.js} +1 -1
- package/dist-web/assets/{requirementDiagram-4Y6WPE33-DYIJe9Dp.js → requirementDiagram-4Y6WPE33-BILYgyLr.js} +1 -1
- package/dist-web/assets/{sankeyDiagram-5OEKKPKP-C6fQmYW1.js → sankeyDiagram-5OEKKPKP-CsB0bfUt.js} +1 -1
- package/dist-web/assets/{sequenceDiagram-3UESZ5HK-j9sFp20c.js → sequenceDiagram-3UESZ5HK-B6sFCfAl.js} +1 -1
- package/dist-web/assets/{stateDiagram-AJRCARHV-BmdayxXt.js → stateDiagram-AJRCARHV-CR0aRL4-.js} +1 -1
- package/dist-web/assets/stateDiagram-v2-BHNVJYJU-UfuPGBrg.js +1 -0
- package/dist-web/assets/{timeline-definition-PNZ67QCA-CoPa3Alw.js → timeline-definition-PNZ67QCA-Bfmc75An.js} +1 -1
- package/dist-web/assets/{vennDiagram-CIIHVFJN-C1znvnC_.js → vennDiagram-CIIHVFJN-bwUT2S9H.js} +1 -1
- package/dist-web/assets/{vue.runtime.esm-bundler-C3-MzG4F.js → vue.runtime.esm-bundler-BJNZCSc8.js} +1 -1
- package/dist-web/assets/{wardley-L42UT6IY-CRUU46rw.js → wardley-L42UT6IY-grqTsjin.js} +1 -1
- package/dist-web/assets/{wardleyDiagram-YWT4CUSO-u3Px8OI4.js → wardleyDiagram-YWT4CUSO-By-aofC4.js} +1 -1
- package/dist-web/assets/{xychartDiagram-2RQKCTM6-CCMgiVYB.js → xychartDiagram-2RQKCTM6-BxqaMGkt.js} +1 -1
- package/dist-web/index.html +2 -2
- package/package.json +3 -3
- package/dist-web/assets/channel-Dx9cvqoI.js +0 -1
- package/dist-web/assets/classDiagram-4FO5ZUOK-CQBVgO9P.js +0 -1
- package/dist-web/assets/classDiagram-v2-Q7XG4LA2-CQBVgO9P.js +0 -1
- package/dist-web/assets/index-Bm5hIhdQ.css +0 -1
- package/dist-web/assets/index-Cr6PBwa_.js +0 -268
- package/dist-web/assets/stateDiagram-v2-BHNVJYJU-BGbtlEvl.js +0 -1
package/dist/main.mjs
CHANGED
|
@@ -67009,6 +67009,39 @@ var GitCwdWriteApprovePermissionPolicy = class {
|
|
|
67009
67009
|
}
|
|
67010
67010
|
};
|
|
67011
67011
|
//#endregion
|
|
67012
|
+
//#region ../../packages/agent-core/src/agent/permission/policies/goal-start-review-ask.ts
|
|
67013
|
+
/**
|
|
67014
|
+
* Starting a goal turns the agent loose on autonomous, multi-turn work, so a
|
|
67015
|
+
* model-issued `CreateGoal` is confirmed with the same menu the `/goal` command
|
|
67016
|
+
* shows: choose the permission mode to run the goal under, or decline. The
|
|
67017
|
+
* chosen mode is applied before the goal is created so the run proceeds under
|
|
67018
|
+
* it. `auto` mode auto-approves the goal upstream and never reaches here.
|
|
67019
|
+
*/
|
|
67020
|
+
var GoalStartReviewAskPermissionPolicy = class {
|
|
67021
|
+
agent;
|
|
67022
|
+
name = "goal-start-review-ask";
|
|
67023
|
+
constructor(agent) {
|
|
67024
|
+
this.agent = agent;
|
|
67025
|
+
}
|
|
67026
|
+
evaluate(context) {
|
|
67027
|
+
if (context.toolCall.name !== "CreateGoal") return;
|
|
67028
|
+
if (this.agent.permission.mode === "auto") return;
|
|
67029
|
+
if (context.execution.display?.kind !== "goal_start") return;
|
|
67030
|
+
return {
|
|
67031
|
+
kind: "ask",
|
|
67032
|
+
resolveApproval: (result) => this.resolveGoalStart(result)
|
|
67033
|
+
};
|
|
67034
|
+
}
|
|
67035
|
+
resolveGoalStart(result) {
|
|
67036
|
+
if (result.decision !== "approved") return void 0;
|
|
67037
|
+
const mode = toPermissionMode(result.selectedLabel);
|
|
67038
|
+
if (mode !== void 0 && mode !== this.agent.permission.mode) this.agent.permission.setMode(mode);
|
|
67039
|
+
}
|
|
67040
|
+
};
|
|
67041
|
+
function toPermissionMode(label) {
|
|
67042
|
+
if (label === "auto" || label === "yolo" || label === "manual") return label;
|
|
67043
|
+
}
|
|
67044
|
+
//#endregion
|
|
67012
67045
|
//#region ../../packages/agent-core/src/agent/permission/policies/plan-mode-guard-deny.ts
|
|
67013
67046
|
var PlanModeGuardDenyPermissionPolicy = class {
|
|
67014
67047
|
agent;
|
|
@@ -69180,6 +69213,7 @@ function createPermissionDecisionPolicies(agent) {
|
|
|
69180
69213
|
new UserConfiguredAskPermissionPolicy(agent),
|
|
69181
69214
|
new UserConfiguredAllowPermissionPolicy(agent),
|
|
69182
69215
|
new ExitPlanModeReviewAskPermissionPolicy(agent),
|
|
69216
|
+
new GoalStartReviewAskPermissionPolicy(agent),
|
|
69183
69217
|
new PlanModeToolApprovePermissionPolicy(agent),
|
|
69184
69218
|
new SensitiveFileAccessAskPermissionPolicy(),
|
|
69185
69219
|
new GitControlPathAccessAskPermissionPolicy(agent),
|
|
@@ -74218,20 +74252,20 @@ function isRecord$11(value) {
|
|
|
74218
74252
|
var custom_theme_default = "---\nname: custom-theme\ndescription: Create or edit a kimi-code custom color theme — a JSON file under the resolved KIMI_CODE_HOME data directory that recolors the TUI. Use when the user wants their own theme, asks for a specific palette or mood, or wants to tweak an existing custom theme's colors.\n---\n\n# Create a kimi-code custom theme (custom-theme)\n\nHelp the user design, write, and apply a custom color theme for the kimi-code TUI. A theme is a single JSON file; the TUI ships with `dark`, `light`, and `auto`, and any file the user adds becomes selectable alongside them.\n\n## Rules of engagement\n\n- **Never write a theme until the user has explicitly clarified what they want.** This skill may only run after the user has confirmed light vs dark, the style or mood, any specific colors they care about, and the intended filename. If any of these are missing, ask before creating files.\n- **Never assume the data directory is `~/.kimi-code`.** Always resolve `$KIMI_CODE_HOME` first with the Bash command below.\n- **Never edit a live theme file in place.** Always create a `.json.new` candidate, validate it, back up the old file, and then `mv` it into place.\n- **Never overwrite an existing theme without reading it first.** Read, back up, then overwrite only after the user confirms.\n\n## Where a theme lives\n\nThe kimi-code runtime resolves the data directory as `KIMI_CODE_HOME` first, falling back to `~/.kimi-code`. Theme files live inside the `themes/` subdirectory of that data directory.\n\nBefore doing anything, resolve the actual data root with Bash so you don't write to the wrong place. Check whether `KIMI_CODE_HOME` is set and fall back to `~/.kimi-code` when it is empty:\n\n```bash\necho \"$KIMI_CODE_HOME\"\necho \"$HOME/.kimi-code\"\n```\n\nUse the first line when it is non-empty; otherwise use the second line. In the rest of this skill, `<KIMI_CODE_HOME>` means that resolved data root — **never assume `~/.kimi-code`**. Theme files live at `<KIMI_CODE_HOME>/themes/<name>.json`. Create the `themes/` directory if it doesn't exist.\n\n## What a theme is\n\n- A theme lives at `<KIMI_CODE_HOME>/themes/<name>.json`.\n- **The filename is the theme name**: `ember.json` shows up in the `/theme` picker as `Custom: ember`.\n- Shape:\n\n ```json\n {\n \"name\": \"ember\",\n \"displayName\": \"Ember\",\n \"colors\": {\n \"primary\": \"#83A598\",\n \"accent\": \"#FE8019\"\n }\n }\n ```\n\n - `name` (required), `displayName` (optional), `base` (optional: `\"dark\"` default, or `\"light\"`), `colors` (each value a 6-digit hex `#RRGGBB`).\n- **Partial themes are fine**: any token you leave out falls back to the **base** palette (`dark` by default; set `\"base\": \"light\"` for a light theme), so you can recolor just a few tokens or all of them.\n\n## Source of truth: the docs token reference\n\nBefore choosing colors, use **FetchURL** to fetch the official custom-theme docs as the authoritative list of tokens and what each controls:\n\n```\nhttps://moonshotai.github.io/kimi-code/en/customization/themes.html\n```\n\nOnly set tokens from this set — unknown keys are silently ignored at load. If FetchURL is unavailable or the fetch fails, fall back to the embedded reference below (it mirrors the same tokens) and tell the user you're working from the built-in list rather than the live docs.\n\n## Color tokens (what each controls)\n\n| Token | Controls |\n| --- | --- |\n| `primary` | The most-used color: links, inline code, the selected item in nearly every dialog, the focused editor border, plan/\"running\" badges, spinners |\n| `accent` | Secondary highlight: approval `▶` prefix, device-code box, image placeholder, BTW / queue panes, registry import |\n| `text` | Body text: dialog bodies, todo titles, footer model label, Markdown headings, assistant/tool message bullets, list bullets |\n| `textStrong` | Emphasized / bold text: input dialogs, status messages |\n| `textDim` | Secondary, dimmed text (the most widely used dim shade): thinking, hints, descriptions, completed todos, Markdown quotes, footer status bar |\n| `textMuted` | Faintest text: counters, scroll info, descriptions, Markdown link URLs, code-block borders |\n| `border` | Pane and editor borders, Markdown horizontal rule |\n| `borderFocus` | Focus / attention border (currently only the approval panel) |\n| `success` | Success state: `✓`, \"enabled\", completed |\n| `warning` | Warning state: auto/yolo badges, stale markers, plan-mode hint |\n| `error` | Error state: error messages, failed tool output |\n| `diffAdded` | Diff added lines |\n| `diffRemoved` | Diff removed lines |\n| `diffAddedStrong` | Diff intra-line changed words, added (bold) |\n| `diffRemovedStrong` | Diff intra-line changed words, removed (bold) |\n| `diffGutter` | Diff line-number gutter |\n| `diffMeta` | Diff meta / hunk headers |\n| `roleUser` | User message bullet and text, skill-activation name (the one role color with its own hue) |\n\n## Workflow\n\n1. **Ask the user what they want first — before choosing any colors.** Clarify, in one short exchange:\n - **Light or dark?** A light theme (dark text on a light background) or a dark theme (light text on a dark background). This sets the whole direction, so settle it first. For a light theme, set `\"base\": \"light\"` so the tokens you leave out inherit the light palette instead of dark.\n - **What style / mood?** e.g. warm vs cool, vivid vs muted, high vs low contrast, a named vibe (\"nord\", \"solarized\", \"sunset\"), or a base to start from (an existing theme, or `dark` / `light`).\n - **Any specific colors?** Whether they have exact hex values to anchor on (a brand color, a preferred `primary`, etc.).\n\n For the discrete choices (light vs dark, a few style options), prefer **AskUserQuestion** if it is available. If you are running in **auto mode** and `AskUserQuestion` is unavailable, ask the same question as a plain-text message with clear numbered or bulleted options, and wait for the user's reply. Don't start picking colors until you at least know light-vs-dark and the rough style.\n\n2. **Resolve the actual theme directory and current theme(s).**\n - Resolve the data root by checking `echo \"$KIMI_CODE_HOME\"`; if empty, use `echo \"$HOME/.kimi-code\"`. Use `<root>/themes` for every subsequent step.\n - If tweaking an existing custom theme, **Read** `<KIMI_CODE_HOME>/themes/<name>.json` first — never overwrite a theme you haven't read.\n - Starting fresh: build a `colors` object from the token table. You can `ls <KIMI_CODE_HOME>/themes/` and Read one of the user's existing themes as a reference for the format.\n\n3. **Pick a starting point and choose colors deliberately.**\n - Every value is a 6-digit hex `#RRGGBB` (not 3-digit, not a named color).\n - Keep contrast usable against the user's terminal background: don't let `text` / `textDim` sit too close to the background, and keep `success` / `warning` / `error` clearly distinguishable from each other.\n - `primary` is the most-seen color (links, selection, focus) — make it readable and distinct from `text`.\n - `roleUser` is the one role color meant to stand on its own — give it a distinct hue.\n\n4. **Create a candidate file; never edit the live theme in place.**\n - Use Bash to create a candidate. If the target theme already exists, copy it verbatim: `cp <name>.json <name>.json.new` (inside `<KIMI_CODE_HOME>/themes/`). If it doesn't exist, use **Write** to create a minimal skeleton named `<name>.json.new`.\n - Use **Edit** on the candidate to change only the intended keys. Keep every existing entry, comment, and formatting intact.\n\n5. **Validate the candidate before overwriting.**\n - Read the candidate with **Read** to visually confirm it is well-formed JSON and that every `colors` value is a full 6-digit hex `#RRGGBB` (not 3-digit, not a named color).\n - Invalid hex values are silently skipped at load (they fall back to the base palette), but fix them so the theme renders as intended.\n\n6. **Back up and overwrite.**\n - Back up the old file first — **always** create a new timestamped backup and never overwrite an existing backup: `cp <name>.json \"<name>.json.$(date +%Y%m%d-%H%M%S).bak\"`.\n - If the target didn't exist, skip the backup.\n - Overwrite with the candidate: `mv <name>.json.new <name>.json`.\n\n7. **Tell the user how to apply it** (next section).\n\n## Applying the theme\n\n- The `/theme` picker re-scans the themes directory every time it opens, so a newly added file shows up **without restarting** — tell the user to run `/theme` and choose `Custom: <name>`.\n- Or set it in `tui.toml`: `theme = \"<name>\"`.\n- **Editing the active theme**: changes to the theme that's *currently in use* are not auto-reloaded. Tell the user to run **`/reload-tui`** (or switch to another theme and back). Re-selecting the **same** theme in `/theme` is a no-op (\"Theme unchanged\").\n\n## Don'ts\n\n- **Don't start creating or editing a theme until the user has clarified light/dark, style/mood, any specific colors, and the filename.** If anything is unclear, ask — don't guess.\n- Don't invent token names — only use the documented set; unknown keys are silently ignored.\n- Don't write 3-digit hex or named colors — use full `#RRGGBB`.\n- Never edit the live theme file in place; work through a candidate and validate before `mv`.\n- Before overwriting an existing theme file, **read it and back it up** so the user can recover.\n- Don't tell the user to restart the app to apply a theme — `/theme` or `/reload-tui` is enough.\n";
|
|
74219
74253
|
//#endregion
|
|
74220
74254
|
//#region ../../packages/agent-core/src/skill/builtin/custom-theme.ts
|
|
74221
|
-
const PSEUDO_PATH$
|
|
74222
|
-
const parsed$
|
|
74255
|
+
const PSEUDO_PATH$4 = "builtin://custom-theme";
|
|
74256
|
+
const parsed$4 = parseSkillText({
|
|
74223
74257
|
skillMdPath: "/builtin/skills/custom-theme.md",
|
|
74224
74258
|
skillDirName: "custom-theme",
|
|
74225
74259
|
source: "builtin",
|
|
74226
74260
|
text: custom_theme_default
|
|
74227
74261
|
});
|
|
74228
74262
|
const CUSTOM_THEME_SKILL = {
|
|
74229
|
-
...parsed$
|
|
74230
|
-
path: PSEUDO_PATH$
|
|
74231
|
-
dir: PSEUDO_PATH$
|
|
74263
|
+
...parsed$4,
|
|
74264
|
+
path: PSEUDO_PATH$4,
|
|
74265
|
+
dir: PSEUDO_PATH$4,
|
|
74232
74266
|
metadata: {
|
|
74233
|
-
...parsed$
|
|
74234
|
-
type: parsed$
|
|
74267
|
+
...parsed$4.metadata,
|
|
74268
|
+
type: parsed$4.metadata.type ?? "inline",
|
|
74235
74269
|
disableModelInvocation: true
|
|
74236
74270
|
}
|
|
74237
74271
|
};
|
|
@@ -74240,20 +74274,20 @@ const CUSTOM_THEME_SKILL = {
|
|
|
74240
74274
|
var import_from_cc_codex_default = "---\nname: import-from-cc-codex\ndescription: Import Claude Code and Codex instructions, skills, and MCP settings into Kimi Code.\ndisable-model-invocation: true\n---\n\n# Import from Claude Code and Codex\n\nThe user invoked `/import-from-cc-codex` (or `/skill:import-from-cc-codex`).\nHelp them migrate selected local Claude Code and Codex assets into Kimi Code.\nThis skill is intentionally conservative: it imports only instructions, skills,\nand MCP server declarations from `.claude` / `.codex` surfaces, with a user\npreview before any write.\n\n## Non-negotiable rules\n\n- Do **not** migrate `.agents` content. Kimi Code already supports `.agents`\n skills and AGENTS files by default.\n- Do **not** migrate Claude custom commands (`.claude/commands/**`). They are\n out of scope for this importer.\n- Do **not** migrate credentials, OAuth tokens, sessions, history, logs, hooks,\n plugins, plugin caches, output styles, or custom agents/subagents.\n- Do **not** run or install anything from the source directories.\n- Do **not** write anything until the user has chosen what to migrate, reviewed\n the final preview, and explicitly confirmed applying it.\n- Only write under Kimi Code targets:\n - User-global: `$KIMI_CODE_HOME` if set, otherwise `~/.kimi-code`.\n - Project instructions/skills: `<project root>/.kimi-code`, where the project\n root is the nearest parent directory containing `.git`; if no `.git` exists,\n use the current working directory.\n - Project-local MCP: `<cwd>/.kimi-code/mcp.json`, because Kimi reads the\n current working directory's Kimi-specific MCP file, not every project-root\n `.kimi-code/mcp.json` from subdirectories.\n- Preserve existing Kimi files. Never overwrite existing skills or replace an\n existing AGENTS.md / mcp.json wholesale.\n\n## Conversation flow\n\n### 1. Ask what to migrate first\n\nBefore reading source files, ask the user which categories to migrate. Use\n`AskUserQuestion` when available; otherwise ask in plain text and stop. Offer a\nmulti-select choice:\n\n- Instructions (`AGENTS.md` / `CLAUDE.md`)\n- Skills\n- MCP settings\n- All of the above\n\nIf the user already gave a preference in the invocation arguments, present it as\nthe default/recommended choice, but still ask for confirmation of the categories.\nIf the user dismisses or refuses the question, stop.\n\n### 2. Scan only the chosen categories\n\nResolve paths explicitly; `~` is the real OS home, and Kimi home follows\n`$KIMI_CODE_HOME` before `~/.kimi-code`.\n\nUser-level sources:\n\n- Claude instructions:\n - `~/.claude/AGENTS.md`\n - `~/.claude/CLAUDE.md`\n- Claude skills:\n - `~/.claude/skills/`\n- Claude MCP candidates:\n - `~/.claude.json` only when MCP is selected. Claude Code stores user-level\n MCP declarations there; do not read it for instruction/skill-only imports.\n- Codex instructions:\n - `~/.codex/AGENTS.md`\n - `~/.codex/CLAUDE.md` if present\n- Codex skills:\n - `~/.codex/skills/`\n- Codex MCP candidates:\n - `~/.codex/config.toml`\n\nProject-level sources, rooted at the project root:\n\n- Claude instructions:\n - `<project root>/.claude/AGENTS.md`\n - `<project root>/.claude/CLAUDE.md`\n- Claude skills:\n - `<project root>/.claude/skills/`\n- Codex instructions:\n - `<project root>/.codex/AGENTS.md`\n - `<project root>/.codex/CLAUDE.md` if present\n- Codex skills:\n - `<project root>/.codex/skills/`\n- Codex MCP candidates:\n - `<project root>/.codex/config.toml`\n\nDo not scan project-root `AGENTS.md`, project-root `CLAUDE.md`, `.agents/**`, or\nproject-root `.mcp.json` in this skill. `AGENTS.md` and `.agents/**` are already\nKimi-readable, and project-root `.mcp.json` is already read by Kimi as a\nClaude-compatible MCP file.\n\n### 3. Build an import plan\n\nCreate a plan with three sections: instructions, skills, and MCP. Include exact\nsource and target paths.\n\n#### Instructions plan\n\nMap user-level instruction sources to:\n\n- `$KIMI_CODE_HOME/AGENTS.md`, or `~/.kimi-code/AGENTS.md` if the env var is not\n set.\n\nMap project-level instruction sources to:\n\n- `<project root>/.kimi-code/AGENTS.md`\n\nAppend imported instruction content as marked blocks. Do not duplicate a block\nthat already exists in the target file.\n\nUse this marker shape:\n\n```md\n<!-- Imported from Claude Code: /absolute/source/path -->\n\n<source content>\n\n<!-- End imported from Claude Code: /absolute/source/path -->\n```\n\nFor Codex, use `Imported from Codex` / `End imported from Codex`.\n\nIf a source file is empty, skip it and report it as skipped. If the target exists\nand cannot be read as UTF-8 text, stop before writing and report the blocker.\n\n#### Skills plan\n\nMap user-level skill sources to:\n\n- `$KIMI_CODE_HOME/skills/`, or `~/.kimi-code/skills/` if the env var is not set.\n\nMap project-level skill sources to:\n\n- `<project root>/.kimi-code/skills/`\n\nRecognize these skill shapes under `.claude/skills/` or `.codex/skills/`:\n\n- Directory bundle: `<skill-name>/SKILL.md`\n- Flat markdown skill: `<skill-name>.md`\n\nCopy the entire directory bundle or flat markdown file. Preserve supporting\nfiles inside bundles. Do not copy hidden directories, `node_modules`, caches, or\nplugin-managed folders.\n\nBefore planning a copy:\n\n- Read a bundle's `SKILL.md` enough to verify that directory skills have\n frontmatter with non-empty `name` and `description`, because Kimi requires\n those fields for directory skills.\n- If the target top-level entry already exists, skip it; do not overwrite.\n- If two source entries would write the same target path, keep the first one in\n this order and report the later one as skipped:\n 1. project Claude\n 2. project Codex\n 3. user Claude\n 4. user Codex\n- Warn when a source skill uses Claude/Codex-specific fields or syntax that Kimi\n may not interpret the same way, such as `allowed-tools`, `disallowed-tools`,\n `context: fork`, `agent`, `hooks`, `paths`, dynamic shell injection with\n ``!`command` ``, or `agents/openai.yaml`. Preserve the file; do not rewrite it\n unless the user explicitly asks.\n\nDo not convert `.claude/commands/*.md`. Commands are out of scope.\n\n#### MCP plan\n\nDo not edit `mcp.json` directly in this import skill. Prepare MCP entries for\nmanual follow-up with `/mcp-config`; that built-in skill is user-invocable only,\nso you must not try to call it through the `Skill` tool.\n\nFor the preview, collect MCP candidates and normalize them into Kimi's MCP shape\nwhen possible:\n\n```json\n{\n \"mcpServers\": {\n \"name\": {\n \"command\": \"...\",\n \"args\": [\"...\"],\n \"env\": { \"KEY\": \"VALUE\" }\n }\n }\n}\n```\n\nClaude user MCP:\n\n- Read `~/.claude.json` only if MCP was selected.\n- Look for a top-level `mcpServers` object.\n- Keep stdio entries with `command`; keep HTTP entries with `url`.\n- Preserve `args`, `env`, `cwd`, `enabled`, `enabledTools`, `disabledTools`,\n `startupTimeoutMs`, `toolTimeoutMs`, `headers`, and `bearerTokenEnvVar` when\n present and valid.\n- Drop unsupported or malformed entries and report why.\n\nCodex MCP:\n\n- Read selected `config.toml` files only if MCP was selected.\n- Look for `[mcp_servers.<name>]` tables.\n- Map Codex fields to Kimi fields:\n - `command` -> `command`\n - `args` -> `args`\n - `env` -> `env`\n - `cwd` -> `cwd`\n - `url` -> `url`\n - `bearer_token_env_var` -> `bearerTokenEnvVar`\n - `enabled` -> `enabled`\n - `enabled_tools` -> `enabledTools`\n - `disabled_tools` -> `disabledTools`\n - `startup_timeout_sec` -> `startupTimeoutMs` in milliseconds\n - `tool_timeout_sec` -> `toolTimeoutMs` in milliseconds\n - `http_headers` -> `headers`\n- Drop unsupported Codex-only fields and report them, especially `required`,\n `default_tools_approval_mode`, `tools.<tool>.approval_mode`,\n `env_vars`, `env_http_headers`, and `experimental_environment`.\n- Do not import project-root `.mcp.json`; Kimi already reads it.\n\nFor each MCP candidate, choose the target scope in the preview:\n\n- User-level source -> user-global MCP target (`$KIMI_CODE_HOME/mcp.json` or\n `~/.kimi-code/mcp.json`).\n- Project-level source -> project-local Kimi MCP target (`<cwd>/.kimi-code/mcp.json`). If `<cwd>` is not the project root, call this out in the preview so the user understands when Kimi will load it.\n\nWarn that stdio MCP entries spawn commands at session start, and the user should\nonly import MCP servers they trust. Warn if an MCP entry contains apparent\nliteral secrets in `env`, `headers`, or token-like fields; prefer env-var\nreferences.\n\nAfter the user confirms applying the final preview, do not write MCP config and\ndo not invoke `mcp-config` programmatically. Instead, finish the non-MCP writes\nand show a copy-pasteable manual follow-up for the user, including:\n\n- the `/mcp-config` command they should run,\n- target scope and target path,\n- the normalized JSON entry or entries to add,\n- collision policy: keep existing Kimi entries on name conflict,\n- the reminder that unrelated entries must be preserved.\n\nMake it clear that MCP import is pending until the user manually runs\n`/mcp-config` with the prepared entries.\n\n### 4. Show the final preview and stop\n\nAfter scanning, show a concise final preview grouped by target file/directory:\n\n- Will append instruction blocks\n- Will copy skill bundles/files\n- Will leave these MCP entries pending for a manual `/mcp-config` follow-up\n- Already present / skipped\n- Warnings and blockers\n\nThen ask for explicit confirmation before writing. Use a clear choice such as:\n\n- Apply import\n- Cancel\n\nIf there are blockers, do not offer apply; explain what must be fixed first.\n\n### 5. Apply only after confirmation\n\nWhen the user confirms:\n\n- Create target directories with private permissions where possible.\n- Append instruction blocks without duplicating existing imported source blocks.\n- Copy skills without overwriting existing target entries.\n- Do not write MCP entries. Show the prepared `/mcp-config` follow-up command\n and mark MCP import as pending user action.\n- Report exactly what changed and what was skipped.\n- Tell the user to start a new session (for example `/new`) or restart Kimi Code\n for newly imported skills, instructions, and MCP servers to be picked up.\n\n## Output style\n\nBe brief but precise. Use absolute paths in previews and summaries. Prefer a\nsmall table or bullet list over long prose. If nothing is found for a selected\ncategory, say so and do not treat it as an error.\n";
|
|
74241
74275
|
//#endregion
|
|
74242
74276
|
//#region ../../packages/agent-core/src/skill/builtin/import-from-cc-codex.ts
|
|
74243
|
-
const PSEUDO_PATH$
|
|
74244
|
-
const parsed$
|
|
74277
|
+
const PSEUDO_PATH$3 = "builtin://import-from-cc-codex";
|
|
74278
|
+
const parsed$3 = parseSkillText({
|
|
74245
74279
|
skillMdPath: "/builtin/skills/import-from-cc-codex.md",
|
|
74246
74280
|
skillDirName: "import-from-cc-codex",
|
|
74247
74281
|
source: "builtin",
|
|
74248
74282
|
text: import_from_cc_codex_default
|
|
74249
74283
|
});
|
|
74250
74284
|
const IMPORT_FROM_CC_CODEX_SKILL = {
|
|
74251
|
-
...parsed$
|
|
74252
|
-
path: PSEUDO_PATH$
|
|
74253
|
-
dir: PSEUDO_PATH$
|
|
74285
|
+
...parsed$3,
|
|
74286
|
+
path: PSEUDO_PATH$3,
|
|
74287
|
+
dir: PSEUDO_PATH$3,
|
|
74254
74288
|
metadata: {
|
|
74255
|
-
...parsed$
|
|
74256
|
-
type: parsed$
|
|
74289
|
+
...parsed$3.metadata,
|
|
74290
|
+
type: parsed$3.metadata.type ?? "inline",
|
|
74257
74291
|
disableModelInvocation: true
|
|
74258
74292
|
}
|
|
74259
74293
|
};
|
|
@@ -74262,20 +74296,20 @@ const IMPORT_FROM_CC_CODEX_SKILL = {
|
|
|
74262
74296
|
var mcp_config_default = "---\nname: mcp-config\ndescription: Configure MCP servers and handle MCP OAuth login.\n---\n\n# Interactive MCP server configuration\n\nThe user invoked this skill through `/mcp-config` or `/skill:mcp-config`.\nEither they want to log into an MCP server that asked for OAuth, or they\nwant to edit the `mcp.json` that lists MCP servers. The work is small and\nlocal — handle it on this turn yourself, no agents or planning todos.\n\nPick the flow from the user's message and your tool list:\n\n- An `mcp__<server>__authenticate` tool is in your list, the user says\n \"log in\" / \"auth\" / \"sign in\", they invoke `/mcp-config login\n <server>`, or they quote a `needs-auth` status → **Login**.\n- Add / edit / remove / list of an `mcp.json` entry → **Config edit**.\n- Bare `/mcp-config` with no `authenticate` tool in your list →\n **Config edit**. If there were a pending login, the authenticate tool\n would be in your list.\n\n## Login\n\nEach MCP server in `needs-auth` exposes one `mcp__<server>__authenticate`\ntool. Call it for the server the user means — its own description owns\nthe OAuth UX (printing the URL, blocking on the callback, reconnecting on\nsuccess). Surface its output verbatim, including the authorization URL\nunchanged; the URL contains state and PKCE parameters that break if\nedited.\n\nIf the user named a server that has no authenticate tool, say so in one\nsentence and stop — do **not** fall into config edit. They're trying to\nlog in to a server that isn't currently waiting for login; quietly\nrewriting `mcp.json` would be the wrong fix. If multiple authenticate\ntools exist and the user didn't name one, ask which.\n\n## Config edit\n\nConfig lives in three files; on key collision, later entries in this\nprecedence order override earlier ones.\n\nThe kimi-code runtime resolves the user-global directory as `KIMI_CODE_HOME`\nfirst, falling back to `~/.kimi-code`. Before touching the user-global file,\nresolve the actual directory with Bash so you don't read or write the wrong\none. Check whether `KIMI_CODE_HOME` is set and fall back to `~/.kimi-code`\nwhen it is empty:\n\n```bash\necho \"$KIMI_CODE_HOME\"\necho \"$HOME/.kimi-code\"\n```\n\nUse the first line when it is non-empty; otherwise use the second line. In the\nrest of this skill, `<KIMI_CODE_HOME>` means that resolved data root —\n**never assume `~/.kimi-code`**.\n\n- User-global: `<KIMI_CODE_HOME>/mcp.json`. Use for servers you want\n everywhere.\n- Project-root: `<project root>/.mcp.json`, where project root is found\n by walking up from `<cwd>` to the nearest `.git`. Use for\n Claude-compatible, repo-shared, or cross-agent servers.\n- Project-local: `<cwd>/.kimi-code/mcp.json`. Use for Kimi-specific\n overrides in the current working directory.\n\nMention once that project-root and project-local stdio entries spawn\ncommands at session start, so they should only live in trusted repos.\n\nAll three files wrap their entries the same way:\n\n```json\n{ \"mcpServers\": { \"<name>\": { /* entry */ } } }\n```\n\nA minimal stdio entry needs `command` (+ optional `args`, `env`, `cwd`).\nFor project-root `.mcp.json`, stdio entries run from the project root by\ndefault; relative `cwd` values are resolved against the directory that\ncontains `.mcp.json`.\nA minimal http entry needs `url`; add `bearerTokenEnvVar: \"ENV_NAME\"` for\nservers that authenticate with a static bearer token from the\nenvironment. Servers that use OAuth take no token field — the login flow\nabove handles them. `transport` is inferred from `command` vs `url`, so\nomit it. For less common fields (`enabled`, `startupTimeoutMs`,\n`toolTimeoutMs`, `enabledTools`, `disabledTools`, `headers`) the source of\ntruth is `McpServerStdioConfigSchema` / `McpServerHttpConfigSchema` in\n`packages/agent-core/src/config/schema.ts`.\n\nIf the user only wants to **see** what's configured, read all three files,\nshow a merged view with enough source-path context to inspect or remove a\nserver from the file that actually declared it, and stop — no scope\nprompt, no write.\n\nFor changes, the flow is:\n\n1. **Pick a scope.** Infer it from the user's words when you can\n (global / everywhere / all projects → user-global; root / repo /\n shared / cross-agent / Claude / `.mcp.json` → project-root; cwd /\n current directory / Kimi-specific / `.kimi-code` → project-local). When\n the request is genuinely scope-less, use one `AskUserQuestion` to ask\n user-global vs project-root vs project-local, defaulting to\n user-global. Use plain text for every other question — `AskUserQuestion`\n is a poor fit for free-form input. If the user dismisses the scope\n question, stop; you can't safely guess where they wanted the change.\n2. **Read and announce.** Read the target file (a missing or empty file\n is fine; you'll create `{ \"mcpServers\": {} }`). If JSON parsing fails,\n surface the error verbatim and stop — silently overwriting a broken\n file could destroy work. Then show the user the target path, what's\n currently in it, and the entry you're about to write or delete. This\n is for transparency, not a confirmation gate — the Edit/Write\n permission prompt is the real gate, and your message is what gives\n the user context when that prompt appears. In yolo / afk modes there\n is no prompt, which is those modes' explicit contract.\n3. **Write and tell them how to reload MCP servers.** Preserve unrelated\n entries and the `mcpServers` wrapper. MCP servers load at session\n start, so tell the user to start a new session (for example `/new`) or\n restart `kimi-code` for the change to take effect.\n\n## Secrets\n\nDon't store secrets (tokens, keys, passwords) as literals in\n`mcp.json` — it's a plain config file on disk. http servers should use\n`bearerTokenEnvVar` to reference an env var instead; if a stdio entry\nmust inline one in `env`, warn the user before writing.\n";
|
|
74263
74297
|
//#endregion
|
|
74264
74298
|
//#region ../../packages/agent-core/src/skill/builtin/mcp-config.ts
|
|
74265
|
-
const PSEUDO_PATH$
|
|
74266
|
-
const parsed$
|
|
74299
|
+
const PSEUDO_PATH$2 = "builtin://mcp-config";
|
|
74300
|
+
const parsed$2 = parseSkillText({
|
|
74267
74301
|
skillMdPath: "/builtin/skills/mcp-config.md",
|
|
74268
74302
|
skillDirName: "mcp-config",
|
|
74269
74303
|
source: "builtin",
|
|
74270
74304
|
text: mcp_config_default
|
|
74271
74305
|
});
|
|
74272
74306
|
const MCP_CONFIG_SKILL = {
|
|
74273
|
-
...parsed$
|
|
74274
|
-
path: PSEUDO_PATH$
|
|
74275
|
-
dir: PSEUDO_PATH$
|
|
74307
|
+
...parsed$2,
|
|
74308
|
+
path: PSEUDO_PATH$2,
|
|
74309
|
+
dir: PSEUDO_PATH$2,
|
|
74276
74310
|
metadata: {
|
|
74277
|
-
...parsed$
|
|
74278
|
-
type: parsed$
|
|
74311
|
+
...parsed$2.metadata,
|
|
74312
|
+
type: parsed$2.metadata.type ?? "inline",
|
|
74279
74313
|
disableModelInvocation: true
|
|
74280
74314
|
}
|
|
74281
74315
|
};
|
|
@@ -74326,14 +74360,35 @@ const SUB_SKILL_CONSOLIDATE = makeBuiltin(SKILL_default$2, "sub-skill.consolidat
|
|
|
74326
74360
|
var update_config_default = "---\nname: update-config\ndescription: Inspect or edit kimi-code's own config — `config.toml` (model, provider, permission, hooks) and `tui.toml` (theme, editor, notifications, auto-update). Use when the user asks what a setting does or wants to change one.\n---\n\n# Configure kimi-code (update-config)\n\nHelp the user inspect, change, and validate kimi-code's configuration files. The files are **TOML** with **snake_case** keys.\n\n## The two config files\n\nkimi-code has two TOML config files, both under `<KIMI_CODE_HOME>/`, both snake_case, but with different ownership — decide which one the user means before doing anything.\n\nThe runtime resolves the data directory as `KIMI_CODE_HOME` first, falling back to `~/.kimi-code`. Before doing anything, resolve the actual directory with Bash so you don't write to the wrong place. Check whether `KIMI_CODE_HOME` is set and fall back to `~/.kimi-code` when it is empty:\n\n```bash\necho \"$KIMI_CODE_HOME\"\necho \"$HOME/.kimi-code\"\n```\n\nUse the first line when it is non-empty; otherwise use the second line. In the rest of this skill, `<KIMI_CODE_HOME>` means that resolved root — **never assume `~/.kimi-code`**.\n\n- **`config.toml`** — agent / runtime settings: `default_model`, `providers`, `models`, `thinking`, `permission`, `hooks`, `loop_control`, etc.\n- **`tui.toml`** — terminal-UI / client preferences: `theme`, `[editor].command`, `[notifications]`, `[upgrade].auto_install` (auto-update). These can usually also be changed with the interactive commands `/config`, `/theme`, `/editor`, which is easier — prefer pointing the user at those.\n\nThe \"read → copy → Edit → validate → back up → overwrite\" flow below applies to both files; only **which reload command applies** differs (see Capability 4).\n\n## Prerequisite 1: the official docs are the single source of truth\n\nBefore touching any config, use **FetchURL** to fetch the official config docs as the one authoritative reference for fields (key names, types, allowed values, owning section):\n\n```\nhttps://moonshotai.github.io/kimi-code/en/configuration/config-files.html\n```\n\n- Use the **snake_case key names and sections exactly as documented** — don't invent them, don't guess camelCase.\n- If FetchURL is unavailable or the fetch fails, tell the user plainly that you can't reach the online docs, and ask them to paste the relevant section or confirm whether to proceed from what you already know. **Never edit blindly without an authoritative reference.**\n\n## Prerequisite 2: read the target file before any change\n\nBefore any modification, use **Read** on the target config file (decide whether it's `config.toml` or `tui.toml` per the above):\n\n- Location: `<KIMI_CODE_HOME>/config.toml` or `<KIMI_CODE_HOME>/tui.toml`. For other scopes/files, defer to the official docs.\n- A missing or empty file is fine — you'll create a minimal skeleton later.\n- If the file exists but **fails to parse as TOML**, report the error verbatim and **stop** — never overwrite a broken file in place (it could destroy the user's existing config).\n\n---\n\n## Capability 1: explain configuration (read-only, no file changes)\n\nWhen the user asks \"what config is there\", \"what does this setting do\", or \"how do I use it\":\n\n1. Fetch the official docs (Prerequisite 1).\n2. Read the current `config.toml` (Prerequisite 2).\n3. Answer against both: list the relevant sections / keys, what each is for, **current value vs default**, and the allowed-value range; say which file and section each lives in.\n4. Present it as a compact grouped list or table. **Stay read-only — write no files.**\n\n## Capability 2: make changes for the user (copy → Edit → validate → back up → overwrite)\n\nDon't edit the target file in place, and **don't rewrite it from scratch** — instead copy it, Edit the copy, and keep the original out of any broken state the whole time:\n\n1. **Clarify intent**: which key, what value, and which file (`config.toml` or `tui.toml`). Ask in one line if ambiguous; for discrete choices (e.g. scope) AskUserQuestion is fine, but use plain questions for free-form input.\n2. **Read the target file** (Prerequisite 2): Read it to understand the current state and confirm it parses.\n3. **Copy out a candidate (do not create from scratch)**: use **Bash** to copy the target verbatim — `cp config.toml config-new.toml` (same directory, `-new` suffix; for tui.toml, `cp tui.toml tui-new.toml`). **Leave the original untouched for now.**\n - Only when the target doesn't exist (nothing to copy) should you use **Write** to create a minimal skeleton candidate (e.g. just the comment line `# <KIMI_CODE_HOME>/config.toml`).\n4. **Edit the candidate**: use the **Edit** tool on the candidate to **change/add only the target key** — never rewrite the whole file. That way every existing section, entry, comment, and bit of formatting stays exactly as-is; only what should change changes. The candidate is identical to the original, so use the content you read in step 2 to locate the Edit anchor. Check the change against the official docs (key / section / value type / allowed values, snake_case).\n5. **Validate the candidate** (see Capability 3, via `kimi doctor`). **If anything fails, keep Editing the candidate and re-validate, looping until it all passes.**\n6. **Back up and overwrite** (only after validation fully passes):\n - **Back up the old file — always create a new timestamped backup, keep all of them, never overwrite an existing backup.** Copy this exactly with **Bash** (for config.toml): `cp config.toml \"config.toml.$(date +%Y%m%d-%H%M%S).bak\"`; for tui.toml: `cp tui.toml \"tui.toml.$(date +%Y%m%d-%H%M%S).bak\"`. Skip the backup only if the target didn't exist.\n - Overwrite with the candidate: `mv config-new.toml config.toml`.\n - If reload errors after the overwrite, the user can recover from **the most recent timestamped backup**.\n7. Tell the user how to apply it (see Capability 4).\n\n## Capability 3: validate the candidate file (must pass before overwrite)\n\nUse **`kimi doctor`** to validate the candidate you wrote — it doesn't start the TUI and doesn't modify any file; it runs kimi's own parser + schema (syntax and schema together), so it's the authoritative check. Pick the subcommand by which file you changed, and pass the **candidate** path explicitly:\n\n- changed `config.toml` → `kimi doctor config <config-new.toml path>`\n- changed `tui.toml` → `kimi doctor tui <tui-new.toml path>`\n\nWhen a path is passed explicitly the file must exist (your candidate does, so that's fine). **Exit code 0 = pass (valid or skipped); non-zero = a specified file is missing or the config is invalid** — show the output verbatim, fix the candidate, and re-run, looping until it's 0.\n\nThen do two checks `kimi doctor` can't:\n\n1. **Cross-check values against the official docs** (single source of truth): are the key / section / enum values as documented, and snake_case? doctor guarantees \"schema-valid\", but \"valid yet not what the user wanted\" (e.g. a misspelled model alias) needs the docs.\n2. **Completeness**: every existing entry is still present (the candidate fully replaces the target — a dropped line is a deletion).\n\n> To also check whether the currently **active** config is OK overall, run `kimi doctor` with no path (it checks the default `config.toml` + `tui.toml`, showing a missing one as skipped).\n\n## Capability 4: tell the user how to apply changes\n\nOnce local validation passes, tell the user how to make the change take effect — **the reload command depends on which file you changed**:\n\n- changed **`config.toml`** → run **`/reload`** in the TUI (reloads the session and applies `config.toml`; it also reloads `tui.toml`).\n- changed **`tui.toml`** → run **`/reload-tui`** (reloads only `tui.toml`, lighter); `/reload` works too (reloads both).\n- changed both → a single **`/reload`** covers it.\n\nNote: `/reload` is available **only when idle** — if a reply is streaming, press Esc / Ctrl-C to stop first. `kimi doctor` already validated the schema before the overwrite, so reload should apply cleanly; if it still errors, follow the message to fix it or recover from the most recent timestamped backup. If you don't want to reload now, the **next new session** picks it up automatically.\n\n## Don'ts\n\n- **Always back up before overwriting**, with a **timestamped name and all history kept** — don't skip the backup, don't keep only a single `.bak`, don't overwrite an old backup.\n- Don't drop unrelated entries (the candidate fully replaces the target — a dropped line is a deletion).\n- When you can't reach the docs / have no authoritative reference, don't edit by guessing.\n";
|
|
74327
74361
|
//#endregion
|
|
74328
74362
|
//#region ../../packages/agent-core/src/skill/builtin/update-config.ts
|
|
74329
|
-
const PSEUDO_PATH = "builtin://update-config";
|
|
74330
|
-
const parsed = parseSkillText({
|
|
74363
|
+
const PSEUDO_PATH$1 = "builtin://update-config";
|
|
74364
|
+
const parsed$1 = parseSkillText({
|
|
74331
74365
|
skillMdPath: "/builtin/skills/update-config.md",
|
|
74332
74366
|
skillDirName: "update-config",
|
|
74333
74367
|
source: "builtin",
|
|
74334
74368
|
text: update_config_default
|
|
74335
74369
|
});
|
|
74336
74370
|
const UPDATE_CONFIG_SKILL = {
|
|
74371
|
+
...parsed$1,
|
|
74372
|
+
path: PSEUDO_PATH$1,
|
|
74373
|
+
dir: PSEUDO_PATH$1,
|
|
74374
|
+
metadata: {
|
|
74375
|
+
...parsed$1.metadata,
|
|
74376
|
+
type: parsed$1.metadata.type ?? "inline"
|
|
74377
|
+
}
|
|
74378
|
+
};
|
|
74379
|
+
//#endregion
|
|
74380
|
+
//#region ../../packages/agent-core/src/skill/builtin/write-goal.md?raw
|
|
74381
|
+
var write_goal_default = "---\nname: write-goal\ndescription: Help the user craft a well-specified `/goal` objective for goal mode — turn a rough intention into a completion contract with a clear finish line, proof, boundaries, and stop rule. Use when the user asks for help writing, refining, or improving a goal.\n---\n\n# Write a good goal (write-goal)\n\nHelp the user turn a rough intention into a `/goal` objective that goal mode can pursue across many turns without supervision. A goal is not a task description — it is a completion contract. It says what must become *true*, how that truth is *proven*, where the work may and may not *reach*, and when to *stop and report* instead of grinding on.\n\nThis skill is about authoring the objective text together with the user. Drafting and starting are separate steps: you settle the wording first, and only once the user has approved it do you start the goal by calling `CreateGoal`. The user still gets a final confirmation before it runs.\n\n## Ask, don't narrate\n\n**This is the most important rule in this skill. Every decision you put to the user goes through `AskUserQuestion`. No exceptions except one (below).**\n\nGoal authoring is a chain of choices — what to scope, which phrasing, whether to add a budget and how large, which permission mode to start under. For every one of them: **stop and call `AskUserQuestion`.** Do not write a paragraph that lists options and asks the user to reply in prose. Do not say \"let me know if you'd prefer A or B.\" Do not bundle three questions into a wall of text. If you catch yourself typing out choices for the user to answer in free text, delete it and call `AskUserQuestion` instead.\n\nA prose menu is a defect, not a style choice: it is slower for the user, easy to skim past, and usually gets a vague answer that forces another round. The only time you may ask in plain text is when `AskUserQuestion` is genuinely unavailable — auto mode, or a host that does not support it — and only then do you fall back to a short message with clearly labelled options and wait. Plain prose for *open-ended* input (\"what would prove this is done?\") is fine; the rule is about **choices between options**, which always use the tool.\n\n## Rules of engagement\n\n- **Only help when the user has asked for it.** Never volunteer to wrap an ordinary request in a goal, and never start one on your own. A normal \"fix this test\" is a normal request; treat it as a goal only when the user says they want a goal. If a task looks like it would suit goal mode, you may mention that once — but wait for the user to choose.\n- **Write in the user's language.** Draft the objective in whatever language the user is writing to you in. If the project configuration or a saved memory names a preferred language, honor that instead. Keep the surrounding discussion in the same language.\n- **Show before you start.** Always present the full drafted goal back to the user and get their agreement before anything runs. The user should read the exact text that will become the objective, not a paraphrase of it.\n- **Draft with the user, not for them.** Goal-writing is a conversation. Offer a draft, explain the choices you made, invite changes, and fold the feedback in. Expect more than one round.\n- **Respect the user's final call.** If, after you have pointed out what is vague or risky, the user still wants a looser or thinner goal, write the goal they asked for. Note the trade-off once; do not keep relitigating it or quietly \"improve\" the wording against their wishes.\n\n## What makes a goal good\n\nThe strongest goals share one shape: they define **proof, not effort**. \"Keep improving the code\" describes effort and never ends. \"Done when `npm test` exits 0 and no file outside `src/auth` changed\" describes proof and is checkable. Aim for a contract with these parts:\n\n1. **End state** — the condition that must become true. Name the finish line concretely: a passing suite, an empty queue, a search that returns zero matches, a deployed artifact.\n2. **Proof** — the observable evidence that the end state holds. Prefer things the agent can run and you can inspect afterward: a command's exit code, a test count, a `grep`/`rg` with no hits, a file that now exists, a metric over a threshold.\n3. **Boundaries** — what the work may and may not touch. Name the scope (which module, which directory) and the off-limits actions (do not edit the spec, do not change unrelated files, do not make destructive data changes).\n4. **The loop** — when the work is iterative, say how to iterate: rerun the check after each change, work through the queue item by item, replay the failing cases until they pass.\n5. **The stop rule** — how to end honestly when \"done\" is not reachable. A \"stop and ask before widening scope\" clause and an explicit blocked path (\"if an external service is down, record it and move on\") let the agent report instead of faking a pass or looping forever. This is about *honesty*, not a spending limit — keep it separate from any budget (see below).\n\nTwo habits make almost any goal better:\n\n- **Make it queue-shaped.** Goals that shrink a list work best: failing tests, open issues, error traces, files to migrate, rows to process. A queue gives the agent a worklist and gives you a countable definition of done.\n- **Lean on existing verification.** Tests, CI, type-checks, lint, eval suites, browser audits, and zero-match searches are leverage — they are what let a goal run unattended and still be trusted. If a task has no way to prove completion, help the user add one or reconsider whether goal mode fits.\n\nLonger runs are not better runs. A tight contract that finishes in a handful of turns beats an open-ended one that burns hours re-running the whole suite after every edit.\n\n## Budgets are opt-in\n\nGoal mode can run under a turn or token budget, but **do not set one by default, and never bake a turn cap into the objective text.** A well-specified goal already stops on its own — when the proof passes or a blocker is hit — so an arbitrary cap usually does nothing except risk cutting off work midway.\n\nWhen a budget is genuinely useful — typically an open-ended or exploratory goal that could run long unattended — you may suggest one, framed around the number users actually feel: token cost. Let the user choose the value, and sanity-check it against the work. A cap far larger than the task needs (say a thousand turns for a goal that will finish in a few) is not a safety net; it just invites wasted tokens. If the user asks for a value that looks oversized, say so and offer a smaller one, but respect their final call.\n\n## Workflow\n\n1. **Understand the intention.** Ask what outcome the user actually wants and what would prove it is done. If a finish line or a check is missing, that gap is the first thing to resolve together. As soon as the open questions reduce to concrete options, put them to the user with **AskUserQuestion** — do not list the options in prose.\n2. **Draft the goal.** Write a concrete objective in the user's language, covering as many parts of the contract above as the task warrants. Keep it readable — one or a few sentences for simple work, a short structured block (end state, checks, boundaries, stop rule) for larger work.\n3. **Show it and explain.** Present the draft in full and walk through the choices: what you picked as the finish line, what proves it, what you fenced off, when it stops. Point out anything still soft.\n4. **Revise together.** Take the user's edits and produce a new draft. When you are weighing alternative phrasings or scopes, offer them as an **AskUserQuestion** choice instead of describing them. Repeat until they are satisfied. If they want it looser than you would recommend, say so once, then write their version.\n5. **Start it.** Once the user approves the wording, start the goal by calling `CreateGoal` with the agreed objective (and a `completionCriterion` if you settled on one). Do not just print the text for the user to paste, and do not start before they have approved. Starting still surfaces a final confirmation, so the user keeps the last word on whether it runs.\n\n## A reusable shape\n\nFor a non-trivial goal, this fill-in-the-blanks structure covers the contract:\n\n```\n<What must become true.>\nDone when <command/search/state that proves it>.\nScope: only <files/area>; do not <off-limits action>.\nLoop: <how to iterate — rerun the check after each change, etc.>.\nIf <blocking condition>, stop and report instead of forcing a pass.\n```\n\nNot every goal needs every line, and none of them is a turn cap — the goal stops when the proof passes or a blocker is hit. A small, well-scoped task can be a single clear sentence. Add structure as the work grows or the cost of a wrong autonomous run rises.\n\n## Weak to strong\n\n- Weak: `Find all bugs in this codebase.` — no finish line, no proof, no stop. The agent may block at once or run far past what you wanted.\n Strong: `Fix every test in test/auth that currently fails, rerun npm test until it exits 0, change no file outside test/ or src/auth, and report anything you cannot fix with its location and why.`\n- Weak: `Optimize the project.` — no scope, no measure.\n Strong: `Migrate the payment module to the new API, make npm test -- payment exit 0, keep the diff limited to payment-related files, and stop and ask before touching shared infrastructure.`\n- Weak: `Make it faster.`\n Strong: `Make renderFrame at least 3x faster measured by the bench/render benchmark; if you cannot reach 3x after several attempts, report the best result and why.`\n\n## Common mistakes\n\n| Mistake | Better |\n| --- | --- |\n| Starting or suggesting a goal the user did not ask for | Only draft a goal once the user asks; mention the option at most once otherwise |\n| Drafting in English when the user is writing in another language | Match the user's language (or the project / memory preference) |\n| Running the goal before the user has seen the exact text | Show the full draft and get agreement first |\n| Polishing the goal silently against the user's stated wishes | Note the trade-off once, then write the goal they asked for |\n| Burying a discrete choice in prose | Offer the options with AskUserQuestion (plain labelled options if it is unavailable) |\n| Specifying effort (\"keep improving X\") | Specify proof (\"done when check X passes\") |\n| Baking a turn cap into the objective or setting a budget unprompted | Let the goal stop on its proof; suggest a budget only when useful, framed on token cost |\n| No blocked path | Add an explicit \"stop and report\" rule for blockers |\n| A goal with no way to verify completion | Anchor it to tests, a search, a metric, or another inspectable check |\n";
|
|
74382
|
+
//#endregion
|
|
74383
|
+
//#region ../../packages/agent-core/src/skill/builtin/write-goal.ts
|
|
74384
|
+
const PSEUDO_PATH = "builtin://write-goal";
|
|
74385
|
+
const parsed = parseSkillText({
|
|
74386
|
+
skillMdPath: "/builtin/skills/write-goal.md",
|
|
74387
|
+
skillDirName: "write-goal",
|
|
74388
|
+
source: "builtin",
|
|
74389
|
+
text: write_goal_default
|
|
74390
|
+
});
|
|
74391
|
+
const WRITE_GOAL_SKILL = {
|
|
74337
74392
|
...parsed,
|
|
74338
74393
|
path: PSEUDO_PATH,
|
|
74339
74394
|
dir: PSEUDO_PATH,
|
|
@@ -74349,6 +74404,7 @@ function registerBuiltinSkills(registry) {
|
|
|
74349
74404
|
registry.registerBuiltinSkill(IMPORT_FROM_CC_CODEX_SKILL);
|
|
74350
74405
|
registry.registerBuiltinSkill(UPDATE_CONFIG_SKILL);
|
|
74351
74406
|
registry.registerBuiltinSkill(CUSTOM_THEME_SKILL);
|
|
74407
|
+
registry.registerBuiltinSkill(WRITE_GOAL_SKILL);
|
|
74352
74408
|
registry.registerBuiltinSkill(SUB_SKILL_PARENT);
|
|
74353
74409
|
registry.registerBuiltinSkill(SUB_SKILL_REVIEW);
|
|
74354
74410
|
registry.registerBuiltinSkill(SUB_SKILL_CONSOLIDATE);
|
|
@@ -83401,6 +83457,12 @@ const ToolInputDisplaySchema = z.discriminatedUnion("kind", [
|
|
|
83401
83457
|
description: z.string()
|
|
83402
83458
|
})).readonly().optional()
|
|
83403
83459
|
}),
|
|
83460
|
+
z.object({
|
|
83461
|
+
kind: z.literal("goal_start"),
|
|
83462
|
+
objective: z.string(),
|
|
83463
|
+
completionCriterion: z.string().optional(),
|
|
83464
|
+
mode: z.enum(["manual", "yolo"])
|
|
83465
|
+
}),
|
|
83404
83466
|
z.object({
|
|
83405
83467
|
kind: z.literal("generic"),
|
|
83406
83468
|
summary: z.string(),
|
|
@@ -83737,6 +83799,8 @@ const sessionSchema = z.object({
|
|
|
83737
83799
|
status: sessionStatusSchema,
|
|
83738
83800
|
archived: z.boolean().optional(),
|
|
83739
83801
|
current_prompt_id: z.string().min(1).optional(),
|
|
83802
|
+
/** Text of the most recent user prompt, for search/preview. Absent for empty sessions. */
|
|
83803
|
+
last_prompt: z.string().optional(),
|
|
83740
83804
|
metadata: sessionMetadataSchema,
|
|
83741
83805
|
agent_config: sessionAgentConfigSchema,
|
|
83742
83806
|
usage: sessionUsageSchema,
|
|
@@ -90953,6 +91017,7 @@ const RATE_LIMIT_RETRY_FACTOR = 2;
|
|
|
90953
91017
|
const RATE_LIMIT_CAPACITY_SHRINK_INTERVAL_MS = 2e3;
|
|
90954
91018
|
const RATE_LIMIT_CAPACITY_RECOVERY_INTERVAL_MS = 180 * 1e3;
|
|
90955
91019
|
const RATE_LIMIT_SUSPENDED_REASON = "Provider rate limit; subagent requeued for retry.";
|
|
91020
|
+
const AGENT_SWARM_MAX_CONCURRENCY_ENV = "KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY";
|
|
90956
91021
|
var SubagentBatch = class {
|
|
90957
91022
|
launcher;
|
|
90958
91023
|
states;
|
|
@@ -90962,6 +91027,7 @@ var SubagentBatch = class {
|
|
|
90962
91027
|
controller = new AbortController();
|
|
90963
91028
|
batchSignal;
|
|
90964
91029
|
batchAbortListener;
|
|
91030
|
+
maxConcurrency;
|
|
90965
91031
|
normalLaunchCount = 0;
|
|
90966
91032
|
normalLaunchTimer;
|
|
90967
91033
|
rateLimitLaunchTimer;
|
|
@@ -90977,8 +91043,9 @@ var SubagentBatch = class {
|
|
|
90977
91043
|
lastCapacityRecoveryAt;
|
|
90978
91044
|
globalRetryIntervalMs = RATE_LIMIT_RETRY_BASE_MS;
|
|
90979
91045
|
nextRateLimitLaunchAt = 0;
|
|
90980
|
-
constructor(launcher, tasks) {
|
|
91046
|
+
constructor(launcher, tasks, options = {}) {
|
|
90981
91047
|
this.launcher = launcher;
|
|
91048
|
+
this.maxConcurrency = options.maxConcurrency;
|
|
90982
91049
|
this.states = tasks.map((task, index) => ({
|
|
90983
91050
|
index,
|
|
90984
91051
|
task,
|
|
@@ -91021,19 +91088,23 @@ var SubagentBatch = class {
|
|
|
91021
91088
|
else this.scheduleNormalLaunch();
|
|
91022
91089
|
}
|
|
91023
91090
|
scheduleNormalLaunch() {
|
|
91024
|
-
while (this.normalLaunchCount < INITIAL_LAUNCH_LIMIT && this.pending.length > 0 && !this.rateLimitMode) {
|
|
91091
|
+
while (this.normalLaunchCount < INITIAL_LAUNCH_LIMIT && this.pending.length > 0 && !this.rateLimitMode && !this.isAtConcurrencyLimit()) {
|
|
91025
91092
|
this.startAttempt(this.pending.shift());
|
|
91026
91093
|
this.normalLaunchCount += 1;
|
|
91027
91094
|
}
|
|
91028
|
-
if (this.pending.length === 0 || this.rateLimitMode || this.normalLaunchTimer !== void 0) return;
|
|
91095
|
+
if (this.pending.length === 0 || this.rateLimitMode || this.normalLaunchTimer !== void 0 || this.isAtConcurrencyLimit()) return;
|
|
91029
91096
|
this.normalLaunchTimer = setTimeout(() => {
|
|
91030
91097
|
this.normalLaunchTimer = void 0;
|
|
91031
91098
|
if (this.finished || this.rateLimitMode || this.pending.length === 0) return;
|
|
91099
|
+
if (this.isAtConcurrencyLimit()) return;
|
|
91032
91100
|
this.startAttempt(this.pending.shift());
|
|
91033
91101
|
this.normalLaunchCount += 1;
|
|
91034
91102
|
this.schedule();
|
|
91035
91103
|
}, INITIAL_LAUNCH_INTERVAL_MS);
|
|
91036
91104
|
}
|
|
91105
|
+
isAtConcurrencyLimit() {
|
|
91106
|
+
return this.maxConcurrency !== void 0 && this.active.size >= this.maxConcurrency;
|
|
91107
|
+
}
|
|
91037
91108
|
scheduleRateLimitLaunch() {
|
|
91038
91109
|
this.clearRateLimitTimer();
|
|
91039
91110
|
if (this.pending.length === 0) return;
|
|
@@ -91329,6 +91400,20 @@ var SubagentBatch = class {
|
|
|
91329
91400
|
return error instanceof Error ? error.message : String(error);
|
|
91330
91401
|
}
|
|
91331
91402
|
};
|
|
91403
|
+
/**
|
|
91404
|
+
* Resolve the optional AgentSwarm normal-phase concurrency cap from the environment.
|
|
91405
|
+
*
|
|
91406
|
+
* Returns `undefined` when the variable is unset/empty. A present value must be a
|
|
91407
|
+
* positive integer; invalid input fails fast so a misconfigured cap never silently
|
|
91408
|
+
* reverts to the uncapped ramp.
|
|
91409
|
+
*/
|
|
91410
|
+
function resolveSwarmMaxConcurrency(env = process.env) {
|
|
91411
|
+
const raw = env[AGENT_SWARM_MAX_CONCURRENCY_ENV];
|
|
91412
|
+
if (raw === void 0 || raw.trim() === "") return void 0;
|
|
91413
|
+
const value = Number(raw);
|
|
91414
|
+
if (!Number.isInteger(value) || value <= 0) throw new Error(`${AGENT_SWARM_MAX_CONCURRENCY_ENV} must be a positive integer, got ${JSON.stringify(raw)}.`);
|
|
91415
|
+
return value;
|
|
91416
|
+
}
|
|
91332
91417
|
//#endregion
|
|
91333
91418
|
//#region ../../packages/agent-core/src/session/summary-continuation.md?raw
|
|
91334
91419
|
var summary_continuation_default = "Your previous response was too brief. Please provide a more comprehensive summary that includes:\n\n1. Specific technical details and implementations\n2. Detailed findings and analysis\n3. All important information that the parent agent should know";
|
|
@@ -91455,7 +91540,8 @@ var SessionSubagentHost = class {
|
|
|
91455
91540
|
};
|
|
91456
91541
|
}
|
|
91457
91542
|
async runQueued(tasks) {
|
|
91458
|
-
|
|
91543
|
+
const maxConcurrency = resolveSwarmMaxConcurrency();
|
|
91544
|
+
return new SubagentBatch(this, tasks, { maxConcurrency }).run();
|
|
91459
91545
|
}
|
|
91460
91546
|
suspended(event) {
|
|
91461
91547
|
(this.session.getReadyAgent?.(this.ownerAgentId))?.emitEvent({
|
|
@@ -98748,6 +98834,20 @@ var WriteTool = class {
|
|
|
98748
98834
|
//#region ../../packages/agent-core/src/tools/builtin/goal/create-goal.md?raw
|
|
98749
98835
|
var create_goal_default = "Create a durable, structured goal that the runtime will pursue across multiple turns.\n\nCall `CreateGoal` only when:\n\n- the user explicitly asks you to start a goal or work autonomously toward an outcome, or\n- a host goal-intake prompt asks you to create one.\n\nDo NOT create a goal for greetings, ordinary questions, or vague requests that lack a\nverifiable completion condition. A goal needs a checkable end state.\n\nWhen the request is vague, ask the user for the missing completion criterion before creating\nthe goal. If the user clearly insists after you warn them that the wording is vague or risky,\nrespect that and create the goal.\n\nInclude a `completionCriterion` when the user provides one, or when it can be stated without\ninventing new requirements. Keep `objective` concise; reference long task descriptions by file\npath rather than pasting them.\n\nUse `replace: true` only when the user explicitly wants to abandon the current goal and start a\nnew one.\n";
|
|
98750
98836
|
//#endregion
|
|
98837
|
+
//#region ../../packages/agent-core/src/tools/builtin/goal/serialize.ts
|
|
98838
|
+
/**
|
|
98839
|
+
* The goalId is a random UUID with no user-facing meaning, and no goal tool
|
|
98840
|
+
* takes one (there is only ever one goal at a time). Keep it out of what the
|
|
98841
|
+
* model sees so it never echoes the id back to the user as if it mattered.
|
|
98842
|
+
*/
|
|
98843
|
+
function goalForModel(goal) {
|
|
98844
|
+
const { goalId: _goalId, ...rest } = goal;
|
|
98845
|
+
return rest;
|
|
98846
|
+
}
|
|
98847
|
+
function goalResultForModel(result) {
|
|
98848
|
+
return { goal: result.goal === null ? null : goalForModel(result.goal) };
|
|
98849
|
+
}
|
|
98850
|
+
//#endregion
|
|
98751
98851
|
//#region ../../packages/agent-core/src/tools/builtin/goal/create-goal.ts
|
|
98752
98852
|
const CreateGoalToolInputSchema = z.object({
|
|
98753
98853
|
objective: z.string().min(1).describe("The objective to pursue. Must have a verifiable end state."),
|
|
@@ -98766,6 +98866,7 @@ var CreateGoalTool = class {
|
|
|
98766
98866
|
const goal = this.agent.goal;
|
|
98767
98867
|
return {
|
|
98768
98868
|
description: "Creating a goal",
|
|
98869
|
+
display: this.resolveGoalStartDisplay(args),
|
|
98769
98870
|
approvalRule: this.name,
|
|
98770
98871
|
execute: async () => {
|
|
98771
98872
|
const snapshot = await goal.createGoal({
|
|
@@ -98773,10 +98874,26 @@ var CreateGoalTool = class {
|
|
|
98773
98874
|
completionCriterion: args.completionCriterion,
|
|
98774
98875
|
replace: args.replace
|
|
98775
98876
|
}, "model");
|
|
98776
|
-
return { output: JSON.stringify({ goal: snapshot }, null, 2) };
|
|
98877
|
+
return { output: JSON.stringify({ goal: goalForModel(snapshot) }, null, 2) };
|
|
98777
98878
|
}
|
|
98778
98879
|
};
|
|
98779
98880
|
}
|
|
98881
|
+
/**
|
|
98882
|
+
* Starting a goal switches the agent into autonomous, multi-turn work, so its
|
|
98883
|
+
* approval reuses the same choice the `/goal` command offers: pick the
|
|
98884
|
+
* permission mode to run under, or decline. `auto` mode auto-approves the goal
|
|
98885
|
+
* upstream and never reaches this prompt, so the menu only covers manual/yolo.
|
|
98886
|
+
*/
|
|
98887
|
+
resolveGoalStartDisplay(args) {
|
|
98888
|
+
const mode = this.agent.permission.mode;
|
|
98889
|
+
if (mode === "auto") return void 0;
|
|
98890
|
+
return {
|
|
98891
|
+
kind: "goal_start",
|
|
98892
|
+
objective: args.objective,
|
|
98893
|
+
completionCriterion: args.completionCriterion,
|
|
98894
|
+
mode
|
|
98895
|
+
};
|
|
98896
|
+
}
|
|
98780
98897
|
};
|
|
98781
98898
|
//#endregion
|
|
98782
98899
|
//#region ../../packages/agent-core/src/tools/builtin/goal/get-goal.md?raw
|
|
@@ -98799,7 +98916,7 @@ var GetGoalTool = class {
|
|
|
98799
98916
|
approvalRule: this.name,
|
|
98800
98917
|
execute: async () => {
|
|
98801
98918
|
const result = store.getGoal();
|
|
98802
|
-
return { output: JSON.stringify(result, null, 2) };
|
|
98919
|
+
return { output: JSON.stringify(goalResultForModel(result), null, 2) };
|
|
98803
98920
|
}
|
|
98804
98921
|
};
|
|
98805
98922
|
}
|
|
@@ -99291,12 +99408,9 @@ var TurnFlow = class {
|
|
|
99291
99408
|
async turnWorker(firstTurnId, input, origin, signal) {
|
|
99292
99409
|
const ownsActiveTurn = () => this.activeTurn !== null && this.activeTurn !== "resuming" && this.activeTurn.controller.signal === signal;
|
|
99293
99410
|
try {
|
|
99294
|
-
|
|
99295
|
-
if (initialGoalStatus === "active") return await this.driveGoal(firstTurnId, input, origin, signal);
|
|
99411
|
+
if (this.agent.goal.getGoal().goal?.status === "active") return await this.driveGoal(firstTurnId, input, origin, signal);
|
|
99296
99412
|
const end = await this.runOneTurn(firstTurnId, input, origin, signal, true);
|
|
99297
|
-
|
|
99298
|
-
const currentGoalStatus = this.agent.goal.getGoal().goal?.status;
|
|
99299
|
-
if (resumedFromPausedOrBlocked && currentGoalStatus === "active" && end.event.reason !== "cancelled" && end.event.reason !== "failed") return await this.driveGoal(this.allocateTurnId(), [{
|
|
99413
|
+
if (this.agent.goal.getGoal().goal?.status === "active" && end.event.reason !== "cancelled" && end.event.reason !== "failed") return await this.driveGoal(this.allocateTurnId(), [{
|
|
99300
99414
|
type: "text",
|
|
99301
99415
|
text: GOAL_CONTINUATION_PROMPT
|
|
99302
99416
|
}], GOAL_CONTINUATION_ORIGIN, signal);
|
|
@@ -99462,7 +99576,7 @@ var TurnFlow = class {
|
|
|
99462
99576
|
reason: "cancelled"
|
|
99463
99577
|
} });
|
|
99464
99578
|
this.agent.emitEvent(ended);
|
|
99465
|
-
if (standalone && this.currentId === turnId) this.activeTurn = null;
|
|
99579
|
+
if (standalone && this.currentId === turnId && this.agent.goal.getGoal().goal?.status !== "active") this.activeTurn = null;
|
|
99466
99580
|
if (this.agent.swarmMode.shouldAutoExit) this.agent.swarmMode.exit();
|
|
99467
99581
|
if (errorEvent !== void 0) this.agent.emitEvent(errorEvent);
|
|
99468
99582
|
if (ended.reason !== "completed") this.trackTurnInterrupted(turnId, this.currentStepByTurn.get(turnId) ?? this.currentStep);
|
|
@@ -155587,6 +155701,7 @@ function toProtocolSession(summary, meta) {
|
|
|
155587
155701
|
updated_at: new Date(summary.updatedAt).toISOString(),
|
|
155588
155702
|
status: "idle",
|
|
155589
155703
|
archived: summary.archived === true,
|
|
155704
|
+
last_prompt: summary.lastPrompt,
|
|
155590
155705
|
metadata: mergedMetadata,
|
|
155591
155706
|
agent_config: { model: "" },
|
|
155592
155707
|
usage: emptySessionUsage(),
|
|
@@ -158944,7 +159059,7 @@ let WorkspaceRegistryService = class WorkspaceRegistryService extends Disposable
|
|
|
158944
159059
|
return entry.root;
|
|
158945
159060
|
}
|
|
158946
159061
|
async hydrate(workspaceId, entry) {
|
|
158947
|
-
const [{ is_git_repo, branch }, session_count] = await Promise.all([detectGit(entry.root),
|
|
159062
|
+
const [{ is_git_repo, branch }, session_count] = await Promise.all([detectGit(entry.root), countActiveSessions(join$1(this.sessionsDir, workspaceId))]);
|
|
158948
159063
|
return {
|
|
158949
159064
|
id: workspaceId,
|
|
158950
159065
|
root: entry.root,
|
|
@@ -159109,7 +159224,7 @@ async function detectGit(root) {
|
|
|
159109
159224
|
branch: ref ? ref[1] ?? null : null
|
|
159110
159225
|
};
|
|
159111
159226
|
}
|
|
159112
|
-
async function
|
|
159227
|
+
async function countActiveSessions(dir) {
|
|
159113
159228
|
let dirents;
|
|
159114
159229
|
try {
|
|
159115
159230
|
dirents = await promises.readdir(dir, { withFileTypes: true });
|
|
@@ -159118,9 +159233,22 @@ async function countSessionDirs(dir) {
|
|
|
159118
159233
|
throw err;
|
|
159119
159234
|
}
|
|
159120
159235
|
let count = 0;
|
|
159121
|
-
for (const d of dirents)
|
|
159236
|
+
for (const d of dirents) {
|
|
159237
|
+
if (!d.isDirectory()) continue;
|
|
159238
|
+
if (await isSessionArchived(join$1(dir, d.name))) continue;
|
|
159239
|
+
count += 1;
|
|
159240
|
+
}
|
|
159122
159241
|
return count;
|
|
159123
159242
|
}
|
|
159243
|
+
async function isSessionArchived(sessionDir) {
|
|
159244
|
+
try {
|
|
159245
|
+
const raw = await promises.readFile(join$1(sessionDir, "state.json"), "utf8");
|
|
159246
|
+
const parsed = JSON.parse(raw);
|
|
159247
|
+
return typeof parsed === "object" && parsed !== null && parsed.archived === true;
|
|
159248
|
+
} catch {
|
|
159249
|
+
return false;
|
|
159250
|
+
}
|
|
159251
|
+
}
|
|
159124
159252
|
registerSingleton(IWorkspaceRegistry, WorkspaceRegistryService, 1);
|
|
159125
159253
|
//#endregion
|
|
159126
159254
|
//#region ../../packages/agent-core/src/services/workspace/workspaceFs.ts
|
|
@@ -162991,6 +163119,7 @@ var KimiHarness = class {
|
|
|
162991
163119
|
activeSessions = /* @__PURE__ */ new Map();
|
|
162992
163120
|
ensureConfigFileImpl;
|
|
162993
163121
|
closeImpl;
|
|
163122
|
+
sessionStartedProperties;
|
|
162994
163123
|
constructor(rpc, options) {
|
|
162995
163124
|
this.rpc = rpc;
|
|
162996
163125
|
this.identity = options.identity;
|
|
@@ -163001,6 +163130,7 @@ var KimiHarness = class {
|
|
|
163001
163130
|
this.auth = options.auth;
|
|
163002
163131
|
this.ensureConfigFileImpl = options.ensureConfigFile;
|
|
163003
163132
|
this.closeImpl = options.onClose;
|
|
163133
|
+
this.sessionStartedProperties = options.sessionStartedProperties ?? {};
|
|
163004
163134
|
}
|
|
163005
163135
|
get sessions() {
|
|
163006
163136
|
return this.activeSessions;
|
|
@@ -163018,7 +163148,7 @@ var KimiHarness = class {
|
|
|
163018
163148
|
this.telemetry.setContext?.(patch);
|
|
163019
163149
|
}
|
|
163020
163150
|
async createSession(options) {
|
|
163021
|
-
const { planMode, kaos, persistenceKaos, ...coreOptions } = options;
|
|
163151
|
+
const { planMode, kaos, persistenceKaos, sessionStartedProperties, ...coreOptions } = options;
|
|
163022
163152
|
const summary = kaos === void 0 && persistenceKaos === void 0 ? await this.rpc.createSession(coreOptions) : await this.rpc.createSessionWithKaos(coreOptions, kaos ?? persistenceKaos, persistenceKaos);
|
|
163023
163153
|
const session = new Session({
|
|
163024
163154
|
id: summary.id,
|
|
@@ -163031,14 +163161,14 @@ var KimiHarness = class {
|
|
|
163031
163161
|
});
|
|
163032
163162
|
this.activeSessions.set(session.id, session);
|
|
163033
163163
|
if (planMode === true) await session.setPlanMode(true);
|
|
163034
|
-
this.trackSessionStarted(summary.id, false);
|
|
163164
|
+
this.trackSessionStarted(summary.id, false, sessionStartedProperties);
|
|
163035
163165
|
this.trackSessionEvent(session.id, "session_new");
|
|
163036
163166
|
return session;
|
|
163037
163167
|
}
|
|
163038
163168
|
async resumeSession(input) {
|
|
163039
163169
|
const id = normalizeSessionId(input.id);
|
|
163040
163170
|
const active = this.activeSessions.get(id);
|
|
163041
|
-
const { kaos, persistenceKaos, ...resumeInput } = input;
|
|
163171
|
+
const { kaos, persistenceKaos, sessionStartedProperties, ...resumeInput } = input;
|
|
163042
163172
|
if (active !== void 0) {
|
|
163043
163173
|
if (kaos !== void 0 || persistenceKaos !== void 0) await this.rpc.resumeSessionWithKaos({
|
|
163044
163174
|
...resumeInput,
|
|
@@ -163063,7 +163193,7 @@ var KimiHarness = class {
|
|
|
163063
163193
|
}
|
|
163064
163194
|
});
|
|
163065
163195
|
this.activeSessions.set(session.id, session);
|
|
163066
|
-
this.trackSessionStarted(summary.id, true);
|
|
163196
|
+
this.trackSessionStarted(summary.id, true, sessionStartedProperties);
|
|
163067
163197
|
this.trackSessionEvent(session.id, "session_resume");
|
|
163068
163198
|
return session;
|
|
163069
163199
|
}
|
|
@@ -163158,8 +163288,10 @@ var KimiHarness = class {
|
|
|
163158
163288
|
trackSessionEvent(eventSessionId, event) {
|
|
163159
163289
|
withTelemetryContext$1(this.telemetry, { sessionId: eventSessionId }).track(event);
|
|
163160
163290
|
}
|
|
163161
|
-
trackSessionStarted(eventSessionId, resumed) {
|
|
163291
|
+
trackSessionStarted(eventSessionId, resumed, sessionScoped) {
|
|
163162
163292
|
withTelemetryContext$1(this.telemetry, { sessionId: eventSessionId }).track("session_started", {
|
|
163293
|
+
...this.sessionStartedProperties,
|
|
163294
|
+
...sessionScoped,
|
|
163163
163295
|
client_name: this.identity?.userAgentProduct ?? null,
|
|
163164
163296
|
client_version: this.identity?.version ?? null,
|
|
163165
163297
|
ui_mode: this.uiMode,
|
|
@@ -163850,7 +163982,8 @@ function createKimiHarness(options) {
|
|
|
163850
163982
|
auth: rpc.auth,
|
|
163851
163983
|
telemetry: rpc.telemetry,
|
|
163852
163984
|
ensureConfigFile: () => rpc.ensureConfigFile(),
|
|
163853
|
-
onClose: () => rpc.close()
|
|
163985
|
+
onClose: () => rpc.close(),
|
|
163986
|
+
sessionStartedProperties: options.sessionStartedProperties
|
|
163854
163987
|
});
|
|
163855
163988
|
}
|
|
163856
163989
|
//#endregion
|
|
@@ -182608,13 +182741,13 @@ var AcpServer = class {
|
|
|
182608
182741
|
workDir: params.cwd,
|
|
182609
182742
|
kaos: acpKaos,
|
|
182610
182743
|
persistenceKaos,
|
|
182744
|
+
sessionStartedProperties: { mode: "new" },
|
|
182611
182745
|
mcpServers
|
|
182612
182746
|
});
|
|
182613
182747
|
const currentModelId = await this.resolveCurrentModelId();
|
|
182614
182748
|
const currentThinkingEnabled = await this.resolveCurrentThinkingEnabled();
|
|
182615
182749
|
const acpSession = new AcpSession(this.conn, session, this.clientCapabilities, this.makeTelemetryTrack(), currentModelId, this.harness, currentThinkingEnabled);
|
|
182616
182750
|
this.sessions.set(session.id, acpSession);
|
|
182617
|
-
this.trackSessionStarted(session.id, "new");
|
|
182618
182751
|
const configOptions = await buildSessionConfigOptions(this.harness, currentModelId, currentThinkingEnabled, DEFAULT_MODE_ID);
|
|
182619
182752
|
this.scheduleAvailableCommandsUpdate(session.id);
|
|
182620
182753
|
return {
|
|
@@ -182649,9 +182782,9 @@ var AcpServer = class {
|
|
|
182649
182782
|
const { session, acpSession, configOptions } = await this.setupSessionFromExisting({
|
|
182650
182783
|
cwd: params.cwd,
|
|
182651
182784
|
sessionId: params.sessionId,
|
|
182652
|
-
mcpServers: params.mcpServers
|
|
182785
|
+
mcpServers: params.mcpServers,
|
|
182786
|
+
mode: "load"
|
|
182653
182787
|
});
|
|
182654
|
-
this.trackSessionStarted(session.id, "load");
|
|
182655
182788
|
await acpSession.replayHistory();
|
|
182656
182789
|
this.scheduleAvailableCommandsUpdate(session.id);
|
|
182657
182790
|
return { configOptions };
|
|
@@ -182679,9 +182812,9 @@ var AcpServer = class {
|
|
|
182679
182812
|
const { session, configOptions } = await this.setupSessionFromExisting({
|
|
182680
182813
|
cwd: params.cwd,
|
|
182681
182814
|
sessionId: params.sessionId,
|
|
182682
|
-
mcpServers: params.mcpServers
|
|
182815
|
+
mcpServers: params.mcpServers,
|
|
182816
|
+
mode: "resume"
|
|
182683
182817
|
});
|
|
182684
|
-
this.trackSessionStarted(session.id, "resume");
|
|
182685
182818
|
this.scheduleAvailableCommandsUpdate(session.id);
|
|
182686
182819
|
return { configOptions };
|
|
182687
182820
|
}
|
|
@@ -182720,6 +182853,7 @@ var AcpServer = class {
|
|
|
182720
182853
|
id: params.sessionId,
|
|
182721
182854
|
kaos: acpKaos,
|
|
182722
182855
|
persistenceKaos,
|
|
182856
|
+
sessionStartedProperties: { mode: params.mode },
|
|
182723
182857
|
mcpServers
|
|
182724
182858
|
});
|
|
182725
182859
|
} catch (err) {
|
|
@@ -182924,8 +183058,7 @@ var AcpServer = class {
|
|
|
182924
183058
|
* throwing) — adapter-level unit tests routinely construct minimal
|
|
182925
183059
|
* `KimiHarness` shapes that only stub `auth.status` + `createSession`.
|
|
182926
183060
|
* Production callers always supply a real harness with both methods;
|
|
182927
|
-
* the swallow-and-fallback path exists purely for test ergonomics
|
|
182928
|
-
* (matches the `track?.bind(...)` pattern at `trackSessionStarted`).
|
|
183061
|
+
* the swallow-and-fallback path exists purely for test ergonomics.
|
|
182929
183062
|
*
|
|
182930
183063
|
* Logged at `warn` when a fallback fires so a dev who forgot to set
|
|
182931
183064
|
* `default_model = ...` sees a breadcrumb in the agent log.
|
|
@@ -182984,7 +183117,7 @@ var AcpServer = class {
|
|
|
182984
183117
|
* Build a {@link TelemetryTrackFn} wrapper bound to the underlying
|
|
182985
183118
|
* harness so the {@link AcpSession} (and its reverse-RPC bridges in
|
|
182986
183119
|
* Phase 13) can emit PII-free breadcrumbs through the same
|
|
182987
|
-
* `harness.track` channel
|
|
183120
|
+
* `harness.track` channel. The wrapper
|
|
182988
183121
|
* shape is required by the broader `Record<string, unknown>` properties
|
|
182989
183122
|
* type {@link TelemetryTrackFn} uses — the harness's own `track` is
|
|
182990
183123
|
* typed against the narrower `TelemetryProperties` (a
|
|
@@ -183026,34 +183159,6 @@ var AcpServer = class {
|
|
|
183026
183159
|
});
|
|
183027
183160
|
}
|
|
183028
183161
|
}
|
|
183029
|
-
/**
|
|
183030
|
-
* Emit the single ACP-adapter telemetry event.
|
|
183031
|
-
*
|
|
183032
|
-
* Wraps {@link KimiHarness.track} so a partial harness stub
|
|
183033
|
-
* (common in unit tests — see `auth-gate.test.ts`, `session-new.test.ts`)
|
|
183034
|
-
* cannot crash the request path. Production callers always supply a
|
|
183035
|
-
* real harness with `.track`; the swallow-and-log fallback exists
|
|
183036
|
-
* purely for test ergonomics.
|
|
183037
|
-
*
|
|
183038
|
-
* Property set is deliberately minimal: `sessionId` + `mode`. No
|
|
183039
|
-
* user content, no IDE identity, no client capabilities — keeping
|
|
183040
|
-
* the breadcrumb PII-free.
|
|
183041
|
-
*/
|
|
183042
|
-
trackSessionStarted(sessionId, mode) {
|
|
183043
|
-
const track = this.harness.track?.bind(this.harness);
|
|
183044
|
-
if (typeof track !== "function") return;
|
|
183045
|
-
try {
|
|
183046
|
-
track("acp_session_started", {
|
|
183047
|
-
sessionId,
|
|
183048
|
-
mode
|
|
183049
|
-
});
|
|
183050
|
-
} catch (err) {
|
|
183051
|
-
log.warn("acp: telemetry track failed", {
|
|
183052
|
-
sessionId,
|
|
183053
|
-
error: err instanceof Error ? err.message : String(err)
|
|
183054
|
-
});
|
|
183055
|
-
}
|
|
183056
|
-
}
|
|
183057
183162
|
};
|
|
183058
183163
|
/**
|
|
183059
183164
|
* Drive an {@link AcpServer} over an arbitrary ACP {@link Stream}.
|
|
@@ -183731,20 +183836,20 @@ function emptyUpdateInstallState() {
|
|
|
183731
183836
|
}
|
|
183732
183837
|
//#endregion
|
|
183733
183838
|
//#region src/cli/update/source.ts
|
|
183734
|
-
const nodeRequire$
|
|
183735
|
-
let cachedSea;
|
|
183736
|
-
function loadSeaModule$
|
|
183737
|
-
if (cachedSea !== void 0) return cachedSea;
|
|
183839
|
+
const nodeRequire$5 = createRequire(import.meta.url);
|
|
183840
|
+
let cachedSea$1;
|
|
183841
|
+
function loadSeaModule$2() {
|
|
183842
|
+
if (cachedSea$1 !== void 0) return cachedSea$1;
|
|
183738
183843
|
try {
|
|
183739
|
-
cachedSea = nodeRequire$
|
|
183844
|
+
cachedSea$1 = nodeRequire$5("node:sea");
|
|
183740
183845
|
} catch {
|
|
183741
|
-
cachedSea = null;
|
|
183846
|
+
cachedSea$1 = null;
|
|
183742
183847
|
}
|
|
183743
|
-
return cachedSea;
|
|
183848
|
+
return cachedSea$1;
|
|
183744
183849
|
}
|
|
183745
183850
|
/** Runtime SEA detection — true when running as a packaged native binary. */
|
|
183746
183851
|
function detectNativeInstall() {
|
|
183747
|
-
const sea = loadSeaModule$
|
|
183852
|
+
const sea = loadSeaModule$2();
|
|
183748
183853
|
if (sea === null) return false;
|
|
183749
183854
|
try {
|
|
183750
183855
|
return sea.isSea();
|
|
@@ -212875,10 +212980,6 @@ function sendMappedError$9(reply, requestId, err) {
|
|
|
212875
212980
|
* **Wire shape**: matches `metaResponseSchema` (REST.md §3.1) exactly. The
|
|
212876
212981
|
* envelope wrap is `okEnvelope(data, req.id)` — `req.id` is the bare 26-char
|
|
212877
212982
|
* ULID set by Fastify's `genReqId` via `resolveRequestId`.
|
|
212878
|
-
*
|
|
212879
|
-
* **Anti-corruption**: no SDK package import, no broker / bridge access. The
|
|
212880
|
-
* version source is the server's own `package.json` read via
|
|
212881
|
-
* `getServerVersion()` — no indirection through services or agent-core.
|
|
212882
212983
|
*/
|
|
212883
212984
|
function registerMetaRoute(app, opts) {
|
|
212884
212985
|
const data = Object.freeze({
|
|
@@ -214974,14 +215075,6 @@ function createServerServiceCollection(input) {
|
|
|
214974
215075
|
}
|
|
214975
215076
|
//#endregion
|
|
214976
215077
|
//#region ../../packages/server/src/version.ts
|
|
214977
|
-
/**
|
|
214978
|
-
* Read the server's own `package.json` version at boot. Mirrors
|
|
214979
|
-
* `packages/agent-core/src/version.ts:4-13` so the server's `/meta` can
|
|
214980
|
-
* report a real version without taking an SDK / agent-core export dep.
|
|
214981
|
-
*
|
|
214982
|
-
* Tries the bundled-at-build `package.json` next to `dist/` first; falls back
|
|
214983
|
-
* to `0.0.0` if the file is unreachable (e.g. tree-shaken bundle).
|
|
214984
|
-
*/
|
|
214985
215078
|
let cached;
|
|
214986
215079
|
function getServerVersion() {
|
|
214987
215080
|
if (cached !== void 0) return cached;
|
|
@@ -222918,7 +223011,7 @@ async function startServer(opts) {
|
|
|
222918
223011
|
app.setValidatorCompiler(() => () => true);
|
|
222919
223012
|
app.setSerializerCompiler(() => (data) => JSON.stringify(data));
|
|
222920
223013
|
installErrorHandler(app);
|
|
222921
|
-
const serverVersion = getServerVersion();
|
|
223014
|
+
const serverVersion = opts.coreProcessOptions?.identity?.version ?? getServerVersion();
|
|
222922
223015
|
async function registerOpenApi() {
|
|
222923
223016
|
const { default: swagger } = await Promise.resolve().then(() => /* @__PURE__ */ __toESM(require_swagger(), 1));
|
|
222924
223017
|
await app.register(swagger, {
|
|
@@ -223273,6 +223366,7 @@ function mapFsWatchError(err) {
|
|
|
223273
223366
|
msg: err instanceof Error ? err.message : "fs watch error"
|
|
223274
223367
|
};
|
|
223275
223368
|
}
|
|
223369
|
+
createRequire(import.meta.url);
|
|
223276
223370
|
//#endregion
|
|
223277
223371
|
//#region src/cli/sub/server/shared.ts
|
|
223278
223372
|
const DEFAULT_SERVER_HOST = "127.0.0.1";
|
|
@@ -223434,20 +223528,44 @@ async function resolveDaemonPort(host = DEFAULT_SERVER_HOST, preferred = DEFAULT
|
|
|
223434
223528
|
for (let candidate = preferred; candidate < preferred + 100 && candidate <= 65535; candidate++) if (await canBind(host, candidate)) return candidate;
|
|
223435
223529
|
return getFreePort(host);
|
|
223436
223530
|
}
|
|
223531
|
+
const nodeRequire$3 = createRequire(import.meta.url);
|
|
223532
|
+
let cachedSea;
|
|
223533
|
+
function loadSeaModule$1() {
|
|
223534
|
+
if (cachedSea !== void 0) return cachedSea;
|
|
223535
|
+
try {
|
|
223536
|
+
cachedSea = nodeRequire$3("node:sea");
|
|
223537
|
+
} catch {
|
|
223538
|
+
cachedSea = null;
|
|
223539
|
+
}
|
|
223540
|
+
return cachedSea;
|
|
223541
|
+
}
|
|
223542
|
+
/** True when running as a compiled single-executable (SEA / native) binary. */
|
|
223543
|
+
function detectSea() {
|
|
223544
|
+
const sea = loadSeaModule$1();
|
|
223545
|
+
if (sea === null) return false;
|
|
223546
|
+
try {
|
|
223547
|
+
return sea.isSea();
|
|
223548
|
+
} catch {
|
|
223549
|
+
return false;
|
|
223550
|
+
}
|
|
223551
|
+
}
|
|
223437
223552
|
/**
|
|
223438
223553
|
* Absolute path to the CLI entry that should be re-execed to run the daemon.
|
|
223439
223554
|
* Mirrors `resolveSupervisorProgram` in `packages/server/src/svc/program.ts`:
|
|
223440
|
-
* when the CLI is a compiled single binary, `argv[1]` is
|
|
223441
|
-
*
|
|
223555
|
+
* when the CLI is a compiled single binary, `argv[1]` is the invoked command
|
|
223556
|
+
* name (e.g. `kimi`) or the first user argument — never a script path — so we
|
|
223557
|
+
* must re-exec `process.execPath` itself.
|
|
223442
223558
|
*/
|
|
223443
|
-
function resolveDaemonProgram(argv = process.argv, cwd = process.cwd(), execPath = process.execPath) {
|
|
223559
|
+
function resolveDaemonProgram(argv = process.argv, cwd = process.cwd(), execPath = process.execPath, isSea = detectSea()) {
|
|
223560
|
+
if (isSea) return execPath;
|
|
223444
223561
|
const candidate = argv[1] === "server" ? execPath : argv[1] ?? execPath;
|
|
223445
223562
|
return isAbsolute$1(candidate) ? candidate : resolve$1(cwd, candidate);
|
|
223446
223563
|
}
|
|
223447
223564
|
function spawnDaemonChild(options) {
|
|
223448
223565
|
const program = resolveDaemonProgram();
|
|
223449
223566
|
const logPath = daemonLogPath();
|
|
223450
|
-
|
|
223567
|
+
const logDir = dirname$1(logPath);
|
|
223568
|
+
mkdirSync(logDir, { recursive: true });
|
|
223451
223569
|
const args = [
|
|
223452
223570
|
"server",
|
|
223453
223571
|
"run",
|
|
@@ -223461,14 +223579,21 @@ function spawnDaemonChild(options) {
|
|
|
223461
223579
|
if (options.idleGraceMs !== void 0) args.push("--idle-grace-ms", String(options.idleGraceMs));
|
|
223462
223580
|
const logFd = openSync(logPath, "a");
|
|
223463
223581
|
try {
|
|
223464
|
-
spawn$1(program, args, {
|
|
223582
|
+
const child = spawn$1(program, args, {
|
|
223465
223583
|
detached: true,
|
|
223584
|
+
cwd: logDir,
|
|
223466
223585
|
stdio: [
|
|
223467
223586
|
"ignore",
|
|
223468
223587
|
logFd,
|
|
223469
223588
|
logFd
|
|
223470
223589
|
]
|
|
223471
|
-
})
|
|
223590
|
+
});
|
|
223591
|
+
child.once("error", (error) => {
|
|
223592
|
+
try {
|
|
223593
|
+
appendFileSync(logPath, `[spawner] failed to launch daemon: ${error.message}\n`);
|
|
223594
|
+
} catch {}
|
|
223595
|
+
});
|
|
223596
|
+
child.unref();
|
|
223472
223597
|
} finally {
|
|
223473
223598
|
closeSync(logFd);
|
|
223474
223599
|
}
|
|
@@ -231323,7 +231448,7 @@ function wrapPlain(text, width) {
|
|
|
231323
231448
|
}
|
|
231324
231449
|
//#endregion
|
|
231325
231450
|
//#region src/tui/components/dialogs/goal-start-permission-prompt.ts
|
|
231326
|
-
const
|
|
231451
|
+
const GOAL_START_MANUAL_OPTIONS = [
|
|
231327
231452
|
{
|
|
231328
231453
|
value: "auto",
|
|
231329
231454
|
label: "Switch to Auto and start",
|
|
@@ -231345,7 +231470,7 @@ const MANUAL_OPTIONS = [
|
|
|
231345
231470
|
description: "Return to the input box with your goal command."
|
|
231346
231471
|
}
|
|
231347
231472
|
];
|
|
231348
|
-
const
|
|
231473
|
+
const GOAL_START_YOLO_OPTIONS = [
|
|
231349
231474
|
{
|
|
231350
231475
|
value: "auto",
|
|
231351
231476
|
label: "Switch to Auto and start",
|
|
@@ -231362,6 +231487,11 @@ const YOLO_OPTIONS = [
|
|
|
231362
231487
|
description: "Return to the input box with your goal command."
|
|
231363
231488
|
}
|
|
231364
231489
|
];
|
|
231490
|
+
function goalStartOptions(mode) {
|
|
231491
|
+
return mode === "yolo" ? GOAL_START_YOLO_OPTIONS : GOAL_START_MANUAL_OPTIONS;
|
|
231492
|
+
}
|
|
231493
|
+
const MANUAL_OPTIONS = GOAL_START_MANUAL_OPTIONS;
|
|
231494
|
+
const YOLO_OPTIONS = GOAL_START_YOLO_OPTIONS;
|
|
231365
231495
|
const MANUAL_NOTICE_LINES = [
|
|
231366
231496
|
"Manual mode asks you before Kimi Code runs commands, edits files, or takes other risky actions.",
|
|
231367
231497
|
"Manual mode is not suitable for unattended goal work.",
|
|
@@ -232479,7 +232609,6 @@ async function startGoal(host, parsed, options) {
|
|
|
232479
232609
|
return false;
|
|
232480
232610
|
}
|
|
232481
232611
|
if (options.beforeSend !== void 0 && !await options.beforeSend()) return false;
|
|
232482
|
-
host.track("goal_create", { replace: parsed.replace });
|
|
232483
232612
|
host.state.transcriptContainer.addChild(new GoalSetMessageComponent());
|
|
232484
232613
|
host.state.ui.requestRender();
|
|
232485
232614
|
if (options.sendInput !== void 0) options.sendInput(parsed.objective);
|
|
@@ -233338,7 +233467,7 @@ async function handlePluginsCommand(host, rawArgs) {
|
|
|
233338
233467
|
return;
|
|
233339
233468
|
}
|
|
233340
233469
|
await session.setPluginMcpServerEnabled(id, server, action === "enable");
|
|
233341
|
-
host.showStatus(`${action === "enable" ? "Enabled" : "Disabled"} MCP server ${server} for ${id}. Run /new to apply.`);
|
|
233470
|
+
host.showStatus(`${action === "enable" ? "Enabled" : "Disabled"} MCP server ${server} for ${id}. Run /new or /reload to apply.`);
|
|
233342
233471
|
return;
|
|
233343
233472
|
}
|
|
233344
233473
|
if (sub === "enable" || sub === "disable") {
|
|
@@ -233472,7 +233601,7 @@ async function applyPluginEnabled(host, id, enabled, showStatus = true) {
|
|
|
233472
233601
|
info = void 0;
|
|
233473
233602
|
}
|
|
233474
233603
|
const mcpHint = enabled && info !== void 0 && info.mcpServerCount > info.enabledMcpServerCount ? ` Some MCP servers are disabled; re-enable with /plugins mcp enable ${id} <server>.` : "";
|
|
233475
|
-
if (showStatus) host.showStatus(`${enabled ? "Enabled" : "Disabled"} ${id}. Run /new to apply.${mcpHint}`);
|
|
233604
|
+
if (showStatus) host.showStatus(`${enabled ? "Enabled" : "Disabled"} ${id}. Run /new or /reload to apply.${mcpHint}`);
|
|
233476
233605
|
const inlineMcpHint = mcpHint.length > 0 ? " · MCP servers disabled" : "";
|
|
233477
233606
|
return `${pluginInlineChangeHint()}${inlineMcpHint}`;
|
|
233478
233607
|
}
|
|
@@ -233570,8 +233699,8 @@ function showPluginInstallResult(host, beforeList, summary, options) {
|
|
|
233570
233699
|
const serverWord = summary.mcpServerCount === 1 ? "server" : "servers";
|
|
233571
233700
|
const mcpHint = summary.mcpServerCount > 0 ? ` Declares ${summary.mcpServerCount} MCP ${serverWord}; enabled by default and configurable from /plugins.` : "";
|
|
233572
233701
|
const action = describeInstallAction(previous, summary);
|
|
233573
|
-
host.showStatus(`${action} (${summary.id}).${mcpHint} Run /new to apply plugin changes.`);
|
|
233574
|
-
if (options?.successNotice === "marketplace") host.showNotice(`Installed or updated ${summary.displayName}`, `Marketplace install or update succeeded for ${summary.id}. Run /new to apply plugin changes.`);
|
|
233702
|
+
host.showStatus(`${action} (${summary.id}).${mcpHint} Run /new or /reload to apply plugin changes.`);
|
|
233703
|
+
if (options?.successNotice === "marketplace") host.showNotice(`Installed or updated ${summary.displayName}`, `Marketplace install or update succeeded for ${summary.id}. Run /new or /reload to apply plugin changes.`);
|
|
233575
233704
|
}
|
|
233576
233705
|
function describeInstallAction(previous, next) {
|
|
233577
233706
|
const sourceLabel = formatPluginSourceLabel(next);
|
|
@@ -233607,7 +233736,7 @@ function resolvePluginInstallSource(source, workDir) {
|
|
|
233607
233736
|
return isAbsolute$1(trimmed) ? trimmed : resolve$1(workDir, trimmed);
|
|
233608
233737
|
}
|
|
233609
233738
|
function pluginInlineChangeHint() {
|
|
233610
|
-
return "require run /new to apply";
|
|
233739
|
+
return "require run /new or /reload to apply";
|
|
233611
233740
|
}
|
|
233612
233741
|
//#endregion
|
|
233613
233742
|
//#region src/tui/components/dialogs/custom-registry-import.ts
|
|
@@ -240081,6 +240210,11 @@ async function runPrompt(opts, version, io = {}) {
|
|
|
240081
240210
|
success: false,
|
|
240082
240211
|
reason: outcome.reason
|
|
240083
240212
|
});
|
|
240213
|
+
},
|
|
240214
|
+
sessionStartedProperties: {
|
|
240215
|
+
yolo: false,
|
|
240216
|
+
plan: false,
|
|
240217
|
+
afk: true
|
|
240084
240218
|
}
|
|
240085
240219
|
});
|
|
240086
240220
|
log.info("kimi-code starting", {
|
|
@@ -240111,7 +240245,7 @@ async function runPrompt(opts, version, io = {}) {
|
|
|
240111
240245
|
await harness.ensureConfigFile();
|
|
240112
240246
|
const config = await harness.getConfig();
|
|
240113
240247
|
for (const warning of (await harness.getConfigDiagnostics()).warnings) stderr.write(`Warning: ${warning}\n`);
|
|
240114
|
-
const { session,
|
|
240248
|
+
const { session, restorePermission, telemetryModel, goalModel } = await resolvePromptSession(harness, opts, workDir, config.defaultModel, stderr, (restorePermission) => {
|
|
240115
240249
|
restorePromptSessionPermission = restorePermission;
|
|
240116
240250
|
});
|
|
240117
240251
|
restorePromptSessionPermission = restorePermission;
|
|
@@ -240124,12 +240258,6 @@ async function runPrompt(opts, version, io = {}) {
|
|
|
240124
240258
|
model: telemetryModel
|
|
240125
240259
|
});
|
|
240126
240260
|
setCrashPhase("runtime");
|
|
240127
|
-
withTelemetryContext({ sessionId: session.id }).track("started", {
|
|
240128
|
-
resumed,
|
|
240129
|
-
yolo: false,
|
|
240130
|
-
plan: false,
|
|
240131
|
-
afk: true
|
|
240132
|
-
});
|
|
240133
240261
|
const outputFormat = opts.outputFormat ?? "text";
|
|
240134
240262
|
const goalCreate = parseHeadlessGoalCreate(opts.prompt);
|
|
240135
240263
|
if (goalCreate !== void 0) await runHeadlessGoal(session, goalCreate, goalModel, outputFormat, stdout, stderr);
|
|
@@ -241550,6 +241678,7 @@ var ApprovalPanelComponent = class extends Container {
|
|
|
241550
241678
|
if (this.feedbackMode && option.requires_feedback === true && isSelected) lines.push(indent(this.renderInlineFeedbackLine(width - 2, labelWithNum)));
|
|
241551
241679
|
else if (isSelected) lines.push(indent(`${selectColorBold("▶")} ${selectColorBold(labelWithNum)}`));
|
|
241552
241680
|
else lines.push(indent(strong(` ${labelWithNum}`)));
|
|
241681
|
+
if (option.description !== void 0 && option.description.length > 0 && !(this.feedbackMode && option.requires_feedback === true && isSelected)) for (const descLine of wrapTextWithAnsi(option.description, Math.max(20, width - 7))) lines.push(indent(` ${dim(descLine)}`));
|
|
241553
241682
|
}
|
|
241554
241683
|
lines.push("");
|
|
241555
241684
|
if (this.feedbackMode) lines.push(indent(dim("Type feedback · ↵ submit.")));
|
|
@@ -248706,6 +248835,7 @@ function adaptPanelResponse(response) {
|
|
|
248706
248835
|
function describeApproval(display, action) {
|
|
248707
248836
|
switch (display.kind) {
|
|
248708
248837
|
case "plan_review": return "";
|
|
248838
|
+
case "goal_start": return "Start a goal?";
|
|
248709
248839
|
case "generic":
|
|
248710
248840
|
if (typeof display.detail === "string" && display.detail.length > 0) return display.detail;
|
|
248711
248841
|
return display.summary ?? action;
|
|
@@ -248826,6 +248956,14 @@ function adaptDisplay(display) {
|
|
|
248826
248956
|
text: `Stop task ${display.task_id ?? ""}: ${display.task_description ?? ""}`
|
|
248827
248957
|
}];
|
|
248828
248958
|
case "plan_review": return [];
|
|
248959
|
+
case "goal_start": {
|
|
248960
|
+
const lines = [`Start goal: ${display.objective}`];
|
|
248961
|
+
if (typeof display.completionCriterion === "string" && display.completionCriterion.length > 0) lines.push(`Done when: ${display.completionCriterion}`);
|
|
248962
|
+
return [{
|
|
248963
|
+
type: "brief",
|
|
248964
|
+
text: lines.join("\n")
|
|
248965
|
+
}];
|
|
248966
|
+
}
|
|
248829
248967
|
case "generic": return [];
|
|
248830
248968
|
case "todo_list": return [];
|
|
248831
248969
|
case "background_task": return [];
|
|
@@ -248834,8 +248972,22 @@ function adaptDisplay(display) {
|
|
|
248834
248972
|
}
|
|
248835
248973
|
function adaptChoices(toolName, display) {
|
|
248836
248974
|
if (toolName === "ExitPlanMode" || display.kind === "plan_review") return adaptPlanReviewChoices(display);
|
|
248975
|
+
if (display.kind === "goal_start") return adaptGoalStartChoices(display);
|
|
248837
248976
|
return DEFAULT_APPROVAL_CHOICES.map((choice) => cloneChoice(choice));
|
|
248838
248977
|
}
|
|
248978
|
+
function adaptGoalStartChoices(display) {
|
|
248979
|
+
return goalStartOptions(display.mode).map((option) => option.value === "cancel" ? {
|
|
248980
|
+
label: option.label,
|
|
248981
|
+
response: "cancelled",
|
|
248982
|
+
selected_label: "cancel",
|
|
248983
|
+
description: option.description
|
|
248984
|
+
} : {
|
|
248985
|
+
label: option.label,
|
|
248986
|
+
response: "approved",
|
|
248987
|
+
selected_label: option.value,
|
|
248988
|
+
description: option.description
|
|
248989
|
+
});
|
|
248990
|
+
}
|
|
248839
248991
|
function adaptPlanReviewChoices(display) {
|
|
248840
248992
|
return [...display.kind === "plan_review" && display.options !== void 0 && display.options.length >= 2 ? display.options.map((option) => ({
|
|
248841
248993
|
label: option.label,
|
|
@@ -251611,7 +251763,7 @@ var KimiTUI = class {
|
|
|
251611
251763
|
}
|
|
251612
251764
|
}
|
|
251613
251765
|
appendApprovalTranscriptEntry(request, response) {
|
|
251614
|
-
if (request.toolName === "ExitPlanMode" || request.display.kind === "plan_review") return;
|
|
251766
|
+
if (request.toolName === "ExitPlanMode" || request.display.kind === "plan_review" || request.display.kind === "goal_start") return;
|
|
251615
251767
|
const parts = [];
|
|
251616
251768
|
switch (response.decision) {
|
|
251617
251769
|
case "approved":
|
|
@@ -252109,6 +252261,12 @@ async function runShell(opts, version, runOptions = {}) {
|
|
|
252109
252261
|
success: false,
|
|
252110
252262
|
reason: outcome.reason
|
|
252111
252263
|
});
|
|
252264
|
+
},
|
|
252265
|
+
sessionStartedProperties: {
|
|
252266
|
+
yolo: opts.yolo,
|
|
252267
|
+
auto: opts.auto,
|
|
252268
|
+
plan: opts.plan,
|
|
252269
|
+
afk: false
|
|
252112
252270
|
}
|
|
252113
252271
|
});
|
|
252114
252272
|
log.info("kimi-code starting", {
|
|
@@ -252149,7 +252307,6 @@ async function runShell(opts, version, runOptions = {}) {
|
|
|
252149
252307
|
uiMode: CLI_UI_MODE
|
|
252150
252308
|
});
|
|
252151
252309
|
setCrashPhase("runtime");
|
|
252152
|
-
const resumed = opts.continue || opts.session !== void 0;
|
|
252153
252310
|
const trackLifecycleForSession = (sessionId, event, properties) => {
|
|
252154
252311
|
if (sessionId.length === 0) {
|
|
252155
252312
|
harness.track(event, properties);
|
|
@@ -252181,13 +252338,6 @@ async function runShell(opts, version, runOptions = {}) {
|
|
|
252181
252338
|
const initStartedAt = Date.now();
|
|
252182
252339
|
await tui.start();
|
|
252183
252340
|
const initMs = Date.now() - initStartedAt;
|
|
252184
|
-
trackLifecycle("started", {
|
|
252185
|
-
resumed,
|
|
252186
|
-
yolo: opts.yolo,
|
|
252187
|
-
auto: opts.auto,
|
|
252188
|
-
plan: opts.plan,
|
|
252189
|
-
afk: false
|
|
252190
|
-
});
|
|
252191
252341
|
const startupSessionId = tui.getCurrentSessionId();
|
|
252192
252342
|
const mcpMs = await tui.getStartupMcpMs();
|
|
252193
252343
|
trackLifecycleForSession(startupSessionId, "startup_perf", {
|