@botiverse/kimi-code-sdk 0.17.1 → 0.18.0-botiverse.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/NOTICE.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # NOTICE
2
2
 
3
3
  @botiverse/kimi-code-sdk is a repackage of the built **@moonshot-ai/kimi-code-sdk** node-sdk
4
- from [MoonshotAI/kimi-code](https://github.com/MoonshotAI/kimi-code) at `@moonshot-ai/kimi-code@0.17.1`, distributed under upstream's MIT License (see LICENSE). Sibling packages are bundled into `dist`.
4
+ from [MoonshotAI/kimi-code](https://github.com/MoonshotAI/kimi-code) at `@moonshot-ai/kimi-code@0.18.0`, distributed under upstream's MIT License (see LICENSE). Sibling packages are bundled into `dist`.
5
5
  Mirror + provenance: https://github.com/botiverse/kimi-code-sdk
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @botiverse/kimi-code-sdk
2
2
 
3
- Built repackage of `@moonshot-ai/kimi-code-sdk` (kimi-code @moonshot-ai/kimi-code@0.17.1) for Slock/Botiverse.
3
+ Built repackage of `@moonshot-ai/kimi-code-sdk` (kimi-code @moonshot-ai/kimi-code@0.18.0) for Slock/Botiverse.
4
4
  Read-only mirror + release notes: https://github.com/botiverse/kimi-code-sdk
5
5
 
6
6
  > Not affiliated with Moonshot AI. MIT (see LICENSE).
package/dist/index.d.mts CHANGED
@@ -1124,6 +1124,7 @@ export declare interface CreateSessionOptions {
1124
1124
  readonly metadata?: JsonObject | undefined;
1125
1125
  readonly kaos?: Kaos | undefined;
1126
1126
  readonly persistenceKaos?: Kaos | undefined;
1127
+ readonly sessionStartedProperties?: TelemetryProperties;
1127
1128
  }
1128
1129
 
1129
1130
  declare interface CreateSessionPayload {
@@ -3448,6 +3449,7 @@ export declare class KimiHarness {
3448
3449
  private readonly activeSessions;
3449
3450
  private readonly ensureConfigFileImpl;
3450
3451
  private readonly closeImpl;
3452
+ private readonly sessionStartedProperties;
3451
3453
  constructor(rpc: SDKRpcClientBase, options: KimiHarnessRuntimeOptions);
3452
3454
  get sessions(): ReadonlyMap<string, Session>;
3453
3455
  get interactiveAgentId(): string;
@@ -3484,6 +3486,7 @@ export declare interface KimiHarnessOptions {
3484
3486
  readonly skillDirs?: readonly string[];
3485
3487
  readonly telemetry?: TelemetryClient | undefined;
3486
3488
  readonly onOAuthRefresh?: ((outcome: OAuthRefreshOutcome) => void) | undefined;
3489
+ readonly sessionStartedProperties?: TelemetryProperties;
3487
3490
  }
3488
3491
 
3489
3492
  export declare interface KimiHarnessRuntimeOptions {
@@ -3495,6 +3498,7 @@ export declare interface KimiHarnessRuntimeOptions {
3495
3498
  readonly telemetry: TelemetryClient;
3496
3499
  readonly ensureConfigFile: () => Promise<void>;
3497
3500
  readonly onClose: () => void | Promise<void>;
3501
+ readonly sessionStartedProperties?: TelemetryProperties;
3498
3502
  }
3499
3503
 
3500
3504
  export declare interface KimiHostIdentity {
@@ -4929,6 +4933,7 @@ export declare interface ResumeSessionInput {
4929
4933
  readonly id: string;
4930
4934
  readonly kaos?: Kaos | undefined;
4931
4935
  readonly persistenceKaos?: Kaos | undefined;
4936
+ readonly sessionStartedProperties?: TelemetryProperties;
4932
4937
  }
4933
4938
 
4934
4939
  declare interface ResumeSessionPayload {
@@ -6453,4 +6458,32 @@ declare type WithSessionId<T> = WithExtraPayload<T, {
6453
6458
  readonly sessionId: string;
6454
6459
  }>;
6455
6460
 
6456
- export { }
6461
+ export { }
6462
+
6463
+ // Botiverse mirror surface extension — see scripts/repackage-sdk.mjs.
6464
+ // Minimal type declaration; runtime implementation is bundled in dist/index.mjs.
6465
+ declare class LocalKaos implements Kaos {
6466
+ static create(): Promise<LocalKaos>;
6467
+ readonly name: string;
6468
+ readonly osEnv: Kaos['osEnv'];
6469
+ pathClass(): 'posix' | 'win32';
6470
+ normpath(path: string): string;
6471
+ gethome(): string;
6472
+ getcwd(): string;
6473
+ chdir(path: string): Promise<void>;
6474
+ withCwd(cwd: string): LocalKaos;
6475
+ withEnv(env: Record<string, string>): LocalKaos;
6476
+ stat: Kaos['stat'];
6477
+ iterdir: Kaos['iterdir'];
6478
+ glob: Kaos['glob'];
6479
+ readBytes: Kaos['readBytes'];
6480
+ readText: Kaos['readText'];
6481
+ readLines: Kaos['readLines'];
6482
+ writeBytes: Kaos['writeBytes'];
6483
+ writeText: Kaos['writeText'];
6484
+ mkdir: Kaos['mkdir'];
6485
+ exec: Kaos['exec'];
6486
+ execWithEnv: Kaos['execWithEnv'];
6487
+ }
6488
+ export { LocalKaos };
6489
+ export type { Kaos };
package/dist/index.mjs CHANGED
@@ -60784,6 +60784,39 @@ var GitCwdWriteApprovePermissionPolicy = class {
60784
60784
  }
60785
60785
  };
60786
60786
  //#endregion
60787
+ //#region ../agent-core/src/agent/permission/policies/goal-start-review-ask.ts
60788
+ /**
60789
+ * Starting a goal turns the agent loose on autonomous, multi-turn work, so a
60790
+ * model-issued `CreateGoal` is confirmed with the same menu the `/goal` command
60791
+ * shows: choose the permission mode to run the goal under, or decline. The
60792
+ * chosen mode is applied before the goal is created so the run proceeds under
60793
+ * it. `auto` mode auto-approves the goal upstream and never reaches here.
60794
+ */
60795
+ var GoalStartReviewAskPermissionPolicy = class {
60796
+ agent;
60797
+ name = "goal-start-review-ask";
60798
+ constructor(agent) {
60799
+ this.agent = agent;
60800
+ }
60801
+ evaluate(context) {
60802
+ if (context.toolCall.name !== "CreateGoal") return;
60803
+ if (this.agent.permission.mode === "auto") return;
60804
+ if (context.execution.display?.kind !== "goal_start") return;
60805
+ return {
60806
+ kind: "ask",
60807
+ resolveApproval: (result) => this.resolveGoalStart(result)
60808
+ };
60809
+ }
60810
+ resolveGoalStart(result) {
60811
+ if (result.decision !== "approved") return void 0;
60812
+ const mode = toPermissionMode(result.selectedLabel);
60813
+ if (mode !== void 0 && mode !== this.agent.permission.mode) this.agent.permission.setMode(mode);
60814
+ }
60815
+ };
60816
+ function toPermissionMode(label) {
60817
+ if (label === "auto" || label === "yolo" || label === "manual") return label;
60818
+ }
60819
+ //#endregion
60787
60820
  //#region ../agent-core/src/agent/permission/policies/plan-mode-guard-deny.ts
60788
60821
  var PlanModeGuardDenyPermissionPolicy = class {
60789
60822
  agent;
@@ -62955,6 +62988,7 @@ function createPermissionDecisionPolicies(agent) {
62955
62988
  new UserConfiguredAskPermissionPolicy(agent),
62956
62989
  new UserConfiguredAllowPermissionPolicy(agent),
62957
62990
  new ExitPlanModeReviewAskPermissionPolicy(agent),
62991
+ new GoalStartReviewAskPermissionPolicy(agent),
62958
62992
  new PlanModeToolApprovePermissionPolicy(agent),
62959
62993
  new SensitiveFileAccessAskPermissionPolicy(),
62960
62994
  new GitControlPathAccessAskPermissionPolicy(agent),
@@ -67980,20 +68014,20 @@ function isRecord$2(value) {
67980
68014
  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";
67981
68015
  //#endregion
67982
68016
  //#region ../agent-core/src/skill/builtin/custom-theme.ts
67983
- const PSEUDO_PATH$3 = "builtin://custom-theme";
67984
- const parsed$3 = parseSkillText({
68017
+ const PSEUDO_PATH$4 = "builtin://custom-theme";
68018
+ const parsed$4 = parseSkillText({
67985
68019
  skillMdPath: "/builtin/skills/custom-theme.md",
67986
68020
  skillDirName: "custom-theme",
67987
68021
  source: "builtin",
67988
68022
  text: custom_theme_default
67989
68023
  });
67990
68024
  const CUSTOM_THEME_SKILL = {
67991
- ...parsed$3,
67992
- path: PSEUDO_PATH$3,
67993
- dir: PSEUDO_PATH$3,
68025
+ ...parsed$4,
68026
+ path: PSEUDO_PATH$4,
68027
+ dir: PSEUDO_PATH$4,
67994
68028
  metadata: {
67995
- ...parsed$3.metadata,
67996
- type: parsed$3.metadata.type ?? "inline",
68029
+ ...parsed$4.metadata,
68030
+ type: parsed$4.metadata.type ?? "inline",
67997
68031
  disableModelInvocation: true
67998
68032
  }
67999
68033
  };
@@ -68002,20 +68036,20 @@ const CUSTOM_THEME_SKILL = {
68002
68036
  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";
68003
68037
  //#endregion
68004
68038
  //#region ../agent-core/src/skill/builtin/import-from-cc-codex.ts
68005
- const PSEUDO_PATH$2 = "builtin://import-from-cc-codex";
68006
- const parsed$2 = parseSkillText({
68039
+ const PSEUDO_PATH$3 = "builtin://import-from-cc-codex";
68040
+ const parsed$3 = parseSkillText({
68007
68041
  skillMdPath: "/builtin/skills/import-from-cc-codex.md",
68008
68042
  skillDirName: "import-from-cc-codex",
68009
68043
  source: "builtin",
68010
68044
  text: import_from_cc_codex_default
68011
68045
  });
68012
68046
  const IMPORT_FROM_CC_CODEX_SKILL = {
68013
- ...parsed$2,
68014
- path: PSEUDO_PATH$2,
68015
- dir: PSEUDO_PATH$2,
68047
+ ...parsed$3,
68048
+ path: PSEUDO_PATH$3,
68049
+ dir: PSEUDO_PATH$3,
68016
68050
  metadata: {
68017
- ...parsed$2.metadata,
68018
- type: parsed$2.metadata.type ?? "inline",
68051
+ ...parsed$3.metadata,
68052
+ type: parsed$3.metadata.type ?? "inline",
68019
68053
  disableModelInvocation: true
68020
68054
  }
68021
68055
  };
@@ -68024,20 +68058,20 @@ const IMPORT_FROM_CC_CODEX_SKILL = {
68024
68058
  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";
68025
68059
  //#endregion
68026
68060
  //#region ../agent-core/src/skill/builtin/mcp-config.ts
68027
- const PSEUDO_PATH$1 = "builtin://mcp-config";
68028
- const parsed$1 = parseSkillText({
68061
+ const PSEUDO_PATH$2 = "builtin://mcp-config";
68062
+ const parsed$2 = parseSkillText({
68029
68063
  skillMdPath: "/builtin/skills/mcp-config.md",
68030
68064
  skillDirName: "mcp-config",
68031
68065
  source: "builtin",
68032
68066
  text: mcp_config_default
68033
68067
  });
68034
68068
  const MCP_CONFIG_SKILL = {
68035
- ...parsed$1,
68036
- path: PSEUDO_PATH$1,
68037
- dir: PSEUDO_PATH$1,
68069
+ ...parsed$2,
68070
+ path: PSEUDO_PATH$2,
68071
+ dir: PSEUDO_PATH$2,
68038
68072
  metadata: {
68039
- ...parsed$1.metadata,
68040
- type: parsed$1.metadata.type ?? "inline",
68073
+ ...parsed$2.metadata,
68074
+ type: parsed$2.metadata.type ?? "inline",
68041
68075
  disableModelInvocation: true
68042
68076
  }
68043
68077
  };
@@ -68088,14 +68122,35 @@ const SUB_SKILL_CONSOLIDATE = makeBuiltin(SKILL_default$2, "sub-skill.consolidat
68088
68122
  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";
68089
68123
  //#endregion
68090
68124
  //#region ../agent-core/src/skill/builtin/update-config.ts
68091
- const PSEUDO_PATH = "builtin://update-config";
68092
- const parsed = parseSkillText({
68125
+ const PSEUDO_PATH$1 = "builtin://update-config";
68126
+ const parsed$1 = parseSkillText({
68093
68127
  skillMdPath: "/builtin/skills/update-config.md",
68094
68128
  skillDirName: "update-config",
68095
68129
  source: "builtin",
68096
68130
  text: update_config_default
68097
68131
  });
68098
68132
  const UPDATE_CONFIG_SKILL = {
68133
+ ...parsed$1,
68134
+ path: PSEUDO_PATH$1,
68135
+ dir: PSEUDO_PATH$1,
68136
+ metadata: {
68137
+ ...parsed$1.metadata,
68138
+ type: parsed$1.metadata.type ?? "inline"
68139
+ }
68140
+ };
68141
+ //#endregion
68142
+ //#region ../agent-core/src/skill/builtin/write-goal.md?raw
68143
+ 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";
68144
+ //#endregion
68145
+ //#region ../agent-core/src/skill/builtin/write-goal.ts
68146
+ const PSEUDO_PATH = "builtin://write-goal";
68147
+ const parsed = parseSkillText({
68148
+ skillMdPath: "/builtin/skills/write-goal.md",
68149
+ skillDirName: "write-goal",
68150
+ source: "builtin",
68151
+ text: write_goal_default
68152
+ });
68153
+ const WRITE_GOAL_SKILL = {
68099
68154
  ...parsed,
68100
68155
  path: PSEUDO_PATH,
68101
68156
  dir: PSEUDO_PATH,
@@ -68111,6 +68166,7 @@ function registerBuiltinSkills(registry) {
68111
68166
  registry.registerBuiltinSkill(IMPORT_FROM_CC_CODEX_SKILL);
68112
68167
  registry.registerBuiltinSkill(UPDATE_CONFIG_SKILL);
68113
68168
  registry.registerBuiltinSkill(CUSTOM_THEME_SKILL);
68169
+ registry.registerBuiltinSkill(WRITE_GOAL_SKILL);
68114
68170
  registry.registerBuiltinSkill(SUB_SKILL_PARENT);
68115
68171
  registry.registerBuiltinSkill(SUB_SKILL_REVIEW);
68116
68172
  registry.registerBuiltinSkill(SUB_SKILL_CONSOLIDATE);
@@ -77121,6 +77177,12 @@ const ToolInputDisplaySchema = z.discriminatedUnion("kind", [
77121
77177
  description: z.string()
77122
77178
  })).readonly().optional()
77123
77179
  }),
77180
+ z.object({
77181
+ kind: z.literal("goal_start"),
77182
+ objective: z.string(),
77183
+ completionCriterion: z.string().optional(),
77184
+ mode: z.enum(["manual", "yolo"])
77185
+ }),
77124
77186
  z.object({
77125
77187
  kind: z.literal("generic"),
77126
77188
  summary: z.string(),
@@ -77456,6 +77518,8 @@ const sessionSchema = z.object({
77456
77518
  status: sessionStatusSchema,
77457
77519
  archived: z.boolean().optional(),
77458
77520
  current_prompt_id: z.string().min(1).optional(),
77521
+ /** Text of the most recent user prompt, for search/preview. Absent for empty sessions. */
77522
+ last_prompt: z.string().optional(),
77459
77523
  metadata: sessionMetadataSchema,
77460
77524
  agent_config: sessionAgentConfigSchema,
77461
77525
  usage: sessionUsageSchema,
@@ -84416,6 +84480,7 @@ const RATE_LIMIT_RETRY_FACTOR = 2;
84416
84480
  const RATE_LIMIT_CAPACITY_SHRINK_INTERVAL_MS = 2e3;
84417
84481
  const RATE_LIMIT_CAPACITY_RECOVERY_INTERVAL_MS = 180 * 1e3;
84418
84482
  const RATE_LIMIT_SUSPENDED_REASON = "Provider rate limit; subagent requeued for retry.";
84483
+ const AGENT_SWARM_MAX_CONCURRENCY_ENV = "KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY";
84419
84484
  var SubagentBatch = class {
84420
84485
  launcher;
84421
84486
  states;
@@ -84425,6 +84490,7 @@ var SubagentBatch = class {
84425
84490
  controller = new AbortController();
84426
84491
  batchSignal;
84427
84492
  batchAbortListener;
84493
+ maxConcurrency;
84428
84494
  normalLaunchCount = 0;
84429
84495
  normalLaunchTimer;
84430
84496
  rateLimitLaunchTimer;
@@ -84440,8 +84506,9 @@ var SubagentBatch = class {
84440
84506
  lastCapacityRecoveryAt;
84441
84507
  globalRetryIntervalMs = RATE_LIMIT_RETRY_BASE_MS;
84442
84508
  nextRateLimitLaunchAt = 0;
84443
- constructor(launcher, tasks) {
84509
+ constructor(launcher, tasks, options = {}) {
84444
84510
  this.launcher = launcher;
84511
+ this.maxConcurrency = options.maxConcurrency;
84445
84512
  this.states = tasks.map((task, index) => ({
84446
84513
  index,
84447
84514
  task,
@@ -84484,19 +84551,23 @@ var SubagentBatch = class {
84484
84551
  else this.scheduleNormalLaunch();
84485
84552
  }
84486
84553
  scheduleNormalLaunch() {
84487
- while (this.normalLaunchCount < INITIAL_LAUNCH_LIMIT && this.pending.length > 0 && !this.rateLimitMode) {
84554
+ while (this.normalLaunchCount < INITIAL_LAUNCH_LIMIT && this.pending.length > 0 && !this.rateLimitMode && !this.isAtConcurrencyLimit()) {
84488
84555
  this.startAttempt(this.pending.shift());
84489
84556
  this.normalLaunchCount += 1;
84490
84557
  }
84491
- if (this.pending.length === 0 || this.rateLimitMode || this.normalLaunchTimer !== void 0) return;
84558
+ if (this.pending.length === 0 || this.rateLimitMode || this.normalLaunchTimer !== void 0 || this.isAtConcurrencyLimit()) return;
84492
84559
  this.normalLaunchTimer = setTimeout(() => {
84493
84560
  this.normalLaunchTimer = void 0;
84494
84561
  if (this.finished || this.rateLimitMode || this.pending.length === 0) return;
84562
+ if (this.isAtConcurrencyLimit()) return;
84495
84563
  this.startAttempt(this.pending.shift());
84496
84564
  this.normalLaunchCount += 1;
84497
84565
  this.schedule();
84498
84566
  }, INITIAL_LAUNCH_INTERVAL_MS);
84499
84567
  }
84568
+ isAtConcurrencyLimit() {
84569
+ return this.maxConcurrency !== void 0 && this.active.size >= this.maxConcurrency;
84570
+ }
84500
84571
  scheduleRateLimitLaunch() {
84501
84572
  this.clearRateLimitTimer();
84502
84573
  if (this.pending.length === 0) return;
@@ -84792,6 +84863,20 @@ var SubagentBatch = class {
84792
84863
  return error instanceof Error ? error.message : String(error);
84793
84864
  }
84794
84865
  };
84866
+ /**
84867
+ * Resolve the optional AgentSwarm normal-phase concurrency cap from the environment.
84868
+ *
84869
+ * Returns `undefined` when the variable is unset/empty. A present value must be a
84870
+ * positive integer; invalid input fails fast so a misconfigured cap never silently
84871
+ * reverts to the uncapped ramp.
84872
+ */
84873
+ function resolveSwarmMaxConcurrency(env = process.env) {
84874
+ const raw = env[AGENT_SWARM_MAX_CONCURRENCY_ENV];
84875
+ if (raw === void 0 || raw.trim() === "") return void 0;
84876
+ const value = Number(raw);
84877
+ if (!Number.isInteger(value) || value <= 0) throw new Error(`${AGENT_SWARM_MAX_CONCURRENCY_ENV} must be a positive integer, got ${JSON.stringify(raw)}.`);
84878
+ return value;
84879
+ }
84795
84880
  //#endregion
84796
84881
  //#region ../agent-core/src/session/summary-continuation.md?raw
84797
84882
  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";
@@ -84918,7 +85003,8 @@ var SessionSubagentHost = class {
84918
85003
  };
84919
85004
  }
84920
85005
  async runQueued(tasks) {
84921
- return new SubagentBatch(this, tasks).run();
85006
+ const maxConcurrency = resolveSwarmMaxConcurrency();
85007
+ return new SubagentBatch(this, tasks, { maxConcurrency }).run();
84922
85008
  }
84923
85009
  suspended(event) {
84924
85010
  (this.session.getReadyAgent?.(this.ownerAgentId))?.emitEvent({
@@ -92211,6 +92297,20 @@ var WriteTool = class {
92211
92297
  //#region ../agent-core/src/tools/builtin/goal/create-goal.md?raw
92212
92298
  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";
92213
92299
  //#endregion
92300
+ //#region ../agent-core/src/tools/builtin/goal/serialize.ts
92301
+ /**
92302
+ * The goalId is a random UUID with no user-facing meaning, and no goal tool
92303
+ * takes one (there is only ever one goal at a time). Keep it out of what the
92304
+ * model sees so it never echoes the id back to the user as if it mattered.
92305
+ */
92306
+ function goalForModel(goal) {
92307
+ const { goalId: _goalId, ...rest } = goal;
92308
+ return rest;
92309
+ }
92310
+ function goalResultForModel(result) {
92311
+ return { goal: result.goal === null ? null : goalForModel(result.goal) };
92312
+ }
92313
+ //#endregion
92214
92314
  //#region ../agent-core/src/tools/builtin/goal/create-goal.ts
92215
92315
  const CreateGoalToolInputSchema = z.object({
92216
92316
  objective: z.string().min(1).describe("The objective to pursue. Must have a verifiable end state."),
@@ -92229,6 +92329,7 @@ var CreateGoalTool = class {
92229
92329
  const goal = this.agent.goal;
92230
92330
  return {
92231
92331
  description: "Creating a goal",
92332
+ display: this.resolveGoalStartDisplay(args),
92232
92333
  approvalRule: this.name,
92233
92334
  execute: async () => {
92234
92335
  const snapshot = await goal.createGoal({
@@ -92236,10 +92337,26 @@ var CreateGoalTool = class {
92236
92337
  completionCriterion: args.completionCriterion,
92237
92338
  replace: args.replace
92238
92339
  }, "model");
92239
- return { output: JSON.stringify({ goal: snapshot }, null, 2) };
92340
+ return { output: JSON.stringify({ goal: goalForModel(snapshot) }, null, 2) };
92240
92341
  }
92241
92342
  };
92242
92343
  }
92344
+ /**
92345
+ * Starting a goal switches the agent into autonomous, multi-turn work, so its
92346
+ * approval reuses the same choice the `/goal` command offers: pick the
92347
+ * permission mode to run under, or decline. `auto` mode auto-approves the goal
92348
+ * upstream and never reaches this prompt, so the menu only covers manual/yolo.
92349
+ */
92350
+ resolveGoalStartDisplay(args) {
92351
+ const mode = this.agent.permission.mode;
92352
+ if (mode === "auto") return void 0;
92353
+ return {
92354
+ kind: "goal_start",
92355
+ objective: args.objective,
92356
+ completionCriterion: args.completionCriterion,
92357
+ mode
92358
+ };
92359
+ }
92243
92360
  };
92244
92361
  //#endregion
92245
92362
  //#region ../agent-core/src/tools/builtin/goal/get-goal.md?raw
@@ -92262,7 +92379,7 @@ var GetGoalTool = class {
92262
92379
  approvalRule: this.name,
92263
92380
  execute: async () => {
92264
92381
  const result = store.getGoal();
92265
- return { output: JSON.stringify(result, null, 2) };
92382
+ return { output: JSON.stringify(goalResultForModel(result), null, 2) };
92266
92383
  }
92267
92384
  };
92268
92385
  }
@@ -92754,12 +92871,9 @@ var TurnFlow = class {
92754
92871
  async turnWorker(firstTurnId, input, origin, signal) {
92755
92872
  const ownsActiveTurn = () => this.activeTurn !== null && this.activeTurn !== "resuming" && this.activeTurn.controller.signal === signal;
92756
92873
  try {
92757
- const initialGoalStatus = this.agent.goal.getGoal().goal?.status;
92758
- if (initialGoalStatus === "active") return await this.driveGoal(firstTurnId, input, origin, signal);
92874
+ if (this.agent.goal.getGoal().goal?.status === "active") return await this.driveGoal(firstTurnId, input, origin, signal);
92759
92875
  const end = await this.runOneTurn(firstTurnId, input, origin, signal, true);
92760
- const resumedFromPausedOrBlocked = initialGoalStatus === "paused" || initialGoalStatus === "blocked";
92761
- const currentGoalStatus = this.agent.goal.getGoal().goal?.status;
92762
- if (resumedFromPausedOrBlocked && currentGoalStatus === "active" && end.event.reason !== "cancelled" && end.event.reason !== "failed") return await this.driveGoal(this.allocateTurnId(), [{
92876
+ if (this.agent.goal.getGoal().goal?.status === "active" && end.event.reason !== "cancelled" && end.event.reason !== "failed") return await this.driveGoal(this.allocateTurnId(), [{
92763
92877
  type: "text",
92764
92878
  text: GOAL_CONTINUATION_PROMPT
92765
92879
  }], GOAL_CONTINUATION_ORIGIN, signal);
@@ -92925,7 +93039,7 @@ var TurnFlow = class {
92925
93039
  reason: "cancelled"
92926
93040
  } });
92927
93041
  this.agent.emitEvent(ended);
92928
- if (standalone && this.currentId === turnId) this.activeTurn = null;
93042
+ if (standalone && this.currentId === turnId && this.agent.goal.getGoal().goal?.status !== "active") this.activeTurn = null;
92929
93043
  if (this.agent.swarmMode.shouldAutoExit) this.agent.swarmMode.exit();
92930
93044
  if (errorEvent !== void 0) this.agent.emitEvent(errorEvent);
92931
93045
  if (ended.reason !== "completed") this.trackTurnInterrupted(turnId, this.currentStepByTurn.get(turnId) ?? this.currentStep);
@@ -147131,6 +147245,7 @@ function toProtocolSession(summary, meta) {
147131
147245
  updated_at: new Date(summary.updatedAt).toISOString(),
147132
147246
  status: "idle",
147133
147247
  archived: summary.archived === true,
147248
+ last_prompt: summary.lastPrompt,
147134
147249
  metadata: mergedMetadata,
147135
147250
  agent_config: { model: "" },
147136
147251
  usage: emptySessionUsage(),
@@ -150485,7 +150600,7 @@ let WorkspaceRegistryService = class WorkspaceRegistryService extends Disposable
150485
150600
  return entry.root;
150486
150601
  }
150487
150602
  async hydrate(workspaceId, entry) {
150488
- const [{ is_git_repo, branch }, session_count] = await Promise.all([detectGit(entry.root), countSessionDirs(join(this.sessionsDir, workspaceId))]);
150603
+ const [{ is_git_repo, branch }, session_count] = await Promise.all([detectGit(entry.root), countActiveSessions(join(this.sessionsDir, workspaceId))]);
150489
150604
  return {
150490
150605
  id: workspaceId,
150491
150606
  root: entry.root,
@@ -150650,7 +150765,7 @@ async function detectGit(root) {
150650
150765
  branch: ref ? ref[1] ?? null : null
150651
150766
  };
150652
150767
  }
150653
- async function countSessionDirs(dir) {
150768
+ async function countActiveSessions(dir) {
150654
150769
  let dirents;
150655
150770
  try {
150656
150771
  dirents = await promises.readdir(dir, { withFileTypes: true });
@@ -150659,9 +150774,22 @@ async function countSessionDirs(dir) {
150659
150774
  throw err;
150660
150775
  }
150661
150776
  let count = 0;
150662
- for (const d of dirents) if (d.isDirectory()) count += 1;
150777
+ for (const d of dirents) {
150778
+ if (!d.isDirectory()) continue;
150779
+ if (await isSessionArchived(join(dir, d.name))) continue;
150780
+ count += 1;
150781
+ }
150663
150782
  return count;
150664
150783
  }
150784
+ async function isSessionArchived(sessionDir) {
150785
+ try {
150786
+ const raw = await promises.readFile(join(sessionDir, "state.json"), "utf8");
150787
+ const parsed = JSON.parse(raw);
150788
+ return typeof parsed === "object" && parsed !== null && parsed.archived === true;
150789
+ } catch {
150790
+ return false;
150791
+ }
150792
+ }
150665
150793
  registerSingleton(IWorkspaceRegistry, WorkspaceRegistryService, 1);
150666
150794
  //#endregion
150667
150795
  //#region ../agent-core/src/services/workspace/workspaceFs.ts
@@ -154505,6 +154633,7 @@ var KimiHarness = class {
154505
154633
  activeSessions = /* @__PURE__ */ new Map();
154506
154634
  ensureConfigFileImpl;
154507
154635
  closeImpl;
154636
+ sessionStartedProperties;
154508
154637
  constructor(rpc, options) {
154509
154638
  this.rpc = rpc;
154510
154639
  this.identity = options.identity;
@@ -154515,6 +154644,7 @@ var KimiHarness = class {
154515
154644
  this.auth = options.auth;
154516
154645
  this.ensureConfigFileImpl = options.ensureConfigFile;
154517
154646
  this.closeImpl = options.onClose;
154647
+ this.sessionStartedProperties = options.sessionStartedProperties ?? {};
154518
154648
  }
154519
154649
  get sessions() {
154520
154650
  return this.activeSessions;
@@ -154532,7 +154662,7 @@ var KimiHarness = class {
154532
154662
  this.telemetry.setContext?.(patch);
154533
154663
  }
154534
154664
  async createSession(options) {
154535
- const { planMode, kaos, persistenceKaos, ...coreOptions } = options;
154665
+ const { planMode, kaos, persistenceKaos, sessionStartedProperties, ...coreOptions } = options;
154536
154666
  const summary = kaos === void 0 && persistenceKaos === void 0 ? await this.rpc.createSession(coreOptions) : await this.rpc.createSessionWithKaos(coreOptions, kaos ?? persistenceKaos, persistenceKaos);
154537
154667
  const session = new Session({
154538
154668
  id: summary.id,
@@ -154545,14 +154675,14 @@ var KimiHarness = class {
154545
154675
  });
154546
154676
  this.activeSessions.set(session.id, session);
154547
154677
  if (planMode === true) await session.setPlanMode(true);
154548
- this.trackSessionStarted(summary.id, false);
154678
+ this.trackSessionStarted(summary.id, false, sessionStartedProperties);
154549
154679
  this.trackSessionEvent(session.id, "session_new");
154550
154680
  return session;
154551
154681
  }
154552
154682
  async resumeSession(input) {
154553
154683
  const id = normalizeSessionId(input.id);
154554
154684
  const active = this.activeSessions.get(id);
154555
- const { kaos, persistenceKaos, ...resumeInput } = input;
154685
+ const { kaos, persistenceKaos, sessionStartedProperties, ...resumeInput } = input;
154556
154686
  if (active !== void 0) {
154557
154687
  if (kaos !== void 0 || persistenceKaos !== void 0) await this.rpc.resumeSessionWithKaos({
154558
154688
  ...resumeInput,
@@ -154577,7 +154707,7 @@ var KimiHarness = class {
154577
154707
  }
154578
154708
  });
154579
154709
  this.activeSessions.set(session.id, session);
154580
- this.trackSessionStarted(summary.id, true);
154710
+ this.trackSessionStarted(summary.id, true, sessionStartedProperties);
154581
154711
  this.trackSessionEvent(session.id, "session_resume");
154582
154712
  return session;
154583
154713
  }
@@ -154672,8 +154802,10 @@ var KimiHarness = class {
154672
154802
  trackSessionEvent(eventSessionId, event) {
154673
154803
  withTelemetryContext(this.telemetry, { sessionId: eventSessionId }).track(event);
154674
154804
  }
154675
- trackSessionStarted(eventSessionId, resumed) {
154805
+ trackSessionStarted(eventSessionId, resumed, sessionScoped) {
154676
154806
  withTelemetryContext(this.telemetry, { sessionId: eventSessionId }).track("session_started", {
154807
+ ...this.sessionStartedProperties,
154808
+ ...sessionScoped,
154677
154809
  client_name: this.identity?.userAgentProduct ?? null,
154678
154810
  client_version: this.identity?.version ?? null,
154679
154811
  ui_mode: this.uiMode,
@@ -155364,7 +155496,8 @@ function createKimiHarness(options) {
155364
155496
  auth: rpc.auth,
155365
155497
  telemetry: rpc.telemetry,
155366
155498
  ensureConfigFile: () => rpc.ensureConfigFile(),
155367
- onClose: () => rpc.close()
155499
+ onClose: () => rpc.close(),
155500
+ sessionStartedProperties: options.sessionStartedProperties
155368
155501
  });
155369
155502
  }
155370
155503
  //#endregion
@@ -155581,4 +155714,4 @@ function applyCatalogProvider(config, options) {
155581
155714
  return { defaultModel };
155582
155715
  }
155583
155716
  //#endregion
155584
- export { CatalogFetchError, DEFAULT_CATALOG_URL, ErrorCodes, KIMI_ERROR_INFO, KimiAuthFacade, KimiConfigRpcClient, KimiError, KimiForCodingProvider, KimiHarness, MCP_OAUTH_AUTHORIZATION_URL_TOOL_UPDATE, SDKRpcClient, SDKRpcClientBase, Session, applyCatalogProvider, catalogBaseUrl, catalogModelToAlias, catalogProviderModels, createKimiConfigRpc, createKimiHarness, fetchCatalog, flushDiagnosticLogs, fromKimiErrorPayload, __toESM as i, inferWireType, installGlobalProxyDispatcher, isKimiError, loadBuiltInCatalog, loadRuntimeConfigSafe, log, __esmMin as n, __require as r, redact, resolveConfigPath, resolveGlobalLogPath, resolveKimiHome, __commonJSMin as t, toKimiErrorPayload };
155717
+ export { CatalogFetchError, DEFAULT_CATALOG_URL, ErrorCodes, KIMI_ERROR_INFO, KimiAuthFacade, KimiConfigRpcClient, KimiError, KimiForCodingProvider, KimiHarness, MCP_OAUTH_AUTHORIZATION_URL_TOOL_UPDATE, SDKRpcClient, SDKRpcClientBase, Session, applyCatalogProvider, catalogBaseUrl, catalogModelToAlias, catalogProviderModels, createKimiConfigRpc, createKimiHarness, fetchCatalog, flushDiagnosticLogs, fromKimiErrorPayload, __toESM as i, inferWireType, installGlobalProxyDispatcher, isKimiError, loadBuiltInCatalog, loadRuntimeConfigSafe, log, __esmMin as n, __require as r, redact, resolveConfigPath, resolveGlobalLogPath, resolveKimiHome, __commonJSMin as t, toKimiErrorPayload, LocalKaos };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@botiverse/kimi-code-sdk",
3
- "version": "0.17.1",
4
- "description": "Botiverse repackage of @moonshot-ai/kimi-code-sdk (from kimi-code @moonshot-ai/kimi-code@0.17.1) — built node-sdk bundle for Slock. Mirror of MoonshotAI/kimi-code.",
3
+ "version": "0.18.0-botiverse.0",
4
+ "description": "Botiverse repackage of @moonshot-ai/kimi-code-sdk (from kimi-code @moonshot-ai/kimi-code@0.18.0) — built node-sdk bundle for Slock. Mirror of MoonshotAI/kimi-code.",
5
5
  "license": "MIT",
6
6
  "author": "Moonshot AI",
7
7
  "homepage": "https://github.com/botiverse/kimi-code-sdk#readme",
@@ -54,7 +54,7 @@
54
54
  "types": "./dist/index.d.mts",
55
55
  "botiverse": {
56
56
  "upstream": "@moonshot-ai/kimi-code-sdk",
57
- "kimiRelease": "@moonshot-ai/kimi-code@0.17.1",
57
+ "kimiRelease": "@moonshot-ai/kimi-code@0.18.0",
58
58
  "source": "https://github.com/MoonshotAI/kimi-code"
59
59
  }
60
60
  }