@moonshot-ai/kimi-code 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/main.mjs +1813 -146
  2. package/package.json +3 -3
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 = {};
@@ -45834,6 +45840,8 @@ const OPENAI_CHAT_TOOL_CALL_ID_POLICY = {
45834
45840
  normalize: (id) => sanitizeToolCallId(id, 64),
45835
45841
  maxLength: 64
45836
45842
  };
45843
+ const TOOL_RESULT_IMAGE_PROMPT = "Attached image(s) from tool result:";
45844
+ const TOOL_RESULT_IMAGE_PLACEHOLDER = "(see attached image)";
45837
45845
  function extractReasoningContent(source, explicitKey) {
45838
45846
  if (typeof source !== "object" || source === null) return void 0;
45839
45847
  const record = source;
@@ -45866,7 +45874,7 @@ function convertMessage$1(message, reasoningKey, toolMessageConversion) {
45866
45874
  const result = { role: message.role };
45867
45875
  if (message.role === "tool") {
45868
45876
  const effectiveConversion = message.content.some((p) => p.type !== "text" && p.type !== "think") ? "extract_text" : toolMessageConversion;
45869
- if (effectiveConversion !== null) result.content = convertToolMessageContent(message, effectiveConversion);
45877
+ if (effectiveConversion !== null) result.content = convertToolMessageContentForChat(message, effectiveConversion);
45870
45878
  else {
45871
45879
  const firstPart = nonThinkParts[0];
45872
45880
  if (nonThinkParts.length === 1 && firstPart?.type === "text") result.content = firstPart.text;
@@ -45890,6 +45898,47 @@ function convertMessage$1(message, reasoningKey, toolMessageConversion) {
45890
45898
  if (reasoningContent) result[reasoningKey ?? DEFAULT_OUTBOUND_REASONING_KEY] = reasoningContent;
45891
45899
  return result;
45892
45900
  }
45901
+ function convertToolMessageContentForChat(message, conversion) {
45902
+ const content = convertToolMessageContent(message, conversion);
45903
+ if (typeof content === "string" && content.length === 0 && message.content.some((part) => part.type === "image_url")) return TOOL_RESULT_IMAGE_PLACEHOLDER;
45904
+ return content;
45905
+ }
45906
+ function toolResultImageParts(message) {
45907
+ const images = [];
45908
+ for (const part of message.content) {
45909
+ if (part.type !== "image_url") continue;
45910
+ images.push({
45911
+ type: "image_url",
45912
+ image_url: part.imageUrl.id === void 0 ? { url: part.imageUrl.url } : {
45913
+ url: part.imageUrl.url,
45914
+ id: part.imageUrl.id
45915
+ }
45916
+ });
45917
+ }
45918
+ return images;
45919
+ }
45920
+ function appendToolResultImagesMessage(messages, pendingToolResultImages) {
45921
+ if (pendingToolResultImages.length === 0) return;
45922
+ messages.push({
45923
+ role: "user",
45924
+ content: [{
45925
+ type: "text",
45926
+ text: TOOL_RESULT_IMAGE_PROMPT
45927
+ }, ...pendingToolResultImages]
45928
+ });
45929
+ pendingToolResultImages.length = 0;
45930
+ }
45931
+ function convertHistoryMessages(history, reasoningKey, toolMessageConversion) {
45932
+ const messages = [];
45933
+ const pendingToolResultImages = [];
45934
+ for (const msg of history) {
45935
+ if (msg.role !== "tool") appendToolResultImagesMessage(messages, pendingToolResultImages);
45936
+ messages.push(convertMessage$1(msg, reasoningKey, toolMessageConversion));
45937
+ if (msg.role === "tool") pendingToolResultImages.push(...toolResultImageParts(msg));
45938
+ }
45939
+ appendToolResultImagesMessage(messages, pendingToolResultImages);
45940
+ return messages;
45941
+ }
45893
45942
  var OpenAILegacyStreamedMessage = class {
45894
45943
  _id = null;
45895
45944
  _usage = null;
@@ -46025,7 +46074,7 @@ var OpenAILegacyChatProvider = class {
46025
46074
  content: systemPrompt
46026
46075
  });
46027
46076
  const normalizedHistory = normalizeToolCallIdsForProvider(history, OPENAI_CHAT_TOOL_CALL_ID_POLICY);
46028
- for (const msg of normalizedHistory) messages.push(convertMessage$1(msg, this._reasoningKey, this._toolMessageConversion));
46077
+ messages.push(...convertHistoryMessages(normalizedHistory, this._reasoningKey, this._toolMessageConversion));
46029
46078
  const kwargs = normalizeGenerationKwargs(this._model, this._generationKwargs);
46030
46079
  let reasoningEffort = this._reasoningEffort;
46031
46080
  if (reasoningEffort === void 0 && kwargs["reasoning_effort"] === void 0) {
@@ -56514,7 +56563,12 @@ var ContextMemory = class {
56514
56563
  this.deferredMessages = [];
56515
56564
  this.agent.microCompaction.reset(this._history.length);
56516
56565
  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.");
56566
+ if (!this.agent.records.restoring && (stoppedAtBoundary || removedUserCount < count)) throw new KimiError(ErrorCodes.REQUEST_INVALID, formatUndoUnavailableMessage(count, removedUserCount, stoppedAtBoundary), { details: {
56567
+ reason: "undo_limit",
56568
+ requestedCount: count,
56569
+ undoableCount: removedUserCount,
56570
+ stoppedAtCompaction: stoppedAtBoundary
56571
+ } });
56518
56572
  }
56519
56573
  applyCompaction(summary) {
56520
56574
  this.agent.records.logRecord({
@@ -56683,6 +56737,13 @@ function isRealUserPrompt(message) {
56683
56737
  if (origin.kind === "skill_activation") return origin.trigger === "user-slash";
56684
56738
  return false;
56685
56739
  }
56740
+ function formatUndoUnavailableMessage(requestedCount, undoableCount, stoppedAtCompaction) {
56741
+ const reason = stoppedAtCompaction ? " after the last compaction" : "";
56742
+ return `Cannot undo ${formatPromptCount(requestedCount)}; only ${formatPromptCount(undoableCount)} can be undone in the active context${reason}.`;
56743
+ function formatPromptCount(count) {
56744
+ return `${String(count)} ${count === 1 ? "prompt" : "prompts"}`;
56745
+ }
56746
+ }
56686
56747
  //#endregion
56687
56748
  //#region ../../packages/agent-core/src/agent/goal/index.ts
56688
56749
  /**
@@ -57459,6 +57520,7 @@ const HOOK_EVENT_TYPES = [
57459
57520
  "UserPromptSubmit",
57460
57521
  "Stop",
57461
57522
  "StopFailure",
57523
+ "Interrupt",
57462
57524
  "SessionStart",
57463
57525
  "SessionEnd",
57464
57526
  "SubagentStart",
@@ -58449,26 +58511,6 @@ var GitControlPathAccessAskPermissionPolicy = class {
58449
58511
  };
58450
58512
  }
58451
58513
  };
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
58514
  function fileAccesses(context) {
58473
58515
  return context.execution.accesses?.filter((access) => access.kind === "file") ?? [];
58474
58516
  }
@@ -60689,7 +60731,6 @@ function createPermissionDecisionPolicies(agent) {
60689
60731
  new PlanModeToolApprovePermissionPolicy(agent),
60690
60732
  new SensitiveFileAccessAskPermissionPolicy(agent),
60691
60733
  new GitControlPathAccessAskPermissionPolicy(agent),
60692
- new CwdOutsideFileWriteAskPermissionPolicy(agent),
60693
60734
  new YoloModeApprovePermissionPolicy(agent),
60694
60735
  new SwarmModeAgentSwarmApprovePermissionPolicy(agent),
60695
60736
  new DefaultToolApprovePermissionPolicy(),
@@ -66161,6 +66202,43 @@ function truncate$1(value, max) {
66161
66202
  return value.length > max ? value.slice(0, max) : value;
66162
66203
  }
66163
66204
  //#endregion
66205
+ //#region ../../packages/agent-core/src/agent/skill/prompt.ts
66206
+ function renderUserSlashSkillPrompt(input) {
66207
+ return [
66208
+ `User activated the skill "${escapeXml(input.skillName)}". Follow the loaded skill instructions.`,
66209
+ "",
66210
+ renderSkillLoadedBlock({
66211
+ ...input,
66212
+ trigger: "user-slash"
66213
+ })
66214
+ ].join("\n");
66215
+ }
66216
+ function renderModelToolSkillPrompt(input) {
66217
+ return [
66218
+ "Skill tool loaded instructions for this request. Follow them.",
66219
+ "",
66220
+ renderSkillLoadedBlock({
66221
+ ...input,
66222
+ trigger: input.trigger
66223
+ })
66224
+ ].join("\n");
66225
+ }
66226
+ function renderSkillLoadedBlock(input) {
66227
+ return [
66228
+ `<kimi-skill-loaded${renderSkillAttributes(input)}>`,
66229
+ input.skillContent,
66230
+ "</kimi-skill-loaded>"
66231
+ ].join("\n");
66232
+ }
66233
+ function renderSkillAttributes(input) {
66234
+ return [
66235
+ ["name", input.skillName],
66236
+ ["trigger", input.trigger],
66237
+ ["source", input.skillSource],
66238
+ ["args", input.skillArgs]
66239
+ ].filter((item) => item[1] !== void 0).map(([name, value]) => ` ${name}="${escapeXml(value)}"`).join("");
66240
+ }
66241
+ //#endregion
66164
66242
  //#region ../../packages/agent-core/src/agent/skill/index.ts
66165
66243
  var SkillManager = class {
66166
66244
  agent;
@@ -66173,12 +66251,16 @@ var SkillManager = class {
66173
66251
  const skill = this.registry.getSkill(input.name);
66174
66252
  if (skill === void 0) throw new KimiError(ErrorCodes.SKILL_NOT_FOUND, `Skill "${input.name}" was not found`);
66175
66253
  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)}"` : "";
66254
+ const skillArgs = input.args ?? "";
66255
+ const skillContent = this.registry.renderSkillPrompt(skill, skillArgs);
66179
66256
  const wrapped = [{
66180
66257
  type: "text",
66181
- text: `<system-reminder>\n<kimi-skill-loaded name="${escapeXml(skill.name)}"${argsAttr}>\n${skillContent}\n</kimi-skill-loaded>\n</system-reminder>`
66258
+ text: renderUserSlashSkillPrompt({
66259
+ skillName: skill.name,
66260
+ skillArgs,
66261
+ skillContent,
66262
+ skillSource: skill.source
66263
+ })
66182
66264
  }];
66183
66265
  this.recordActivation({
66184
66266
  kind: "skill_activation",
@@ -74401,8 +74483,1283 @@ function makeInterruptedEvent(reason, attemptedSteps, activeStep, message) {
74401
74483
  };
74402
74484
  }
74403
74485
  //#endregion
74404
- //#region ../../packages/agent-core/src/rpc/events.ts
74486
+ //#region ../../packages/protocol/src/error-codes.ts
74487
+ /**
74488
+ * Integer namespaces:
74489
+ * - 0 success
74490
+ * - 4xxxx 客户端错误 (HTTP-4xx analog)
74491
+ * - 5xxxx daemon 内部错误
74492
+ * - 6xxxx 工具运行时
74493
+ * - 7xxxx LLM provider 透传 (msg = original upstream text)
74494
+ * - 8xxxx MCP server 透传 (msg = original upstream text)
74495
+ * - 9xxxx 预留
74496
+ */
74497
+ const ErrorCode$1 = {
74498
+ /** 成功 */
74499
+ SUCCESS: 0,
74500
+ /** Zod 校验失败,`details` 含字段路径列表 */
74501
+ VALIDATION_FAILED: 40001,
74502
+ /** JSON 解析失败、字段类型错 */
74503
+ REQUEST_MALFORMED: 40002,
74504
+ /** daemon 没有任何 provider 配置 */
74505
+ AUTH_PROVISIONING_REQUIRED: 40110,
74506
+ /** provider 存在但 token / api_key 缺失 */
74507
+ AUTH_TOKEN_MISSING: 40111,
74508
+ /** 刷新 token 收到 401(用户撤销了授权) */
74509
+ AUTH_TOKEN_UNAUTHORIZED: 40112,
74510
+ /** 默认 / 请求的 model 解析不到 provider */
74511
+ AUTH_MODEL_NOT_RESOLVED: 40113,
74512
+ /** session_id 不存在 */
74513
+ SESSION_NOT_FOUND: 40401,
74514
+ /** prompt_id 不存在 */
74515
+ PROMPT_NOT_FOUND: 40402,
74516
+ /** message_id 不存在 */
74517
+ MESSAGE_NOT_FOUND: 40403,
74518
+ /** approval_id 不存在 */
74519
+ APPROVAL_NOT_FOUND: 40404,
74520
+ /** question_id 不存在 */
74521
+ QUESTION_NOT_FOUND: 40405,
74522
+ /** task_id 不存在 */
74523
+ TASK_NOT_FOUND: 40406,
74524
+ /** file_id 不存在 */
74525
+ FILE_NOT_FOUND: 40407,
74526
+ /** mcp_server_id 不存在 */
74527
+ MCP_SERVER_NOT_FOUND: 40408,
74528
+ /** fs path 不存在 */
74529
+ FS_PATH_NOT_FOUND: 40409,
74530
+ /** workspace_id 不存在 */
74531
+ WORKSPACE_NOT_FOUND: 40410,
74532
+ /** fs 路径存在但当前进程无权限读取 */
74533
+ FS_PERMISSION_DENIED: 40411,
74534
+ /** provider_id 不存在 */
74535
+ PROVIDER_NOT_FOUND: 40412,
74536
+ /** model_id 不存在 */
74537
+ MODEL_NOT_FOUND: 40413,
74538
+ /** session 有正在进行的 prompt,拒绝新请求 */
74539
+ SESSION_BUSY: 40901,
74540
+ /** approval 已被其他 client 应答 */
74541
+ APPROVAL_ALREADY_RESOLVED: 40902,
74542
+ /** prompt 已结束(abort 幂等返回 0) */
74543
+ PROMPT_ALREADY_COMPLETED: 40903,
74544
+ /** task 已完结,无法取消 */
74545
+ TASK_ALREADY_FINISHED: 40904,
74546
+ /** mcp restart 时若已在 connecting/connected */
74547
+ MCP_ALREADY_CONNECTED: 40905,
74548
+ /** fs.read 请求 file,但 path 是目录 */
74549
+ FS_IS_DIRECTORY: 40906,
74550
+ /** fs.read 请求 utf-8,但 path 是二进制;client 改走 `:download` */
74551
+ FS_IS_BINARY: 40907,
74552
+ /** fs.git_status 但 session.cwd 不是 git repo */
74553
+ FS_GIT_UNAVAILABLE: 40908,
74554
+ /** 用户 ESC / 关闭面板放弃整组(client 调 `:dismiss`) */
74555
+ QUESTION_DISMISSED: 40909,
74556
+ /** 当前历史没有可 compact 的前缀 */
74557
+ COMPACTION_UNABLE: 40910,
74558
+ /** 当前历史没有足够的用户提示词可撤回 */
74559
+ SESSION_UNDO_UNAVAILABLE: 40911,
74560
+ /** approval 60s 超时 */
74561
+ APPROVAL_EXPIRED: 41001,
74562
+ /** question 60s 超时 */
74563
+ QUESTION_EXPIRED: 41002,
74564
+ /** 临时文件已过期 */
74565
+ FILE_EXPIRED: 41003,
74566
+ /** 上传超 50MB */
74567
+ FILE_TOO_LARGE: 41301,
74568
+ /** fs.read 超 10MB */
74569
+ FS_TOO_LARGE: 41302,
74570
+ /** fs.list / fs.search / fs.grep 命中超上限 */
74571
+ FS_TOO_MANY_RESULTS: 41303,
74572
+ /** path 越出 session cwd 边界 */
74573
+ FS_PATH_ESCAPES_SESSION: 41304,
74574
+ /** fs.grep 执行 >30s */
74575
+ FS_GREP_TIMEOUT: 41305,
74576
+ /** WS 单连接 watch_paths > 100 */
74577
+ FS_WATCH_LIMIT_EXCEEDED: 42902,
74578
+ /** 兜底 */
74579
+ INTERNAL_ERROR: 50001,
74580
+ /** 写入 session 持久化失败 */
74581
+ PERSISTENCE_FAILURE: 50003,
74582
+ /** tool 执行抛错 */
74583
+ TOOL_EXECUTION_FAILED: 60001,
74584
+ /** tool 在此 session 未启用 */
74585
+ TOOL_NOT_AVAILABLE: 60002
74586
+ };
74587
+ 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;
74588
+ //#endregion
74589
+ //#region ../../packages/protocol/src/pagination.ts
74590
+ const cursorQuerySchema = z.object({
74591
+ before_id: z.string().min(1).optional(),
74592
+ after_id: z.string().min(1).optional(),
74593
+ page_size: z.number().int().min(1).max(100).optional()
74594
+ }).superRefine((value, ctx) => {
74595
+ if (value.before_id !== void 0 && value.after_id !== void 0) ctx.addIssue({
74596
+ code: "custom",
74597
+ message: "before_id and after_id are mutually exclusive",
74598
+ path: ["before_id"],
74599
+ params: { code: ErrorCode$1.VALIDATION_FAILED }
74600
+ });
74601
+ });
74602
+ const pageResponseSchema = (item) => z.object({
74603
+ items: z.array(item),
74604
+ has_more: z.boolean()
74605
+ });
74606
+ //#endregion
74607
+ //#region ../../packages/protocol/src/time.ts
74608
+ 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})?)$/;
74609
+ const isoDateTimeSchema = z.string().refine((value) => ISO_8601_REGEX.test(value), { message: "must be an ISO 8601 datetime string" }).transform((value, ctx) => {
74610
+ const ms = Date.parse(value);
74611
+ if (Number.isNaN(ms)) {
74612
+ ctx.addIssue({
74613
+ code: "custom",
74614
+ message: "invalid ISO 8601 datetime"
74615
+ });
74616
+ return z.NEVER;
74617
+ }
74618
+ return new Date(ms).toISOString();
74619
+ });
74620
+ //#endregion
74621
+ //#region ../../packages/protocol/src/events.ts
74405
74622
  const MCP_OAUTH_AUTHORIZATION_URL_TOOL_UPDATE = "mcp.oauth.authorization_url";
74623
+ z.discriminatedUnion("kind", [
74624
+ z.object({
74625
+ kind: z.literal("command"),
74626
+ command: z.string(),
74627
+ cwd: z.string().optional(),
74628
+ description: z.string().optional(),
74629
+ language: z.literal("bash").optional()
74630
+ }),
74631
+ z.object({
74632
+ kind: z.literal("file_io"),
74633
+ operation: z.enum([
74634
+ "read",
74635
+ "write",
74636
+ "edit",
74637
+ "glob",
74638
+ "grep"
74639
+ ]),
74640
+ path: z.string(),
74641
+ detail: z.string().optional(),
74642
+ content: z.string().optional(),
74643
+ before: z.string().optional(),
74644
+ after: z.string().optional()
74645
+ }),
74646
+ z.object({
74647
+ kind: z.literal("diff"),
74648
+ path: z.string(),
74649
+ before: z.string(),
74650
+ after: z.string(),
74651
+ hunks: z.number().optional()
74652
+ }),
74653
+ z.object({
74654
+ kind: z.literal("search"),
74655
+ query: z.string(),
74656
+ scope: z.string().optional()
74657
+ }),
74658
+ z.object({
74659
+ kind: z.literal("url_fetch"),
74660
+ url: z.string(),
74661
+ method: z.string().optional()
74662
+ }),
74663
+ z.object({
74664
+ kind: z.literal("agent_call"),
74665
+ agent_name: z.string(),
74666
+ prompt: z.string(),
74667
+ background: z.boolean().optional()
74668
+ }),
74669
+ z.object({
74670
+ kind: z.literal("skill_call"),
74671
+ skill_name: z.string(),
74672
+ args: z.string().optional()
74673
+ }),
74674
+ z.object({
74675
+ kind: z.literal("todo_list"),
74676
+ items: z.array(z.object({
74677
+ title: z.string(),
74678
+ status: z.string()
74679
+ }))
74680
+ }),
74681
+ z.object({
74682
+ kind: z.literal("background_task"),
74683
+ task_id: z.string(),
74684
+ status: z.string(),
74685
+ description: z.string(),
74686
+ task_kind: z.string().optional()
74687
+ }),
74688
+ z.object({
74689
+ kind: z.literal("task_stop"),
74690
+ task_id: z.string(),
74691
+ task_description: z.string()
74692
+ }),
74693
+ z.object({
74694
+ kind: z.literal("plan_review"),
74695
+ plan: z.string(),
74696
+ path: z.string().optional(),
74697
+ options: z.array(z.object({
74698
+ label: z.string(),
74699
+ description: z.string()
74700
+ })).readonly().optional()
74701
+ }),
74702
+ z.object({
74703
+ kind: z.literal("generic"),
74704
+ summary: z.string(),
74705
+ detail: z.unknown().optional()
74706
+ })
74707
+ ]);
74708
+ z.discriminatedUnion("kind", [
74709
+ z.object({
74710
+ kind: z.literal("command_output"),
74711
+ exit_code: z.number(),
74712
+ stdout: z.string().optional(),
74713
+ stderr: z.string().optional()
74714
+ }),
74715
+ z.object({
74716
+ kind: z.literal("file_content"),
74717
+ path: z.string(),
74718
+ content: z.string(),
74719
+ range: z.object({
74720
+ start: z.number(),
74721
+ end: z.number()
74722
+ }).optional(),
74723
+ truncated: z.boolean().optional()
74724
+ }),
74725
+ z.object({
74726
+ kind: z.literal("diff"),
74727
+ path: z.string(),
74728
+ before: z.string(),
74729
+ after: z.string(),
74730
+ hunks: z.number().optional()
74731
+ }),
74732
+ z.object({
74733
+ kind: z.literal("search_results"),
74734
+ query: z.string(),
74735
+ matches: z.array(z.object({
74736
+ file: z.string(),
74737
+ line: z.number(),
74738
+ text: z.string()
74739
+ }))
74740
+ }),
74741
+ z.object({
74742
+ kind: z.literal("url_content"),
74743
+ url: z.string(),
74744
+ status: z.number(),
74745
+ preview: z.string().optional(),
74746
+ content_type: z.string().optional()
74747
+ }),
74748
+ z.object({
74749
+ kind: z.literal("agent_summary"),
74750
+ agent_name: z.string(),
74751
+ result: z.string().optional(),
74752
+ steps: z.number().optional()
74753
+ }),
74754
+ z.object({
74755
+ kind: z.literal("background_task"),
74756
+ task_id: z.string(),
74757
+ status: z.string(),
74758
+ description: z.string()
74759
+ }),
74760
+ z.object({
74761
+ kind: z.literal("todo_list"),
74762
+ items: z.array(z.object({
74763
+ title: z.string(),
74764
+ status: z.string()
74765
+ }))
74766
+ }),
74767
+ z.object({
74768
+ kind: z.literal("structured"),
74769
+ data: z.unknown()
74770
+ }),
74771
+ z.object({
74772
+ kind: z.literal("text"),
74773
+ text: z.string(),
74774
+ truncated: z.boolean().optional()
74775
+ }),
74776
+ z.object({
74777
+ kind: z.literal("error"),
74778
+ message: z.string(),
74779
+ code: z.string().optional()
74780
+ }),
74781
+ z.object({
74782
+ kind: z.literal("generic"),
74783
+ summary: z.string(),
74784
+ detail: z.unknown().optional()
74785
+ })
74786
+ ]);
74787
+ //#endregion
74788
+ //#region ../../packages/protocol/src/ws-control.ts
74789
+ /**
74790
+ * Event: { type, seq, session_id?, timestamp, payload }
74791
+ * Control: { type, id?, payload }
74792
+ * Ack: { type: 'ack', id, code, msg, payload }
74793
+ */
74794
+ const serverHelloPayloadSchema = z.object({
74795
+ ws_connection_id: z.string(),
74796
+ heartbeat_ms: z.number().int().positive(),
74797
+ max_event_buffer_size: z.number().int().positive(),
74798
+ capabilities: z.object({
74799
+ event_batching: z.boolean(),
74800
+ compression: z.boolean()
74801
+ })
74802
+ });
74803
+ const serverHelloMessageSchema = z.object({
74804
+ type: z.literal("server_hello"),
74805
+ timestamp: isoDateTimeSchema,
74806
+ payload: serverHelloPayloadSchema
74807
+ });
74808
+ const clientHelloPayloadSchema = z.object({
74809
+ client_id: z.string(),
74810
+ subscriptions: z.array(z.string()),
74811
+ last_seq_by_session: z.record(z.string(), z.number().int().nonnegative()).optional()
74812
+ });
74813
+ const clientHelloMessageSchema = z.object({
74814
+ type: z.literal("client_hello"),
74815
+ id: z.string(),
74816
+ payload: clientHelloPayloadSchema
74817
+ });
74818
+ z.object({
74819
+ accepted_subscriptions: z.array(z.string()).optional(),
74820
+ accepted: z.array(z.string()).optional(),
74821
+ not_found: z.array(z.string()).optional(),
74822
+ resync_required: z.array(z.string())
74823
+ });
74824
+ const watchFsConfigSchema = z.object({
74825
+ paths: z.array(z.string()),
74826
+ recursive: z.boolean().optional()
74827
+ });
74828
+ const subscribePayloadSchema = z.object({
74829
+ session_ids: z.array(z.string()),
74830
+ last_seq_by_session: z.record(z.string(), z.number().int().nonnegative()).optional(),
74831
+ watch_fs: z.record(z.string(), watchFsConfigSchema).optional()
74832
+ });
74833
+ const subscribeMessageSchema = z.object({
74834
+ type: z.literal("subscribe"),
74835
+ id: z.string(),
74836
+ payload: subscribePayloadSchema
74837
+ });
74838
+ const unsubscribePayloadSchema = z.object({ session_ids: z.array(z.string()) });
74839
+ const unsubscribeMessageSchema = z.object({
74840
+ type: z.literal("unsubscribe"),
74841
+ id: z.string(),
74842
+ payload: unsubscribePayloadSchema
74843
+ });
74844
+ const watchFsAddPayloadSchema = z.object({
74845
+ session_id: z.string(),
74846
+ paths: z.array(z.string()),
74847
+ recursive: z.boolean().optional()
74848
+ });
74849
+ const watchFsAddMessageSchema = z.object({
74850
+ type: z.literal("watch_fs_add"),
74851
+ id: z.string(),
74852
+ payload: watchFsAddPayloadSchema
74853
+ });
74854
+ const watchFsRemovePayloadSchema = z.object({
74855
+ session_id: z.string(),
74856
+ paths: z.array(z.string())
74857
+ });
74858
+ const watchFsRemoveMessageSchema = z.object({
74859
+ type: z.literal("watch_fs_remove"),
74860
+ id: z.string(),
74861
+ payload: watchFsRemovePayloadSchema
74862
+ });
74863
+ z.object({
74864
+ watched_paths: z.array(z.string()).optional(),
74865
+ current_count: z.number().int().nonnegative().optional()
74866
+ });
74867
+ const abortPayloadSchema = z.object({
74868
+ session_id: z.string(),
74869
+ prompt_id: z.string()
74870
+ });
74871
+ const abortMessageSchema = z.object({
74872
+ type: z.literal("abort"),
74873
+ id: z.string(),
74874
+ payload: abortPayloadSchema
74875
+ });
74876
+ z.object({
74877
+ aborted: z.boolean().optional(),
74878
+ at_seq: z.number().int().nonnegative().optional()
74879
+ });
74880
+ const pingPayloadSchema = z.object({ nonce: z.string() });
74881
+ const pingMessageSchema = z.object({
74882
+ type: z.literal("ping"),
74883
+ timestamp: isoDateTimeSchema,
74884
+ payload: pingPayloadSchema
74885
+ });
74886
+ const pongPayloadSchema = z.object({ nonce: z.string() });
74887
+ const pongMessageSchema = z.object({
74888
+ type: z.literal("pong"),
74889
+ payload: pongPayloadSchema
74890
+ });
74891
+ const resyncRequiredPayloadSchema = z.object({
74892
+ session_id: z.string(),
74893
+ reason: z.enum(["buffer_overflow", "session_recreated"]),
74894
+ current_seq: z.number().int().nonnegative()
74895
+ });
74896
+ const resyncRequiredMessageSchema = z.object({
74897
+ type: z.literal("resync_required"),
74898
+ timestamp: isoDateTimeSchema,
74899
+ payload: resyncRequiredPayloadSchema
74900
+ });
74901
+ const wsErrorPayloadSchema = z.object({
74902
+ code: z.number().int(),
74903
+ msg: z.string(),
74904
+ fatal: z.boolean(),
74905
+ request_id: z.string().optional(),
74906
+ details: z.unknown().optional()
74907
+ });
74908
+ const wsErrorMessageSchema = z.object({
74909
+ type: z.literal("error"),
74910
+ timestamp: isoDateTimeSchema,
74911
+ payload: wsErrorPayloadSchema
74912
+ });
74913
+ z.discriminatedUnion("type", [
74914
+ clientHelloMessageSchema,
74915
+ subscribeMessageSchema,
74916
+ unsubscribeMessageSchema,
74917
+ watchFsAddMessageSchema,
74918
+ watchFsRemoveMessageSchema,
74919
+ abortMessageSchema,
74920
+ pongMessageSchema
74921
+ ]);
74922
+ z.discriminatedUnion("type", [
74923
+ serverHelloMessageSchema,
74924
+ pingMessageSchema,
74925
+ resyncRequiredMessageSchema,
74926
+ wsErrorMessageSchema
74927
+ ]);
74928
+ //#endregion
74929
+ //#region ../../packages/protocol/src/message.ts
74930
+ const messageRoleSchema = z.enum([
74931
+ "user",
74932
+ "assistant",
74933
+ "tool",
74934
+ "system"
74935
+ ]);
74936
+ const textContentSchema = z.object({
74937
+ type: z.literal("text"),
74938
+ text: z.string()
74939
+ });
74940
+ const toolUseContentSchema = z.object({
74941
+ type: z.literal("tool_use"),
74942
+ tool_call_id: z.string().min(1),
74943
+ tool_name: z.string().min(1),
74944
+ input: z.unknown()
74945
+ });
74946
+ const toolResultContentSchema = z.object({
74947
+ type: z.literal("tool_result"),
74948
+ tool_call_id: z.string().min(1),
74949
+ output: z.unknown(),
74950
+ is_error: z.boolean().optional()
74951
+ });
74952
+ const imageSourceSchema = z.discriminatedUnion("kind", [
74953
+ z.object({
74954
+ kind: z.literal("url"),
74955
+ url: z.string().min(1)
74956
+ }),
74957
+ z.object({
74958
+ kind: z.literal("base64"),
74959
+ media_type: z.string().min(1),
74960
+ data: z.string().min(1)
74961
+ }),
74962
+ z.object({
74963
+ kind: z.literal("file"),
74964
+ file_id: z.string().min(1)
74965
+ })
74966
+ ]);
74967
+ const imageContentSchema = z.object({
74968
+ type: z.literal("image"),
74969
+ source: imageSourceSchema
74970
+ });
74971
+ const fileContentSchema = z.object({
74972
+ type: z.literal("file"),
74973
+ file_id: z.string().min(1),
74974
+ name: z.string(),
74975
+ media_type: z.string().min(1),
74976
+ size: z.number().int().nonnegative()
74977
+ });
74978
+ const thinkingContentSchema = z.object({
74979
+ type: z.literal("thinking"),
74980
+ thinking: z.string(),
74981
+ signature: z.string().optional()
74982
+ });
74983
+ const messageContentSchema = z.discriminatedUnion("type", [
74984
+ textContentSchema,
74985
+ toolUseContentSchema,
74986
+ toolResultContentSchema,
74987
+ imageContentSchema,
74988
+ fileContentSchema,
74989
+ thinkingContentSchema
74990
+ ]);
74991
+ const messageSchema = z.object({
74992
+ id: z.string().min(1),
74993
+ session_id: z.string().min(1),
74994
+ role: messageRoleSchema,
74995
+ content: z.array(messageContentSchema),
74996
+ created_at: isoDateTimeSchema,
74997
+ prompt_id: z.string().min(1).optional(),
74998
+ parent_message_id: z.string().min(1).optional(),
74999
+ metadata: z.record(z.string(), z.unknown()).optional()
75000
+ });
75001
+ //#endregion
75002
+ //#region ../../packages/protocol/src/rest/prompt.ts
75003
+ /**
75004
+ * POST /v1/sessions/{sid}/prompts
75005
+ * Body: PromptSubmission {
75006
+ * content: MessageContent[],
75007
+ * metadata?: ...,
75008
+ * model?: string,
75009
+ * thinking?: 'off'|'low'|'medium'|'high'|'xhigh'|'max',
75010
+ * permission_mode?: 'manual'|'yolo'|'auto',
75011
+ * plan_mode?: boolean,
75012
+ * }
75013
+ * Reply: PromptSubmitResult { prompt_id, user_message_id, status, content, created_at }
75014
+ * status='running' when sent immediately, status='queued' when
75015
+ * another prompt is already active.
75016
+ *
75017
+ * GET /v1/sessions/{sid}/prompts
75018
+ * Reply: { active: PromptItem | null, queued: PromptItem[] }
75019
+ *
75020
+ * POST /v1/sessions/{sid}/prompts/{pid}:steer
75021
+ * POST /v1/sessions/{sid}/prompts:steer
75022
+ * Body: { prompt_ids: string[] } for the collection route
75023
+ * Reply: { steered: true, prompt_ids: string[] }
75024
+ *
75025
+ * POST /v1/sessions/{sid}/prompts/{pid}:abort
75026
+ * Body: empty
75027
+ * Reply: { aborted: true, at_seq: number } (envelope code 0)
75028
+ * { aborted: false, at_seq: number } (envelope code 40903, idempotent)
75029
+ */
75030
+ const promptThinkingSchema = z.enum([
75031
+ "off",
75032
+ "low",
75033
+ "medium",
75034
+ "high",
75035
+ "xhigh",
75036
+ "max"
75037
+ ]);
75038
+ const promptPermissionModeSchema = z.enum([
75039
+ "manual",
75040
+ "yolo",
75041
+ "auto"
75042
+ ]);
75043
+ z.object({
75044
+ content: z.array(messageContentSchema).min(1),
75045
+ metadata: z.record(z.string(), z.unknown()).optional(),
75046
+ model: z.string().min(1).optional(),
75047
+ thinking: promptThinkingSchema.optional(),
75048
+ permission_mode: promptPermissionModeSchema.optional(),
75049
+ plan_mode: z.boolean().optional()
75050
+ });
75051
+ const promptStatusSchema = z.enum(["running", "queued"]);
75052
+ const promptItemSchema = z.object({
75053
+ prompt_id: z.string().min(1),
75054
+ user_message_id: z.string().min(1),
75055
+ status: promptStatusSchema,
75056
+ content: z.array(messageContentSchema).min(1),
75057
+ created_at: isoDateTimeSchema
75058
+ });
75059
+ z.object({
75060
+ active: promptItemSchema.nullable(),
75061
+ queued: z.array(promptItemSchema)
75062
+ });
75063
+ z.object({ prompt_ids: z.array(z.string().min(1)).min(1) });
75064
+ z.object({
75065
+ steered: z.literal(true),
75066
+ prompt_ids: z.array(z.string().min(1)).min(1)
75067
+ });
75068
+ z.object({
75069
+ aborted: z.boolean(),
75070
+ at_seq: z.number().int().nonnegative().optional()
75071
+ });
75072
+ //#endregion
75073
+ //#region ../../packages/protocol/src/workspace.ts
75074
+ const workspaceIdSchema = z.string().regex(/^wd_[a-z0-9._-]+_[0-9a-f]{12}$/, { message: "workspace_id must be a wd_<slug>_<hash12> string" });
75075
+ const workspaceSchema = z.object({
75076
+ id: workspaceIdSchema,
75077
+ root: z.string().min(1),
75078
+ name: z.string().min(1).max(100),
75079
+ is_git_repo: z.boolean(),
75080
+ branch: z.string().nullable(),
75081
+ created_at: isoDateTimeSchema,
75082
+ last_opened_at: isoDateTimeSchema,
75083
+ session_count: z.number().int().nonnegative()
75084
+ });
75085
+ z.object({
75086
+ root: z.string().min(1),
75087
+ name: z.string().min(1).max(100).optional()
75088
+ });
75089
+ z.object({ name: z.string().min(1).max(100) });
75090
+ //#endregion
75091
+ //#region ../../packages/protocol/src/session.ts
75092
+ const sessionStatusSchema = z.enum([
75093
+ "idle",
75094
+ "running",
75095
+ "awaiting_approval",
75096
+ "awaiting_question",
75097
+ "aborted"
75098
+ ]);
75099
+ const sessionUsageSchema = z.object({
75100
+ input_tokens: z.number().int().nonnegative(),
75101
+ output_tokens: z.number().int().nonnegative(),
75102
+ cache_read_tokens: z.number().int().nonnegative(),
75103
+ cache_creation_tokens: z.number().int().nonnegative(),
75104
+ total_cost_usd: z.number().nonnegative(),
75105
+ context_tokens: z.number().int().nonnegative(),
75106
+ context_limit: z.number().int().nonnegative(),
75107
+ turn_count: z.number().int().nonnegative()
75108
+ });
75109
+ const permissionRuleMatcherSchema = z.object({
75110
+ kind: z.enum([
75111
+ "command_prefix",
75112
+ "path_glob",
75113
+ "exact_input",
75114
+ "always"
75115
+ ]),
75116
+ value: z.string().optional()
75117
+ });
75118
+ const permissionRuleSchema = z.object({
75119
+ id: z.string().min(1),
75120
+ tool_name: z.string().min(1),
75121
+ matcher: permissionRuleMatcherSchema.optional(),
75122
+ decision: z.literal("approved"),
75123
+ created_at: isoDateTimeSchema,
75124
+ created_by: z.enum(["user", "agent"])
75125
+ });
75126
+ const sessionAgentConfigSchema = z.object({
75127
+ model: z.string(),
75128
+ system_prompt: z.string().optional(),
75129
+ tools: z.array(z.string()).optional(),
75130
+ mcp_servers: z.array(z.string()).optional(),
75131
+ thinking: promptThinkingSchema.optional(),
75132
+ permission_mode: promptPermissionModeSchema.optional(),
75133
+ plan_mode: z.boolean().optional()
75134
+ });
75135
+ const sessionAgentConfigPartialSchema = sessionAgentConfigSchema.partial();
75136
+ const sessionMetadataSchema = z.object({ cwd: z.string().min(1) }).catchall(z.unknown());
75137
+ const sessionSchema = z.object({
75138
+ id: z.string().min(1),
75139
+ workspace_id: workspaceIdSchema,
75140
+ title: z.string(),
75141
+ created_at: isoDateTimeSchema,
75142
+ updated_at: isoDateTimeSchema,
75143
+ status: sessionStatusSchema,
75144
+ current_prompt_id: z.string().min(1).optional(),
75145
+ metadata: sessionMetadataSchema,
75146
+ agent_config: sessionAgentConfigSchema,
75147
+ usage: sessionUsageSchema,
75148
+ permission_rules: z.array(permissionRuleSchema),
75149
+ message_count: z.number().int().nonnegative(),
75150
+ last_seq: z.number().int().nonnegative()
75151
+ });
75152
+ z.object({
75153
+ title: z.string().min(1).optional(),
75154
+ metadata: sessionMetadataSchema.optional(),
75155
+ agent_config: sessionAgentConfigPartialSchema.optional(),
75156
+ workspace_id: workspaceIdSchema.optional()
75157
+ });
75158
+ z.object({
75159
+ title: z.string().min(1).optional(),
75160
+ metadata: sessionMetadataSchema.partial().optional(),
75161
+ agent_config: sessionAgentConfigPartialSchema.optional(),
75162
+ permission_rules: z.array(permissionRuleSchema).optional()
75163
+ });
75164
+ z.object({
75165
+ title: z.string().min(1).optional(),
75166
+ metadata: z.record(z.string(), z.unknown()).optional()
75167
+ });
75168
+ z.object({
75169
+ title: z.string().min(1).optional(),
75170
+ metadata: z.record(z.string(), z.unknown()).optional()
75171
+ });
75172
+ //#endregion
75173
+ //#region ../../packages/protocol/src/approval.ts
75174
+ const approvalDecisionSchema = z.enum([
75175
+ "approved",
75176
+ "rejected",
75177
+ "cancelled"
75178
+ ]);
75179
+ const approvalScopeSchema = z.enum(["session"]);
75180
+ const approvalRequestSchema = z.object({
75181
+ approval_id: z.string().min(1),
75182
+ session_id: z.string().min(1),
75183
+ turn_id: z.number().int().nonnegative().optional(),
75184
+ tool_call_id: z.string().min(1),
75185
+ tool_name: z.string().min(1),
75186
+ action: z.string(),
75187
+ tool_input_display: z.unknown(),
75188
+ created_at: isoDateTimeSchema,
75189
+ expires_at: isoDateTimeSchema
75190
+ });
75191
+ z.object({
75192
+ decision: approvalDecisionSchema,
75193
+ scope: approvalScopeSchema.optional(),
75194
+ feedback: z.string().optional(),
75195
+ selected_label: z.string().optional()
75196
+ });
75197
+ //#endregion
75198
+ //#region ../../packages/protocol/src/question.ts
75199
+ const questionOptionSchema = z.object({
75200
+ id: z.string().min(1),
75201
+ label: z.string().min(1),
75202
+ description: z.string().optional()
75203
+ });
75204
+ const questionItemSchema = z.object({
75205
+ id: z.string().min(1),
75206
+ question: z.string().min(1),
75207
+ header: z.string().optional(),
75208
+ body: z.string().optional(),
75209
+ options: z.array(questionOptionSchema).min(2).max(4),
75210
+ multi_select: z.boolean().optional(),
75211
+ allow_other: z.boolean().optional(),
75212
+ other_label: z.string().optional(),
75213
+ other_description: z.string().optional()
75214
+ });
75215
+ const questionRequestSchema = z.object({
75216
+ question_id: z.string().min(1),
75217
+ session_id: z.string().min(1),
75218
+ turn_id: z.number().int().nonnegative().optional(),
75219
+ tool_call_id: z.string().min(1).optional(),
75220
+ questions: z.array(questionItemSchema).min(1).max(4),
75221
+ created_at: isoDateTimeSchema,
75222
+ expires_at: isoDateTimeSchema
75223
+ });
75224
+ const questionAnswerSchema = z.discriminatedUnion("kind", [
75225
+ z.object({
75226
+ kind: z.literal("single"),
75227
+ option_id: z.string().min(1)
75228
+ }),
75229
+ z.object({
75230
+ kind: z.literal("multi"),
75231
+ option_ids: z.array(z.string().min(1)).min(1)
75232
+ }),
75233
+ z.object({
75234
+ kind: z.literal("other"),
75235
+ text: z.string()
75236
+ }),
75237
+ z.object({
75238
+ kind: z.literal("multi_with_other"),
75239
+ option_ids: z.array(z.string().min(1)),
75240
+ other_text: z.string()
75241
+ }),
75242
+ z.object({ kind: z.literal("skipped") })
75243
+ ]);
75244
+ const questionAnswerMethodSchema = z.enum([
75245
+ "enter",
75246
+ "space",
75247
+ "number_key",
75248
+ "click"
75249
+ ]);
75250
+ z.object({
75251
+ answers: z.record(z.string().min(1), questionAnswerSchema),
75252
+ method: questionAnswerMethodSchema.optional(),
75253
+ note: z.string().optional()
75254
+ });
75255
+ //#endregion
75256
+ //#region ../../packages/protocol/src/tool.ts
75257
+ const toolSourceSchema = z.enum([
75258
+ "builtin",
75259
+ "skill",
75260
+ "mcp"
75261
+ ]);
75262
+ const toolDescriptorSchema = z.object({
75263
+ name: z.string().min(1),
75264
+ description: z.string(),
75265
+ input_schema: z.unknown(),
75266
+ source: toolSourceSchema,
75267
+ mcp_server_id: z.string().min(1).optional()
75268
+ });
75269
+ const mcpServerStatusSchema = z.enum([
75270
+ "connected",
75271
+ "connecting",
75272
+ "disconnected",
75273
+ "error"
75274
+ ]);
75275
+ const mcpServerTransportSchema = z.enum([
75276
+ "stdio",
75277
+ "http",
75278
+ "sse"
75279
+ ]);
75280
+ const mcpServerSchema = z.object({
75281
+ id: z.string().min(1),
75282
+ name: z.string().min(1),
75283
+ transport: mcpServerTransportSchema,
75284
+ status: mcpServerStatusSchema,
75285
+ last_error: z.string().optional(),
75286
+ tool_count: z.number().int().nonnegative()
75287
+ });
75288
+ //#endregion
75289
+ //#region ../../packages/protocol/src/task.ts
75290
+ const backgroundTaskKindSchema = z.enum([
75291
+ "subagent",
75292
+ "bash",
75293
+ "tool"
75294
+ ]);
75295
+ const backgroundTaskStatusSchema = z.enum([
75296
+ "running",
75297
+ "completed",
75298
+ "failed",
75299
+ "cancelled"
75300
+ ]);
75301
+ const backgroundTaskSchema = z.object({
75302
+ id: z.string().min(1),
75303
+ session_id: z.string().min(1),
75304
+ kind: backgroundTaskKindSchema,
75305
+ description: z.string(),
75306
+ status: backgroundTaskStatusSchema,
75307
+ created_at: isoDateTimeSchema,
75308
+ started_at: isoDateTimeSchema.optional(),
75309
+ completed_at: isoDateTimeSchema.optional(),
75310
+ output_preview: z.string().optional(),
75311
+ output_bytes: z.number().int().nonnegative().optional()
75312
+ });
75313
+ //#endregion
75314
+ //#region ../../packages/protocol/src/fs.ts
75315
+ const fsKindSchema = z.enum([
75316
+ "file",
75317
+ "directory",
75318
+ "symlink"
75319
+ ]);
75320
+ const fsGitStatusSchema = z.enum([
75321
+ "clean",
75322
+ "modified",
75323
+ "added",
75324
+ "deleted",
75325
+ "renamed",
75326
+ "untracked",
75327
+ "ignored",
75328
+ "conflicted"
75329
+ ]);
75330
+ const fsEntrySchema = z.object({
75331
+ path: z.string(),
75332
+ name: z.string(),
75333
+ kind: fsKindSchema,
75334
+ size: z.number().int().nonnegative().optional(),
75335
+ modified_at: isoDateTimeSchema,
75336
+ etag: z.string().optional(),
75337
+ mime: z.string().optional(),
75338
+ language_id: z.string().optional(),
75339
+ is_binary: z.boolean().optional(),
75340
+ is_symlink_to: z.string().optional(),
75341
+ git_status: fsGitStatusSchema.optional(),
75342
+ child_count: z.number().int().nonnegative().optional()
75343
+ });
75344
+ const fsSearchHitSchema = z.object({
75345
+ path: z.string(),
75346
+ name: z.string(),
75347
+ kind: fsKindSchema,
75348
+ score: z.number().min(0).max(1),
75349
+ match_positions: z.array(z.number().int().nonnegative())
75350
+ });
75351
+ const fsGrepMatchSchema = z.object({
75352
+ line: z.number().int().positive(),
75353
+ col: z.number().int().positive(),
75354
+ text: z.string(),
75355
+ before: z.array(z.string()),
75356
+ after: z.array(z.string())
75357
+ });
75358
+ const fsGrepFileHitSchema = z.object({
75359
+ path: z.string(),
75360
+ matches: z.array(fsGrepMatchSchema)
75361
+ });
75362
+ z.object({
75363
+ path: z.string(),
75364
+ status: fsGitStatusSchema,
75365
+ rename_from: z.string().optional()
75366
+ });
75367
+ const fsChangeKindSchema = z.enum([
75368
+ "file",
75369
+ "directory",
75370
+ "symlink"
75371
+ ]);
75372
+ const fsChangeActionSchema = z.enum([
75373
+ "created",
75374
+ "modified",
75375
+ "deleted"
75376
+ ]);
75377
+ const fsChangeEntrySchema = z.object({
75378
+ path: z.string(),
75379
+ change: fsChangeActionSchema,
75380
+ kind: fsChangeKindSchema,
75381
+ size_delta: z.number().int().optional(),
75382
+ etag: z.string().optional()
75383
+ });
75384
+ z.object({
75385
+ changes: z.array(fsChangeEntrySchema),
75386
+ coalesced_window_ms: z.number().int().positive(),
75387
+ truncated: z.boolean().optional(),
75388
+ count: z.number().int().nonnegative().optional()
75389
+ });
75390
+ z.object({
75391
+ id: z.string().min(1),
75392
+ name: z.string().min(1),
75393
+ media_type: z.string().min(1),
75394
+ size: z.number().int().nonnegative(),
75395
+ created_at: isoDateTimeSchema,
75396
+ expires_at: isoDateTimeSchema.optional()
75397
+ });
75398
+ //#endregion
75399
+ //#region ../../packages/protocol/src/modelCatalog.ts
75400
+ const modelCatalogItemSchema = z.object({
75401
+ provider: z.string().min(1),
75402
+ model: z.string().min(1),
75403
+ display_name: z.string().min(1).optional(),
75404
+ max_context_size: z.number().int().min(1),
75405
+ capabilities: z.array(z.string()).optional()
75406
+ });
75407
+ const providerCatalogStatusSchema = z.enum([
75408
+ "connected",
75409
+ "error",
75410
+ "unconfigured"
75411
+ ]);
75412
+ const providerCatalogItemSchema = z.object({
75413
+ id: z.string().min(1),
75414
+ type: z.string().min(1),
75415
+ base_url: z.string().min(1).optional(),
75416
+ default_model: z.string().min(1).optional(),
75417
+ has_api_key: z.boolean(),
75418
+ status: providerCatalogStatusSchema,
75419
+ models: z.array(z.string().min(1)).optional()
75420
+ });
75421
+ //#endregion
75422
+ //#region ../../packages/protocol/src/rest/meta.ts
75423
+ /**
75424
+ * GET /v1/meta
75425
+ * Reply: MetaResponse {
75426
+ * daemon_version,
75427
+ * capabilities,
75428
+ * daemon_id,
75429
+ * started_at
75430
+ * }
75431
+ */
75432
+ const metaCapabilitiesSchema = z.object({
75433
+ websocket: z.literal(true),
75434
+ file_upload: z.literal(true),
75435
+ fs_query: z.literal(true),
75436
+ mcp: z.literal(true),
75437
+ background_tasks: z.literal(true)
75438
+ });
75439
+ z.object({
75440
+ daemon_version: z.string().min(1),
75441
+ capabilities: metaCapabilitiesSchema,
75442
+ daemon_id: z.string().min(1),
75443
+ started_at: isoDateTimeSchema
75444
+ });
75445
+ //#endregion
75446
+ //#region ../../packages/protocol/src/rest/auth.ts
75447
+ /**
75448
+ * GET /v1/auth
75449
+ * Reply: AuthSummary {
75450
+ * ready,
75451
+ * providers_count,
75452
+ * default_model,
75453
+ * managed_provider
75454
+ * }
75455
+ */
75456
+ const managedProviderStatusSchema = z.enum([
75457
+ "authenticated",
75458
+ "expired",
75459
+ "revoked",
75460
+ "unauthenticated"
75461
+ ]);
75462
+ const managedProviderSummarySchema = z.object({
75463
+ name: z.string().min(1),
75464
+ status: managedProviderStatusSchema
75465
+ });
75466
+ z.object({
75467
+ ready: z.boolean(),
75468
+ providers_count: z.number().int().nonnegative(),
75469
+ default_model: z.string().nullable(),
75470
+ managed_provider: managedProviderSummarySchema.nullable()
75471
+ });
75472
+ //#endregion
75473
+ //#region ../../packages/protocol/src/rest/oauth.ts
75474
+ /**
75475
+ * POST /v1/oauth/login body: { provider? } data: OAuthFlowStart
75476
+ * GET /v1/oauth/login query: { provider? } data: OAuthFlowStatus | null
75477
+ * DELETE /v1/oauth/login query: { provider? } data: { cancelled, status }
75478
+ * POST /v1/oauth/logout body: { provider? } data: { logged_out, provider }
75479
+ */
75480
+ const oauthFlowStatusEnum = z.enum([
75481
+ "pending",
75482
+ "authenticated",
75483
+ "denied",
75484
+ "expired",
75485
+ "cancelled"
75486
+ ]);
75487
+ z.object({ provider: z.string().min(1).optional() });
75488
+ z.object({
75489
+ flow_id: z.string().min(1),
75490
+ provider: z.string().min(1),
75491
+ verification_uri: z.string().url(),
75492
+ verification_uri_complete: z.string().url(),
75493
+ user_code: z.string().min(1),
75494
+ expires_in: z.number().int().positive(),
75495
+ interval: z.number().int().positive(),
75496
+ status: z.literal("pending"),
75497
+ expires_at: isoDateTimeSchema
75498
+ });
75499
+ z.object({
75500
+ flow_id: z.string().min(1),
75501
+ provider: z.string().min(1),
75502
+ status: oauthFlowStatusEnum,
75503
+ verification_uri: z.string().url(),
75504
+ verification_uri_complete: z.string().url(),
75505
+ user_code: z.string().min(1),
75506
+ expires_in: z.number().int().positive(),
75507
+ expires_at: isoDateTimeSchema,
75508
+ interval: z.number().int().positive(),
75509
+ resolved_at: isoDateTimeSchema.optional(),
75510
+ error_message: z.string().optional()
75511
+ });
75512
+ z.object({ provider: z.string().min(1).optional() });
75513
+ z.object({
75514
+ cancelled: z.boolean(),
75515
+ status: oauthFlowStatusEnum
75516
+ });
75517
+ z.object({ provider: z.string().min(1).optional() });
75518
+ z.object({
75519
+ logged_out: z.literal(true),
75520
+ provider: z.string().min(1)
75521
+ });
75522
+ cursorQuerySchema.and(z.object({ status: sessionStatusSchema.optional() }));
75523
+ pageResponseSchema(sessionSchema);
75524
+ const sessionStatusResponseSchema = z.object({
75525
+ model: z.string().optional(),
75526
+ thinking_level: z.string(),
75527
+ permission: z.string(),
75528
+ plan_mode: z.boolean(),
75529
+ context_tokens: z.number().int().nonnegative(),
75530
+ max_context_tokens: z.number().int().nonnegative(),
75531
+ context_usage: z.number().min(0).max(1)
75532
+ });
75533
+ z.preprocess((value) => value === void 0 ? {} : value, z.object({ instruction: z.string().optional() }));
75534
+ z.object({});
75535
+ z.preprocess((value) => value === void 0 ? {} : value, z.object({
75536
+ count: z.number().int().positive().default(1),
75537
+ page_size: z.number().int().min(1).max(100).optional()
75538
+ }));
75539
+ z.object({
75540
+ messages: pageResponseSchema(messageSchema),
75541
+ status: sessionStatusResponseSchema
75542
+ });
75543
+ z.object({ deleted: z.literal(true) });
75544
+ z.object({ items: z.array(workspaceSchema) });
75545
+ z.object({ workspace_id: workspaceIdSchema });
75546
+ z.object({ deleted: z.literal(true) });
75547
+ z.object({ path: z.string().min(1).optional() });
75548
+ const fsBrowseEntrySchema = z.object({
75549
+ name: z.string().min(1),
75550
+ path: z.string().min(1),
75551
+ is_dir: z.literal(true),
75552
+ is_git_repo: z.boolean(),
75553
+ branch: z.string().optional()
75554
+ });
75555
+ z.object({
75556
+ path: z.string().min(1),
75557
+ parent: z.string().min(1).nullable(),
75558
+ entries: z.array(fsBrowseEntrySchema)
75559
+ });
75560
+ z.object({
75561
+ home: z.string().min(1),
75562
+ recent_roots: z.array(z.string().min(1))
75563
+ });
75564
+ cursorQuerySchema.and(z.object({ role: messageRoleSchema.optional() }));
75565
+ z.object({
75566
+ items: z.array(messageSchema),
75567
+ has_more: z.boolean()
75568
+ });
75569
+ z.object({ status: z.literal("pending") });
75570
+ z.object({ items: z.array(approvalRequestSchema) });
75571
+ z.object({
75572
+ resolved: z.literal(true),
75573
+ resolved_at: isoDateTimeSchema
75574
+ });
75575
+ z.object({ resolved: z.literal(false) });
75576
+ z.object({ status: z.literal("pending") });
75577
+ z.object({ items: z.array(questionRequestSchema) });
75578
+ z.object({
75579
+ resolved: z.literal(true),
75580
+ resolved_at: isoDateTimeSchema
75581
+ });
75582
+ z.object({ resolved: z.literal(false) });
75583
+ z.object({
75584
+ dismissed: z.literal(true),
75585
+ dismissed_at: isoDateTimeSchema
75586
+ });
75587
+ z.object({ session_id: z.string().min(1).optional() });
75588
+ z.object({ tools: z.array(toolDescriptorSchema) });
75589
+ z.object({ servers: z.array(mcpServerSchema) });
75590
+ z.object({ restarting: z.literal(true) });
75591
+ z.object({ status: backgroundTaskStatusSchema.optional() });
75592
+ z.object({ items: z.array(backgroundTaskSchema) });
75593
+ z.object({
75594
+ with_output: z.coerce.boolean().optional(),
75595
+ output_bytes: z.coerce.number().int().nonnegative().optional()
75596
+ });
75597
+ z.object({ cancelled: z.literal(true) });
75598
+ z.object({ cancelled: z.literal(false) });
75599
+ //#endregion
75600
+ //#region ../../packages/protocol/src/rest/fs.ts
75601
+ /**
75602
+ * POST /v1/sessions/{sid}/fs:list
75603
+ * Body: FsListRequest
75604
+ * Response data: FsListResponse { items, children_by_path?, truncated }
75605
+ * Errors: 40401, 40409, 41304, 41303
75606
+ *
75607
+ * POST /v1/sessions/{sid}/fs:read
75608
+ * Body: FsReadRequest
75609
+ * Response data: FsReadResponse
75610
+ * Errors: 40401, 40409, 40906, 40907, 41302, 41304
75611
+ * POST /v1/sessions/{sid}/fs:list_many
75612
+ * Body: FsListManyRequest (paths[] up to 100)
75613
+ * Response data: FsListManyResponse { results, truncated_paths?,
75614
+ * partial_errors? }
75615
+ *
75616
+ * POST /v1/sessions/{sid}/fs:stat
75617
+ * Body: FsStatRequest
75618
+ * Response data: FsEntry
75619
+ * Errors: 40401, 40409, 41304
75620
+ *
75621
+ * POST /v1/sessions/{sid}/fs:stat_many
75622
+ * Body: FsStatManyRequest (paths[] up to 1000)
75623
+ * Response data: FsStatManyResponse { entries: { [path]: FsEntry | null } }
75624
+ * Per-path failures land as `null` (REST.md §3.9 line 524); only
75625
+ * path-safety (41304) fails the whole call.
75626
+ * POST /v1/sessions/{sid}/fs:search
75627
+ * Body: FsSearchRequest { query, limit?, include_globs?, exclude_globs?,
75628
+ * follow_gitignore? }
75629
+ * Response data: FsSearchResponse { items, truncated }
75630
+ * Errors: 40401, 41303, 41304
75631
+ *
75632
+ * POST /v1/sessions/{sid}/fs:grep
75633
+ * Body: FsGrepRequest
75634
+ * Response data: FsGrepResponse { files, files_scanned, truncated,
75635
+ * elapsed_ms }
75636
+ * Errors: 40401, 41303, 41304, 41305 (>30s grep timeout)
75637
+ * POST /v1/sessions/{sid}/fs:git_status
75638
+ * Body: FsGitStatusRequest { paths? }
75639
+ * Response data: FsGitStatusResponse { branch, ahead, behind, entries }
75640
+ * Errors: 40401, 40908 (not a git repo), 41304
75641
+ *
75642
+ * GET /v1/sessions/{sid}/fs/{path}:download
75643
+ * Response: binary stream or envelope (40401 / 40409 / 41304)
75644
+ */
75645
+ const fsListSortSchema = z.enum([
75646
+ "type_first",
75647
+ "name_asc",
75648
+ "name_desc",
75649
+ "mtime_desc",
75650
+ "size_desc"
75651
+ ]);
75652
+ z.object({
75653
+ path: z.string().default("."),
75654
+ depth: z.number().int().min(1).max(10).default(1),
75655
+ limit: z.number().int().min(1).max(1e3).default(200),
75656
+ show_hidden: z.boolean().default(false),
75657
+ follow_gitignore: z.boolean().default(true),
75658
+ exclude_globs: z.array(z.string()).optional(),
75659
+ sort: fsListSortSchema.default("type_first"),
75660
+ include_git_status: z.boolean().default(false)
75661
+ });
75662
+ z.object({
75663
+ items: z.array(fsEntrySchema),
75664
+ children_by_path: z.record(z.string(), z.array(fsEntrySchema)).optional(),
75665
+ truncated: z.boolean()
75666
+ });
75667
+ const fsReadEncodingRequestSchema = z.enum([
75668
+ "auto",
75669
+ "utf-8",
75670
+ "base64"
75671
+ ]);
75672
+ const fsReadEncodingResponseSchema = z.enum(["utf-8", "base64"]);
75673
+ z.object({
75674
+ path: z.string().min(1),
75675
+ offset: z.number().int().nonnegative().default(0),
75676
+ length: z.number().int().min(1).max(10485760).default(1048576),
75677
+ encoding: fsReadEncodingRequestSchema.default("auto")
75678
+ });
75679
+ z.object({
75680
+ path: z.string(),
75681
+ content: z.string(),
75682
+ encoding: fsReadEncodingResponseSchema,
75683
+ size: z.number().int().nonnegative(),
75684
+ truncated: z.boolean(),
75685
+ etag: z.string(),
75686
+ mime: z.string(),
75687
+ language_id: z.string().optional(),
75688
+ line_count: z.number().int().nonnegative().optional(),
75689
+ is_binary: z.boolean()
75690
+ });
75691
+ z.object({
75692
+ paths: z.array(z.string().min(1)).min(1).max(100),
75693
+ depth: z.number().int().min(1).max(10).default(1),
75694
+ limit: z.number().int().min(1).max(1e3).default(200),
75695
+ show_hidden: z.boolean().default(false),
75696
+ follow_gitignore: z.boolean().default(true),
75697
+ exclude_globs: z.array(z.string()).optional(),
75698
+ sort: fsListSortSchema.default("type_first"),
75699
+ include_git_status: z.boolean().default(false)
75700
+ });
75701
+ const fsListManyPartialErrorSchema = z.object({
75702
+ code: z.number().int(),
75703
+ msg: z.string()
75704
+ });
75705
+ z.object({
75706
+ results: z.record(z.string(), z.array(fsEntrySchema)),
75707
+ truncated_paths: z.array(z.string()).optional(),
75708
+ partial_errors: z.record(z.string(), fsListManyPartialErrorSchema).optional()
75709
+ });
75710
+ z.object({ path: z.string().min(1) });
75711
+ z.object({ paths: z.array(z.string().min(1)).min(1).max(1e3) });
75712
+ z.object({ entries: z.record(z.string(), fsEntrySchema.nullable()) });
75713
+ z.object({
75714
+ query: z.string().min(1),
75715
+ limit: z.number().int().min(1).max(200).default(50),
75716
+ include_globs: z.array(z.string()).optional(),
75717
+ exclude_globs: z.array(z.string()).optional(),
75718
+ follow_gitignore: z.boolean().default(true)
75719
+ });
75720
+ z.object({
75721
+ items: z.array(fsSearchHitSchema),
75722
+ truncated: z.boolean()
75723
+ });
75724
+ z.object({
75725
+ pattern: z.string().min(1),
75726
+ regex: z.boolean().default(false),
75727
+ case_sensitive: z.boolean().default(true),
75728
+ include_globs: z.array(z.string()).optional(),
75729
+ exclude_globs: z.array(z.string()).optional(),
75730
+ follow_gitignore: z.boolean().default(true),
75731
+ max_files: z.number().int().min(1).max(1e4).default(200),
75732
+ max_matches_per_file: z.number().int().min(1).max(1e4).default(50),
75733
+ max_total_matches: z.number().int().min(1).max(1e5).default(5e3),
75734
+ context_lines: z.number().int().min(0).max(10).default(2)
75735
+ });
75736
+ z.object({
75737
+ files: z.array(fsGrepFileHitSchema),
75738
+ files_scanned: z.number().int().nonnegative(),
75739
+ truncated: z.boolean(),
75740
+ elapsed_ms: z.number().int().nonnegative()
75741
+ });
75742
+ z.object({ paths: z.array(z.string().min(1)).optional() });
75743
+ z.object({
75744
+ branch: z.string(),
75745
+ ahead: z.number().int().nonnegative(),
75746
+ behind: z.number().int().nonnegative(),
75747
+ entries: z.record(z.string(), fsGitStatusSchema)
75748
+ });
75749
+ z.object({
75750
+ path: z.string().min(1),
75751
+ range: z.string().optional(),
75752
+ if_none_match: z.string().optional()
75753
+ });
75754
+ z.object({ file_id: z.string().min(1) });
75755
+ z.object({ file_id: z.string().min(1) });
75756
+ z.object({ deleted: z.literal(true) });
75757
+ z.object({ items: z.array(modelCatalogItemSchema) });
75758
+ z.object({ items: z.array(providerCatalogItemSchema) });
75759
+ z.object({
75760
+ default_model: z.string().min(1),
75761
+ model: modelCatalogItemSchema
75762
+ });
74406
75763
  //#endregion
74407
75764
  //#region ../../packages/agent-core/src/mcp/oauth/callback-server.ts
74408
75765
  /**
@@ -80754,9 +82111,19 @@ var SkillTool = class SkillTool {
80754
82111
  const skillArgs = args.args ?? "";
80755
82112
  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
82113
  const origin = skillOrigin(skill, skillArgs, currentDepth);
82114
+ const promptTrigger = origin.trigger === "nested-skill" ? "nested-skill" : "model-tool";
80757
82115
  skills.recordActivation(origin);
80758
82116
  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);
82117
+ this.agent.context.appendUserMessage([{
82118
+ type: "text",
82119
+ text: renderModelToolSkillPrompt({
82120
+ skillName: skill.name,
82121
+ skillArgs,
82122
+ skillContent,
82123
+ skillSource: skill.source,
82124
+ trigger: promptTrigger
82125
+ })
82126
+ }], origin);
80760
82127
  return { output: `Skill "${skill.name}" loaded inline. Follow its instructions.` };
80761
82128
  }
80762
82129
  };
@@ -80816,7 +82183,7 @@ function makeCarriageReturnsVisible(text) {
80816
82183
  }
80817
82184
  //#endregion
80818
82185
  //#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.";
82186
+ 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
82187
  //#endregion
80821
82188
  //#region ../../packages/agent-core/src/tools/builtin/file/edit.ts
80822
82189
  const EditInputSchema = z.object({
@@ -87103,7 +88470,7 @@ var ReadMediaFileTool = class {
87103
88470
  };
87104
88471
  //#endregion
87105
88472
  //#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";
88473
+ 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
88474
  //#endregion
87108
88475
  //#region ../../packages/agent-core/src/tools/builtin/file/write.ts
87109
88476
  /** Mask isolating the file-type bits of a stat mode. */
@@ -87893,6 +89260,10 @@ var TurnFlow = class {
87893
89260
  }
87894
89261
  }
87895
89262
  if (this.currentId === turnId) this.agent.usage.endTurn();
89263
+ if (ended.reason === "cancelled" && isUserCancellation(signal.reason)) this.agent.hooks?.fireAndForgetTrigger("Interrupt", { inputData: {
89264
+ turnId,
89265
+ reason: "cancelled"
89266
+ } });
87896
89267
  this.agent.emitEvent(ended);
87897
89268
  if (standalone && this.currentId === turnId) this.activeTurn = null;
87898
89269
  if (this.agent.swarmMode.shouldAutoExit) this.agent.swarmMode.exit();
@@ -137212,6 +138583,9 @@ new AsyncLocalStorage();
137212
138583
  //#endregion
137213
138584
  //#region ../../packages/agent-core/src/rpc/core-impl.ts
137214
138585
  const KIMI_CODE_PROVIDER_NAME$1 = "managed:kimi-code";
138586
+ const KIMI_CODE_BASE_URL_ENV = "KIMI_CODE_BASE_URL";
138587
+ const KIMI_CODE_OAUTH_HOST_ENV = "KIMI_CODE_OAUTH_HOST";
138588
+ const KIMI_OAUTH_HOST_ENV = "KIMI_OAUTH_HOST";
137215
138589
  var KimiCore = class {
137216
138590
  rpcClient;
137217
138591
  sdk;
@@ -137417,6 +138791,7 @@ var KimiCore = class {
137417
138791
  async forkSession(input) {
137418
138792
  const source = await this.sessionStore.get(input.sessionId);
137419
138793
  const active = this.sessions.get(source.id);
138794
+ 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
138795
  if (active !== void 0) await active.flushMetadata();
137421
138796
  const id = input.id ?? createSessionId();
137422
138797
  await this.sessionStore.fork({
@@ -137700,13 +139075,38 @@ var KimiCore = class {
137700
139075
  });
137701
139076
  }
137702
139077
  mergePluginMcpConfig(base) {
137703
- const pluginServers = this.plugins.enabledMcpServers();
139078
+ const pluginServers = this.withManagedKimiPluginEnv(this.plugins.enabledMcpServers());
137704
139079
  if (Object.keys(pluginServers).length === 0) return base;
137705
139080
  return { servers: {
137706
139081
  ...base?.servers,
137707
139082
  ...pluginServers
137708
139083
  } };
137709
139084
  }
139085
+ withManagedKimiPluginEnv(pluginServers) {
139086
+ const managedEnv = this.managedKimiCodeEnvForPlugins();
139087
+ if (Object.keys(managedEnv).length === 0) return pluginServers;
139088
+ const out = {};
139089
+ for (const [name, server] of Object.entries(pluginServers)) out[name] = server.transport === "stdio" ? {
139090
+ ...server,
139091
+ env: {
139092
+ ...server.env,
139093
+ ...managedEnv
139094
+ }
139095
+ } : server;
139096
+ return out;
139097
+ }
139098
+ managedKimiCodeEnvForPlugins() {
139099
+ const provider = this.config.providers[KIMI_CODE_PROVIDER_NAME$1];
139100
+ const envBaseUrl = process.env[KIMI_CODE_BASE_URL_ENV];
139101
+ const envOAuthHost = process.env[KIMI_CODE_OAUTH_HOST_ENV] ?? process.env[KIMI_OAUTH_HOST_ENV];
139102
+ const hasEnvOverride = envBaseUrl !== void 0 || envOAuthHost !== void 0;
139103
+ const baseUrl = envBaseUrl !== void 0 ? envBaseUrl.replace(/\/+$/, "") : provider?.baseUrl;
139104
+ const oauthHost = hasEnvOverride ? envOAuthHost : provider?.oauth?.oauthHost;
139105
+ const env = {};
139106
+ if (baseUrl !== void 0) env[KIMI_CODE_BASE_URL_ENV] = baseUrl;
139107
+ if (oauthHost !== void 0) env[KIMI_CODE_OAUTH_HOST_ENV] = oauthHost;
139108
+ return env;
139109
+ }
137710
139110
  sessionApi(sessionId) {
137711
139111
  const session = this.sessions.get(sessionId);
137712
139112
  if (session === void 0) throw new KimiError(ErrorCodes.SESSION_NOT_FOUND, `Session "${sessionId}" was not found`, { details: { sessionId } });
@@ -160203,6 +161603,163 @@ var WelcomeComponent = class {
160203
161603
  }
160204
161604
  };
160205
161605
  //#endregion
161606
+ //#region src/tui/components/dialogs/compaction.ts
161607
+ /**
161608
+ * Renders a compaction block in the transcript.
161609
+ *
161610
+ * Lifecycle:
161611
+ * - constructed on `compaction.started` → blinking white bullet +
161612
+ * "Compacting context..." and optional custom instruction
161613
+ * - `markDone()` on `compaction.completed` → solid green bullet +
161614
+ * "Compaction complete (X → Y tokens)"
161615
+ * - `markCanceled()` on `compaction.cancelled` → solid warning bullet +
161616
+ * "Compaction cancelled"
161617
+ *
161618
+ * Bullet animation mirrors `ToolCallComponent` (500ms blink) so the user
161619
+ * reads the same "work in progress" signal across the UI.
161620
+ */
161621
+ const BLINK_INTERVAL = 500;
161622
+ var CompactionComponent = class extends Container {
161623
+ ui;
161624
+ headerText;
161625
+ instruction;
161626
+ blinkOn = true;
161627
+ blinkTimer = null;
161628
+ done = false;
161629
+ canceled = false;
161630
+ tokensBefore;
161631
+ tokensAfter;
161632
+ constructor(ui, instruction) {
161633
+ super();
161634
+ this.ui = ui;
161635
+ this.instruction = instruction;
161636
+ this.addChild(new Spacer(1));
161637
+ this.headerText = new Text(this.buildHeader(), 0, 0);
161638
+ this.addChild(this.headerText);
161639
+ this.addInstructionChild();
161640
+ this.startBlink();
161641
+ }
161642
+ addInstructionChild() {
161643
+ if (this.instruction !== void 0) this.addChild(new Text(currentTheme.dim(` ${this.instruction}`), 0, 0));
161644
+ }
161645
+ invalidate() {
161646
+ this.headerText.setText(this.buildHeader());
161647
+ if (this.instruction !== void 0) {
161648
+ if (this.children.length > 2) this.children.pop();
161649
+ this.addInstructionChild();
161650
+ }
161651
+ super.invalidate();
161652
+ }
161653
+ markDone(tokensBefore, tokensAfter) {
161654
+ if (this.done || this.canceled) return;
161655
+ this.done = true;
161656
+ this.tokensBefore = tokensBefore;
161657
+ this.tokensAfter = tokensAfter;
161658
+ this.stopBlink();
161659
+ this.headerText.setText(this.buildHeader());
161660
+ this.ui?.requestRender();
161661
+ }
161662
+ markCanceled() {
161663
+ if (this.done || this.canceled) return;
161664
+ this.canceled = true;
161665
+ this.stopBlink();
161666
+ this.headerText.setText(this.buildHeader());
161667
+ this.ui?.requestRender();
161668
+ }
161669
+ dispose() {
161670
+ this.stopBlink();
161671
+ }
161672
+ buildHeader() {
161673
+ 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)`) : ""}`;
161674
+ if (this.canceled) return `${currentTheme.fg("warning", STATUS_BULLET)}${currentTheme.boldFg("warning", "Compaction cancelled")}`;
161675
+ return `${this.blinkOn ? currentTheme.fg("text", STATUS_BULLET) : " "}${currentTheme.boldFg("primary", "Compacting context...")}`;
161676
+ }
161677
+ startBlink() {
161678
+ this.blinkTimer = setInterval(() => {
161679
+ this.blinkOn = !this.blinkOn;
161680
+ this.headerText.setText(this.buildHeader());
161681
+ this.ui?.requestRender();
161682
+ }, BLINK_INTERVAL);
161683
+ }
161684
+ stopBlink() {
161685
+ if (this.blinkTimer !== null) {
161686
+ clearInterval(this.blinkTimer);
161687
+ this.blinkTimer = null;
161688
+ }
161689
+ }
161690
+ };
161691
+ //#endregion
161692
+ //#region src/tui/components/dialogs/undo-selector.ts
161693
+ const MAX_VISIBLE_CHOICES = 5;
161694
+ const PREFERRED_SELECTED_OFFSET = 2;
161695
+ var UndoSelectorComponent = class extends Container {
161696
+ focused = false;
161697
+ opts;
161698
+ list;
161699
+ submitted = false;
161700
+ constructor(opts) {
161701
+ super();
161702
+ this.opts = opts;
161703
+ this.list = new SearchableList({
161704
+ items: opts.choices,
161705
+ toSearchText: (choice) => choice.label,
161706
+ initialIndex: Math.max(0, opts.choices.length - 1)
161707
+ });
161708
+ }
161709
+ handleInput(data) {
161710
+ if (this.submitted) return;
161711
+ if (matchesKey(data, Key.escape)) {
161712
+ this.opts.onCancel();
161713
+ return;
161714
+ }
161715
+ if (this.list.handleKey(data)) return;
161716
+ if (matchesKey(data, Key.enter)) {
161717
+ const selected = this.list.selected();
161718
+ if (selected !== void 0) {
161719
+ this.submitted = true;
161720
+ this.opts.onSelect(selected);
161721
+ }
161722
+ }
161723
+ }
161724
+ render(width) {
161725
+ const view = this.list.view();
161726
+ const lines = [
161727
+ currentTheme.fg("primary", "─".repeat(width)),
161728
+ currentTheme.boldFg("primary", " Select messages to undo"),
161729
+ currentTheme.fg("textMuted", " " + [
161730
+ "↑↓ navigate",
161731
+ "Enter select",
161732
+ "Esc cancel"
161733
+ ].join(" · ")),
161734
+ ""
161735
+ ];
161736
+ if (view.items.length === 0) lines.push(currentTheme.fg("textMuted", " No messages"));
161737
+ else {
161738
+ const visibleCount = Math.min(MAX_VISIBLE_CHOICES, view.items.length);
161739
+ const maxStart = view.items.length - visibleCount;
161740
+ const start = Math.min(Math.max(0, view.selectedIndex - PREFERRED_SELECTED_OFFSET), maxStart);
161741
+ const end = start + visibleCount;
161742
+ for (let i = start; i < end; i++) {
161743
+ const choice = view.items[i];
161744
+ if (choice === void 0) continue;
161745
+ lines.push(this.renderChoiceLine(choice, i === view.selectedIndex, i > view.selectedIndex, width));
161746
+ }
161747
+ }
161748
+ lines.push("");
161749
+ lines.push(currentTheme.fg("primary", "─".repeat(width)));
161750
+ return lines.map((line) => truncateToWidth(line, width));
161751
+ }
161752
+ renderChoiceLine(choice, isSelected, inUndoRange, width) {
161753
+ const prefix = ` ${isSelected ? "❯" : " "} `;
161754
+ const labelBudget = Math.max(8, width - visibleWidth(prefix));
161755
+ const label = truncateToWidth(choice.label, labelBudget, "…");
161756
+ const token = isSelected ? "primary" : inUndoRange ? "textDim" : "text";
161757
+ let line = currentTheme.fg(isSelected ? "primary" : "textDim", prefix);
161758
+ line += isSelected ? currentTheme.boldFg(token, label) : currentTheme.fg(token, label);
161759
+ return line;
161760
+ }
161761
+ };
161762
+ //#endregion
160206
161763
  //#region src/tui/components/messages/agent-group.ts
160207
161764
  const THROTTLE_MS$1 = 200;
160208
161765
  var AgentGroupComponent = class extends Container {
@@ -164517,34 +166074,64 @@ function getTranscriptComponentEntry(component) {
164517
166074
  return componentEntries.get(component);
164518
166075
  }
164519
166076
  //#endregion
166077
+ //#region src/tui/utils/transcript-id.ts
166078
+ let transcriptIdCounter = 0;
166079
+ function nextTranscriptId() {
166080
+ transcriptIdCounter += 1;
166081
+ return `entry-${String(transcriptIdCounter)}`;
166082
+ }
166083
+ //#endregion
164520
166084
  //#region src/tui/commands/undo.ts
166085
+ const UNDO_LIMIT_STATUS_TURN_ID = "undo-limit-status";
164521
166086
  async function handleUndoCommand(host, args = "") {
164522
166087
  if (host.state.appState.streamingPhase !== "idle") {
164523
166088
  host.showError("Cannot undo while streaming — press Esc or Ctrl-C first.");
164524
166089
  return;
164525
166090
  }
164526
- const count = parseUndoCount(args);
166091
+ const trimmed = args.trim();
166092
+ if (trimmed.length === 0) {
166093
+ await showUndoSelector(host);
166094
+ return;
166095
+ }
166096
+ const count = parseUndoCount(trimmed);
164527
166097
  if (count === void 0) {
164528
166098
  host.showError("Usage: /undo [count], where count is a positive integer.");
164529
166099
  return;
164530
166100
  }
166101
+ if (host.session === void 0) {
166102
+ host.showError(NO_ACTIVE_SESSION_MESSAGE);
166103
+ return;
166104
+ }
166105
+ const availability = await resolveUndoAvailability(host);
166106
+ if (count > availability.maxCount) {
166107
+ showUndoLimitStatus(host, formatUndoLimitMessage(count, availability));
166108
+ return;
166109
+ }
166110
+ await undoByCount(host, count);
166111
+ }
166112
+ async function undoByCount(host, count) {
164531
166113
  const session = host.session;
164532
166114
  if (session === void 0) {
164533
166115
  host.showError(NO_ACTIVE_SESSION_MESSAGE);
164534
- return;
166116
+ return false;
164535
166117
  }
164536
166118
  const entries = host.state.transcriptEntries;
164537
166119
  const lastUserIndex = findUndoAnchorEntryIndex(entries, count);
164538
166120
  if (lastUserIndex === void 0) {
164539
- host.showError("Nothing to undo.");
164540
- return;
166121
+ showUndoLimitStatus(host, "Nothing to undo.");
166122
+ return false;
164541
166123
  }
164542
166124
  try {
164543
166125
  await session.undoHistory(count);
164544
166126
  } catch (error) {
166127
+ const limit = undoLimitFromError(error);
166128
+ if (limit !== void 0) {
166129
+ showUndoLimitStatus(host, formatUndoLimitMessage(limit.requestedCount, limit));
166130
+ return false;
166131
+ }
164545
166132
  const message = formatErrorMessage$2(error);
164546
166133
  host.showError(`Failed to undo: ${message}`);
164547
- return;
166134
+ return false;
164548
166135
  }
164549
166136
  const children = host.state.transcriptContainer.children;
164550
166137
  const lastUserComponentIndex = findUndoAnchorComponentIndex(children, count);
@@ -164556,6 +166143,34 @@ async function handleUndoCommand(host, args = "") {
164556
166143
  entries.splice(lastUserIndex, entries.length - lastUserIndex, ...preservedEntries);
164557
166144
  if (entries.length === 0) renderWelcome(host);
164558
166145
  host.state.ui.requestRender();
166146
+ return true;
166147
+ }
166148
+ async function showUndoSelector(host) {
166149
+ if (host.session === void 0) {
166150
+ host.showError(NO_ACTIVE_SESSION_MESSAGE);
166151
+ return;
166152
+ }
166153
+ const availability = await resolveUndoAvailability(host);
166154
+ const choices = createUndoChoices(host.state.transcriptEntries, host.state.transcriptContainer.children, availability.maxCount);
166155
+ if (choices.length === 0) {
166156
+ showUndoLimitStatus(host, formatNothingToUndoMessage(availability));
166157
+ return;
166158
+ }
166159
+ host.mountEditorReplacement(new UndoSelectorComponent({
166160
+ choices,
166161
+ onSelect: (choice) => {
166162
+ undoByCount(host, choice.count).then((undone) => {
166163
+ if (undone) {
166164
+ host.restoreInputText(choice.input);
166165
+ return;
166166
+ }
166167
+ host.restoreEditor();
166168
+ });
166169
+ },
166170
+ onCancel: () => {
166171
+ host.restoreEditor();
166172
+ }
166173
+ }));
164559
166174
  }
164560
166175
  function parseUndoCount(args) {
164561
166176
  const value = args.trim();
@@ -164564,6 +166179,138 @@ function parseUndoCount(args) {
164564
166179
  const count = Number(value);
164565
166180
  return Number.isSafeInteger(count) ? count : void 0;
164566
166181
  }
166182
+ async function resolveUndoAvailability(host) {
166183
+ const local = undoAvailabilityFromTranscript(host.state.transcriptEntries, host.state.transcriptContainer.children);
166184
+ const context = await getSessionContext(host.session);
166185
+ if (context === void 0) return local;
166186
+ const activeContext = undoAvailabilityFromContext(context.history);
166187
+ return {
166188
+ maxCount: Math.min(local.maxCount, activeContext.maxCount),
166189
+ stoppedAtCompaction: local.stoppedAtCompaction || activeContext.stoppedAtCompaction
166190
+ };
166191
+ }
166192
+ async function getSessionContext(session) {
166193
+ const getContext = session?.getContext;
166194
+ if (session === void 0 || getContext === void 0) return void 0;
166195
+ try {
166196
+ return await getContext.call(session);
166197
+ } catch {
166198
+ return;
166199
+ }
166200
+ }
166201
+ function undoAvailabilityFromTranscript(entries, children) {
166202
+ const { anchors, stoppedAtCompaction } = activeUndoAnchorEntries(entries, children);
166203
+ return {
166204
+ maxCount: anchors.length,
166205
+ stoppedAtCompaction
166206
+ };
166207
+ }
166208
+ function undoAvailabilityFromContext(history) {
166209
+ let maxCount = 0;
166210
+ let stoppedAtCompaction = false;
166211
+ for (let i = history.length - 1; i >= 0; i--) {
166212
+ const message = history[i];
166213
+ if (message === void 0) continue;
166214
+ if (message.origin?.kind === "injection") continue;
166215
+ if (message.origin?.kind === "compaction_summary") {
166216
+ stoppedAtCompaction = true;
166217
+ break;
166218
+ }
166219
+ if (isContextUndoAnchor(message)) maxCount++;
166220
+ }
166221
+ return {
166222
+ maxCount,
166223
+ stoppedAtCompaction
166224
+ };
166225
+ }
166226
+ function isContextUndoAnchor(message) {
166227
+ if (message.role !== "user") return false;
166228
+ const origin = message.origin;
166229
+ if (origin === void 0 || origin.kind === "user") return true;
166230
+ if (origin.kind === "skill_activation") return origin.trigger === "user-slash";
166231
+ return false;
166232
+ }
166233
+ function createUndoChoices(entries, children, maxCount) {
166234
+ if (maxCount <= 0) return [];
166235
+ const anchors = activeUndoAnchorEntries(entries, children).anchors.slice(-maxCount);
166236
+ return anchors.map((entry, index) => ({
166237
+ id: entry.id,
166238
+ count: anchors.length - index,
166239
+ input: formatUndoChoiceInput(entry),
166240
+ label: formatUndoChoiceLabel(entry)
166241
+ }));
166242
+ }
166243
+ function activeUndoAnchorEntries(entries, children) {
166244
+ const lastCompactionChildIndex = children.findLastIndex((child) => child instanceof CompactionComponent);
166245
+ if (lastCompactionChildIndex >= 0) return {
166246
+ anchors: children.slice(lastCompactionChildIndex + 1).map((child) => getTranscriptComponentEntry(child)).filter((entry) => entry !== void 0).filter(isUndoAnchorEntry),
166247
+ stoppedAtCompaction: true
166248
+ };
166249
+ const lastCompactionEntryIndex = entries.findLastIndex((entry) => entry.compactionData !== void 0);
166250
+ return {
166251
+ anchors: (lastCompactionEntryIndex >= 0 ? entries.slice(lastCompactionEntryIndex + 1) : entries).filter(isUndoAnchorEntry),
166252
+ stoppedAtCompaction: lastCompactionEntryIndex >= 0
166253
+ };
166254
+ }
166255
+ function formatUndoChoiceLabel(entry) {
166256
+ if (entry.kind === "skill_activation") {
166257
+ const name = singleLine$2(entry.skillName ?? entry.content.replace(/^Activated skill:\s*/, ""));
166258
+ const args = singleLine$2(entry.skillArgs ?? "");
166259
+ if (name.length === 0) return "Skill: unknown";
166260
+ return args.length > 0 ? `/${name} ${args}` : `/${name}`;
166261
+ }
166262
+ const content = singleLine$2(entry.content);
166263
+ const imageCount = entry.imageAttachmentIds?.length ?? 0;
166264
+ if (content.length > 0) return content;
166265
+ if (imageCount > 0) return `User message (${String(imageCount)} ${imageCount === 1 ? "image" : "images"})`;
166266
+ return "User message";
166267
+ }
166268
+ function formatUndoChoiceInput(entry) {
166269
+ if (entry.kind === "skill_activation") {
166270
+ const name = singleLine$2(entry.skillName ?? entry.content.replace(/^Activated skill:\s*/, ""));
166271
+ const args = singleLine$2(entry.skillArgs ?? "");
166272
+ if (name.length === 0) return "";
166273
+ return args.length > 0 ? `/${name} ${args}` : `/${name}`;
166274
+ }
166275
+ return entry.content;
166276
+ }
166277
+ function singleLine$2(text) {
166278
+ return text.replaceAll(/\s+/g, " ").trim();
166279
+ }
166280
+ function formatUndoLimitMessage(requestedCount, availability) {
166281
+ const reason = availability.stoppedAtCompaction ? " after the last compaction" : "";
166282
+ return `Cannot undo ${formatPromptCount(requestedCount)}; only ${formatPromptCount(availability.maxCount)} can be undone in the active context${reason}.`;
166283
+ }
166284
+ function formatNothingToUndoMessage(availability) {
166285
+ if (availability.stoppedAtCompaction) return "Nothing to undo after the last compaction.";
166286
+ return "Nothing to undo.";
166287
+ }
166288
+ function formatPromptCount(count) {
166289
+ return `${String(count)} ${count === 1 ? "prompt" : "prompts"}`;
166290
+ }
166291
+ function showUndoLimitStatus(host, message) {
166292
+ host.appendTranscriptEntry({
166293
+ id: nextTranscriptId(),
166294
+ kind: "status",
166295
+ turnId: UNDO_LIMIT_STATUS_TURN_ID,
166296
+ renderMode: "plain",
166297
+ content: message
166298
+ });
166299
+ }
166300
+ function undoLimitFromError(error) {
166301
+ if (!isKimiError(error)) return void 0;
166302
+ const details = error.details;
166303
+ if (details?.["reason"] !== "undo_limit") return void 0;
166304
+ const requestedCount = details["requestedCount"];
166305
+ const maxCount = details["undoableCount"];
166306
+ const stoppedAtCompaction = details["stoppedAtCompaction"];
166307
+ if (typeof requestedCount !== "number" || typeof maxCount !== "number" || typeof stoppedAtCompaction !== "boolean") return;
166308
+ return {
166309
+ requestedCount,
166310
+ maxCount,
166311
+ stoppedAtCompaction
166312
+ };
166313
+ }
164567
166314
  function isUndoAnchorEntry(entry) {
164568
166315
  return entry.kind === "user" || entry.kind === "skill_activation" && entry.skillTrigger === "user-slash";
164569
166316
  }
@@ -166187,92 +167934,6 @@ function stripLeadingSpace(s) {
166187
167934
  return s.replace(/^ +/, "");
166188
167935
  }
166189
167936
  //#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
167937
  //#region src/tui/components/dialogs/help-panel.ts
166277
167938
  /**
166278
167939
  * HelpPanel — modal `/help` display. Lists keyboard shortcuts, slash
@@ -169022,6 +170683,14 @@ var EditorKeyboardController = class {
169022
170683
  };
169023
170684
  //#endregion
169024
170685
  //#region src/tui/components/messages/goal-markers.ts
170686
+ /**
170687
+ * Low-profile transcript markers for the autonomous goal loop.
170688
+ *
170689
+ * Lifecycle changes (paused / resumed / cancelled) and `no_progress` verdicts
170690
+ * render as a single dim line — `◦ Goal paused` — that expands (ctrl+o, shared
170691
+ * with tool output) to show the reason when there is one. Terminal outcomes use
170692
+ * the richer completion card (the `/goal` box), not this marker.
170693
+ */
169025
170694
  const HEAD_INDENT = " ";
169026
170695
  const DETAIL_INDENT = " ";
169027
170696
  var GoalMarkerComponent = class {
@@ -169051,13 +170720,18 @@ var GoalMarkerComponent = class {
169051
170720
  render(width) {
169052
170721
  const dot = currentTheme.fg(this.accentToken, this.marker);
169053
170722
  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)")}`]);
170723
+ if (!(this.detail !== void 0 && this.detail.length > 0)) return this.clampToWidth([`${this.indent}${dot} ${head}`], width);
170724
+ if (!this.expandable) return this.clampToWidth([`${this.indent}${dot} ${head}`], width);
170725
+ if (!this.expanded) return this.clampToWidth([`${this.indent}${dot} ${head} ${currentTheme.fg("textMuted", "(ctrl+o)")}`], width);
169057
170726
  const out = [`${this.indent}${dot} ${head}`];
169058
170727
  const wrapWidth = Math.max(20, width - 4);
169059
170728
  for (const line of wrap(this.detail, wrapWidth)) out.push(DETAIL_INDENT + currentTheme.fg("textDim", line));
169060
- return this.withLeadingBlank(out);
170729
+ return this.clampToWidth(out, width);
170730
+ }
170731
+ clampToWidth(lines, width) {
170732
+ const withBlank = this.withLeadingBlank(lines);
170733
+ if (width <= 0) return withBlank.map(() => "");
170734
+ return withBlank.map((line) => truncateToWidth(line, width));
169061
170735
  }
169062
170736
  withLeadingBlank(lines) {
169063
170737
  return this.leadingBlank ? ["", ...lines] : lines;
@@ -169118,7 +170792,7 @@ function lowercaseFirst(text) {
169118
170792
  return text.length === 0 ? text : `${text[0].toLowerCase()}${text.slice(1)}`;
169119
170793
  }
169120
170794
  function wrap(text, width) {
169121
- const words = text.replace(/\s+/g, " ").trim().split(" ");
170795
+ const words = text.replaceAll(/\s+/g, " ").trim().split(" ");
169122
170796
  const lines = [];
169123
170797
  let current = "";
169124
170798
  for (const word of words) {
@@ -169381,13 +171055,6 @@ function formatDuration(ms) {
169381
171055
  return `${(ms / 1e3).toFixed(1)}s`;
169382
171056
  }
169383
171057
  //#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
171058
  //#region src/tui/utils/background-agent-status.ts
169392
171059
  const MAX_BACKGROUND_FIELD_LENGTH = 240;
169393
171060
  function normalizeBackgroundField(value) {