@gajae-code/coding-agent 0.11.7 → 0.11.9

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 (213) hide show
  1. package/CHANGELOG.md +73 -1
  2. package/dist/types/cli/args.d.ts +0 -2
  3. package/dist/types/cli.d.ts +1 -0
  4. package/dist/types/config/keybindings.d.ts +33 -3
  5. package/dist/types/config/model-profile-activation.d.ts +4 -3
  6. package/dist/types/config/model-profile-contract.d.ts +38 -0
  7. package/dist/types/config/model-profiles.d.ts +2 -3
  8. package/dist/types/config/settings-schema.d.ts +15 -2
  9. package/dist/types/edit/modes/patch.d.ts +13 -0
  10. package/dist/types/edit/path-mutation-lock.d.ts +15 -0
  11. package/dist/types/eval/py/executor.d.ts +1 -1
  12. package/dist/types/eval/py/tool-bridge.d.ts +1 -2
  13. package/dist/types/gjc-runtime/deep-interview-ambiguity.d.ts +12 -5
  14. package/dist/types/gjc-runtime/deep-interview-draft.d.ts +8 -0
  15. package/dist/types/gjc-runtime/deep-interview-payload.d.ts +41 -0
  16. package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +32 -17
  17. package/dist/types/gjc-runtime/deep-interview-repair.d.ts +17 -0
  18. package/dist/types/gjc-runtime/deep-interview-state.d.ts +135 -4
  19. package/dist/types/gjc-runtime/repository-binding.d.ts +63 -0
  20. package/dist/types/gjc-runtime/state-writer.d.ts +44 -0
  21. package/dist/types/gjc-runtime/ultragoal-guard.d.ts +1 -0
  22. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +24 -0
  23. package/dist/types/gjc-runtime/workflow-manifest.d.ts +5 -3
  24. package/dist/types/main.d.ts +8 -0
  25. package/dist/types/modes/components/runtime-mcp-add-wizard.d.ts +2 -1
  26. package/dist/types/modes/components/tool-status-header.d.ts +3 -2
  27. package/dist/types/modes/components/welcome.d.ts +4 -0
  28. package/dist/types/modes/controllers/command-controller.d.ts +2 -0
  29. package/dist/types/modes/controllers/selector-controller.d.ts +2 -1
  30. package/dist/types/modes/interactive-mode.d.ts +5 -2
  31. package/dist/types/modes/prompt-action-autocomplete.d.ts +6 -1
  32. package/dist/types/modes/prompt-suggestion-controller.d.ts +35 -0
  33. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +2 -2
  34. package/dist/types/modes/types.d.ts +3 -0
  35. package/dist/types/modes/utils/hotkeys-markdown.d.ts +2 -1
  36. package/dist/types/runtime-mcp/manager.d.ts +1 -1
  37. package/dist/types/runtime-mcp/oauth-flow.d.ts +0 -5
  38. package/dist/types/runtime-mcp/plugin-network-boundary.d.ts +14 -0
  39. package/dist/types/runtime-mcp/redaction.d.ts +2 -0
  40. package/dist/types/sdk/broker/broker.d.ts +2 -0
  41. package/dist/types/sdk/broker/lifecycle.d.ts +6 -0
  42. package/dist/types/sdk/bus/chat-daemon-control.d.ts +7 -1
  43. package/dist/types/sdk/bus/config-commands.d.ts +2 -2
  44. package/dist/types/sdk/bus/config.d.ts +2 -0
  45. package/dist/types/sdk/bus/conversation-store.d.ts +1 -0
  46. package/dist/types/sdk/bus/index.d.ts +25 -0
  47. package/dist/types/sdk/bus/notification-orchestration.d.ts +1 -0
  48. package/dist/types/sdk/bus/prompt-reconciliation.d.ts +105 -0
  49. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +15 -3
  50. package/dist/types/sdk/bus/telegram-daemon-control.d.ts +5 -1
  51. package/dist/types/sdk/bus/telegram-daemon.d.ts +128 -1
  52. package/dist/types/sdk/bus/telegram-reference.d.ts +2 -0
  53. package/dist/types/sdk/host/control/operations.d.ts +1 -1
  54. package/dist/types/sdk/host/host.d.ts +1 -1
  55. package/dist/types/sdk/host/query/handlers.d.ts +9 -0
  56. package/dist/types/sdk/index.d.ts +2 -0
  57. package/dist/types/sdk/prompt-status.d.ts +88 -0
  58. package/dist/types/sdk/session-directory.d.ts +1 -1
  59. package/dist/types/sdk/startup-capability.d.ts +3 -0
  60. package/dist/types/session/agent-session.d.ts +2 -0
  61. package/dist/types/session/internal/managed-session-scope.d.ts +22 -3
  62. package/dist/types/session/internal/managed-session-storage.d.ts +24 -4
  63. package/dist/types/session/internal/native-publish-outcome.d.ts +48 -0
  64. package/dist/types/session/session-manager.d.ts +5 -1
  65. package/dist/types/session/session-storage.d.ts +31 -0
  66. package/dist/types/skill-state/active-state.d.ts +4 -0
  67. package/dist/types/task/index.d.ts +3 -1
  68. package/dist/types/task/receipt.d.ts +2 -0
  69. package/dist/types/task/types.d.ts +94 -0
  70. package/dist/types/tools/ask.d.ts +454 -174
  71. package/dist/types/tools/image-gen.d.ts +47 -1
  72. package/dist/types/tools/index.d.ts +4 -0
  73. package/dist/types/utils/prompt-suggestion.d.ts +33 -0
  74. package/package.json +8 -8
  75. package/scripts/capture-platform-shortcut-labels-showcase.ts +342 -0
  76. package/scripts/dogfood-repository-binding.ts +209 -0
  77. package/scripts/generate-sdk-operation-inventory.ts +2 -0
  78. package/scripts/run-test-manifest.ts +4 -4
  79. package/src/cli/args.ts +2 -92
  80. package/src/cli/mcp-cli.ts +4 -21
  81. package/src/cli/notify-cli.ts +5 -38
  82. package/src/cli.ts +50 -0
  83. package/src/commands/deep-interview.ts +9 -4
  84. package/src/commands/sdk.ts +2 -2
  85. package/src/commit/agentic/index.ts +3 -3
  86. package/src/commit/map-reduce/index.ts +2 -2
  87. package/src/config/keybindings.ts +157 -24
  88. package/src/config/model-profile-activation.ts +7 -18
  89. package/src/config/model-profile-contract.ts +161 -0
  90. package/src/config/model-profiles.ts +2 -3
  91. package/src/config/model-registry.ts +11 -1
  92. package/src/config/settings-schema.ts +17 -2
  93. package/src/coordinator-mcp/model-preset.ts +21 -74
  94. package/src/defaults/gjc/skills/deep-interview/SKILL.md +80 -165
  95. package/src/defaults/gjc/skills/ralplan/SKILL.md +3 -1
  96. package/src/edit/index.ts +3 -6
  97. package/src/edit/modes/patch.ts +38 -1
  98. package/src/edit/modes/replace.ts +42 -0
  99. package/src/edit/path-mutation-lock.ts +112 -0
  100. package/src/eval/py/executor.ts +30 -11
  101. package/src/eval/py/prelude.py +2 -2
  102. package/src/eval/py/tool-bridge.ts +34 -18
  103. package/src/extensibility/gjc-plugins/runtime-adapters.ts +2 -1
  104. package/src/gjc-runtime/deep-interview-ambiguity.ts +68 -47
  105. package/src/gjc-runtime/deep-interview-draft.ts +842 -0
  106. package/src/gjc-runtime/deep-interview-payload.ts +262 -0
  107. package/src/gjc-runtime/deep-interview-recorder.ts +294 -226
  108. package/src/gjc-runtime/deep-interview-repair.ts +1674 -0
  109. package/src/gjc-runtime/deep-interview-runtime.ts +264 -103
  110. package/src/gjc-runtime/deep-interview-state.ts +916 -4
  111. package/src/gjc-runtime/launch-tmux.ts +1 -1
  112. package/src/gjc-runtime/managed-owner-supervisor.ts +83 -4
  113. package/src/gjc-runtime/ralplan-runtime.ts +78 -4
  114. package/src/gjc-runtime/repository-binding.ts +267 -0
  115. package/src/gjc-runtime/session-state-sidecar.ts +25 -9
  116. package/src/gjc-runtime/state-writer.ts +166 -2
  117. package/src/gjc-runtime/tmux-owner-isolation.ts +2 -1
  118. package/src/gjc-runtime/tmux-sessions.ts +45 -6
  119. package/src/gjc-runtime/ultragoal-guard.ts +5 -5
  120. package/src/gjc-runtime/ultragoal-runtime.ts +181 -19
  121. package/src/gjc-runtime/workflow-manifest.generated.json +386 -1
  122. package/src/gjc-runtime/workflow-manifest.ts +191 -5
  123. package/src/internal-urls/docs-index.generated.ts +8 -6
  124. package/src/internal-urls/local-protocol.ts +33 -16
  125. package/src/internal-urls/mcp-protocol.ts +73 -11
  126. package/src/main.ts +25 -10
  127. package/src/modes/DESIGN.md +5 -0
  128. package/src/modes/acp/acp-agent.ts +50 -16
  129. package/src/modes/components/model-selector.ts +42 -8
  130. package/src/modes/components/plan-preview-overlay.ts +1 -1
  131. package/src/modes/components/runtime-mcp-add-wizard.ts +5 -0
  132. package/src/modes/components/tool-status-header.ts +20 -4
  133. package/src/modes/components/welcome.ts +32 -20
  134. package/src/modes/controllers/command-controller.ts +97 -54
  135. package/src/modes/controllers/event-controller.ts +10 -0
  136. package/src/modes/controllers/input-controller.ts +7 -2
  137. package/src/modes/controllers/runtime-mcp-command-controller.ts +29 -6
  138. package/src/modes/controllers/selector-controller.ts +46 -54
  139. package/src/modes/interactive-mode.ts +70 -36
  140. package/src/modes/prompt-action-autocomplete.ts +32 -13
  141. package/src/modes/prompt-suggestion-controller.ts +96 -0
  142. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +2 -2
  143. package/src/modes/types.ts +3 -0
  144. package/src/modes/utils/hotkeys-markdown.ts +64 -36
  145. package/src/modes/utils/ui-helpers.ts +5 -3
  146. package/src/prompts/agents/architect.md +0 -1
  147. package/src/prompts/agents/critic.md +0 -1
  148. package/src/prompts/system/prompt-suggestion-system.md +32 -0
  149. package/src/prompts/system/system-prompt.md +7 -4
  150. package/src/prompts/tools/cron.md +3 -1
  151. package/src/runtime-mcp/json-rpc.ts +7 -4
  152. package/src/runtime-mcp/manager.ts +51 -53
  153. package/src/runtime-mcp/oauth-flow.ts +0 -72
  154. package/src/runtime-mcp/plugin-network-boundary.ts +101 -0
  155. package/src/runtime-mcp/redaction.ts +30 -0
  156. package/src/runtime-mcp/transports/http.ts +13 -6
  157. package/src/sdk/broker/broker.ts +34 -20
  158. package/src/sdk/broker/lifecycle.ts +185 -36
  159. package/src/sdk/broker/session-index.ts +11 -1
  160. package/src/sdk/bus/chat-daemon-control.ts +20 -5
  161. package/src/sdk/bus/config-commands.ts +2 -2
  162. package/src/sdk/bus/config.ts +9 -1
  163. package/src/sdk/bus/conversation-store.ts +40 -6
  164. package/src/sdk/bus/index.ts +240 -65
  165. package/src/sdk/bus/lifecycle-commands.ts +47 -3
  166. package/src/sdk/bus/lifecycle-control-runtime.ts +11 -2
  167. package/src/sdk/bus/lifecycle-orchestrator.ts +32 -1
  168. package/src/sdk/bus/notification-orchestration.ts +12 -0
  169. package/src/sdk/bus/notification-service.ts +27 -2
  170. package/src/sdk/bus/prompt-reconciliation.ts +239 -0
  171. package/src/sdk/bus/recent-activity.ts +90 -26
  172. package/src/sdk/bus/telegram-daemon-contract.ts +15 -3
  173. package/src/sdk/bus/telegram-daemon-control.ts +145 -33
  174. package/src/sdk/bus/telegram-daemon.ts +853 -112
  175. package/src/sdk/bus/telegram-reference.ts +20 -2
  176. package/src/sdk/cli/session-cli.ts +15 -2
  177. package/src/sdk/host/control/dispatch.ts +1 -1
  178. package/src/sdk/host/control/operations.ts +1 -1
  179. package/src/sdk/host/host.ts +2 -6
  180. package/src/sdk/host/query/handlers.ts +70 -5
  181. package/src/sdk/index.ts +12 -0
  182. package/src/sdk/prompt-status.ts +97 -0
  183. package/src/sdk/protocol/operation-inventory.generated.json +47 -0
  184. package/src/sdk/protocol/operation-registry.ts +18 -4
  185. package/src/sdk/session-directory.ts +5 -1
  186. package/src/sdk/session.ts +2 -0
  187. package/src/sdk/startup-capability.ts +9 -1
  188. package/src/session/agent-session.ts +138 -5
  189. package/src/session/blob-store.ts +7 -2
  190. package/src/session/internal/managed-session-scope.ts +998 -133
  191. package/src/session/internal/managed-session-storage.ts +268 -203
  192. package/src/session/internal/native-publish-outcome.ts +266 -0
  193. package/src/session/session-manager.ts +406 -360
  194. package/src/session/session-storage.ts +151 -11
  195. package/src/skill-state/active-state.ts +10 -0
  196. package/src/task/executor.ts +13 -5
  197. package/src/task/gjc-command.ts +2 -2
  198. package/src/task/index.ts +121 -15
  199. package/src/task/receipt.ts +3 -0
  200. package/src/task/types.ts +34 -3
  201. package/src/tools/ask.ts +199 -88
  202. package/src/tools/ast-edit.ts +2 -2
  203. package/src/tools/bash-pty-selection.ts +2 -2
  204. package/src/tools/browser/screenshot-format.ts +6 -1
  205. package/src/tools/cron.ts +1 -1
  206. package/src/tools/image-gen.ts +178 -6
  207. package/src/tools/index.ts +4 -0
  208. package/src/tools/render-utils.ts +7 -1
  209. package/src/utils/edit-mode.ts +2 -2
  210. package/src/utils/prompt-suggestion.ts +265 -0
  211. package/src/utils/sixel.ts +3 -3
  212. package/src/web/insane/url-guard.ts +3 -1
  213. package/src/web/scrapers/docs-rs.ts +30 -5
@@ -245,6 +245,7 @@ import { loadActiveSubskillTools } from "../extensibility/gjc-plugins/tools";
245
245
  import type { HookCommandContext } from "../extensibility/hooks/types";
246
246
  import { buildSkillPromptMessage, type Skill, type SkillWarning } from "../extensibility/skills";
247
247
  import { expandSlashCommand, type FileSlashCommand } from "../extensibility/slash-commands";
248
+ import { assertDeepInterviewIntentManifest } from "../gjc-runtime/deep-interview-state";
248
249
  import { buildGjcRuntimeSessionEnv, consumePendingGoalModeRequest } from "../gjc-runtime/goal-mode-request";
249
250
  import {
250
251
  assertNonEmptyGjcSessionId,
@@ -252,6 +253,7 @@ import {
252
253
  sessionStateDir,
253
254
  } from "../gjc-runtime/session-layout";
254
255
  import {
256
+ ownerTerminalContextFromEnvironment,
255
257
  persistCoordinatorRuntimeStateFromEvent,
256
258
  registerCoordinatorRuntimeStateFinalizer,
257
259
  } from "../gjc-runtime/session-state-sidecar";
@@ -260,7 +262,7 @@ import { GoalRuntime } from "../goals/runtime";
260
262
  import type { Goal, GoalModeState } from "../goals/state";
261
263
  import type { HindsightSessionState } from "../hindsight/state";
262
264
  import { buildSkillStopOutput, ensureWorkflowSkillActivationState } from "../hooks/skill-state";
263
- import { type LocalProtocolOptions, resolveLocalUrlToPath } from "../internal-urls";
265
+ import { initializeLocalRoot, type LocalProtocolOptions, resolveLocalUrlToPath } from "../internal-urls";
264
266
  import { shutdownAll as shutdownAllLspClients } from "../lsp/client";
265
267
  import { resolveMemoryBackend } from "../memory-backend";
266
268
  import {
@@ -783,6 +785,22 @@ type RetryErrorClassification =
783
785
 
784
786
  const BARE_DEFAULT_WATCHDOG_ERROR =
785
787
  /^(?:[A-Za-z][A-Za-z0-9-]*(?: [A-Za-z][A-Za-z0-9-]*){0,3} )stream (?:timed out while waiting for the first event|stalled while waiting for the next event)$/;
788
+ const KIMI_CODE_FIRST_EVENT_TIMEOUT_MESSAGES = {
789
+ "anthropic-messages": new Set([
790
+ "Provider stream timed out while waiting for the first event",
791
+ "Anthropic stream timed out while waiting for the first event",
792
+ ]),
793
+ "openai-completions": new Set([
794
+ "Provider stream timed out while waiting for the first event",
795
+ "OpenAI completions stream timed out while waiting for the first event",
796
+ ]),
797
+ } as const;
798
+
799
+ const ALIBABA_TOKEN_PLAN_PROVIDER = "alibaba-token-plan";
800
+ const ALIBABA_TOKEN_PLAN_FIRST_EVENT_TIMEOUT_MESSAGES = {
801
+ "openai-responses": "OpenAI responses stream timed out while waiting for the first event",
802
+ "openai-completions": "OpenAI completions stream timed out while waiting for the first event",
803
+ } as const;
786
804
 
787
805
  function hasBareDefaultRetryDisqualifyingFacts(message: AssistantMessage): boolean {
788
806
  if (message.errorKind !== undefined || message.errorStatus !== undefined) return true;
@@ -1668,6 +1686,7 @@ export class AgentSession {
1668
1686
 
1669
1687
  #skillsSettings: SkillsSettings | undefined;
1670
1688
  #activeSkillState: { skill: string; sessionId?: string } | undefined;
1689
+ #restoredWorkflowSkillState: { skill: string; sessionId: string } | undefined;
1671
1690
 
1672
1691
  // Model registry for API key resolution
1673
1692
  #modelRegistry: ModelRegistry;
@@ -2487,6 +2506,34 @@ export class AgentSession {
2487
2506
  return undefined;
2488
2507
  }
2489
2508
  }
2509
+ /** Provider-facing ask metadata must expose only the active deep-interview phase. */
2510
+ getDeepInterviewAskStage(): "topology" | "post-topology" | undefined {
2511
+ const currentSessionId = this.sessionManager.getSessionId();
2512
+ const inMemory = this.#activeSkillState;
2513
+ const active =
2514
+ inMemory && (!inMemory.sessionId || inMemory.sessionId === currentSessionId)
2515
+ ? inMemory
2516
+ : this.#restoredWorkflowSkillState?.sessionId === currentSessionId
2517
+ ? this.#restoredWorkflowSkillState
2518
+ : undefined;
2519
+ if (active?.skill !== "deep-interview") return undefined;
2520
+ try {
2521
+ assertNonEmptyGjcSessionId(currentSessionId, "AgentSession.getDeepInterviewAskStage");
2522
+ const stateDir = sessionStateDir(this.sessionManager.getCwd(), currentSessionId);
2523
+ const filePath = path.join(
2524
+ stateDir,
2525
+ path.basename(sessionModeStatePath(this.sessionManager.getCwd(), currentSessionId, active.skill)),
2526
+ );
2527
+ const raw = fs.readFileSync(filePath, "utf-8");
2528
+ const parsed = JSON.parse(raw) as { state?: { intent_contract?: unknown } };
2529
+ const intentContract = parsed.state?.intent_contract;
2530
+ if (intentContract === undefined) return "topology";
2531
+ assertDeepInterviewIntentManifest(intentContract);
2532
+ return "post-topology";
2533
+ } catch {
2534
+ return undefined;
2535
+ }
2536
+ }
2490
2537
 
2491
2538
  /** Peek the in-flight directive's invocation handler for use by the resolve tool. */
2492
2539
  peekQueueInvoker(): ((input: unknown) => Promise<unknown> | unknown) | undefined {
@@ -4553,6 +4600,8 @@ export class AgentSession {
4553
4600
  return {
4554
4601
  getArtifactsDir: () => this.sessionManager.getArtifactsDir(),
4555
4602
  isManagedDestination: () => this.sessionManager.isManagedDestination(),
4603
+ // Required for verified legacy local:// migration on managed sessions (#2797 / #2925).
4604
+ getManagedLegacyLocalMigrationSource: () => this.sessionManager.getManagedLegacyLocalMigrationSource(),
4556
4605
  getSessionId: () => this.sessionManager.getSessionId(),
4557
4606
  };
4558
4607
  }
@@ -5127,7 +5176,7 @@ export class AgentSession {
5127
5176
  // No-op when this session opened no tabs. Failure is logged, not thrown.
5128
5177
  this.#unregisterResourceGc?.();
5129
5178
  this.#unregisterResourceGc = undefined;
5130
- this.#unregisterRuntimeStateFinalizer?.();
5179
+ if (ownerTerminalContextFromEnvironment() === null) this.#unregisterRuntimeStateFinalizer?.();
5131
5180
  this.#unregisterRuntimeStateFinalizer = undefined;
5132
5181
  await releaseTabsForOwner(this.sessionManager.getSessionId()).catch((error: unknown) =>
5133
5182
  logger.warn("session dispose: releaseTabsForOwner failed", { error }),
@@ -6780,8 +6829,9 @@ export class AgentSession {
6780
6829
  if (!activeSkill) {
6781
6830
  try {
6782
6831
  const activeState = await readVisibleSkillActiveState(this.sessionManager.getCwd(), sessionId);
6783
- activeSkill =
6784
- activeState?.skill ?? activeState?.active_skills?.find(entry => entry.active !== false)?.skill;
6832
+ activeSkill = activeState?.active_skills?.find(
6833
+ entry => entry.active !== false && entry.session_id === sessionId,
6834
+ )?.skill;
6785
6835
  } catch (error) {
6786
6836
  logger.warn("Failed to read durable workflow skill state while restoring ask tool", {
6787
6837
  error: error instanceof Error ? error.message : String(error),
@@ -6793,7 +6843,12 @@ export class AgentSession {
6793
6843
  // a predecessor session's workflow state to the current identity.
6794
6844
  if (this.#isDisposed || this.sessionManager.getSessionId() !== sessionId) return;
6795
6845
  }
6796
- if (activeSkill && isCanonicalGjcWorkflowSkill(activeSkill.trim())) this.#attachAskTool();
6846
+ if (activeSkill && isCanonicalGjcWorkflowSkill(activeSkill.trim())) {
6847
+ if (!inMemoryActiveSkill) this.#restoredWorkflowSkillState = { skill: activeSkill.trim(), sessionId };
6848
+ this.#attachAskTool();
6849
+ } else if (this.#restoredWorkflowSkillState?.sessionId === sessionId) {
6850
+ this.#restoredWorkflowSkillState = undefined;
6851
+ }
6797
6852
  }
6798
6853
 
6799
6854
  #attachAskTool(): void {
@@ -7345,6 +7400,7 @@ export class AgentSession {
7345
7400
  }
7346
7401
  }
7347
7402
  // In-memory tracking keeps `getActiveSkillState` accurate for the chain guard.
7403
+ this.#restoredWorkflowSkillState = undefined;
7348
7404
  this.#activeSkillState = active ? { skill, sessionId } : undefined;
7349
7405
  if (active) {
7350
7406
  await this.refreshGjcSubskillTools();
@@ -12392,6 +12448,7 @@ export class AgentSession {
12392
12448
  }
12393
12449
  const retryAfterMs = this.#parseRetryAfterMsFromError(message);
12394
12450
  const shouldRetry =
12451
+ !this.#isTerminalProviderCompactionTimeout(candidate, message) &&
12395
12452
  retrySettings.enabled &&
12396
12453
  attempt < retrySettings.maxRetries &&
12397
12454
  (retryAfterMs !== undefined ||
@@ -12577,7 +12634,61 @@ export class AgentSession {
12577
12634
  * unknown/no-code errors are retryable.
12578
12635
  */
12579
12636
 
12637
+ #isKimiCodeFirstEventTimeout(message: AssistantMessage): boolean {
12638
+ if (message.stopReason !== "error" || message.provider !== "kimi-code") return false;
12639
+ const errorMessage = message.errorMessage ?? "";
12640
+ if (message.api === "anthropic-messages") {
12641
+ return KIMI_CODE_FIRST_EVENT_TIMEOUT_MESSAGES["anthropic-messages"].has(errorMessage);
12642
+ }
12643
+ if (message.api === "openai-completions") {
12644
+ return KIMI_CODE_FIRST_EVENT_TIMEOUT_MESSAGES["openai-completions"].has(errorMessage);
12645
+ }
12646
+ return false;
12647
+ }
12648
+
12649
+ #isKimiCodeCompactionTimeout(candidate: Model, errorMessage: string): boolean {
12650
+ if (candidate.provider !== "kimi-code") return false;
12651
+ return /^(?:Summarization failed|Turn prefix summarization failed): (?:Provider|Anthropic|OpenAI completions) stream timed out while waiting for the first event$/.test(
12652
+ errorMessage,
12653
+ );
12654
+ }
12655
+
12656
+ #alibabaTokenPlanCanonicalTimeoutForApi(api: string): string | undefined {
12657
+ if (api === "openai-responses" || api === "openai-completions") {
12658
+ return ALIBABA_TOKEN_PLAN_FIRST_EVENT_TIMEOUT_MESSAGES[api];
12659
+ }
12660
+ return undefined;
12661
+ }
12662
+
12663
+ #isAlibabaTokenPlanFirstEventTimeout(message: AssistantMessage): boolean {
12664
+ if (message.stopReason !== "error" || message.provider !== ALIBABA_TOKEN_PLAN_PROVIDER) return false;
12665
+ const canonicalMessage = this.#alibabaTokenPlanCanonicalTimeoutForApi(message.api);
12666
+ return canonicalMessage !== undefined && message.errorMessage === canonicalMessage;
12667
+ }
12668
+
12669
+ #isAlibabaTokenPlanCompactionTimeout(candidate: Model, errorMessage: string): boolean {
12670
+ if (candidate.provider !== ALIBABA_TOKEN_PLAN_PROVIDER) return false;
12671
+ const canonicalMessage = this.#alibabaTokenPlanCanonicalTimeoutForApi(candidate.api);
12672
+ if (canonicalMessage === undefined) return false;
12673
+ return (
12674
+ errorMessage === `Summarization failed: ${canonicalMessage}` ||
12675
+ errorMessage === `Turn prefix summarization failed: ${canonicalMessage}`
12676
+ );
12677
+ }
12678
+
12679
+ #isTerminalProviderFirstEventTimeout(message: AssistantMessage): boolean {
12680
+ return this.#isKimiCodeFirstEventTimeout(message) || this.#isAlibabaTokenPlanFirstEventTimeout(message);
12681
+ }
12682
+
12683
+ #isTerminalProviderCompactionTimeout(candidate: Model, errorMessage: string): boolean {
12684
+ return (
12685
+ this.#isKimiCodeCompactionTimeout(candidate, errorMessage) ||
12686
+ this.#isAlibabaTokenPlanCompactionTimeout(candidate, errorMessage)
12687
+ );
12688
+ }
12689
+
12580
12690
  #isRetryableError(message: AssistantMessage): boolean {
12691
+ if (this.#isTerminalProviderFirstEventTimeout(message)) return false;
12581
12692
  if (message.errorMessage?.startsWith("Model fallback chain exhausted;")) return false;
12582
12693
  const transportFailure = message.transportFailure;
12583
12694
  const contextWindow = this.model?.contextWindow ?? 0;
@@ -12727,6 +12838,9 @@ export class AgentSession {
12727
12838
  if (isTerminalHttp4xx && (explicitStatus !== undefined || !/rate.?limit|too many requests/i.test(err))) {
12728
12839
  return "terminal";
12729
12840
  }
12841
+ if (this.#isTerminalProviderFirstEventTimeout(message)) {
12842
+ return "terminal";
12843
+ }
12730
12844
  // A first-event timeout on ollama-cloud (the ollama-chat API) must not
12731
12845
  // join the unbounded transient class: each continuation retry re-issues
12732
12846
  // the full request to a remote, billable backend, so an unbounded loop
@@ -12909,6 +13023,18 @@ export class AgentSession {
12909
13023
  },
12910
13024
  };
12911
13025
  }
13026
+ if (this.#isTerminalProviderFirstEventTimeout(outcome.failure.message)) {
13027
+ // The managed transport discarded this attempt before session policy saw it.
13028
+ // Remove its provisional controller charge and surface the original message.
13029
+ this.#defaultFallbackChain().discardStartedAttempt();
13030
+ return {
13031
+ type: "terminal",
13032
+ terminal: {
13033
+ stopReason: "error",
13034
+ messages: [outcome.failure.message],
13035
+ },
13036
+ };
13037
+ }
12912
13038
  return this.#handleRetryableError(
12913
13039
  outcome.failure.message,
12914
13040
  true,
@@ -14507,6 +14633,13 @@ export class AgentSession {
14507
14633
  await this.sessionManager.ensureOnDisk();
14508
14634
 
14509
14635
  if (switchingToDifferentSession) {
14636
+ // Interactive /resume (and any other switchSession identity change) must
14637
+ // await verified legacy local:// migration for the *new* session before
14638
+ // post-commit session_switch / local path resolution. createAgentSession
14639
+ // already does this at cold start (#2797); switchSession previously omitted
14640
+ // it, so resolving local:// after /resume could fail-closed with
14641
+ // "legacy migration must complete before path resolution" (#2925).
14642
+ await initializeLocalRoot(this.#localProtocolOptions());
14510
14643
  this.#resetHindsightConversationTrackingIfHindsight();
14511
14644
  this.#resetIrcRosterDeliveryState();
14512
14645
  }
@@ -124,8 +124,13 @@ export class BlobStore {
124
124
  },
125
125
  };
126
126
 
127
- await Bun.write(blobPath, data);
128
- await fsp.chmod(blobPath, BLOB_FILE_MODE);
127
+ // Create the blob directory 0700 and the file 0600 at creation, mirroring
128
+ // putSync/putImmutableSync. The previous Bun.write let the parent dir be
129
+ // created with the process umask (e.g. 0755) and the file at 0644 before a
130
+ // follow-up chmod, violating the owner-only contract above and leaving a
131
+ // group/other-readable window a managed-tree snapshot fails closed on.
132
+ await fsp.mkdir(this.dir, { recursive: true, mode: BLOB_DIR_MODE });
133
+ await fsp.writeFile(blobPath, data, { mode: BLOB_FILE_MODE });
129
134
  return result;
130
135
  }
131
136