@moonshot-ai/kimi-code 0.13.0 → 0.13.1

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 (2) hide show
  1. package/dist/main.mjs +1763 -144
  2. package/package.json +2 -2
package/dist/main.mjs CHANGED
@@ -8220,15 +8220,16 @@ const OPENAI_VISION_TOOL_PREFIXES = [
8220
8220
  "gpt-4.1",
8221
8221
  "gpt-4.5"
8222
8222
  ];
8223
- const CLAUDE_3_PREFIXES = [
8223
+ const CLAUDE_VISION_TOOL_PREFIXES = [
8224
8224
  "claude-3-",
8225
8225
  "claude-3.5-",
8226
8226
  "claude-3.7-"
8227
8227
  ];
8228
- const CLAUDE_4_PREFIXES = [
8228
+ const CLAUDE_THINKING_VISION_TOOL_PREFIXES = [
8229
8229
  "claude-opus-4",
8230
8230
  "claude-sonnet-4",
8231
- "claude-haiku-4"
8231
+ "claude-haiku-4",
8232
+ "claude-fable"
8232
8233
  ];
8233
8234
  const GEMINI_CATALOGUED_PREFIXES = [
8234
8235
  "gemini-1.5-pro",
@@ -8316,10 +8317,10 @@ const OPENAI_RESPONSES_CAPABILITY_CATALOG = [{
8316
8317
  capability: OPENAI_VISION_TOOL_CAPABILITY
8317
8318
  }];
8318
8319
  const ANTHROPIC_CAPABILITY_CATALOG = [{
8319
- matches: (name) => hasPrefix(name, CLAUDE_3_PREFIXES),
8320
+ matches: (name) => hasPrefix(name, CLAUDE_VISION_TOOL_PREFIXES),
8320
8321
  capability: ANTHROPIC_VISION_TOOL_CAPABILITY
8321
8322
  }, {
8322
- matches: (name) => hasPrefix(name, CLAUDE_4_PREFIXES),
8323
+ matches: (name) => hasPrefix(name, CLAUDE_THINKING_VISION_TOOL_PREFIXES),
8323
8324
  capability: ANTHROPIC_THINKING_VISION_TOOL_CAPABILITY
8324
8325
  }];
8325
8326
  function normalizeModelName(modelName) {
@@ -8552,6 +8553,7 @@ const ANTHROPIC_TOOL_CALL_ID_POLICY = {
8552
8553
  * family's baseline rather than the generic fallback.
8553
8554
  */
8554
8555
  const CEILING_BY_FAMILY_VERSION = {
8556
+ "fable-5": 128e3,
8555
8557
  "opus-4-7": 128e3,
8556
8558
  "opus-4-6": 128e3,
8557
8559
  "opus-4-5": 64e3,
@@ -8573,7 +8575,7 @@ const CEILING_BY_FAMILY_VERSION = {
8573
8575
  "haiku-3": 4096
8574
8576
  };
8575
8577
  const FALLBACK_MAX_TOKENS = 32e3;
8576
- const FAMILY_FIRST_RE = /(opus|sonnet|haiku)[-._](\d{1,2})(?!\d)(?:[-._](\d{1,2})(?!\d))?/;
8578
+ const FAMILY_FIRST_RE = /(opus|sonnet|haiku|fable)[-._](\d{1,2})(?!\d)(?:[-._](\d{1,2})(?!\d))?/;
8577
8579
  const VERSION_FIRST_RE = /(\d{1,2})[-._](\d{1,2})[-._](opus|sonnet|haiku)/;
8578
8580
  const BARE_FAMILY_RE = /(\d{1,2})[-._](opus|sonnet|haiku)/;
8579
8581
  /**
@@ -8660,10 +8662,10 @@ function versionAtLeast(version, minimum) {
8660
8662
  }
8661
8663
  function supportsAdaptiveThinking(model) {
8662
8664
  const version = parseClaudeAliasVersion(model);
8663
- if (version === null || version.minor === null) return false;
8665
+ if (version === null) return false;
8664
8666
  return versionAtLeast({
8665
8667
  major: version.major,
8666
- minor: version.minor
8668
+ minor: version.minor ?? 0
8667
8669
  }, ADAPTIVE_MIN_VERSION);
8668
8670
  }
8669
8671
  function isOpus47(model) {
@@ -8672,6 +8674,9 @@ function isOpus47(model) {
8672
8674
  const version = parseVersion(match);
8673
8675
  return version.major === 4 && version.minor === 7;
8674
8676
  }
8677
+ function isFableModel(model) {
8678
+ return parseClaudeAliasVersion(model)?.family === "fable";
8679
+ }
8675
8680
  function supportsEffortParam(model, adaptive) {
8676
8681
  if (adaptive) return true;
8677
8682
  const normalized = model.toLowerCase();
@@ -8679,7 +8684,7 @@ function supportsEffortParam(model, adaptive) {
8679
8684
  }
8680
8685
  function clampEffort(effort, model, adaptive) {
8681
8686
  if (effort === "off") return effort;
8682
- if (effort === "xhigh" && !isOpus47(model)) return "high";
8687
+ if (effort === "xhigh" && !isOpus47(model) && !isFableModel(model)) return "high";
8683
8688
  if (effort === "max" && !adaptive) return "high";
8684
8689
  return effort;
8685
8690
  }
@@ -9114,7 +9119,8 @@ var AnthropicChatProvider = class {
9114
9119
  if (this._generationKwargs.temperature !== void 0) kwargs["temperature"] = this._generationKwargs.temperature;
9115
9120
  if (this._generationKwargs.top_k !== void 0) kwargs["top_k"] = this._generationKwargs.top_k;
9116
9121
  if (this._generationKwargs.top_p !== void 0) kwargs["top_p"] = this._generationKwargs.top_p;
9117
- if (this._generationKwargs.thinking !== void 0) kwargs["thinking"] = this._generationKwargs.thinking;
9122
+ const thinking = this._generationKwargs.thinking;
9123
+ if (thinking !== void 0 && !(thinking.type === "disabled" && isFableModel(this._model))) kwargs["thinking"] = thinking;
9118
9124
  if (this._generationKwargs.output_config !== void 0) kwargs["output_config"] = this._generationKwargs.output_config;
9119
9125
  const betas = this._generationKwargs.betaFeatures ?? [];
9120
9126
  const extraHeaders = {};
@@ -56514,7 +56520,12 @@ var ContextMemory = class {
56514
56520
  this.deferredMessages = [];
56515
56521
  this.agent.microCompaction.reset(this._history.length);
56516
56522
  this.agent.emitStatusUpdated();
56517
- if (!this.agent.records.restoring && (stoppedAtBoundary || removedUserCount < count)) throw new KimiError(ErrorCodes.REQUEST_INVALID, "Nothing to undo in the active context.");
56523
+ if (!this.agent.records.restoring && (stoppedAtBoundary || removedUserCount < count)) throw new KimiError(ErrorCodes.REQUEST_INVALID, formatUndoUnavailableMessage(count, removedUserCount, stoppedAtBoundary), { details: {
56524
+ reason: "undo_limit",
56525
+ requestedCount: count,
56526
+ undoableCount: removedUserCount,
56527
+ stoppedAtCompaction: stoppedAtBoundary
56528
+ } });
56518
56529
  }
56519
56530
  applyCompaction(summary) {
56520
56531
  this.agent.records.logRecord({
@@ -56683,6 +56694,13 @@ function isRealUserPrompt(message) {
56683
56694
  if (origin.kind === "skill_activation") return origin.trigger === "user-slash";
56684
56695
  return false;
56685
56696
  }
56697
+ function formatUndoUnavailableMessage(requestedCount, undoableCount, stoppedAtCompaction) {
56698
+ const reason = stoppedAtCompaction ? " after the last compaction" : "";
56699
+ return `Cannot undo ${formatPromptCount(requestedCount)}; only ${formatPromptCount(undoableCount)} can be undone in the active context${reason}.`;
56700
+ function formatPromptCount(count) {
56701
+ return `${String(count)} ${count === 1 ? "prompt" : "prompts"}`;
56702
+ }
56703
+ }
56686
56704
  //#endregion
56687
56705
  //#region ../../packages/agent-core/src/agent/goal/index.ts
56688
56706
  /**
@@ -58449,26 +58467,6 @@ var GitControlPathAccessAskPermissionPolicy = class {
58449
58467
  };
58450
58468
  }
58451
58469
  };
58452
- var CwdOutsideFileWriteAskPermissionPolicy = class {
58453
- agent;
58454
- name = "cwd-outside-file-write-ask";
58455
- constructor(agent) {
58456
- this.agent = agent;
58457
- }
58458
- evaluate(context) {
58459
- const cwd = this.agent.config.cwd;
58460
- if (cwd.length === 0) return;
58461
- const pathClass = this.agent.kaos.pathClass();
58462
- const access = writeFileAccesses(context).find((fileAccess) => {
58463
- return !isWithinDirectory(fileAccess.path, cwd, pathClass);
58464
- });
58465
- if (access === void 0) return;
58466
- return {
58467
- kind: "ask",
58468
- reason: fileAccessReason(access, { cwd_outside: true })
58469
- };
58470
- }
58471
- };
58472
58470
  function fileAccesses(context) {
58473
58471
  return context.execution.accesses?.filter((access) => access.kind === "file") ?? [];
58474
58472
  }
@@ -60689,7 +60687,6 @@ function createPermissionDecisionPolicies(agent) {
60689
60687
  new PlanModeToolApprovePermissionPolicy(agent),
60690
60688
  new SensitiveFileAccessAskPermissionPolicy(agent),
60691
60689
  new GitControlPathAccessAskPermissionPolicy(agent),
60692
- new CwdOutsideFileWriteAskPermissionPolicy(agent),
60693
60690
  new YoloModeApprovePermissionPolicy(agent),
60694
60691
  new SwarmModeAgentSwarmApprovePermissionPolicy(agent),
60695
60692
  new DefaultToolApprovePermissionPolicy(),
@@ -66161,6 +66158,43 @@ function truncate$1(value, max) {
66161
66158
  return value.length > max ? value.slice(0, max) : value;
66162
66159
  }
66163
66160
  //#endregion
66161
+ //#region ../../packages/agent-core/src/agent/skill/prompt.ts
66162
+ function renderUserSlashSkillPrompt(input) {
66163
+ return [
66164
+ `User activated the skill "${escapeXml(input.skillName)}". Follow the loaded skill instructions.`,
66165
+ "",
66166
+ renderSkillLoadedBlock({
66167
+ ...input,
66168
+ trigger: "user-slash"
66169
+ })
66170
+ ].join("\n");
66171
+ }
66172
+ function renderModelToolSkillPrompt(input) {
66173
+ return [
66174
+ "Skill tool loaded instructions for this request. Follow them.",
66175
+ "",
66176
+ renderSkillLoadedBlock({
66177
+ ...input,
66178
+ trigger: input.trigger
66179
+ })
66180
+ ].join("\n");
66181
+ }
66182
+ function renderSkillLoadedBlock(input) {
66183
+ return [
66184
+ `<kimi-skill-loaded${renderSkillAttributes(input)}>`,
66185
+ input.skillContent,
66186
+ "</kimi-skill-loaded>"
66187
+ ].join("\n");
66188
+ }
66189
+ function renderSkillAttributes(input) {
66190
+ return [
66191
+ ["name", input.skillName],
66192
+ ["trigger", input.trigger],
66193
+ ["source", input.skillSource],
66194
+ ["args", input.skillArgs]
66195
+ ].filter((item) => item[1] !== void 0).map(([name, value]) => ` ${name}="${escapeXml(value)}"`).join("");
66196
+ }
66197
+ //#endregion
66164
66198
  //#region ../../packages/agent-core/src/agent/skill/index.ts
66165
66199
  var SkillManager = class {
66166
66200
  agent;
@@ -66173,12 +66207,16 @@ var SkillManager = class {
66173
66207
  const skill = this.registry.getSkill(input.name);
66174
66208
  if (skill === void 0) throw new KimiError(ErrorCodes.SKILL_NOT_FOUND, `Skill "${input.name}" was not found`);
66175
66209
  if (!isUserActivatableSkillType(skill.metadata.type)) throw new KimiError(ErrorCodes.SKILL_TYPE_UNSUPPORTED, `Skill "${skill.name}" cannot be activated by the user`);
66176
- const skillContent = this.registry.renderSkillPrompt(skill, input.args ?? "");
66177
- const args = input.args;
66178
- const argsAttr = args ? ` args="${escapeXml(args)}"` : "";
66210
+ const skillArgs = input.args ?? "";
66211
+ const skillContent = this.registry.renderSkillPrompt(skill, skillArgs);
66179
66212
  const wrapped = [{
66180
66213
  type: "text",
66181
- text: `<system-reminder>\n<kimi-skill-loaded name="${escapeXml(skill.name)}"${argsAttr}>\n${skillContent}\n</kimi-skill-loaded>\n</system-reminder>`
66214
+ text: renderUserSlashSkillPrompt({
66215
+ skillName: skill.name,
66216
+ skillArgs,
66217
+ skillContent,
66218
+ skillSource: skill.source
66219
+ })
66182
66220
  }];
66183
66221
  this.recordActivation({
66184
66222
  kind: "skill_activation",
@@ -74401,8 +74439,1283 @@ function makeInterruptedEvent(reason, attemptedSteps, activeStep, message) {
74401
74439
  };
74402
74440
  }
74403
74441
  //#endregion
74404
- //#region ../../packages/agent-core/src/rpc/events.ts
74442
+ //#region ../../packages/protocol/src/error-codes.ts
74443
+ /**
74444
+ * Integer namespaces:
74445
+ * - 0 success
74446
+ * - 4xxxx 客户端错误 (HTTP-4xx analog)
74447
+ * - 5xxxx daemon 内部错误
74448
+ * - 6xxxx 工具运行时
74449
+ * - 7xxxx LLM provider 透传 (msg = original upstream text)
74450
+ * - 8xxxx MCP server 透传 (msg = original upstream text)
74451
+ * - 9xxxx 预留
74452
+ */
74453
+ const ErrorCode$1 = {
74454
+ /** 成功 */
74455
+ SUCCESS: 0,
74456
+ /** Zod 校验失败,`details` 含字段路径列表 */
74457
+ VALIDATION_FAILED: 40001,
74458
+ /** JSON 解析失败、字段类型错 */
74459
+ REQUEST_MALFORMED: 40002,
74460
+ /** daemon 没有任何 provider 配置 */
74461
+ AUTH_PROVISIONING_REQUIRED: 40110,
74462
+ /** provider 存在但 token / api_key 缺失 */
74463
+ AUTH_TOKEN_MISSING: 40111,
74464
+ /** 刷新 token 收到 401(用户撤销了授权) */
74465
+ AUTH_TOKEN_UNAUTHORIZED: 40112,
74466
+ /** 默认 / 请求的 model 解析不到 provider */
74467
+ AUTH_MODEL_NOT_RESOLVED: 40113,
74468
+ /** session_id 不存在 */
74469
+ SESSION_NOT_FOUND: 40401,
74470
+ /** prompt_id 不存在 */
74471
+ PROMPT_NOT_FOUND: 40402,
74472
+ /** message_id 不存在 */
74473
+ MESSAGE_NOT_FOUND: 40403,
74474
+ /** approval_id 不存在 */
74475
+ APPROVAL_NOT_FOUND: 40404,
74476
+ /** question_id 不存在 */
74477
+ QUESTION_NOT_FOUND: 40405,
74478
+ /** task_id 不存在 */
74479
+ TASK_NOT_FOUND: 40406,
74480
+ /** file_id 不存在 */
74481
+ FILE_NOT_FOUND: 40407,
74482
+ /** mcp_server_id 不存在 */
74483
+ MCP_SERVER_NOT_FOUND: 40408,
74484
+ /** fs path 不存在 */
74485
+ FS_PATH_NOT_FOUND: 40409,
74486
+ /** workspace_id 不存在 */
74487
+ WORKSPACE_NOT_FOUND: 40410,
74488
+ /** fs 路径存在但当前进程无权限读取 */
74489
+ FS_PERMISSION_DENIED: 40411,
74490
+ /** provider_id 不存在 */
74491
+ PROVIDER_NOT_FOUND: 40412,
74492
+ /** model_id 不存在 */
74493
+ MODEL_NOT_FOUND: 40413,
74494
+ /** session 有正在进行的 prompt,拒绝新请求 */
74495
+ SESSION_BUSY: 40901,
74496
+ /** approval 已被其他 client 应答 */
74497
+ APPROVAL_ALREADY_RESOLVED: 40902,
74498
+ /** prompt 已结束(abort 幂等返回 0) */
74499
+ PROMPT_ALREADY_COMPLETED: 40903,
74500
+ /** task 已完结,无法取消 */
74501
+ TASK_ALREADY_FINISHED: 40904,
74502
+ /** mcp restart 时若已在 connecting/connected */
74503
+ MCP_ALREADY_CONNECTED: 40905,
74504
+ /** fs.read 请求 file,但 path 是目录 */
74505
+ FS_IS_DIRECTORY: 40906,
74506
+ /** fs.read 请求 utf-8,但 path 是二进制;client 改走 `:download` */
74507
+ FS_IS_BINARY: 40907,
74508
+ /** fs.git_status 但 session.cwd 不是 git repo */
74509
+ FS_GIT_UNAVAILABLE: 40908,
74510
+ /** 用户 ESC / 关闭面板放弃整组(client 调 `:dismiss`) */
74511
+ QUESTION_DISMISSED: 40909,
74512
+ /** 当前历史没有可 compact 的前缀 */
74513
+ COMPACTION_UNABLE: 40910,
74514
+ /** 当前历史没有足够的用户提示词可撤回 */
74515
+ SESSION_UNDO_UNAVAILABLE: 40911,
74516
+ /** approval 60s 超时 */
74517
+ APPROVAL_EXPIRED: 41001,
74518
+ /** question 60s 超时 */
74519
+ QUESTION_EXPIRED: 41002,
74520
+ /** 临时文件已过期 */
74521
+ FILE_EXPIRED: 41003,
74522
+ /** 上传超 50MB */
74523
+ FILE_TOO_LARGE: 41301,
74524
+ /** fs.read 超 10MB */
74525
+ FS_TOO_LARGE: 41302,
74526
+ /** fs.list / fs.search / fs.grep 命中超上限 */
74527
+ FS_TOO_MANY_RESULTS: 41303,
74528
+ /** path 越出 session cwd 边界 */
74529
+ FS_PATH_ESCAPES_SESSION: 41304,
74530
+ /** fs.grep 执行 >30s */
74531
+ FS_GREP_TIMEOUT: 41305,
74532
+ /** WS 单连接 watch_paths > 100 */
74533
+ FS_WATCH_LIMIT_EXCEEDED: 42902,
74534
+ /** 兜底 */
74535
+ INTERNAL_ERROR: 50001,
74536
+ /** 写入 session 持久化失败 */
74537
+ PERSISTENCE_FAILURE: 50003,
74538
+ /** tool 执行抛错 */
74539
+ TOOL_EXECUTION_FAILED: 60001,
74540
+ /** tool 在此 session 未启用 */
74541
+ TOOL_NOT_AVAILABLE: 60002
74542
+ };
74543
+ ErrorCode$1.SUCCESS, ErrorCode$1.VALIDATION_FAILED, ErrorCode$1.REQUEST_MALFORMED, ErrorCode$1.AUTH_PROVISIONING_REQUIRED, ErrorCode$1.AUTH_TOKEN_MISSING, ErrorCode$1.AUTH_TOKEN_UNAUTHORIZED, ErrorCode$1.AUTH_MODEL_NOT_RESOLVED, ErrorCode$1.SESSION_NOT_FOUND, ErrorCode$1.PROMPT_NOT_FOUND, ErrorCode$1.MESSAGE_NOT_FOUND, ErrorCode$1.APPROVAL_NOT_FOUND, ErrorCode$1.QUESTION_NOT_FOUND, ErrorCode$1.TASK_NOT_FOUND, ErrorCode$1.FILE_NOT_FOUND, ErrorCode$1.MCP_SERVER_NOT_FOUND, ErrorCode$1.FS_PATH_NOT_FOUND, ErrorCode$1.WORKSPACE_NOT_FOUND, ErrorCode$1.FS_PERMISSION_DENIED, ErrorCode$1.PROVIDER_NOT_FOUND, ErrorCode$1.MODEL_NOT_FOUND, ErrorCode$1.SESSION_BUSY, ErrorCode$1.APPROVAL_ALREADY_RESOLVED, ErrorCode$1.PROMPT_ALREADY_COMPLETED, ErrorCode$1.TASK_ALREADY_FINISHED, ErrorCode$1.MCP_ALREADY_CONNECTED, ErrorCode$1.FS_IS_DIRECTORY, ErrorCode$1.FS_IS_BINARY, ErrorCode$1.FS_GIT_UNAVAILABLE, ErrorCode$1.QUESTION_DISMISSED, ErrorCode$1.COMPACTION_UNABLE, ErrorCode$1.SESSION_UNDO_UNAVAILABLE, ErrorCode$1.APPROVAL_EXPIRED, ErrorCode$1.QUESTION_EXPIRED, ErrorCode$1.FILE_EXPIRED, ErrorCode$1.FILE_TOO_LARGE, ErrorCode$1.FS_TOO_LARGE, ErrorCode$1.FS_TOO_MANY_RESULTS, ErrorCode$1.FS_PATH_ESCAPES_SESSION, ErrorCode$1.FS_GREP_TIMEOUT, ErrorCode$1.FS_WATCH_LIMIT_EXCEEDED, ErrorCode$1.INTERNAL_ERROR, ErrorCode$1.PERSISTENCE_FAILURE, ErrorCode$1.TOOL_EXECUTION_FAILED, ErrorCode$1.TOOL_NOT_AVAILABLE;
74544
+ //#endregion
74545
+ //#region ../../packages/protocol/src/pagination.ts
74546
+ const cursorQuerySchema = z.object({
74547
+ before_id: z.string().min(1).optional(),
74548
+ after_id: z.string().min(1).optional(),
74549
+ page_size: z.number().int().min(1).max(100).optional()
74550
+ }).superRefine((value, ctx) => {
74551
+ if (value.before_id !== void 0 && value.after_id !== void 0) ctx.addIssue({
74552
+ code: "custom",
74553
+ message: "before_id and after_id are mutually exclusive",
74554
+ path: ["before_id"],
74555
+ params: { code: ErrorCode$1.VALIDATION_FAILED }
74556
+ });
74557
+ });
74558
+ const pageResponseSchema = (item) => z.object({
74559
+ items: z.array(item),
74560
+ has_more: z.boolean()
74561
+ });
74562
+ //#endregion
74563
+ //#region ../../packages/protocol/src/time.ts
74564
+ const ISO_8601_REGEX = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?(?:Z|[+-]\d{2}(?::?\d{2})?)$/;
74565
+ const isoDateTimeSchema = z.string().refine((value) => ISO_8601_REGEX.test(value), { message: "must be an ISO 8601 datetime string" }).transform((value, ctx) => {
74566
+ const ms = Date.parse(value);
74567
+ if (Number.isNaN(ms)) {
74568
+ ctx.addIssue({
74569
+ code: "custom",
74570
+ message: "invalid ISO 8601 datetime"
74571
+ });
74572
+ return z.NEVER;
74573
+ }
74574
+ return new Date(ms).toISOString();
74575
+ });
74576
+ //#endregion
74577
+ //#region ../../packages/protocol/src/events.ts
74405
74578
  const MCP_OAUTH_AUTHORIZATION_URL_TOOL_UPDATE = "mcp.oauth.authorization_url";
74579
+ z.discriminatedUnion("kind", [
74580
+ z.object({
74581
+ kind: z.literal("command"),
74582
+ command: z.string(),
74583
+ cwd: z.string().optional(),
74584
+ description: z.string().optional(),
74585
+ language: z.literal("bash").optional()
74586
+ }),
74587
+ z.object({
74588
+ kind: z.literal("file_io"),
74589
+ operation: z.enum([
74590
+ "read",
74591
+ "write",
74592
+ "edit",
74593
+ "glob",
74594
+ "grep"
74595
+ ]),
74596
+ path: z.string(),
74597
+ detail: z.string().optional(),
74598
+ content: z.string().optional(),
74599
+ before: z.string().optional(),
74600
+ after: z.string().optional()
74601
+ }),
74602
+ z.object({
74603
+ kind: z.literal("diff"),
74604
+ path: z.string(),
74605
+ before: z.string(),
74606
+ after: z.string(),
74607
+ hunks: z.number().optional()
74608
+ }),
74609
+ z.object({
74610
+ kind: z.literal("search"),
74611
+ query: z.string(),
74612
+ scope: z.string().optional()
74613
+ }),
74614
+ z.object({
74615
+ kind: z.literal("url_fetch"),
74616
+ url: z.string(),
74617
+ method: z.string().optional()
74618
+ }),
74619
+ z.object({
74620
+ kind: z.literal("agent_call"),
74621
+ agent_name: z.string(),
74622
+ prompt: z.string(),
74623
+ background: z.boolean().optional()
74624
+ }),
74625
+ z.object({
74626
+ kind: z.literal("skill_call"),
74627
+ skill_name: z.string(),
74628
+ args: z.string().optional()
74629
+ }),
74630
+ z.object({
74631
+ kind: z.literal("todo_list"),
74632
+ items: z.array(z.object({
74633
+ title: z.string(),
74634
+ status: z.string()
74635
+ }))
74636
+ }),
74637
+ z.object({
74638
+ kind: z.literal("background_task"),
74639
+ task_id: z.string(),
74640
+ status: z.string(),
74641
+ description: z.string(),
74642
+ task_kind: z.string().optional()
74643
+ }),
74644
+ z.object({
74645
+ kind: z.literal("task_stop"),
74646
+ task_id: z.string(),
74647
+ task_description: z.string()
74648
+ }),
74649
+ z.object({
74650
+ kind: z.literal("plan_review"),
74651
+ plan: z.string(),
74652
+ path: z.string().optional(),
74653
+ options: z.array(z.object({
74654
+ label: z.string(),
74655
+ description: z.string()
74656
+ })).readonly().optional()
74657
+ }),
74658
+ z.object({
74659
+ kind: z.literal("generic"),
74660
+ summary: z.string(),
74661
+ detail: z.unknown().optional()
74662
+ })
74663
+ ]);
74664
+ z.discriminatedUnion("kind", [
74665
+ z.object({
74666
+ kind: z.literal("command_output"),
74667
+ exit_code: z.number(),
74668
+ stdout: z.string().optional(),
74669
+ stderr: z.string().optional()
74670
+ }),
74671
+ z.object({
74672
+ kind: z.literal("file_content"),
74673
+ path: z.string(),
74674
+ content: z.string(),
74675
+ range: z.object({
74676
+ start: z.number(),
74677
+ end: z.number()
74678
+ }).optional(),
74679
+ truncated: z.boolean().optional()
74680
+ }),
74681
+ z.object({
74682
+ kind: z.literal("diff"),
74683
+ path: z.string(),
74684
+ before: z.string(),
74685
+ after: z.string(),
74686
+ hunks: z.number().optional()
74687
+ }),
74688
+ z.object({
74689
+ kind: z.literal("search_results"),
74690
+ query: z.string(),
74691
+ matches: z.array(z.object({
74692
+ file: z.string(),
74693
+ line: z.number(),
74694
+ text: z.string()
74695
+ }))
74696
+ }),
74697
+ z.object({
74698
+ kind: z.literal("url_content"),
74699
+ url: z.string(),
74700
+ status: z.number(),
74701
+ preview: z.string().optional(),
74702
+ content_type: z.string().optional()
74703
+ }),
74704
+ z.object({
74705
+ kind: z.literal("agent_summary"),
74706
+ agent_name: z.string(),
74707
+ result: z.string().optional(),
74708
+ steps: z.number().optional()
74709
+ }),
74710
+ z.object({
74711
+ kind: z.literal("background_task"),
74712
+ task_id: z.string(),
74713
+ status: z.string(),
74714
+ description: z.string()
74715
+ }),
74716
+ z.object({
74717
+ kind: z.literal("todo_list"),
74718
+ items: z.array(z.object({
74719
+ title: z.string(),
74720
+ status: z.string()
74721
+ }))
74722
+ }),
74723
+ z.object({
74724
+ kind: z.literal("structured"),
74725
+ data: z.unknown()
74726
+ }),
74727
+ z.object({
74728
+ kind: z.literal("text"),
74729
+ text: z.string(),
74730
+ truncated: z.boolean().optional()
74731
+ }),
74732
+ z.object({
74733
+ kind: z.literal("error"),
74734
+ message: z.string(),
74735
+ code: z.string().optional()
74736
+ }),
74737
+ z.object({
74738
+ kind: z.literal("generic"),
74739
+ summary: z.string(),
74740
+ detail: z.unknown().optional()
74741
+ })
74742
+ ]);
74743
+ //#endregion
74744
+ //#region ../../packages/protocol/src/ws-control.ts
74745
+ /**
74746
+ * Event: { type, seq, session_id?, timestamp, payload }
74747
+ * Control: { type, id?, payload }
74748
+ * Ack: { type: 'ack', id, code, msg, payload }
74749
+ */
74750
+ const serverHelloPayloadSchema = z.object({
74751
+ ws_connection_id: z.string(),
74752
+ heartbeat_ms: z.number().int().positive(),
74753
+ max_event_buffer_size: z.number().int().positive(),
74754
+ capabilities: z.object({
74755
+ event_batching: z.boolean(),
74756
+ compression: z.boolean()
74757
+ })
74758
+ });
74759
+ const serverHelloMessageSchema = z.object({
74760
+ type: z.literal("server_hello"),
74761
+ timestamp: isoDateTimeSchema,
74762
+ payload: serverHelloPayloadSchema
74763
+ });
74764
+ const clientHelloPayloadSchema = z.object({
74765
+ client_id: z.string(),
74766
+ subscriptions: z.array(z.string()),
74767
+ last_seq_by_session: z.record(z.string(), z.number().int().nonnegative()).optional()
74768
+ });
74769
+ const clientHelloMessageSchema = z.object({
74770
+ type: z.literal("client_hello"),
74771
+ id: z.string(),
74772
+ payload: clientHelloPayloadSchema
74773
+ });
74774
+ z.object({
74775
+ accepted_subscriptions: z.array(z.string()).optional(),
74776
+ accepted: z.array(z.string()).optional(),
74777
+ not_found: z.array(z.string()).optional(),
74778
+ resync_required: z.array(z.string())
74779
+ });
74780
+ const watchFsConfigSchema = z.object({
74781
+ paths: z.array(z.string()),
74782
+ recursive: z.boolean().optional()
74783
+ });
74784
+ const subscribePayloadSchema = z.object({
74785
+ session_ids: z.array(z.string()),
74786
+ last_seq_by_session: z.record(z.string(), z.number().int().nonnegative()).optional(),
74787
+ watch_fs: z.record(z.string(), watchFsConfigSchema).optional()
74788
+ });
74789
+ const subscribeMessageSchema = z.object({
74790
+ type: z.literal("subscribe"),
74791
+ id: z.string(),
74792
+ payload: subscribePayloadSchema
74793
+ });
74794
+ const unsubscribePayloadSchema = z.object({ session_ids: z.array(z.string()) });
74795
+ const unsubscribeMessageSchema = z.object({
74796
+ type: z.literal("unsubscribe"),
74797
+ id: z.string(),
74798
+ payload: unsubscribePayloadSchema
74799
+ });
74800
+ const watchFsAddPayloadSchema = z.object({
74801
+ session_id: z.string(),
74802
+ paths: z.array(z.string()),
74803
+ recursive: z.boolean().optional()
74804
+ });
74805
+ const watchFsAddMessageSchema = z.object({
74806
+ type: z.literal("watch_fs_add"),
74807
+ id: z.string(),
74808
+ payload: watchFsAddPayloadSchema
74809
+ });
74810
+ const watchFsRemovePayloadSchema = z.object({
74811
+ session_id: z.string(),
74812
+ paths: z.array(z.string())
74813
+ });
74814
+ const watchFsRemoveMessageSchema = z.object({
74815
+ type: z.literal("watch_fs_remove"),
74816
+ id: z.string(),
74817
+ payload: watchFsRemovePayloadSchema
74818
+ });
74819
+ z.object({
74820
+ watched_paths: z.array(z.string()).optional(),
74821
+ current_count: z.number().int().nonnegative().optional()
74822
+ });
74823
+ const abortPayloadSchema = z.object({
74824
+ session_id: z.string(),
74825
+ prompt_id: z.string()
74826
+ });
74827
+ const abortMessageSchema = z.object({
74828
+ type: z.literal("abort"),
74829
+ id: z.string(),
74830
+ payload: abortPayloadSchema
74831
+ });
74832
+ z.object({
74833
+ aborted: z.boolean().optional(),
74834
+ at_seq: z.number().int().nonnegative().optional()
74835
+ });
74836
+ const pingPayloadSchema = z.object({ nonce: z.string() });
74837
+ const pingMessageSchema = z.object({
74838
+ type: z.literal("ping"),
74839
+ timestamp: isoDateTimeSchema,
74840
+ payload: pingPayloadSchema
74841
+ });
74842
+ const pongPayloadSchema = z.object({ nonce: z.string() });
74843
+ const pongMessageSchema = z.object({
74844
+ type: z.literal("pong"),
74845
+ payload: pongPayloadSchema
74846
+ });
74847
+ const resyncRequiredPayloadSchema = z.object({
74848
+ session_id: z.string(),
74849
+ reason: z.enum(["buffer_overflow", "session_recreated"]),
74850
+ current_seq: z.number().int().nonnegative()
74851
+ });
74852
+ const resyncRequiredMessageSchema = z.object({
74853
+ type: z.literal("resync_required"),
74854
+ timestamp: isoDateTimeSchema,
74855
+ payload: resyncRequiredPayloadSchema
74856
+ });
74857
+ const wsErrorPayloadSchema = z.object({
74858
+ code: z.number().int(),
74859
+ msg: z.string(),
74860
+ fatal: z.boolean(),
74861
+ request_id: z.string().optional(),
74862
+ details: z.unknown().optional()
74863
+ });
74864
+ const wsErrorMessageSchema = z.object({
74865
+ type: z.literal("error"),
74866
+ timestamp: isoDateTimeSchema,
74867
+ payload: wsErrorPayloadSchema
74868
+ });
74869
+ z.discriminatedUnion("type", [
74870
+ clientHelloMessageSchema,
74871
+ subscribeMessageSchema,
74872
+ unsubscribeMessageSchema,
74873
+ watchFsAddMessageSchema,
74874
+ watchFsRemoveMessageSchema,
74875
+ abortMessageSchema,
74876
+ pongMessageSchema
74877
+ ]);
74878
+ z.discriminatedUnion("type", [
74879
+ serverHelloMessageSchema,
74880
+ pingMessageSchema,
74881
+ resyncRequiredMessageSchema,
74882
+ wsErrorMessageSchema
74883
+ ]);
74884
+ //#endregion
74885
+ //#region ../../packages/protocol/src/message.ts
74886
+ const messageRoleSchema = z.enum([
74887
+ "user",
74888
+ "assistant",
74889
+ "tool",
74890
+ "system"
74891
+ ]);
74892
+ const textContentSchema = z.object({
74893
+ type: z.literal("text"),
74894
+ text: z.string()
74895
+ });
74896
+ const toolUseContentSchema = z.object({
74897
+ type: z.literal("tool_use"),
74898
+ tool_call_id: z.string().min(1),
74899
+ tool_name: z.string().min(1),
74900
+ input: z.unknown()
74901
+ });
74902
+ const toolResultContentSchema = z.object({
74903
+ type: z.literal("tool_result"),
74904
+ tool_call_id: z.string().min(1),
74905
+ output: z.unknown(),
74906
+ is_error: z.boolean().optional()
74907
+ });
74908
+ const imageSourceSchema = z.discriminatedUnion("kind", [
74909
+ z.object({
74910
+ kind: z.literal("url"),
74911
+ url: z.string().min(1)
74912
+ }),
74913
+ z.object({
74914
+ kind: z.literal("base64"),
74915
+ media_type: z.string().min(1),
74916
+ data: z.string().min(1)
74917
+ }),
74918
+ z.object({
74919
+ kind: z.literal("file"),
74920
+ file_id: z.string().min(1)
74921
+ })
74922
+ ]);
74923
+ const imageContentSchema = z.object({
74924
+ type: z.literal("image"),
74925
+ source: imageSourceSchema
74926
+ });
74927
+ const fileContentSchema = z.object({
74928
+ type: z.literal("file"),
74929
+ file_id: z.string().min(1),
74930
+ name: z.string(),
74931
+ media_type: z.string().min(1),
74932
+ size: z.number().int().nonnegative()
74933
+ });
74934
+ const thinkingContentSchema = z.object({
74935
+ type: z.literal("thinking"),
74936
+ thinking: z.string(),
74937
+ signature: z.string().optional()
74938
+ });
74939
+ const messageContentSchema = z.discriminatedUnion("type", [
74940
+ textContentSchema,
74941
+ toolUseContentSchema,
74942
+ toolResultContentSchema,
74943
+ imageContentSchema,
74944
+ fileContentSchema,
74945
+ thinkingContentSchema
74946
+ ]);
74947
+ const messageSchema = z.object({
74948
+ id: z.string().min(1),
74949
+ session_id: z.string().min(1),
74950
+ role: messageRoleSchema,
74951
+ content: z.array(messageContentSchema),
74952
+ created_at: isoDateTimeSchema,
74953
+ prompt_id: z.string().min(1).optional(),
74954
+ parent_message_id: z.string().min(1).optional(),
74955
+ metadata: z.record(z.string(), z.unknown()).optional()
74956
+ });
74957
+ //#endregion
74958
+ //#region ../../packages/protocol/src/rest/prompt.ts
74959
+ /**
74960
+ * POST /v1/sessions/{sid}/prompts
74961
+ * Body: PromptSubmission {
74962
+ * content: MessageContent[],
74963
+ * metadata?: ...,
74964
+ * model?: string,
74965
+ * thinking?: 'off'|'low'|'medium'|'high'|'xhigh'|'max',
74966
+ * permission_mode?: 'manual'|'yolo'|'auto',
74967
+ * plan_mode?: boolean,
74968
+ * }
74969
+ * Reply: PromptSubmitResult { prompt_id, user_message_id, status, content, created_at }
74970
+ * status='running' when sent immediately, status='queued' when
74971
+ * another prompt is already active.
74972
+ *
74973
+ * GET /v1/sessions/{sid}/prompts
74974
+ * Reply: { active: PromptItem | null, queued: PromptItem[] }
74975
+ *
74976
+ * POST /v1/sessions/{sid}/prompts/{pid}:steer
74977
+ * POST /v1/sessions/{sid}/prompts:steer
74978
+ * Body: { prompt_ids: string[] } for the collection route
74979
+ * Reply: { steered: true, prompt_ids: string[] }
74980
+ *
74981
+ * POST /v1/sessions/{sid}/prompts/{pid}:abort
74982
+ * Body: empty
74983
+ * Reply: { aborted: true, at_seq: number } (envelope code 0)
74984
+ * { aborted: false, at_seq: number } (envelope code 40903, idempotent)
74985
+ */
74986
+ const promptThinkingSchema = z.enum([
74987
+ "off",
74988
+ "low",
74989
+ "medium",
74990
+ "high",
74991
+ "xhigh",
74992
+ "max"
74993
+ ]);
74994
+ const promptPermissionModeSchema = z.enum([
74995
+ "manual",
74996
+ "yolo",
74997
+ "auto"
74998
+ ]);
74999
+ z.object({
75000
+ content: z.array(messageContentSchema).min(1),
75001
+ metadata: z.record(z.string(), z.unknown()).optional(),
75002
+ model: z.string().min(1).optional(),
75003
+ thinking: promptThinkingSchema.optional(),
75004
+ permission_mode: promptPermissionModeSchema.optional(),
75005
+ plan_mode: z.boolean().optional()
75006
+ });
75007
+ const promptStatusSchema = z.enum(["running", "queued"]);
75008
+ const promptItemSchema = z.object({
75009
+ prompt_id: z.string().min(1),
75010
+ user_message_id: z.string().min(1),
75011
+ status: promptStatusSchema,
75012
+ content: z.array(messageContentSchema).min(1),
75013
+ created_at: isoDateTimeSchema
75014
+ });
75015
+ z.object({
75016
+ active: promptItemSchema.nullable(),
75017
+ queued: z.array(promptItemSchema)
75018
+ });
75019
+ z.object({ prompt_ids: z.array(z.string().min(1)).min(1) });
75020
+ z.object({
75021
+ steered: z.literal(true),
75022
+ prompt_ids: z.array(z.string().min(1)).min(1)
75023
+ });
75024
+ z.object({
75025
+ aborted: z.boolean(),
75026
+ at_seq: z.number().int().nonnegative().optional()
75027
+ });
75028
+ //#endregion
75029
+ //#region ../../packages/protocol/src/workspace.ts
75030
+ const workspaceIdSchema = z.string().regex(/^wd_[a-z0-9._-]+_[0-9a-f]{12}$/, { message: "workspace_id must be a wd_<slug>_<hash12> string" });
75031
+ const workspaceSchema = z.object({
75032
+ id: workspaceIdSchema,
75033
+ root: z.string().min(1),
75034
+ name: z.string().min(1).max(100),
75035
+ is_git_repo: z.boolean(),
75036
+ branch: z.string().nullable(),
75037
+ created_at: isoDateTimeSchema,
75038
+ last_opened_at: isoDateTimeSchema,
75039
+ session_count: z.number().int().nonnegative()
75040
+ });
75041
+ z.object({
75042
+ root: z.string().min(1),
75043
+ name: z.string().min(1).max(100).optional()
75044
+ });
75045
+ z.object({ name: z.string().min(1).max(100) });
75046
+ //#endregion
75047
+ //#region ../../packages/protocol/src/session.ts
75048
+ const sessionStatusSchema = z.enum([
75049
+ "idle",
75050
+ "running",
75051
+ "awaiting_approval",
75052
+ "awaiting_question",
75053
+ "aborted"
75054
+ ]);
75055
+ const sessionUsageSchema = z.object({
75056
+ input_tokens: z.number().int().nonnegative(),
75057
+ output_tokens: z.number().int().nonnegative(),
75058
+ cache_read_tokens: z.number().int().nonnegative(),
75059
+ cache_creation_tokens: z.number().int().nonnegative(),
75060
+ total_cost_usd: z.number().nonnegative(),
75061
+ context_tokens: z.number().int().nonnegative(),
75062
+ context_limit: z.number().int().nonnegative(),
75063
+ turn_count: z.number().int().nonnegative()
75064
+ });
75065
+ const permissionRuleMatcherSchema = z.object({
75066
+ kind: z.enum([
75067
+ "command_prefix",
75068
+ "path_glob",
75069
+ "exact_input",
75070
+ "always"
75071
+ ]),
75072
+ value: z.string().optional()
75073
+ });
75074
+ const permissionRuleSchema = z.object({
75075
+ id: z.string().min(1),
75076
+ tool_name: z.string().min(1),
75077
+ matcher: permissionRuleMatcherSchema.optional(),
75078
+ decision: z.literal("approved"),
75079
+ created_at: isoDateTimeSchema,
75080
+ created_by: z.enum(["user", "agent"])
75081
+ });
75082
+ const sessionAgentConfigSchema = z.object({
75083
+ model: z.string(),
75084
+ system_prompt: z.string().optional(),
75085
+ tools: z.array(z.string()).optional(),
75086
+ mcp_servers: z.array(z.string()).optional(),
75087
+ thinking: promptThinkingSchema.optional(),
75088
+ permission_mode: promptPermissionModeSchema.optional(),
75089
+ plan_mode: z.boolean().optional()
75090
+ });
75091
+ const sessionAgentConfigPartialSchema = sessionAgentConfigSchema.partial();
75092
+ const sessionMetadataSchema = z.object({ cwd: z.string().min(1) }).catchall(z.unknown());
75093
+ const sessionSchema = z.object({
75094
+ id: z.string().min(1),
75095
+ workspace_id: workspaceIdSchema,
75096
+ title: z.string(),
75097
+ created_at: isoDateTimeSchema,
75098
+ updated_at: isoDateTimeSchema,
75099
+ status: sessionStatusSchema,
75100
+ current_prompt_id: z.string().min(1).optional(),
75101
+ metadata: sessionMetadataSchema,
75102
+ agent_config: sessionAgentConfigSchema,
75103
+ usage: sessionUsageSchema,
75104
+ permission_rules: z.array(permissionRuleSchema),
75105
+ message_count: z.number().int().nonnegative(),
75106
+ last_seq: z.number().int().nonnegative()
75107
+ });
75108
+ z.object({
75109
+ title: z.string().min(1).optional(),
75110
+ metadata: sessionMetadataSchema.optional(),
75111
+ agent_config: sessionAgentConfigPartialSchema.optional(),
75112
+ workspace_id: workspaceIdSchema.optional()
75113
+ });
75114
+ z.object({
75115
+ title: z.string().min(1).optional(),
75116
+ metadata: sessionMetadataSchema.partial().optional(),
75117
+ agent_config: sessionAgentConfigPartialSchema.optional(),
75118
+ permission_rules: z.array(permissionRuleSchema).optional()
75119
+ });
75120
+ z.object({
75121
+ title: z.string().min(1).optional(),
75122
+ metadata: z.record(z.string(), z.unknown()).optional()
75123
+ });
75124
+ z.object({
75125
+ title: z.string().min(1).optional(),
75126
+ metadata: z.record(z.string(), z.unknown()).optional()
75127
+ });
75128
+ //#endregion
75129
+ //#region ../../packages/protocol/src/approval.ts
75130
+ const approvalDecisionSchema = z.enum([
75131
+ "approved",
75132
+ "rejected",
75133
+ "cancelled"
75134
+ ]);
75135
+ const approvalScopeSchema = z.enum(["session"]);
75136
+ const approvalRequestSchema = z.object({
75137
+ approval_id: z.string().min(1),
75138
+ session_id: z.string().min(1),
75139
+ turn_id: z.number().int().nonnegative().optional(),
75140
+ tool_call_id: z.string().min(1),
75141
+ tool_name: z.string().min(1),
75142
+ action: z.string(),
75143
+ tool_input_display: z.unknown(),
75144
+ created_at: isoDateTimeSchema,
75145
+ expires_at: isoDateTimeSchema
75146
+ });
75147
+ z.object({
75148
+ decision: approvalDecisionSchema,
75149
+ scope: approvalScopeSchema.optional(),
75150
+ feedback: z.string().optional(),
75151
+ selected_label: z.string().optional()
75152
+ });
75153
+ //#endregion
75154
+ //#region ../../packages/protocol/src/question.ts
75155
+ const questionOptionSchema = z.object({
75156
+ id: z.string().min(1),
75157
+ label: z.string().min(1),
75158
+ description: z.string().optional()
75159
+ });
75160
+ const questionItemSchema = z.object({
75161
+ id: z.string().min(1),
75162
+ question: z.string().min(1),
75163
+ header: z.string().optional(),
75164
+ body: z.string().optional(),
75165
+ options: z.array(questionOptionSchema).min(2).max(4),
75166
+ multi_select: z.boolean().optional(),
75167
+ allow_other: z.boolean().optional(),
75168
+ other_label: z.string().optional(),
75169
+ other_description: z.string().optional()
75170
+ });
75171
+ const questionRequestSchema = z.object({
75172
+ question_id: z.string().min(1),
75173
+ session_id: z.string().min(1),
75174
+ turn_id: z.number().int().nonnegative().optional(),
75175
+ tool_call_id: z.string().min(1).optional(),
75176
+ questions: z.array(questionItemSchema).min(1).max(4),
75177
+ created_at: isoDateTimeSchema,
75178
+ expires_at: isoDateTimeSchema
75179
+ });
75180
+ const questionAnswerSchema = z.discriminatedUnion("kind", [
75181
+ z.object({
75182
+ kind: z.literal("single"),
75183
+ option_id: z.string().min(1)
75184
+ }),
75185
+ z.object({
75186
+ kind: z.literal("multi"),
75187
+ option_ids: z.array(z.string().min(1)).min(1)
75188
+ }),
75189
+ z.object({
75190
+ kind: z.literal("other"),
75191
+ text: z.string()
75192
+ }),
75193
+ z.object({
75194
+ kind: z.literal("multi_with_other"),
75195
+ option_ids: z.array(z.string().min(1)),
75196
+ other_text: z.string()
75197
+ }),
75198
+ z.object({ kind: z.literal("skipped") })
75199
+ ]);
75200
+ const questionAnswerMethodSchema = z.enum([
75201
+ "enter",
75202
+ "space",
75203
+ "number_key",
75204
+ "click"
75205
+ ]);
75206
+ z.object({
75207
+ answers: z.record(z.string().min(1), questionAnswerSchema),
75208
+ method: questionAnswerMethodSchema.optional(),
75209
+ note: z.string().optional()
75210
+ });
75211
+ //#endregion
75212
+ //#region ../../packages/protocol/src/tool.ts
75213
+ const toolSourceSchema = z.enum([
75214
+ "builtin",
75215
+ "skill",
75216
+ "mcp"
75217
+ ]);
75218
+ const toolDescriptorSchema = z.object({
75219
+ name: z.string().min(1),
75220
+ description: z.string(),
75221
+ input_schema: z.unknown(),
75222
+ source: toolSourceSchema,
75223
+ mcp_server_id: z.string().min(1).optional()
75224
+ });
75225
+ const mcpServerStatusSchema = z.enum([
75226
+ "connected",
75227
+ "connecting",
75228
+ "disconnected",
75229
+ "error"
75230
+ ]);
75231
+ const mcpServerTransportSchema = z.enum([
75232
+ "stdio",
75233
+ "http",
75234
+ "sse"
75235
+ ]);
75236
+ const mcpServerSchema = z.object({
75237
+ id: z.string().min(1),
75238
+ name: z.string().min(1),
75239
+ transport: mcpServerTransportSchema,
75240
+ status: mcpServerStatusSchema,
75241
+ last_error: z.string().optional(),
75242
+ tool_count: z.number().int().nonnegative()
75243
+ });
75244
+ //#endregion
75245
+ //#region ../../packages/protocol/src/task.ts
75246
+ const backgroundTaskKindSchema = z.enum([
75247
+ "subagent",
75248
+ "bash",
75249
+ "tool"
75250
+ ]);
75251
+ const backgroundTaskStatusSchema = z.enum([
75252
+ "running",
75253
+ "completed",
75254
+ "failed",
75255
+ "cancelled"
75256
+ ]);
75257
+ const backgroundTaskSchema = z.object({
75258
+ id: z.string().min(1),
75259
+ session_id: z.string().min(1),
75260
+ kind: backgroundTaskKindSchema,
75261
+ description: z.string(),
75262
+ status: backgroundTaskStatusSchema,
75263
+ created_at: isoDateTimeSchema,
75264
+ started_at: isoDateTimeSchema.optional(),
75265
+ completed_at: isoDateTimeSchema.optional(),
75266
+ output_preview: z.string().optional(),
75267
+ output_bytes: z.number().int().nonnegative().optional()
75268
+ });
75269
+ //#endregion
75270
+ //#region ../../packages/protocol/src/fs.ts
75271
+ const fsKindSchema = z.enum([
75272
+ "file",
75273
+ "directory",
75274
+ "symlink"
75275
+ ]);
75276
+ const fsGitStatusSchema = z.enum([
75277
+ "clean",
75278
+ "modified",
75279
+ "added",
75280
+ "deleted",
75281
+ "renamed",
75282
+ "untracked",
75283
+ "ignored",
75284
+ "conflicted"
75285
+ ]);
75286
+ const fsEntrySchema = z.object({
75287
+ path: z.string(),
75288
+ name: z.string(),
75289
+ kind: fsKindSchema,
75290
+ size: z.number().int().nonnegative().optional(),
75291
+ modified_at: isoDateTimeSchema,
75292
+ etag: z.string().optional(),
75293
+ mime: z.string().optional(),
75294
+ language_id: z.string().optional(),
75295
+ is_binary: z.boolean().optional(),
75296
+ is_symlink_to: z.string().optional(),
75297
+ git_status: fsGitStatusSchema.optional(),
75298
+ child_count: z.number().int().nonnegative().optional()
75299
+ });
75300
+ const fsSearchHitSchema = z.object({
75301
+ path: z.string(),
75302
+ name: z.string(),
75303
+ kind: fsKindSchema,
75304
+ score: z.number().min(0).max(1),
75305
+ match_positions: z.array(z.number().int().nonnegative())
75306
+ });
75307
+ const fsGrepMatchSchema = z.object({
75308
+ line: z.number().int().positive(),
75309
+ col: z.number().int().positive(),
75310
+ text: z.string(),
75311
+ before: z.array(z.string()),
75312
+ after: z.array(z.string())
75313
+ });
75314
+ const fsGrepFileHitSchema = z.object({
75315
+ path: z.string(),
75316
+ matches: z.array(fsGrepMatchSchema)
75317
+ });
75318
+ z.object({
75319
+ path: z.string(),
75320
+ status: fsGitStatusSchema,
75321
+ rename_from: z.string().optional()
75322
+ });
75323
+ const fsChangeKindSchema = z.enum([
75324
+ "file",
75325
+ "directory",
75326
+ "symlink"
75327
+ ]);
75328
+ const fsChangeActionSchema = z.enum([
75329
+ "created",
75330
+ "modified",
75331
+ "deleted"
75332
+ ]);
75333
+ const fsChangeEntrySchema = z.object({
75334
+ path: z.string(),
75335
+ change: fsChangeActionSchema,
75336
+ kind: fsChangeKindSchema,
75337
+ size_delta: z.number().int().optional(),
75338
+ etag: z.string().optional()
75339
+ });
75340
+ z.object({
75341
+ changes: z.array(fsChangeEntrySchema),
75342
+ coalesced_window_ms: z.number().int().positive(),
75343
+ truncated: z.boolean().optional(),
75344
+ count: z.number().int().nonnegative().optional()
75345
+ });
75346
+ z.object({
75347
+ id: z.string().min(1),
75348
+ name: z.string().min(1),
75349
+ media_type: z.string().min(1),
75350
+ size: z.number().int().nonnegative(),
75351
+ created_at: isoDateTimeSchema,
75352
+ expires_at: isoDateTimeSchema.optional()
75353
+ });
75354
+ //#endregion
75355
+ //#region ../../packages/protocol/src/modelCatalog.ts
75356
+ const modelCatalogItemSchema = z.object({
75357
+ provider: z.string().min(1),
75358
+ model: z.string().min(1),
75359
+ display_name: z.string().min(1).optional(),
75360
+ max_context_size: z.number().int().min(1),
75361
+ capabilities: z.array(z.string()).optional()
75362
+ });
75363
+ const providerCatalogStatusSchema = z.enum([
75364
+ "connected",
75365
+ "error",
75366
+ "unconfigured"
75367
+ ]);
75368
+ const providerCatalogItemSchema = z.object({
75369
+ id: z.string().min(1),
75370
+ type: z.string().min(1),
75371
+ base_url: z.string().min(1).optional(),
75372
+ default_model: z.string().min(1).optional(),
75373
+ has_api_key: z.boolean(),
75374
+ status: providerCatalogStatusSchema,
75375
+ models: z.array(z.string().min(1)).optional()
75376
+ });
75377
+ //#endregion
75378
+ //#region ../../packages/protocol/src/rest/meta.ts
75379
+ /**
75380
+ * GET /v1/meta
75381
+ * Reply: MetaResponse {
75382
+ * daemon_version,
75383
+ * capabilities,
75384
+ * daemon_id,
75385
+ * started_at
75386
+ * }
75387
+ */
75388
+ const metaCapabilitiesSchema = z.object({
75389
+ websocket: z.literal(true),
75390
+ file_upload: z.literal(true),
75391
+ fs_query: z.literal(true),
75392
+ mcp: z.literal(true),
75393
+ background_tasks: z.literal(true)
75394
+ });
75395
+ z.object({
75396
+ daemon_version: z.string().min(1),
75397
+ capabilities: metaCapabilitiesSchema,
75398
+ daemon_id: z.string().min(1),
75399
+ started_at: isoDateTimeSchema
75400
+ });
75401
+ //#endregion
75402
+ //#region ../../packages/protocol/src/rest/auth.ts
75403
+ /**
75404
+ * GET /v1/auth
75405
+ * Reply: AuthSummary {
75406
+ * ready,
75407
+ * providers_count,
75408
+ * default_model,
75409
+ * managed_provider
75410
+ * }
75411
+ */
75412
+ const managedProviderStatusSchema = z.enum([
75413
+ "authenticated",
75414
+ "expired",
75415
+ "revoked",
75416
+ "unauthenticated"
75417
+ ]);
75418
+ const managedProviderSummarySchema = z.object({
75419
+ name: z.string().min(1),
75420
+ status: managedProviderStatusSchema
75421
+ });
75422
+ z.object({
75423
+ ready: z.boolean(),
75424
+ providers_count: z.number().int().nonnegative(),
75425
+ default_model: z.string().nullable(),
75426
+ managed_provider: managedProviderSummarySchema.nullable()
75427
+ });
75428
+ //#endregion
75429
+ //#region ../../packages/protocol/src/rest/oauth.ts
75430
+ /**
75431
+ * POST /v1/oauth/login body: { provider? } data: OAuthFlowStart
75432
+ * GET /v1/oauth/login query: { provider? } data: OAuthFlowStatus | null
75433
+ * DELETE /v1/oauth/login query: { provider? } data: { cancelled, status }
75434
+ * POST /v1/oauth/logout body: { provider? } data: { logged_out, provider }
75435
+ */
75436
+ const oauthFlowStatusEnum = z.enum([
75437
+ "pending",
75438
+ "authenticated",
75439
+ "denied",
75440
+ "expired",
75441
+ "cancelled"
75442
+ ]);
75443
+ z.object({ provider: z.string().min(1).optional() });
75444
+ z.object({
75445
+ flow_id: z.string().min(1),
75446
+ provider: z.string().min(1),
75447
+ verification_uri: z.string().url(),
75448
+ verification_uri_complete: z.string().url(),
75449
+ user_code: z.string().min(1),
75450
+ expires_in: z.number().int().positive(),
75451
+ interval: z.number().int().positive(),
75452
+ status: z.literal("pending"),
75453
+ expires_at: isoDateTimeSchema
75454
+ });
75455
+ z.object({
75456
+ flow_id: z.string().min(1),
75457
+ provider: z.string().min(1),
75458
+ status: oauthFlowStatusEnum,
75459
+ verification_uri: z.string().url(),
75460
+ verification_uri_complete: z.string().url(),
75461
+ user_code: z.string().min(1),
75462
+ expires_in: z.number().int().positive(),
75463
+ expires_at: isoDateTimeSchema,
75464
+ interval: z.number().int().positive(),
75465
+ resolved_at: isoDateTimeSchema.optional(),
75466
+ error_message: z.string().optional()
75467
+ });
75468
+ z.object({ provider: z.string().min(1).optional() });
75469
+ z.object({
75470
+ cancelled: z.boolean(),
75471
+ status: oauthFlowStatusEnum
75472
+ });
75473
+ z.object({ provider: z.string().min(1).optional() });
75474
+ z.object({
75475
+ logged_out: z.literal(true),
75476
+ provider: z.string().min(1)
75477
+ });
75478
+ cursorQuerySchema.and(z.object({ status: sessionStatusSchema.optional() }));
75479
+ pageResponseSchema(sessionSchema);
75480
+ const sessionStatusResponseSchema = z.object({
75481
+ model: z.string().optional(),
75482
+ thinking_level: z.string(),
75483
+ permission: z.string(),
75484
+ plan_mode: z.boolean(),
75485
+ context_tokens: z.number().int().nonnegative(),
75486
+ max_context_tokens: z.number().int().nonnegative(),
75487
+ context_usage: z.number().min(0).max(1)
75488
+ });
75489
+ z.preprocess((value) => value === void 0 ? {} : value, z.object({ instruction: z.string().optional() }));
75490
+ z.object({});
75491
+ z.preprocess((value) => value === void 0 ? {} : value, z.object({
75492
+ count: z.number().int().positive().default(1),
75493
+ page_size: z.number().int().min(1).max(100).optional()
75494
+ }));
75495
+ z.object({
75496
+ messages: pageResponseSchema(messageSchema),
75497
+ status: sessionStatusResponseSchema
75498
+ });
75499
+ z.object({ deleted: z.literal(true) });
75500
+ z.object({ items: z.array(workspaceSchema) });
75501
+ z.object({ workspace_id: workspaceIdSchema });
75502
+ z.object({ deleted: z.literal(true) });
75503
+ z.object({ path: z.string().min(1).optional() });
75504
+ const fsBrowseEntrySchema = z.object({
75505
+ name: z.string().min(1),
75506
+ path: z.string().min(1),
75507
+ is_dir: z.literal(true),
75508
+ is_git_repo: z.boolean(),
75509
+ branch: z.string().optional()
75510
+ });
75511
+ z.object({
75512
+ path: z.string().min(1),
75513
+ parent: z.string().min(1).nullable(),
75514
+ entries: z.array(fsBrowseEntrySchema)
75515
+ });
75516
+ z.object({
75517
+ home: z.string().min(1),
75518
+ recent_roots: z.array(z.string().min(1))
75519
+ });
75520
+ cursorQuerySchema.and(z.object({ role: messageRoleSchema.optional() }));
75521
+ z.object({
75522
+ items: z.array(messageSchema),
75523
+ has_more: z.boolean()
75524
+ });
75525
+ z.object({ status: z.literal("pending") });
75526
+ z.object({ items: z.array(approvalRequestSchema) });
75527
+ z.object({
75528
+ resolved: z.literal(true),
75529
+ resolved_at: isoDateTimeSchema
75530
+ });
75531
+ z.object({ resolved: z.literal(false) });
75532
+ z.object({ status: z.literal("pending") });
75533
+ z.object({ items: z.array(questionRequestSchema) });
75534
+ z.object({
75535
+ resolved: z.literal(true),
75536
+ resolved_at: isoDateTimeSchema
75537
+ });
75538
+ z.object({ resolved: z.literal(false) });
75539
+ z.object({
75540
+ dismissed: z.literal(true),
75541
+ dismissed_at: isoDateTimeSchema
75542
+ });
75543
+ z.object({ session_id: z.string().min(1).optional() });
75544
+ z.object({ tools: z.array(toolDescriptorSchema) });
75545
+ z.object({ servers: z.array(mcpServerSchema) });
75546
+ z.object({ restarting: z.literal(true) });
75547
+ z.object({ status: backgroundTaskStatusSchema.optional() });
75548
+ z.object({ items: z.array(backgroundTaskSchema) });
75549
+ z.object({
75550
+ with_output: z.coerce.boolean().optional(),
75551
+ output_bytes: z.coerce.number().int().nonnegative().optional()
75552
+ });
75553
+ z.object({ cancelled: z.literal(true) });
75554
+ z.object({ cancelled: z.literal(false) });
75555
+ //#endregion
75556
+ //#region ../../packages/protocol/src/rest/fs.ts
75557
+ /**
75558
+ * POST /v1/sessions/{sid}/fs:list
75559
+ * Body: FsListRequest
75560
+ * Response data: FsListResponse { items, children_by_path?, truncated }
75561
+ * Errors: 40401, 40409, 41304, 41303
75562
+ *
75563
+ * POST /v1/sessions/{sid}/fs:read
75564
+ * Body: FsReadRequest
75565
+ * Response data: FsReadResponse
75566
+ * Errors: 40401, 40409, 40906, 40907, 41302, 41304
75567
+ * POST /v1/sessions/{sid}/fs:list_many
75568
+ * Body: FsListManyRequest (paths[] up to 100)
75569
+ * Response data: FsListManyResponse { results, truncated_paths?,
75570
+ * partial_errors? }
75571
+ *
75572
+ * POST /v1/sessions/{sid}/fs:stat
75573
+ * Body: FsStatRequest
75574
+ * Response data: FsEntry
75575
+ * Errors: 40401, 40409, 41304
75576
+ *
75577
+ * POST /v1/sessions/{sid}/fs:stat_many
75578
+ * Body: FsStatManyRequest (paths[] up to 1000)
75579
+ * Response data: FsStatManyResponse { entries: { [path]: FsEntry | null } }
75580
+ * Per-path failures land as `null` (REST.md §3.9 line 524); only
75581
+ * path-safety (41304) fails the whole call.
75582
+ * POST /v1/sessions/{sid}/fs:search
75583
+ * Body: FsSearchRequest { query, limit?, include_globs?, exclude_globs?,
75584
+ * follow_gitignore? }
75585
+ * Response data: FsSearchResponse { items, truncated }
75586
+ * Errors: 40401, 41303, 41304
75587
+ *
75588
+ * POST /v1/sessions/{sid}/fs:grep
75589
+ * Body: FsGrepRequest
75590
+ * Response data: FsGrepResponse { files, files_scanned, truncated,
75591
+ * elapsed_ms }
75592
+ * Errors: 40401, 41303, 41304, 41305 (>30s grep timeout)
75593
+ * POST /v1/sessions/{sid}/fs:git_status
75594
+ * Body: FsGitStatusRequest { paths? }
75595
+ * Response data: FsGitStatusResponse { branch, ahead, behind, entries }
75596
+ * Errors: 40401, 40908 (not a git repo), 41304
75597
+ *
75598
+ * GET /v1/sessions/{sid}/fs/{path}:download
75599
+ * Response: binary stream or envelope (40401 / 40409 / 41304)
75600
+ */
75601
+ const fsListSortSchema = z.enum([
75602
+ "type_first",
75603
+ "name_asc",
75604
+ "name_desc",
75605
+ "mtime_desc",
75606
+ "size_desc"
75607
+ ]);
75608
+ z.object({
75609
+ path: z.string().default("."),
75610
+ depth: z.number().int().min(1).max(10).default(1),
75611
+ limit: z.number().int().min(1).max(1e3).default(200),
75612
+ show_hidden: z.boolean().default(false),
75613
+ follow_gitignore: z.boolean().default(true),
75614
+ exclude_globs: z.array(z.string()).optional(),
75615
+ sort: fsListSortSchema.default("type_first"),
75616
+ include_git_status: z.boolean().default(false)
75617
+ });
75618
+ z.object({
75619
+ items: z.array(fsEntrySchema),
75620
+ children_by_path: z.record(z.string(), z.array(fsEntrySchema)).optional(),
75621
+ truncated: z.boolean()
75622
+ });
75623
+ const fsReadEncodingRequestSchema = z.enum([
75624
+ "auto",
75625
+ "utf-8",
75626
+ "base64"
75627
+ ]);
75628
+ const fsReadEncodingResponseSchema = z.enum(["utf-8", "base64"]);
75629
+ z.object({
75630
+ path: z.string().min(1),
75631
+ offset: z.number().int().nonnegative().default(0),
75632
+ length: z.number().int().min(1).max(10485760).default(1048576),
75633
+ encoding: fsReadEncodingRequestSchema.default("auto")
75634
+ });
75635
+ z.object({
75636
+ path: z.string(),
75637
+ content: z.string(),
75638
+ encoding: fsReadEncodingResponseSchema,
75639
+ size: z.number().int().nonnegative(),
75640
+ truncated: z.boolean(),
75641
+ etag: z.string(),
75642
+ mime: z.string(),
75643
+ language_id: z.string().optional(),
75644
+ line_count: z.number().int().nonnegative().optional(),
75645
+ is_binary: z.boolean()
75646
+ });
75647
+ z.object({
75648
+ paths: z.array(z.string().min(1)).min(1).max(100),
75649
+ depth: z.number().int().min(1).max(10).default(1),
75650
+ limit: z.number().int().min(1).max(1e3).default(200),
75651
+ show_hidden: z.boolean().default(false),
75652
+ follow_gitignore: z.boolean().default(true),
75653
+ exclude_globs: z.array(z.string()).optional(),
75654
+ sort: fsListSortSchema.default("type_first"),
75655
+ include_git_status: z.boolean().default(false)
75656
+ });
75657
+ const fsListManyPartialErrorSchema = z.object({
75658
+ code: z.number().int(),
75659
+ msg: z.string()
75660
+ });
75661
+ z.object({
75662
+ results: z.record(z.string(), z.array(fsEntrySchema)),
75663
+ truncated_paths: z.array(z.string()).optional(),
75664
+ partial_errors: z.record(z.string(), fsListManyPartialErrorSchema).optional()
75665
+ });
75666
+ z.object({ path: z.string().min(1) });
75667
+ z.object({ paths: z.array(z.string().min(1)).min(1).max(1e3) });
75668
+ z.object({ entries: z.record(z.string(), fsEntrySchema.nullable()) });
75669
+ z.object({
75670
+ query: z.string().min(1),
75671
+ limit: z.number().int().min(1).max(200).default(50),
75672
+ include_globs: z.array(z.string()).optional(),
75673
+ exclude_globs: z.array(z.string()).optional(),
75674
+ follow_gitignore: z.boolean().default(true)
75675
+ });
75676
+ z.object({
75677
+ items: z.array(fsSearchHitSchema),
75678
+ truncated: z.boolean()
75679
+ });
75680
+ z.object({
75681
+ pattern: z.string().min(1),
75682
+ regex: z.boolean().default(false),
75683
+ case_sensitive: z.boolean().default(true),
75684
+ include_globs: z.array(z.string()).optional(),
75685
+ exclude_globs: z.array(z.string()).optional(),
75686
+ follow_gitignore: z.boolean().default(true),
75687
+ max_files: z.number().int().min(1).max(1e4).default(200),
75688
+ max_matches_per_file: z.number().int().min(1).max(1e4).default(50),
75689
+ max_total_matches: z.number().int().min(1).max(1e5).default(5e3),
75690
+ context_lines: z.number().int().min(0).max(10).default(2)
75691
+ });
75692
+ z.object({
75693
+ files: z.array(fsGrepFileHitSchema),
75694
+ files_scanned: z.number().int().nonnegative(),
75695
+ truncated: z.boolean(),
75696
+ elapsed_ms: z.number().int().nonnegative()
75697
+ });
75698
+ z.object({ paths: z.array(z.string().min(1)).optional() });
75699
+ z.object({
75700
+ branch: z.string(),
75701
+ ahead: z.number().int().nonnegative(),
75702
+ behind: z.number().int().nonnegative(),
75703
+ entries: z.record(z.string(), fsGitStatusSchema)
75704
+ });
75705
+ z.object({
75706
+ path: z.string().min(1),
75707
+ range: z.string().optional(),
75708
+ if_none_match: z.string().optional()
75709
+ });
75710
+ z.object({ file_id: z.string().min(1) });
75711
+ z.object({ file_id: z.string().min(1) });
75712
+ z.object({ deleted: z.literal(true) });
75713
+ z.object({ items: z.array(modelCatalogItemSchema) });
75714
+ z.object({ items: z.array(providerCatalogItemSchema) });
75715
+ z.object({
75716
+ default_model: z.string().min(1),
75717
+ model: modelCatalogItemSchema
75718
+ });
74406
75719
  //#endregion
74407
75720
  //#region ../../packages/agent-core/src/mcp/oauth/callback-server.ts
74408
75721
  /**
@@ -80754,9 +82067,19 @@ var SkillTool = class SkillTool {
80754
82067
  const skillArgs = args.args ?? "";
80755
82068
  if (!isInlineSkillType(skill.metadata.type)) return errorResult(`Skill "${skill.name}" is not an inline skill and cannot be invoked by the model in v1.`);
80756
82069
  const origin = skillOrigin(skill, skillArgs, currentDepth);
82070
+ const promptTrigger = origin.trigger === "nested-skill" ? "nested-skill" : "model-tool";
80757
82071
  skills.recordActivation(origin);
80758
82072
  const skillContent = skills.registry.renderSkillPrompt(skill, skillArgs);
80759
- this.agent.context.appendSystemReminder(`<kimi-skill-loaded name="${escapeXml(skill.name)}" args="${escapeXml(skillArgs)}">\n${skillContent}\n</kimi-skill-loaded>`, origin);
82073
+ this.agent.context.appendUserMessage([{
82074
+ type: "text",
82075
+ text: renderModelToolSkillPrompt({
82076
+ skillName: skill.name,
82077
+ skillArgs,
82078
+ skillContent,
82079
+ skillSource: skill.source,
82080
+ trigger: promptTrigger
82081
+ })
82082
+ }], origin);
80760
82083
  return { output: `Skill "${skill.name}" loaded inline. Follow its instructions.` };
80761
82084
  }
80762
82085
  };
@@ -80816,7 +82139,7 @@ function makeCarriageReturnsVisible(text) {
80816
82139
  }
80817
82140
  //#endregion
80818
82141
  //#region ../../packages/agent-core/src/tools/builtin/file/edit.md
80819
- var edit_default = "Perform exact string replacements against the text view returned by Read.\n\n- When copying from Read output, omit the line-number prefix and tab; match only the file content.\n- By default, old_string must occur exactly once. If it matches multiple locations, add surrounding context or set replace_all when every occurrence should change.\n- Prefer Edit for targeted changes to existing files; use Write only for new files or complete overwrites.\n- To modify a file, always use Edit; do not run a Shell `sed` command for edits.\n- When making several independent changes, issue multiple Edit calls in parallel within a single response; edits to the same file are serialized automatically by a write lock.\n- When several parallel Edit calls target the same file, a write lock serializes them; they apply in the order the calls appear in your response. An edit fails with `old_string not found` if its old_string was taken from text an earlier edit already replaced — base every old_string on the latest Read view and order dependent edits accordingly.\n- For pure CRLF files, Read shows LF and Edit.old_string/new_string should use LF; Edit writes the file back with CRLF preserved.\n- For mixed line endings or lone carriage returns, Read displays carriage returns as \\r; include actual \\r escapes in old_string/new_string for those positions.";
82142
+ var edit_default = "Perform exact replacements in existing files.\n\n- Edit is mandatory for every incremental change, especially small edits. DO NOT use Write or Bash `sed`.\n- Read the target file before every Edit. DO NOT call Edit from memory, stale context, or a guessed `old_string`.\n- Take `old_string` and `new_string` from the Read output view.\n- Drop the line-number prefix and tab; match only file content.\n- `old_string` must be unique unless `replace_all` is set.\n- If `old_string` is ambiguous, add surrounding context. Use `replace_all` only when every occurrence should change.\n- Multiple Edit calls may run in one response only when they do not target the same file.\n- DO NOT issue consecutive Edit calls on the same file. A previous Edit can invalidate a later Edit's `old_string`, causing `old_string not found`. Read the file again before the next Edit.\n- A write lock serializes same-file edits in response order, but serialization does not make stale `old_string` valid.\n- For pure CRLF files, Read shows LF; use LF in `old_string` and `new_string`, and Edit writes CRLF back.\n- For mixed endings or lone carriage returns, Read shows carriage returns as \\r; include actual \\r escapes in those positions.\n";
80820
82143
  //#endregion
80821
82144
  //#region ../../packages/agent-core/src/tools/builtin/file/edit.ts
80822
82145
  const EditInputSchema = z.object({
@@ -87103,7 +88426,7 @@ var ReadMediaFileTool = class {
87103
88426
  };
87104
88427
  //#endregion
87105
88428
  //#region ../../packages/agent-core/src/tools/builtin/file/write.md
87106
- var write_default = "Overwrite or append to a file with content exactly as provided, creating the file if needed; the parent directory must already exist. Defaults to overwrite; append adds content to the end without adding a newline. Write does not use the Read/Edit model text view and does not preserve or infer the previous line-ending style: \\n stays LF, \\r\\n stays CRLF. Use Edit for targeted changes to existing files. When the content is very large, you can split it across multiple calls: write the first chunk with overwrite, then add the remaining chunks with append.\n";
88429
+ var write_default = "Create, append to, or replace a file entirely.\n\n- The parent directory must already exist.\n- Mode defaults to overwrite; append adds content at EOF without adding a newline.\n- Write is NOT ALLOWED for incremental changes to existing files, including trivial, one-line, quick, or cosmetic edits. Use Edit instead.\n- Use Write only when the file does not exist, you intend a complete replacement, or the new contents have little continuity with the old contents.\n- Read before overwriting an existing file.\n- Write ignores the Read/Edit line-number view. NEVER include line prefixes.\n- Write outputs content literally, including supplied line endings: \\n stays LF, \\r\\n stays CRLF.\n- For new content too large for one call, overwrite the first chunk, then append subsequent chunks. Never chunk Write to modify an existing file.\n";
87107
88430
  //#endregion
87108
88431
  //#region ../../packages/agent-core/src/tools/builtin/file/write.ts
87109
88432
  /** Mask isolating the file-type bits of a stat mode. */
@@ -137212,6 +138535,9 @@ new AsyncLocalStorage();
137212
138535
  //#endregion
137213
138536
  //#region ../../packages/agent-core/src/rpc/core-impl.ts
137214
138537
  const KIMI_CODE_PROVIDER_NAME$1 = "managed:kimi-code";
138538
+ const KIMI_CODE_BASE_URL_ENV = "KIMI_CODE_BASE_URL";
138539
+ const KIMI_CODE_OAUTH_HOST_ENV = "KIMI_CODE_OAUTH_HOST";
138540
+ const KIMI_OAUTH_HOST_ENV = "KIMI_OAUTH_HOST";
137215
138541
  var KimiCore = class {
137216
138542
  rpcClient;
137217
138543
  sdk;
@@ -137417,6 +138743,7 @@ var KimiCore = class {
137417
138743
  async forkSession(input) {
137418
138744
  const source = await this.sessionStore.get(input.sessionId);
137419
138745
  const active = this.sessions.get(source.id);
138746
+ if (active?.hasActiveTurn === true) throw new KimiError(ErrorCodes.SESSION_FORK_ACTIVE_TURN, `Session "${source.id}" cannot be forked while a turn is running`, { details: { sessionId: source.id } });
137420
138747
  if (active !== void 0) await active.flushMetadata();
137421
138748
  const id = input.id ?? createSessionId();
137422
138749
  await this.sessionStore.fork({
@@ -137700,13 +139027,38 @@ var KimiCore = class {
137700
139027
  });
137701
139028
  }
137702
139029
  mergePluginMcpConfig(base) {
137703
- const pluginServers = this.plugins.enabledMcpServers();
139030
+ const pluginServers = this.withManagedKimiPluginEnv(this.plugins.enabledMcpServers());
137704
139031
  if (Object.keys(pluginServers).length === 0) return base;
137705
139032
  return { servers: {
137706
139033
  ...base?.servers,
137707
139034
  ...pluginServers
137708
139035
  } };
137709
139036
  }
139037
+ withManagedKimiPluginEnv(pluginServers) {
139038
+ const managedEnv = this.managedKimiCodeEnvForPlugins();
139039
+ if (Object.keys(managedEnv).length === 0) return pluginServers;
139040
+ const out = {};
139041
+ for (const [name, server] of Object.entries(pluginServers)) out[name] = server.transport === "stdio" ? {
139042
+ ...server,
139043
+ env: {
139044
+ ...server.env,
139045
+ ...managedEnv
139046
+ }
139047
+ } : server;
139048
+ return out;
139049
+ }
139050
+ managedKimiCodeEnvForPlugins() {
139051
+ const provider = this.config.providers[KIMI_CODE_PROVIDER_NAME$1];
139052
+ const envBaseUrl = process.env[KIMI_CODE_BASE_URL_ENV];
139053
+ const envOAuthHost = process.env[KIMI_CODE_OAUTH_HOST_ENV] ?? process.env[KIMI_OAUTH_HOST_ENV];
139054
+ const hasEnvOverride = envBaseUrl !== void 0 || envOAuthHost !== void 0;
139055
+ const baseUrl = envBaseUrl !== void 0 ? envBaseUrl.replace(/\/+$/, "") : provider?.baseUrl;
139056
+ const oauthHost = hasEnvOverride ? envOAuthHost : provider?.oauth?.oauthHost;
139057
+ const env = {};
139058
+ if (baseUrl !== void 0) env[KIMI_CODE_BASE_URL_ENV] = baseUrl;
139059
+ if (oauthHost !== void 0) env[KIMI_CODE_OAUTH_HOST_ENV] = oauthHost;
139060
+ return env;
139061
+ }
137710
139062
  sessionApi(sessionId) {
137711
139063
  const session = this.sessions.get(sessionId);
137712
139064
  if (session === void 0) throw new KimiError(ErrorCodes.SESSION_NOT_FOUND, `Session "${sessionId}" was not found`, { details: { sessionId } });
@@ -160203,6 +161555,163 @@ var WelcomeComponent = class {
160203
161555
  }
160204
161556
  };
160205
161557
  //#endregion
161558
+ //#region src/tui/components/dialogs/compaction.ts
161559
+ /**
161560
+ * Renders a compaction block in the transcript.
161561
+ *
161562
+ * Lifecycle:
161563
+ * - constructed on `compaction.started` → blinking white bullet +
161564
+ * "Compacting context..." and optional custom instruction
161565
+ * - `markDone()` on `compaction.completed` → solid green bullet +
161566
+ * "Compaction complete (X → Y tokens)"
161567
+ * - `markCanceled()` on `compaction.cancelled` → solid warning bullet +
161568
+ * "Compaction cancelled"
161569
+ *
161570
+ * Bullet animation mirrors `ToolCallComponent` (500ms blink) so the user
161571
+ * reads the same "work in progress" signal across the UI.
161572
+ */
161573
+ const BLINK_INTERVAL = 500;
161574
+ var CompactionComponent = class extends Container {
161575
+ ui;
161576
+ headerText;
161577
+ instruction;
161578
+ blinkOn = true;
161579
+ blinkTimer = null;
161580
+ done = false;
161581
+ canceled = false;
161582
+ tokensBefore;
161583
+ tokensAfter;
161584
+ constructor(ui, instruction) {
161585
+ super();
161586
+ this.ui = ui;
161587
+ this.instruction = instruction;
161588
+ this.addChild(new Spacer(1));
161589
+ this.headerText = new Text(this.buildHeader(), 0, 0);
161590
+ this.addChild(this.headerText);
161591
+ this.addInstructionChild();
161592
+ this.startBlink();
161593
+ }
161594
+ addInstructionChild() {
161595
+ if (this.instruction !== void 0) this.addChild(new Text(currentTheme.dim(` ${this.instruction}`), 0, 0));
161596
+ }
161597
+ invalidate() {
161598
+ this.headerText.setText(this.buildHeader());
161599
+ if (this.instruction !== void 0) {
161600
+ if (this.children.length > 2) this.children.pop();
161601
+ this.addInstructionChild();
161602
+ }
161603
+ super.invalidate();
161604
+ }
161605
+ markDone(tokensBefore, tokensAfter) {
161606
+ if (this.done || this.canceled) return;
161607
+ this.done = true;
161608
+ this.tokensBefore = tokensBefore;
161609
+ this.tokensAfter = tokensAfter;
161610
+ this.stopBlink();
161611
+ this.headerText.setText(this.buildHeader());
161612
+ this.ui?.requestRender();
161613
+ }
161614
+ markCanceled() {
161615
+ if (this.done || this.canceled) return;
161616
+ this.canceled = true;
161617
+ this.stopBlink();
161618
+ this.headerText.setText(this.buildHeader());
161619
+ this.ui?.requestRender();
161620
+ }
161621
+ dispose() {
161622
+ this.stopBlink();
161623
+ }
161624
+ buildHeader() {
161625
+ if (this.done) return `${currentTheme.fg("success", STATUS_BULLET)}${currentTheme.boldFg("success", "Compaction complete")}${this.tokensBefore !== void 0 && this.tokensAfter !== void 0 ? currentTheme.dim(` (${String(this.tokensBefore)} → ${String(this.tokensAfter)} tokens)`) : ""}`;
161626
+ if (this.canceled) return `${currentTheme.fg("warning", STATUS_BULLET)}${currentTheme.boldFg("warning", "Compaction cancelled")}`;
161627
+ return `${this.blinkOn ? currentTheme.fg("text", STATUS_BULLET) : " "}${currentTheme.boldFg("primary", "Compacting context...")}`;
161628
+ }
161629
+ startBlink() {
161630
+ this.blinkTimer = setInterval(() => {
161631
+ this.blinkOn = !this.blinkOn;
161632
+ this.headerText.setText(this.buildHeader());
161633
+ this.ui?.requestRender();
161634
+ }, BLINK_INTERVAL);
161635
+ }
161636
+ stopBlink() {
161637
+ if (this.blinkTimer !== null) {
161638
+ clearInterval(this.blinkTimer);
161639
+ this.blinkTimer = null;
161640
+ }
161641
+ }
161642
+ };
161643
+ //#endregion
161644
+ //#region src/tui/components/dialogs/undo-selector.ts
161645
+ const MAX_VISIBLE_CHOICES = 5;
161646
+ const PREFERRED_SELECTED_OFFSET = 2;
161647
+ var UndoSelectorComponent = class extends Container {
161648
+ focused = false;
161649
+ opts;
161650
+ list;
161651
+ submitted = false;
161652
+ constructor(opts) {
161653
+ super();
161654
+ this.opts = opts;
161655
+ this.list = new SearchableList({
161656
+ items: opts.choices,
161657
+ toSearchText: (choice) => choice.label,
161658
+ initialIndex: Math.max(0, opts.choices.length - 1)
161659
+ });
161660
+ }
161661
+ handleInput(data) {
161662
+ if (this.submitted) return;
161663
+ if (matchesKey(data, Key.escape)) {
161664
+ this.opts.onCancel();
161665
+ return;
161666
+ }
161667
+ if (this.list.handleKey(data)) return;
161668
+ if (matchesKey(data, Key.enter)) {
161669
+ const selected = this.list.selected();
161670
+ if (selected !== void 0) {
161671
+ this.submitted = true;
161672
+ this.opts.onSelect(selected);
161673
+ }
161674
+ }
161675
+ }
161676
+ render(width) {
161677
+ const view = this.list.view();
161678
+ const lines = [
161679
+ currentTheme.fg("primary", "─".repeat(width)),
161680
+ currentTheme.boldFg("primary", " Select messages to undo"),
161681
+ currentTheme.fg("textMuted", " " + [
161682
+ "↑↓ navigate",
161683
+ "Enter select",
161684
+ "Esc cancel"
161685
+ ].join(" · ")),
161686
+ ""
161687
+ ];
161688
+ if (view.items.length === 0) lines.push(currentTheme.fg("textMuted", " No messages"));
161689
+ else {
161690
+ const visibleCount = Math.min(MAX_VISIBLE_CHOICES, view.items.length);
161691
+ const maxStart = view.items.length - visibleCount;
161692
+ const start = Math.min(Math.max(0, view.selectedIndex - PREFERRED_SELECTED_OFFSET), maxStart);
161693
+ const end = start + visibleCount;
161694
+ for (let i = start; i < end; i++) {
161695
+ const choice = view.items[i];
161696
+ if (choice === void 0) continue;
161697
+ lines.push(this.renderChoiceLine(choice, i === view.selectedIndex, i > view.selectedIndex, width));
161698
+ }
161699
+ }
161700
+ lines.push("");
161701
+ lines.push(currentTheme.fg("primary", "─".repeat(width)));
161702
+ return lines.map((line) => truncateToWidth(line, width));
161703
+ }
161704
+ renderChoiceLine(choice, isSelected, inUndoRange, width) {
161705
+ const prefix = ` ${isSelected ? "❯" : " "} `;
161706
+ const labelBudget = Math.max(8, width - visibleWidth(prefix));
161707
+ const label = truncateToWidth(choice.label, labelBudget, "…");
161708
+ const token = isSelected ? "primary" : inUndoRange ? "textDim" : "text";
161709
+ let line = currentTheme.fg(isSelected ? "primary" : "textDim", prefix);
161710
+ line += isSelected ? currentTheme.boldFg(token, label) : currentTheme.fg(token, label);
161711
+ return line;
161712
+ }
161713
+ };
161714
+ //#endregion
160206
161715
  //#region src/tui/components/messages/agent-group.ts
160207
161716
  const THROTTLE_MS$1 = 200;
160208
161717
  var AgentGroupComponent = class extends Container {
@@ -164517,34 +166026,64 @@ function getTranscriptComponentEntry(component) {
164517
166026
  return componentEntries.get(component);
164518
166027
  }
164519
166028
  //#endregion
166029
+ //#region src/tui/utils/transcript-id.ts
166030
+ let transcriptIdCounter = 0;
166031
+ function nextTranscriptId() {
166032
+ transcriptIdCounter += 1;
166033
+ return `entry-${String(transcriptIdCounter)}`;
166034
+ }
166035
+ //#endregion
164520
166036
  //#region src/tui/commands/undo.ts
166037
+ const UNDO_LIMIT_STATUS_TURN_ID = "undo-limit-status";
164521
166038
  async function handleUndoCommand(host, args = "") {
164522
166039
  if (host.state.appState.streamingPhase !== "idle") {
164523
166040
  host.showError("Cannot undo while streaming — press Esc or Ctrl-C first.");
164524
166041
  return;
164525
166042
  }
164526
- const count = parseUndoCount(args);
166043
+ const trimmed = args.trim();
166044
+ if (trimmed.length === 0) {
166045
+ await showUndoSelector(host);
166046
+ return;
166047
+ }
166048
+ const count = parseUndoCount(trimmed);
164527
166049
  if (count === void 0) {
164528
166050
  host.showError("Usage: /undo [count], where count is a positive integer.");
164529
166051
  return;
164530
166052
  }
166053
+ if (host.session === void 0) {
166054
+ host.showError(NO_ACTIVE_SESSION_MESSAGE);
166055
+ return;
166056
+ }
166057
+ const availability = await resolveUndoAvailability(host);
166058
+ if (count > availability.maxCount) {
166059
+ showUndoLimitStatus(host, formatUndoLimitMessage(count, availability));
166060
+ return;
166061
+ }
166062
+ await undoByCount(host, count);
166063
+ }
166064
+ async function undoByCount(host, count) {
164531
166065
  const session = host.session;
164532
166066
  if (session === void 0) {
164533
166067
  host.showError(NO_ACTIVE_SESSION_MESSAGE);
164534
- return;
166068
+ return false;
164535
166069
  }
164536
166070
  const entries = host.state.transcriptEntries;
164537
166071
  const lastUserIndex = findUndoAnchorEntryIndex(entries, count);
164538
166072
  if (lastUserIndex === void 0) {
164539
- host.showError("Nothing to undo.");
164540
- return;
166073
+ showUndoLimitStatus(host, "Nothing to undo.");
166074
+ return false;
164541
166075
  }
164542
166076
  try {
164543
166077
  await session.undoHistory(count);
164544
166078
  } catch (error) {
166079
+ const limit = undoLimitFromError(error);
166080
+ if (limit !== void 0) {
166081
+ showUndoLimitStatus(host, formatUndoLimitMessage(limit.requestedCount, limit));
166082
+ return false;
166083
+ }
164545
166084
  const message = formatErrorMessage$2(error);
164546
166085
  host.showError(`Failed to undo: ${message}`);
164547
- return;
166086
+ return false;
164548
166087
  }
164549
166088
  const children = host.state.transcriptContainer.children;
164550
166089
  const lastUserComponentIndex = findUndoAnchorComponentIndex(children, count);
@@ -164556,6 +166095,34 @@ async function handleUndoCommand(host, args = "") {
164556
166095
  entries.splice(lastUserIndex, entries.length - lastUserIndex, ...preservedEntries);
164557
166096
  if (entries.length === 0) renderWelcome(host);
164558
166097
  host.state.ui.requestRender();
166098
+ return true;
166099
+ }
166100
+ async function showUndoSelector(host) {
166101
+ if (host.session === void 0) {
166102
+ host.showError(NO_ACTIVE_SESSION_MESSAGE);
166103
+ return;
166104
+ }
166105
+ const availability = await resolveUndoAvailability(host);
166106
+ const choices = createUndoChoices(host.state.transcriptEntries, host.state.transcriptContainer.children, availability.maxCount);
166107
+ if (choices.length === 0) {
166108
+ showUndoLimitStatus(host, formatNothingToUndoMessage(availability));
166109
+ return;
166110
+ }
166111
+ host.mountEditorReplacement(new UndoSelectorComponent({
166112
+ choices,
166113
+ onSelect: (choice) => {
166114
+ undoByCount(host, choice.count).then((undone) => {
166115
+ if (undone) {
166116
+ host.restoreInputText(choice.input);
166117
+ return;
166118
+ }
166119
+ host.restoreEditor();
166120
+ });
166121
+ },
166122
+ onCancel: () => {
166123
+ host.restoreEditor();
166124
+ }
166125
+ }));
164559
166126
  }
164560
166127
  function parseUndoCount(args) {
164561
166128
  const value = args.trim();
@@ -164564,6 +166131,138 @@ function parseUndoCount(args) {
164564
166131
  const count = Number(value);
164565
166132
  return Number.isSafeInteger(count) ? count : void 0;
164566
166133
  }
166134
+ async function resolveUndoAvailability(host) {
166135
+ const local = undoAvailabilityFromTranscript(host.state.transcriptEntries, host.state.transcriptContainer.children);
166136
+ const context = await getSessionContext(host.session);
166137
+ if (context === void 0) return local;
166138
+ const activeContext = undoAvailabilityFromContext(context.history);
166139
+ return {
166140
+ maxCount: Math.min(local.maxCount, activeContext.maxCount),
166141
+ stoppedAtCompaction: local.stoppedAtCompaction || activeContext.stoppedAtCompaction
166142
+ };
166143
+ }
166144
+ async function getSessionContext(session) {
166145
+ const getContext = session?.getContext;
166146
+ if (session === void 0 || getContext === void 0) return void 0;
166147
+ try {
166148
+ return await getContext.call(session);
166149
+ } catch {
166150
+ return;
166151
+ }
166152
+ }
166153
+ function undoAvailabilityFromTranscript(entries, children) {
166154
+ const { anchors, stoppedAtCompaction } = activeUndoAnchorEntries(entries, children);
166155
+ return {
166156
+ maxCount: anchors.length,
166157
+ stoppedAtCompaction
166158
+ };
166159
+ }
166160
+ function undoAvailabilityFromContext(history) {
166161
+ let maxCount = 0;
166162
+ let stoppedAtCompaction = false;
166163
+ for (let i = history.length - 1; i >= 0; i--) {
166164
+ const message = history[i];
166165
+ if (message === void 0) continue;
166166
+ if (message.origin?.kind === "injection") continue;
166167
+ if (message.origin?.kind === "compaction_summary") {
166168
+ stoppedAtCompaction = true;
166169
+ break;
166170
+ }
166171
+ if (isContextUndoAnchor(message)) maxCount++;
166172
+ }
166173
+ return {
166174
+ maxCount,
166175
+ stoppedAtCompaction
166176
+ };
166177
+ }
166178
+ function isContextUndoAnchor(message) {
166179
+ if (message.role !== "user") return false;
166180
+ const origin = message.origin;
166181
+ if (origin === void 0 || origin.kind === "user") return true;
166182
+ if (origin.kind === "skill_activation") return origin.trigger === "user-slash";
166183
+ return false;
166184
+ }
166185
+ function createUndoChoices(entries, children, maxCount) {
166186
+ if (maxCount <= 0) return [];
166187
+ const anchors = activeUndoAnchorEntries(entries, children).anchors.slice(-maxCount);
166188
+ return anchors.map((entry, index) => ({
166189
+ id: entry.id,
166190
+ count: anchors.length - index,
166191
+ input: formatUndoChoiceInput(entry),
166192
+ label: formatUndoChoiceLabel(entry)
166193
+ }));
166194
+ }
166195
+ function activeUndoAnchorEntries(entries, children) {
166196
+ const lastCompactionChildIndex = children.findLastIndex((child) => child instanceof CompactionComponent);
166197
+ if (lastCompactionChildIndex >= 0) return {
166198
+ anchors: children.slice(lastCompactionChildIndex + 1).map((child) => getTranscriptComponentEntry(child)).filter((entry) => entry !== void 0).filter(isUndoAnchorEntry),
166199
+ stoppedAtCompaction: true
166200
+ };
166201
+ const lastCompactionEntryIndex = entries.findLastIndex((entry) => entry.compactionData !== void 0);
166202
+ return {
166203
+ anchors: (lastCompactionEntryIndex >= 0 ? entries.slice(lastCompactionEntryIndex + 1) : entries).filter(isUndoAnchorEntry),
166204
+ stoppedAtCompaction: lastCompactionEntryIndex >= 0
166205
+ };
166206
+ }
166207
+ function formatUndoChoiceLabel(entry) {
166208
+ if (entry.kind === "skill_activation") {
166209
+ const name = singleLine$2(entry.skillName ?? entry.content.replace(/^Activated skill:\s*/, ""));
166210
+ const args = singleLine$2(entry.skillArgs ?? "");
166211
+ if (name.length === 0) return "Skill: unknown";
166212
+ return args.length > 0 ? `/${name} ${args}` : `/${name}`;
166213
+ }
166214
+ const content = singleLine$2(entry.content);
166215
+ const imageCount = entry.imageAttachmentIds?.length ?? 0;
166216
+ if (content.length > 0) return content;
166217
+ if (imageCount > 0) return `User message (${String(imageCount)} ${imageCount === 1 ? "image" : "images"})`;
166218
+ return "User message";
166219
+ }
166220
+ function formatUndoChoiceInput(entry) {
166221
+ if (entry.kind === "skill_activation") {
166222
+ const name = singleLine$2(entry.skillName ?? entry.content.replace(/^Activated skill:\s*/, ""));
166223
+ const args = singleLine$2(entry.skillArgs ?? "");
166224
+ if (name.length === 0) return "";
166225
+ return args.length > 0 ? `/${name} ${args}` : `/${name}`;
166226
+ }
166227
+ return entry.content;
166228
+ }
166229
+ function singleLine$2(text) {
166230
+ return text.replaceAll(/\s+/g, " ").trim();
166231
+ }
166232
+ function formatUndoLimitMessage(requestedCount, availability) {
166233
+ const reason = availability.stoppedAtCompaction ? " after the last compaction" : "";
166234
+ return `Cannot undo ${formatPromptCount(requestedCount)}; only ${formatPromptCount(availability.maxCount)} can be undone in the active context${reason}.`;
166235
+ }
166236
+ function formatNothingToUndoMessage(availability) {
166237
+ if (availability.stoppedAtCompaction) return "Nothing to undo after the last compaction.";
166238
+ return "Nothing to undo.";
166239
+ }
166240
+ function formatPromptCount(count) {
166241
+ return `${String(count)} ${count === 1 ? "prompt" : "prompts"}`;
166242
+ }
166243
+ function showUndoLimitStatus(host, message) {
166244
+ host.appendTranscriptEntry({
166245
+ id: nextTranscriptId(),
166246
+ kind: "status",
166247
+ turnId: UNDO_LIMIT_STATUS_TURN_ID,
166248
+ renderMode: "plain",
166249
+ content: message
166250
+ });
166251
+ }
166252
+ function undoLimitFromError(error) {
166253
+ if (!isKimiError(error)) return void 0;
166254
+ const details = error.details;
166255
+ if (details?.["reason"] !== "undo_limit") return void 0;
166256
+ const requestedCount = details["requestedCount"];
166257
+ const maxCount = details["undoableCount"];
166258
+ const stoppedAtCompaction = details["stoppedAtCompaction"];
166259
+ if (typeof requestedCount !== "number" || typeof maxCount !== "number" || typeof stoppedAtCompaction !== "boolean") return;
166260
+ return {
166261
+ requestedCount,
166262
+ maxCount,
166263
+ stoppedAtCompaction
166264
+ };
166265
+ }
164567
166266
  function isUndoAnchorEntry(entry) {
164568
166267
  return entry.kind === "user" || entry.kind === "skill_activation" && entry.skillTrigger === "user-slash";
164569
166268
  }
@@ -166187,92 +167886,6 @@ function stripLeadingSpace(s) {
166187
167886
  return s.replace(/^ +/, "");
166188
167887
  }
166189
167888
  //#endregion
166190
- //#region src/tui/components/dialogs/compaction.ts
166191
- /**
166192
- * Renders a compaction block in the transcript.
166193
- *
166194
- * Lifecycle:
166195
- * - constructed on `compaction.started` → blinking white bullet +
166196
- * "Compacting context..." and optional custom instruction
166197
- * - `markDone()` on `compaction.completed` → solid green bullet +
166198
- * "Compaction complete (X → Y tokens)"
166199
- * - `markCanceled()` on `compaction.cancelled` → solid warning bullet +
166200
- * "Compaction cancelled"
166201
- *
166202
- * Bullet animation mirrors `ToolCallComponent` (500ms blink) so the user
166203
- * reads the same "work in progress" signal across the UI.
166204
- */
166205
- const BLINK_INTERVAL = 500;
166206
- var CompactionComponent = class extends Container {
166207
- ui;
166208
- headerText;
166209
- instruction;
166210
- blinkOn = true;
166211
- blinkTimer = null;
166212
- done = false;
166213
- canceled = false;
166214
- tokensBefore;
166215
- tokensAfter;
166216
- constructor(ui, instruction) {
166217
- super();
166218
- this.ui = ui;
166219
- this.instruction = instruction;
166220
- this.addChild(new Spacer(1));
166221
- this.headerText = new Text(this.buildHeader(), 0, 0);
166222
- this.addChild(this.headerText);
166223
- this.addInstructionChild();
166224
- this.startBlink();
166225
- }
166226
- addInstructionChild() {
166227
- if (this.instruction !== void 0) this.addChild(new Text(currentTheme.dim(` ${this.instruction}`), 0, 0));
166228
- }
166229
- invalidate() {
166230
- this.headerText.setText(this.buildHeader());
166231
- if (this.instruction !== void 0) {
166232
- if (this.children.length > 2) this.children.pop();
166233
- this.addInstructionChild();
166234
- }
166235
- super.invalidate();
166236
- }
166237
- markDone(tokensBefore, tokensAfter) {
166238
- if (this.done || this.canceled) return;
166239
- this.done = true;
166240
- this.tokensBefore = tokensBefore;
166241
- this.tokensAfter = tokensAfter;
166242
- this.stopBlink();
166243
- this.headerText.setText(this.buildHeader());
166244
- this.ui?.requestRender();
166245
- }
166246
- markCanceled() {
166247
- if (this.done || this.canceled) return;
166248
- this.canceled = true;
166249
- this.stopBlink();
166250
- this.headerText.setText(this.buildHeader());
166251
- this.ui?.requestRender();
166252
- }
166253
- dispose() {
166254
- this.stopBlink();
166255
- }
166256
- buildHeader() {
166257
- if (this.done) return `${currentTheme.fg("success", STATUS_BULLET)}${currentTheme.boldFg("success", "Compaction complete")}${this.tokensBefore !== void 0 && this.tokensAfter !== void 0 ? currentTheme.dim(` (${String(this.tokensBefore)} → ${String(this.tokensAfter)} tokens)`) : ""}`;
166258
- if (this.canceled) return `${currentTheme.fg("warning", STATUS_BULLET)}${currentTheme.boldFg("warning", "Compaction cancelled")}`;
166259
- return `${this.blinkOn ? currentTheme.fg("text", STATUS_BULLET) : " "}${currentTheme.boldFg("primary", "Compacting context...")}`;
166260
- }
166261
- startBlink() {
166262
- this.blinkTimer = setInterval(() => {
166263
- this.blinkOn = !this.blinkOn;
166264
- this.headerText.setText(this.buildHeader());
166265
- this.ui?.requestRender();
166266
- }, BLINK_INTERVAL);
166267
- }
166268
- stopBlink() {
166269
- if (this.blinkTimer !== null) {
166270
- clearInterval(this.blinkTimer);
166271
- this.blinkTimer = null;
166272
- }
166273
- }
166274
- };
166275
- //#endregion
166276
167889
  //#region src/tui/components/dialogs/help-panel.ts
166277
167890
  /**
166278
167891
  * HelpPanel — modal `/help` display. Lists keyboard shortcuts, slash
@@ -169022,6 +170635,14 @@ var EditorKeyboardController = class {
169022
170635
  };
169023
170636
  //#endregion
169024
170637
  //#region src/tui/components/messages/goal-markers.ts
170638
+ /**
170639
+ * Low-profile transcript markers for the autonomous goal loop.
170640
+ *
170641
+ * Lifecycle changes (paused / resumed / cancelled) and `no_progress` verdicts
170642
+ * render as a single dim line — `◦ Goal paused` — that expands (ctrl+o, shared
170643
+ * with tool output) to show the reason when there is one. Terminal outcomes use
170644
+ * the richer completion card (the `/goal` box), not this marker.
170645
+ */
169025
170646
  const HEAD_INDENT = " ";
169026
170647
  const DETAIL_INDENT = " ";
169027
170648
  var GoalMarkerComponent = class {
@@ -169051,13 +170672,18 @@ var GoalMarkerComponent = class {
169051
170672
  render(width) {
169052
170673
  const dot = currentTheme.fg(this.accentToken, this.marker);
169053
170674
  const head = currentTheme.fg(this.textToken, this.headline);
169054
- if (!(this.detail !== void 0 && this.detail.length > 0)) return this.withLeadingBlank([`${this.indent}${dot} ${head}`]);
169055
- if (!this.expandable) return this.withLeadingBlank([`${this.indent}${dot} ${head}`]);
169056
- if (!this.expanded) return this.withLeadingBlank([`${this.indent}${dot} ${head} ${currentTheme.fg("textMuted", "(ctrl+o)")}`]);
170675
+ if (!(this.detail !== void 0 && this.detail.length > 0)) return this.clampToWidth([`${this.indent}${dot} ${head}`], width);
170676
+ if (!this.expandable) return this.clampToWidth([`${this.indent}${dot} ${head}`], width);
170677
+ if (!this.expanded) return this.clampToWidth([`${this.indent}${dot} ${head} ${currentTheme.fg("textMuted", "(ctrl+o)")}`], width);
169057
170678
  const out = [`${this.indent}${dot} ${head}`];
169058
170679
  const wrapWidth = Math.max(20, width - 4);
169059
170680
  for (const line of wrap(this.detail, wrapWidth)) out.push(DETAIL_INDENT + currentTheme.fg("textDim", line));
169060
- return this.withLeadingBlank(out);
170681
+ return this.clampToWidth(out, width);
170682
+ }
170683
+ clampToWidth(lines, width) {
170684
+ const withBlank = this.withLeadingBlank(lines);
170685
+ if (width <= 0) return withBlank.map(() => "");
170686
+ return withBlank.map((line) => truncateToWidth(line, width));
169061
170687
  }
169062
170688
  withLeadingBlank(lines) {
169063
170689
  return this.leadingBlank ? ["", ...lines] : lines;
@@ -169118,7 +170744,7 @@ function lowercaseFirst(text) {
169118
170744
  return text.length === 0 ? text : `${text[0].toLowerCase()}${text.slice(1)}`;
169119
170745
  }
169120
170746
  function wrap(text, width) {
169121
- const words = text.replace(/\s+/g, " ").trim().split(" ");
170747
+ const words = text.replaceAll(/\s+/g, " ").trim().split(" ");
169122
170748
  const lines = [];
169123
170749
  let current = "";
169124
170750
  for (const word of words) {
@@ -169381,13 +171007,6 @@ function formatDuration(ms) {
169381
171007
  return `${(ms / 1e3).toFixed(1)}s`;
169382
171008
  }
169383
171009
  //#endregion
169384
- //#region src/tui/utils/transcript-id.ts
169385
- let transcriptIdCounter = 0;
169386
- function nextTranscriptId() {
169387
- transcriptIdCounter += 1;
169388
- return `entry-${String(transcriptIdCounter)}`;
169389
- }
169390
- //#endregion
169391
171010
  //#region src/tui/utils/background-agent-status.ts
169392
171011
  const MAX_BACKGROUND_FIELD_LENGTH = 240;
169393
171012
  function normalizeBackgroundField(value) {