@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.
Files changed (68) hide show
  1. package/dist/main.mjs +281 -131
  2. package/dist-web/assets/{CodeBlockNode-xopu-OEb.js → CodeBlockNode-BBTPBNlr.js} +1 -1
  3. 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
  4. package/dist-web/assets/{Tooltip-DzPFYPha.js → Tooltip-BEPNqHjy.js} +1 -1
  5. package/dist-web/assets/{arc-D9ISmG8O.js → arc-DsEMn4wL.js} +1 -1
  6. package/dist-web/assets/{architectureDiagram-3BPJPVTR-Bde5KvUn.js → architectureDiagram-3BPJPVTR-CRMgytTq.js} +1 -1
  7. package/dist-web/assets/{blockDiagram-GPEHLZMM-JCl1lMhx.js → blockDiagram-GPEHLZMM-DZjTWP93.js} +1 -1
  8. package/dist-web/assets/{c4Diagram-AAUBKEIU-CbJhvcRt.js → c4Diagram-AAUBKEIU-XN05Flkv.js} +1 -1
  9. package/dist-web/assets/channel-Dyiajwlv.js +1 -0
  10. package/dist-web/assets/{chunk-2J33WTMH-L9nQnfKd.js → chunk-2J33WTMH-DB2YVfPY.js} +1 -1
  11. package/dist-web/assets/{chunk-4BX2VUAB-zohve9Ok.js → chunk-4BX2VUAB-Bed6jJZo.js} +1 -1
  12. package/dist-web/assets/{chunk-55IACEB6-DR3E48TL.js → chunk-55IACEB6-CHhaYL59.js} +1 -1
  13. package/dist-web/assets/{chunk-727SXJPM-C18LQHi4.js → chunk-727SXJPM-BOJiU2Eb.js} +1 -1
  14. package/dist-web/assets/{chunk-AQP2D5EJ-BsjNQvhe.js → chunk-AQP2D5EJ-C8k6MI_Z.js} +1 -1
  15. package/dist-web/assets/{chunk-FMBD7UC4-774mj8wI.js → chunk-FMBD7UC4-C-MvWtbr.js} +1 -1
  16. package/dist-web/assets/{chunk-ND2GUHAM-BahAcenP.js → chunk-ND2GUHAM-CEqD9cw0.js} +1 -1
  17. package/dist-web/assets/{chunk-QZHKN3VN-Dc2ML4_y.js → chunk-QZHKN3VN-BcJHlqi-.js} +1 -1
  18. package/dist-web/assets/classDiagram-4FO5ZUOK-Cq15LdMD.js +1 -0
  19. package/dist-web/assets/classDiagram-v2-Q7XG4LA2-Cq15LdMD.js +1 -0
  20. package/dist-web/assets/{cose-bilkent-S5V4N54A-BHhvV2M3.js → cose-bilkent-S5V4N54A-DJ8zjD1S.js} +1 -1
  21. package/dist-web/assets/{dagre-BM42HDAG-CCUkqn3c.js → dagre-BM42HDAG-BrTwtLB1.js} +1 -1
  22. package/dist-web/assets/{diagram-2AECGRRQ-CJAIuD9v.js → diagram-2AECGRRQ-Y7FcZPzP.js} +1 -1
  23. package/dist-web/assets/{diagram-5GNKFQAL-CIzOyklY.js → diagram-5GNKFQAL-DKHdXG1y.js} +1 -1
  24. package/dist-web/assets/{diagram-KO2AKTUF-Dy0TSkF9.js → diagram-KO2AKTUF-VCCXGLOR.js} +1 -1
  25. package/dist-web/assets/{diagram-LMA3HP47-D0VZv9QJ.js → diagram-LMA3HP47-CYLE3Fzr.js} +1 -1
  26. package/dist-web/assets/{diagram-OG6HWLK6-BOmRuoa3.js → diagram-OG6HWLK6-DoP7AdmG.js} +1 -1
  27. package/dist-web/assets/{erDiagram-TEJ5UH35-XD82Xp5G.js → erDiagram-TEJ5UH35-BMcb04Oc.js} +1 -1
  28. package/dist-web/assets/{flowDiagram-I6XJVG4X-Cjx82rYf.js → flowDiagram-I6XJVG4X-C6UZeyqx.js} +1 -1
  29. package/dist-web/assets/{ganttDiagram-6RSMTGT7-uApHfVFI.js → ganttDiagram-6RSMTGT7-ejmlce9Q.js} +1 -1
  30. package/dist-web/assets/{gitGraphDiagram-PVQCEYII-pCJa6Sqh.js → gitGraphDiagram-PVQCEYII-0oVWkTiE.js} +1 -1
  31. package/dist-web/assets/{index-ruKp3ITH.js → index-Bj6xsK-Y.js} +1 -1
  32. package/dist-web/assets/index-CNwU-esk.js +268 -0
  33. package/dist-web/assets/index-D6vWyrW-.css +1 -0
  34. package/dist-web/assets/{index-DSJEhgK2.js → index-DrcjPgrD.js} +3 -3
  35. package/dist-web/assets/{index10-BU_fP3cF.js → index10-BIb6yLoQ.js} +1 -1
  36. package/dist-web/assets/{index11-4vKmecHt.js → index11-BcLwmlar.js} +2 -2
  37. package/dist-web/assets/{index5-B_Zm1CXv.js → index5-BOBUDie_.js} +1 -1
  38. package/dist-web/assets/{index6-Bcj2CUc2.js → index6-B1AecMuA.js} +1 -1
  39. package/dist-web/assets/{index7-CktYDBgt.js → index7-B1vZsaF7.js} +1 -1
  40. package/dist-web/assets/{index8-Dv0bVWi6.js → index8-jsIBLdbS.js} +2 -2
  41. package/dist-web/assets/{infoDiagram-5YYISTIA-ntWeW9KZ.js → infoDiagram-5YYISTIA-C3E_KFZS.js} +1 -1
  42. package/dist-web/assets/{ishikawaDiagram-YF4QCWOH-LIB-i9cU.js → ishikawaDiagram-YF4QCWOH-DTMAsXar.js} +1 -1
  43. package/dist-web/assets/{journeyDiagram-JHISSGLW-BlfBWGGp.js → journeyDiagram-JHISSGLW-DlMqknWB.js} +1 -1
  44. package/dist-web/assets/{kanban-definition-UN3LZRKU-D5dIR3XR.js → kanban-definition-UN3LZRKU-D8W-yZwQ.js} +1 -1
  45. package/dist-web/assets/{linear-DModnwwD.js → linear-CXvIR_Cz.js} +1 -1
  46. package/dist-web/assets/{mermaid.core-vCZSrzF3.js → mermaid.core-Cm0scdl_.js} +4 -4
  47. package/dist-web/assets/{mindmap-definition-RKZ34NQL-DtXX70f6.js → mindmap-definition-RKZ34NQL-BTR5HSvV.js} +1 -1
  48. package/dist-web/assets/{pieDiagram-4H26LBE5-BTWE5xhz.js → pieDiagram-4H26LBE5-DgBdBron.js} +1 -1
  49. package/dist-web/assets/{quadrantDiagram-W4KKPZXB-BIf4h40K.js → quadrantDiagram-W4KKPZXB-DlJDz6Co.js} +1 -1
  50. package/dist-web/assets/{requirementDiagram-4Y6WPE33-DYIJe9Dp.js → requirementDiagram-4Y6WPE33-BILYgyLr.js} +1 -1
  51. package/dist-web/assets/{sankeyDiagram-5OEKKPKP-C6fQmYW1.js → sankeyDiagram-5OEKKPKP-CsB0bfUt.js} +1 -1
  52. package/dist-web/assets/{sequenceDiagram-3UESZ5HK-j9sFp20c.js → sequenceDiagram-3UESZ5HK-B6sFCfAl.js} +1 -1
  53. package/dist-web/assets/{stateDiagram-AJRCARHV-BmdayxXt.js → stateDiagram-AJRCARHV-CR0aRL4-.js} +1 -1
  54. package/dist-web/assets/stateDiagram-v2-BHNVJYJU-UfuPGBrg.js +1 -0
  55. package/dist-web/assets/{timeline-definition-PNZ67QCA-CoPa3Alw.js → timeline-definition-PNZ67QCA-Bfmc75An.js} +1 -1
  56. package/dist-web/assets/{vennDiagram-CIIHVFJN-C1znvnC_.js → vennDiagram-CIIHVFJN-bwUT2S9H.js} +1 -1
  57. package/dist-web/assets/{vue.runtime.esm-bundler-C3-MzG4F.js → vue.runtime.esm-bundler-BJNZCSc8.js} +1 -1
  58. package/dist-web/assets/{wardley-L42UT6IY-CRUU46rw.js → wardley-L42UT6IY-grqTsjin.js} +1 -1
  59. package/dist-web/assets/{wardleyDiagram-YWT4CUSO-u3Px8OI4.js → wardleyDiagram-YWT4CUSO-By-aofC4.js} +1 -1
  60. package/dist-web/assets/{xychartDiagram-2RQKCTM6-CCMgiVYB.js → xychartDiagram-2RQKCTM6-BxqaMGkt.js} +1 -1
  61. package/dist-web/index.html +2 -2
  62. package/package.json +3 -3
  63. package/dist-web/assets/channel-Dx9cvqoI.js +0 -1
  64. package/dist-web/assets/classDiagram-4FO5ZUOK-CQBVgO9P.js +0 -1
  65. package/dist-web/assets/classDiagram-v2-Q7XG4LA2-CQBVgO9P.js +0 -1
  66. package/dist-web/assets/index-Bm5hIhdQ.css +0 -1
  67. package/dist-web/assets/index-Cr6PBwa_.js +0 -268
  68. 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$3 = "builtin://custom-theme";
74222
- const parsed$3 = parseSkillText({
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$3,
74230
- path: PSEUDO_PATH$3,
74231
- dir: PSEUDO_PATH$3,
74263
+ ...parsed$4,
74264
+ path: PSEUDO_PATH$4,
74265
+ dir: PSEUDO_PATH$4,
74232
74266
  metadata: {
74233
- ...parsed$3.metadata,
74234
- type: parsed$3.metadata.type ?? "inline",
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$2 = "builtin://import-from-cc-codex";
74244
- const parsed$2 = parseSkillText({
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$2,
74252
- path: PSEUDO_PATH$2,
74253
- dir: PSEUDO_PATH$2,
74285
+ ...parsed$3,
74286
+ path: PSEUDO_PATH$3,
74287
+ dir: PSEUDO_PATH$3,
74254
74288
  metadata: {
74255
- ...parsed$2.metadata,
74256
- type: parsed$2.metadata.type ?? "inline",
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$1 = "builtin://mcp-config";
74266
- const parsed$1 = parseSkillText({
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$1,
74274
- path: PSEUDO_PATH$1,
74275
- dir: PSEUDO_PATH$1,
74307
+ ...parsed$2,
74308
+ path: PSEUDO_PATH$2,
74309
+ dir: PSEUDO_PATH$2,
74276
74310
  metadata: {
74277
- ...parsed$1.metadata,
74278
- type: parsed$1.metadata.type ?? "inline",
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
- return new SubagentBatch(this, tasks).run();
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
- const initialGoalStatus = this.agent.goal.getGoal().goal?.status;
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
- const resumedFromPausedOrBlocked = initialGoalStatus === "paused" || initialGoalStatus === "blocked";
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), countSessionDirs(join$1(this.sessionsDir, workspaceId))]);
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 countSessionDirs(dir) {
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) if (d.isDirectory()) count += 1;
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 `trackSessionStarted` uses. The wrapper
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$3 = createRequire(import.meta.url);
183735
- let cachedSea;
183736
- function loadSeaModule$1() {
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$3("node:sea");
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$1();
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 literally `server`
223441
- * and we must fall back to `process.execPath`.
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
- mkdirSync(dirname$1(logPath), { recursive: true });
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
- }).unref();
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 MANUAL_OPTIONS = [
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 YOLO_OPTIONS = [
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, resumed, restorePermission, telemetryModel, goalModel } = await resolvePromptSession(harness, opts, workDir, config.defaultModel, stderr, (restorePermission) => {
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", {