@gajae-code/coding-agent 0.18.12 → 0.19.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 (305) hide show
  1. package/CHANGELOG.md +467 -0
  2. package/dist/types/capability/rule.d.ts +7 -2
  3. package/dist/types/cli/append-system-prompt.d.ts +6 -0
  4. package/dist/types/cli/args.d.ts +7 -2
  5. package/dist/types/cli/customize-doctor-precedence.d.ts +16 -0
  6. package/dist/types/cli/customize-doctor.d.ts +4 -3
  7. package/dist/types/cli/public-command-errors.d.ts +1 -0
  8. package/dist/types/cli/root-flags.d.ts +0 -12
  9. package/dist/types/cli/update-cli.d.ts +7 -2
  10. package/dist/types/cli-main.d.ts +0 -6
  11. package/dist/types/commands/launch.d.ts +0 -6
  12. package/dist/types/commands/migrate.d.ts +1 -1
  13. package/dist/types/commands/sdk.d.ts +8 -0
  14. package/dist/types/commit/map-reduce/index.d.ts +4 -4
  15. package/dist/types/config/autorouting-tier-map.d.ts +23 -1
  16. package/dist/types/config/config-hot-reload.d.ts +5 -0
  17. package/dist/types/config/file-lock.d.ts +44 -2
  18. package/dist/types/config/model-profile-activation.d.ts +19 -5
  19. package/dist/types/config/model-registry.d.ts +16 -3
  20. package/dist/types/config/model-resolver.d.ts +5 -4
  21. package/dist/types/config/settings-schema.d.ts +11 -1
  22. package/dist/types/coordinator-mcp/server.d.ts +4 -0
  23. package/dist/types/customization/import.d.ts +2 -0
  24. package/dist/types/customization/types.d.ts +1 -1
  25. package/dist/types/dap/session.d.ts +11 -2
  26. package/dist/types/discovery/helpers.d.ts +7 -2
  27. package/dist/types/edit/index.d.ts +5 -0
  28. package/dist/types/edit/modes/patch.d.ts +9 -0
  29. package/dist/types/eval/py/runtime.d.ts +9 -0
  30. package/dist/types/export/ttsr.d.ts +19 -0
  31. package/dist/types/extensibility/extensions/types.d.ts +5 -1
  32. package/dist/types/extensibility/slash-commands.d.ts +1 -0
  33. package/dist/types/gjc-runtime/ralplan-current-final.d.ts +54 -0
  34. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +5 -0
  35. package/dist/types/gjc-runtime/tmux-sessions.d.ts +24 -0
  36. package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +6 -0
  37. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +1 -0
  38. package/dist/types/harness-control-plane/receipt-spool.d.ts +4 -0
  39. package/dist/types/hindsight/content.d.ts +5 -6
  40. package/dist/types/internal-urls/types.d.ts +2 -0
  41. package/dist/types/lsp/clients/swiftlint-client.d.ts +0 -4
  42. package/dist/types/main.d.ts +23 -18
  43. package/dist/types/migrate/action-planner.d.ts +10 -1
  44. package/dist/types/migrate/adapters/codex.d.ts +1 -1
  45. package/dist/types/migrate/adapters/index.d.ts +35 -3
  46. package/dist/types/migrate/hook-module.d.ts +23 -0
  47. package/dist/types/migrate/report.d.ts +2 -1
  48. package/dist/types/migrate/types.d.ts +69 -2
  49. package/dist/types/modes/components/agent-dashboard.d.ts +1 -1
  50. package/dist/types/modes/components/model-selector.d.ts +43 -0
  51. package/dist/types/modes/prompt-suggestion-controller.d.ts +1 -1
  52. package/dist/types/modes/utils/host-status.d.ts +15 -11
  53. package/dist/types/runtime-mcp/project-host-values.d.ts +11 -5
  54. package/dist/types/sdk/broker/broker-exit.d.ts +1 -1
  55. package/dist/types/sdk/broker/broker.d.ts +22 -1
  56. package/dist/types/sdk/broker/ensure.d.ts +5 -2
  57. package/dist/types/sdk/broker/hop.d.ts +9 -0
  58. package/dist/types/sdk/broker/lifecycle.d.ts +22 -0
  59. package/dist/types/sdk/broker/session-index.d.ts +2 -0
  60. package/dist/types/sdk/broker/transport.d.ts +2 -0
  61. package/dist/types/sdk/bus/index.d.ts +21 -0
  62. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +7 -1
  63. package/dist/types/sdk/bus/telegram-daemon.d.ts +2 -0
  64. package/dist/types/sdk/bus/threaded-render.d.ts +2 -1
  65. package/dist/types/sdk/host/control/operations.d.ts +5 -1
  66. package/dist/types/sdk/host/events.d.ts +4 -0
  67. package/dist/types/sdk/host/host.d.ts +2 -1
  68. package/dist/types/sdk/host/prompt-image-upload.d.ts +43 -0
  69. package/dist/types/sdk/host/session-runtime.d.ts +8 -8
  70. package/dist/types/sdk/host/surface-policy.d.ts +2 -1
  71. package/dist/types/sdk/lifecycle/service.d.ts +12 -0
  72. package/dist/types/sdk/prompt-status.d.ts +11 -4
  73. package/dist/types/session/agent-session.d.ts +50 -8
  74. package/dist/types/session/session-manager.d.ts +16 -0
  75. package/dist/types/skill-state/workflow-mutation-guard.d.ts +13 -1
  76. package/dist/types/slash-commands/helpers/mcp.d.ts +5 -0
  77. package/dist/types/ssh/ssh-executor.d.ts +8 -1
  78. package/dist/types/system-prompt.d.ts +3 -2
  79. package/dist/types/task/role-body.d.ts +11 -0
  80. package/dist/types/tools/awaiting-input.d.ts +28 -0
  81. package/dist/types/tools/bash-allowed-prefixes.d.ts +6 -0
  82. package/dist/types/tools/bash-skill-urls.d.ts +4 -0
  83. package/dist/types/tools/bash.d.ts +7 -0
  84. package/dist/types/tools/descriptors.d.ts +13 -2
  85. package/dist/types/tools/fetch.d.ts +6 -0
  86. package/dist/types/tools/irc.d.ts +5 -3
  87. package/dist/types/tools/tmux-self-injection-guard.d.ts +2 -0
  88. package/dist/types/tools/ultragoal-ask-guard.d.ts +1 -1
  89. package/dist/types/tools/write.d.ts +2 -0
  90. package/dist/types/utils/file-mentions.d.ts +5 -0
  91. package/dist/types/utils/image-limits.d.ts +7 -0
  92. package/dist/types/utils/image-loading.d.ts +0 -1
  93. package/dist/types/utils/open.d.ts +0 -1
  94. package/dist/types/utils/pasted-image-loading.d.ts +1 -5
  95. package/dist/types/utils/prompt-suggestion.d.ts +2 -2
  96. package/dist/types/utils/shell-snapshot.d.ts +2 -0
  97. package/dist/types/utils/title-generator.d.ts +13 -3
  98. package/dist/types/web/search/providers/codex.d.ts +6 -7
  99. package/package.json +9 -8
  100. package/scripts/acp-conformance-agent.ts +12 -2
  101. package/scripts/generate-sdk-operation-inventory.ts +16 -0
  102. package/src/capability/fs.ts +31 -3
  103. package/src/capability/rule.ts +11 -2
  104. package/src/cli/append-system-prompt.ts +12 -0
  105. package/src/cli/args.ts +11 -7
  106. package/src/cli/customize-doctor-precedence.ts +31 -0
  107. package/src/cli/customize-doctor.ts +49 -39
  108. package/src/cli/fast-help.ts +0 -2
  109. package/src/cli/migrate-cli.ts +14 -3
  110. package/src/cli/public-command-errors.ts +2 -0
  111. package/src/cli/root-flags.ts +0 -2
  112. package/src/cli/update-cli.ts +247 -6
  113. package/src/commands/harness.ts +25 -15
  114. package/src/commands/migrate.ts +3 -3
  115. package/src/commands/sdk.ts +81 -11
  116. package/src/commit/agentic/agent.ts +6 -6
  117. package/src/commit/analysis/conventional.ts +14 -5
  118. package/src/commit/map-reduce/index.ts +7 -7
  119. package/src/commit/pipeline.ts +12 -12
  120. package/src/config/autorouting-tier-map.ts +20 -1
  121. package/src/config/config-file.ts +106 -3
  122. package/src/config/config-hot-reload.ts +8 -0
  123. package/src/config/file-lock.ts +1431 -304
  124. package/src/config/keybindings.ts +154 -7
  125. package/src/config/model-profile-activation.ts +177 -39
  126. package/src/config/model-registry.ts +380 -55
  127. package/src/config/model-resolver.ts +49 -21
  128. package/src/config/settings-schema.ts +13 -1
  129. package/src/config/settings.ts +2 -0
  130. package/src/coordinator-mcp/server.ts +37 -2
  131. package/src/crash/sanitize.ts +3 -1
  132. package/src/customization/import.ts +276 -7
  133. package/src/customization/inventory.ts +24 -8
  134. package/src/customization/types.ts +1 -0
  135. package/src/dap/client.ts +3 -2
  136. package/src/dap/session.ts +161 -36
  137. package/src/debug/crash-diagnostics.ts +87 -5
  138. package/src/debug/report-bundle.ts +71 -2
  139. package/src/discovery/builtin.ts +4 -3
  140. package/src/discovery/helpers.ts +24 -14
  141. package/src/edit/index.ts +191 -5
  142. package/src/edit/modes/patch.ts +27 -0
  143. package/src/eval/py/runtime.ts +44 -4
  144. package/src/exec/non-interactive-env.ts +0 -1
  145. package/src/export/html/index.ts +60 -20
  146. package/src/export/ttsr.ts +176 -1
  147. package/src/extensibility/extensions/loader.ts +2 -0
  148. package/src/extensibility/extensions/ouroboros-ooo-bridge.ts +63 -1
  149. package/src/extensibility/extensions/types.ts +5 -1
  150. package/src/extensibility/hooks/loader.ts +10 -2
  151. package/src/extensibility/plugins/marketplace/manager.ts +36 -10
  152. package/src/extensibility/slash-commands.ts +5 -0
  153. package/src/gjc-runtime/gc-runtime.ts +4 -1
  154. package/src/gjc-runtime/launch-tmux.ts +23 -13
  155. package/src/gjc-runtime/ralplan-current-final.ts +294 -0
  156. package/src/gjc-runtime/ralplan-runtime.ts +95 -1
  157. package/src/gjc-runtime/state-writer.ts +109 -5
  158. package/src/gjc-runtime/tmux-sessions.ts +93 -13
  159. package/src/gjc-runtime/ultragoal-change-set.ts +90 -11
  160. package/src/gjc-runtime/ultragoal-guard.ts +9 -1
  161. package/src/gjc-runtime/ultragoal-runtime.ts +15 -5
  162. package/src/harness-control-plane/finalize.ts +11 -0
  163. package/src/harness-control-plane/receipt-spool.ts +105 -28
  164. package/src/harness-control-plane/storage.ts +124 -6
  165. package/src/hindsight/content.ts +116 -16
  166. package/src/hindsight/mental-models.ts +22 -10
  167. package/src/hindsight/state.ts +7 -4
  168. package/src/hooks/native-skill-hook.ts +3 -1
  169. package/src/internal-urls/artifact-protocol.ts +3 -1
  170. package/src/internal-urls/docs-index.generated.ts +14 -14
  171. package/src/internal-urls/local-protocol.ts +28 -3
  172. package/src/internal-urls/types.ts +2 -0
  173. package/src/lsp/client.ts +2 -1
  174. package/src/lsp/clients/biome-client.ts +2 -0
  175. package/src/lsp/clients/swiftlint-client.ts +2 -0
  176. package/src/main.ts +330 -92
  177. package/src/memories/index.ts +25 -2
  178. package/src/migrate/action-planner.ts +517 -2
  179. package/src/migrate/adapters/claude-code.ts +141 -3
  180. package/src/migrate/adapters/codex.ts +57 -5
  181. package/src/migrate/adapters/index.ts +240 -5
  182. package/src/migrate/adapters/opencode.ts +4 -0
  183. package/src/migrate/executor.ts +141 -3
  184. package/src/migrate/hook-module.ts +193 -0
  185. package/src/migrate/report.ts +45 -1
  186. package/src/migrate/types.ts +73 -3
  187. package/src/modes/acp/acp-agent.ts +10 -1
  188. package/src/modes/components/agent-dashboard.ts +20 -4
  189. package/src/modes/components/customization/customization-dashboard.ts +7 -0
  190. package/src/modes/components/customization/import-wizard.ts +29 -3
  191. package/src/modes/components/model-selector.ts +157 -103
  192. package/src/modes/components/welcome.ts +3 -1
  193. package/src/modes/controllers/command-controller.ts +271 -16
  194. package/src/modes/controllers/event-controller.ts +1 -1
  195. package/src/modes/controllers/extension-ui-controller.ts +31 -1
  196. package/src/modes/controllers/goal-mode-controller.ts +79 -10
  197. package/src/modes/controllers/input-controller.ts +2 -0
  198. package/src/modes/controllers/plan-mode-controller.ts +49 -4
  199. package/src/modes/controllers/runtime-mcp-command-controller.ts +7 -6
  200. package/src/modes/controllers/selector-controller.ts +14 -1
  201. package/src/modes/interactive-mode.ts +55 -4
  202. package/src/modes/prompt-suggestion-controller.ts +1 -1
  203. package/src/modes/runtime-init.ts +5 -1
  204. package/src/modes/utils/host-status.ts +21 -10
  205. package/src/prompts/agent-fragments/browser-aside.md +2 -2
  206. package/src/prompts/system/irc-incoming.md +3 -1
  207. package/src/prompts/tools/irc.md +1 -1
  208. package/src/runtime-mcp/manager.ts +8 -3
  209. package/src/runtime-mcp/project-host-values.ts +12 -8
  210. package/src/runtime-mcp/tool-bridge.ts +68 -4
  211. package/src/runtime-mcp/transports/stdio.ts +2 -1
  212. package/src/sdk/broker/broker-exit.ts +2 -0
  213. package/src/sdk/broker/broker.ts +143 -4
  214. package/src/sdk/broker/ensure.ts +74 -6
  215. package/src/sdk/broker/hop.ts +13 -1
  216. package/src/sdk/broker/lifecycle-ledger.ts +3 -0
  217. package/src/sdk/broker/lifecycle.ts +102 -6
  218. package/src/sdk/broker/session-index.ts +29 -4
  219. package/src/sdk/broker/transport.ts +17 -1
  220. package/src/sdk/bus/chat-daemon-control.ts +2 -2
  221. package/src/sdk/bus/index.ts +408 -14
  222. package/src/sdk/bus/session-control.ts +2 -0
  223. package/src/sdk/bus/slack-daemon.ts +105 -9
  224. package/src/sdk/bus/telegram-daemon-contract.ts +7 -1
  225. package/src/sdk/bus/telegram-daemon.ts +10 -2
  226. package/src/sdk/bus/threaded-render.ts +20 -1
  227. package/src/sdk/cli/session-cli.ts +2 -0
  228. package/src/sdk/host/control/dispatch.ts +13 -1
  229. package/src/sdk/host/control/operations.ts +10 -1
  230. package/src/sdk/host/events.ts +67 -4
  231. package/src/sdk/host/host.ts +8 -2
  232. package/src/sdk/host/prompt-image-upload.ts +438 -0
  233. package/src/sdk/host/sdk-surface-parity.test.ts +15 -0
  234. package/src/sdk/host/session-runtime.test.ts +1537 -24
  235. package/src/sdk/host/session-runtime.ts +332 -36
  236. package/src/sdk/host/surface-policy.ts +4 -0
  237. package/src/sdk/host/websocket-transport.lifecycle.test.ts +90 -2
  238. package/src/sdk/host/websocket-transport.ts +19 -7
  239. package/src/sdk/lifecycle/service.ts +14 -1
  240. package/src/sdk/prompt-status.ts +6 -4
  241. package/src/sdk/protocol/adapter-validation.ts +28 -1
  242. package/src/sdk/protocol/operation-inventory.generated.json +160 -0
  243. package/src/sdk/protocol/operation-registry.ts +33 -3
  244. package/src/sdk/session.ts +123 -36
  245. package/src/session/agent-session.ts +1614 -329
  246. package/src/session/history-storage.ts +182 -12
  247. package/src/session/internal/managed-session-scope.ts +47 -18
  248. package/src/session/internal/managed-session-storage.ts +71 -1
  249. package/src/session/session-manager.ts +90 -5
  250. package/src/session-import/redact.ts +53 -2
  251. package/src/skill-state/workflow-mutation-guard.ts +1498 -18
  252. package/src/slash-commands/builtin-registry.ts +6 -3
  253. package/src/slash-commands/helpers/mcp.ts +11 -3
  254. package/src/ssh/ssh-executor.ts +9 -2
  255. package/src/stt/recorder.ts +26 -9
  256. package/src/system-prompt.ts +61 -16
  257. package/src/task/executor.ts +12 -8
  258. package/src/task/role-body.ts +84 -0
  259. package/src/task/token-log-mode.test.ts +162 -0
  260. package/src/task/token-log.ts +91 -2
  261. package/src/tools/archive-reader.ts +650 -37
  262. package/src/tools/ask.ts +1 -0
  263. package/src/tools/ast-grep.ts +7 -2
  264. package/src/tools/auto-generated-guard.ts +12 -3
  265. package/src/tools/awaiting-input.ts +114 -0
  266. package/src/tools/bash-allowed-prefixes.ts +61 -1
  267. package/src/tools/bash-skill-urls.ts +58 -5
  268. package/src/tools/bash.ts +99 -26
  269. package/src/tools/browser/tab-worker.ts +39 -13
  270. package/src/tools/browser.ts +17 -7
  271. package/src/tools/cron.ts +10 -1
  272. package/src/tools/debug.ts +9 -2
  273. package/src/tools/descriptors.test.ts +4 -4
  274. package/src/tools/descriptors.ts +16 -4
  275. package/src/tools/eval.ts +15 -0
  276. package/src/tools/fetch.ts +90 -2
  277. package/src/tools/gh.ts +27 -12
  278. package/src/tools/image-gen.ts +20 -6
  279. package/src/tools/irc.ts +5 -3
  280. package/src/tools/monitor.ts +9 -1
  281. package/src/tools/output-meta.ts +51 -3
  282. package/src/tools/read.ts +9 -2
  283. package/src/tools/recipe/runner.ts +23 -12
  284. package/src/tools/render-utils.ts +2 -2
  285. package/src/tools/search.ts +3 -2
  286. package/src/tools/ssh.ts +274 -8
  287. package/src/tools/subagent.ts +10 -4
  288. package/src/tools/tmux-self-injection-guard.ts +3301 -122
  289. package/src/tools/tool-catalog.generated.ts +1 -1
  290. package/src/tools/ultragoal-ask-guard.ts +13 -1
  291. package/src/tools/write.ts +7 -0
  292. package/src/tui/tree-list.ts +15 -1
  293. package/src/utils/commit-message-generator.ts +3 -2
  294. package/src/utils/external-editor.ts +21 -7
  295. package/src/utils/file-mentions.ts +46 -6
  296. package/src/utils/git.ts +38 -7
  297. package/src/utils/image-limits.ts +8 -0
  298. package/src/utils/image-loading.ts +1 -1
  299. package/src/utils/open.ts +73 -4
  300. package/src/utils/pasted-image-loading.ts +9 -8
  301. package/src/utils/prompt-suggestion.ts +5 -4
  302. package/src/utils/shell-snapshot.ts +9 -1
  303. package/src/utils/title-generator.ts +65 -20
  304. package/src/web/search/index.ts +2 -1
  305. package/src/web/search/providers/codex.ts +29 -32
@@ -80,6 +80,7 @@ export interface SdkSurfacePolicy {
80
80
  export interface SdkSurfacePolicyOptions {
81
81
  bindings: Iterable<string>;
82
82
  workflowGateAvailable: boolean;
83
+ imageUploadsAvailable?: boolean;
83
84
  isBindingInstalled?: (binding: string) => boolean;
84
85
  }
85
86
 
@@ -96,6 +97,7 @@ export function createSdkSurfacePolicy(options: SdkSurfacePolicyOptions): SdkSur
96
97
  operation.kind === kind &&
97
98
  !BROKER_LIFECYCLE_CONTROL_OPERATIONS.has(operation.sdkId) &&
98
99
  !UNINSTALLED_CONTROL_OPERATIONS.has(operation.sdkId) &&
100
+ (!operation.sdkId.startsWith("turn.image.") || options.imageUploadsAvailable === true) &&
99
101
  (!WORKFLOW_GATE_CONTROL_OPERATIONS.has(operation.sdkId) || options.workflowGateAvailable) &&
100
102
  (!required[operation.sdkId] || hasBinding(required[operation.sdkId]!)),
101
103
  ).map(operation => operation.sdkId),
@@ -129,11 +131,13 @@ export function createSdkCapabilities(
129
131
  export function createSdkSurfacePolicyForContext(
130
132
  ctx: ExtensionContext,
131
133
  workflowGateAvailable = false,
134
+ imageUploadsAvailable = false,
132
135
  ): SdkSurfacePolicy {
133
136
  const bindings = ctx.sdkBindings?.() ?? [];
134
137
  return createSdkSurfacePolicy({
135
138
  bindings,
136
139
  workflowGateAvailable,
140
+ imageUploadsAvailable,
137
141
  isBindingInstalled: binding => typeof (ctx as unknown as Record<string, unknown>)[binding] === "function",
138
142
  });
139
143
  }
@@ -3,6 +3,7 @@ import * as fs from "node:fs/promises";
3
3
  import * as os from "node:os";
4
4
  import * as path from "node:path";
5
5
  import { SdkClient } from "../client/client";
6
+ import { SESSION_HOST_OBSERVER_CAPABILITY, TURN_STREAM_CAPABILITY } from "./host";
6
7
  import { SessionSdkSessionRuntime, type SessionSdkTransport } from "./session-runtime";
7
8
  import { createSdkWebSocketTransport, type SdkWebSocketTransportDependencies } from "./websocket-transport";
8
9
 
@@ -29,6 +30,28 @@ async function probeWebSocketEndpoint(url: string, token: string): Promise<void>
29
30
  }
30
31
  }
31
32
 
33
+ async function waitForFrame(
34
+ frames: readonly Record<string, unknown>[],
35
+ predicate: (frame: Record<string, unknown>) => boolean,
36
+ label: string,
37
+ ): Promise<Record<string, unknown>> {
38
+ const deadline = Date.now() + 5_000;
39
+ while (true) {
40
+ const frame = frames.find(predicate);
41
+ if (frame) return frame;
42
+ if (Date.now() >= deadline) throw new Error(`Timed out waiting for ${label}`);
43
+ await Bun.sleep(5);
44
+ }
45
+ }
46
+
47
+ async function waitFor(predicate: () => boolean, label: string): Promise<void> {
48
+ const deadline = Date.now() + 5_000;
49
+ while (!predicate()) {
50
+ if (Date.now() >= deadline) throw new Error(`Timed out waiting for ${label}`);
51
+ await Bun.sleep(5);
52
+ }
53
+ }
54
+
32
55
  describe("SDK WebSocket transport lifecycle", () => {
33
56
  test("concurrent start calls share one endpoint and one server", async () => {
34
57
  const stateRoot = await tempStateRoot();
@@ -193,7 +216,72 @@ describe("SDK WebSocket transport lifecycle", () => {
193
216
  await fs.rm(stateRoot, { recursive: true, force: true });
194
217
  }
195
218
  });
196
- test("event replay capability claims cannot authorize gated replay", async () => {
219
+ test("loopback replay preserves replay-first, split, and subset capability negotiation", async () => {
220
+ const stateRoot = await tempStateRoot();
221
+ const transport = await createSdkWebSocketTransport({
222
+ sessionId: "loopback-split-capabilities",
223
+ stateRoot,
224
+ token: "token",
225
+ });
226
+ const runtime = new SessionSdkSessionRuntime({ transport });
227
+ const frames: Record<string, unknown>[] = [];
228
+ let socket: WebSocket | undefined;
229
+ const required = [TURN_STREAM_CAPABILITY, SESSION_HOST_OBSERVER_CAPABILITY];
230
+ try {
231
+ const endpoint = await runtime.start();
232
+ socket = new WebSocket(`${endpoint.url}?token=token`);
233
+ socket.addEventListener("message", event => {
234
+ frames.push(JSON.parse(String((event as MessageEvent).data)) as Record<string, unknown>);
235
+ });
236
+ await waitForFrame(frames, frame => frame.type === "hello", "server hello");
237
+ socket.send(
238
+ JSON.stringify({
239
+ type: "event_replay",
240
+ id: "replay-before-hello",
241
+ sinceSeq: 0,
242
+ capabilities: [],
243
+ }),
244
+ );
245
+ await waitForFrame(
246
+ frames,
247
+ frame => frame.type === "event_replay_result" && frame.id === "replay-before-hello",
248
+ "replay before hello",
249
+ );
250
+ socket.send(JSON.stringify({ type: "hello", protocolVersion: 3, capabilities: [TURN_STREAM_CAPABILITY] }));
251
+ await waitFor(
252
+ () => runtime.connectionIdsWithCapabilities([TURN_STREAM_CAPABILITY]).length === 1,
253
+ "hello after replay",
254
+ );
255
+
256
+ const replayIds = ["observer-addition", "observer-subset", "observer-empty"];
257
+ for (const [index, capabilities] of [
258
+ [SESSION_HOST_OBSERVER_CAPABILITY],
259
+ [SESSION_HOST_OBSERVER_CAPABILITY],
260
+ [],
261
+ ].entries()) {
262
+ const id = replayIds[index]!;
263
+ socket.send(JSON.stringify({ type: "event_replay", id, sinceSeq: 0, capabilities }));
264
+ await waitForFrame(frames, frame => frame.type === "event_replay_result" && frame.id === id, id);
265
+ expect(runtime.connectionIdsWithCapabilities(required)).toHaveLength(1);
266
+ }
267
+
268
+ runtime.sendFrameToCapabilities(required, {
269
+ type: "event",
270
+ kind: "tool_activity",
271
+ payload: { phase: "started" },
272
+ });
273
+ await waitForFrame(
274
+ frames,
275
+ frame => frame.type === "event" && frame.kind === "tool_activity",
276
+ "live observer event",
277
+ );
278
+ } finally {
279
+ socket?.close();
280
+ await runtime.stop().catch(() => undefined);
281
+ await fs.rm(stateRoot, { recursive: true, force: true });
282
+ }
283
+ }, 30_000);
284
+ test("event replay keeps tool activity gated without tool_activity_v2", async () => {
197
285
  const stateRoot = await tempStateRoot();
198
286
  const transport = await createSdkWebSocketTransport({
199
287
  sessionId: "replay-capability-claim",
@@ -223,7 +311,7 @@ describe("SDK WebSocket transport lifecycle", () => {
223
311
  id: "forged-capability-claim",
224
312
  sinceGeneration: 1,
225
313
  sinceSeq: 0,
226
- capabilities: ["tool_activity_v2"],
314
+ capabilities: [SESSION_HOST_OBSERVER_CAPABILITY],
227
315
  }),
228
316
  );
229
317
  const frame = await replay;
@@ -3,6 +3,7 @@ import * as fs from "node:fs/promises";
3
3
  import * as path from "node:path";
4
4
  import { exactUnlink, type NativeExactFileIdentity } from "@gajae-code/natives";
5
5
  import {
6
+ AWAITING_INPUT_CAPABILITY,
6
7
  canDeliverSdkEvent,
7
8
  SESSION_HOST_OBSERVER_CAPABILITY,
8
9
  TOOL_ACTIVITY_CAPABILITY,
@@ -167,6 +168,9 @@ export async function createSdkWebSocketTransport(
167
168
  if (!socket) throw new Error("SDK connection is no longer available.");
168
169
  socket.send(JSON.stringify(frame));
169
170
  },
171
+ isConnectionOpen(connectionId) {
172
+ return sockets.has(connectionId);
173
+ },
170
174
  start: async () => {
171
175
  if (stopPromise) await stopPromise;
172
176
  if (startPromise) return await startPromise;
@@ -203,6 +207,7 @@ export async function createSdkWebSocketTransport(
203
207
  protocolVersion: 3,
204
208
  connectionId: socket.data.connectionId,
205
209
  capabilities: [
210
+ AWAITING_INPUT_CAPABILITY,
206
211
  TOOL_ACTIVITY_CAPABILITY,
207
212
  TURN_STREAM_CAPABILITY,
208
213
  SESSION_HOST_OBSERVER_CAPABILITY,
@@ -226,16 +231,23 @@ export async function createSdkWebSocketTransport(
226
231
  );
227
232
  return;
228
233
  }
229
- if (
234
+ const isInitialHello =
230
235
  frame.type === "hello" &&
231
236
  frame.protocolVersion === 3 &&
232
- (frame.capabilities === undefined || Array.isArray(frame.capabilities)) &&
233
- !helloReceived.has(socket.data.connectionId)
237
+ !helloReceived.has(socket.data.connectionId);
238
+ if (
239
+ (isInitialHello || frame.type === "event_replay") &&
240
+ (frame.capabilities === undefined ||
241
+ (Array.isArray(frame.capabilities) &&
242
+ frame.capabilities.every((value: unknown) => typeof value === "string")))
234
243
  ) {
235
- const capabilities = Array.isArray(frame.capabilities)
236
- ? frame.capabilities.filter((value): value is string => typeof value === "string")
237
- : [];
238
- helloReceived.add(socket.data.connectionId);
244
+ const capabilities = [
245
+ ...new Set([
246
+ ...(negotiatedCapabilities.get(socket.data.connectionId) ?? []),
247
+ ...((frame.capabilities as string[] | undefined) ?? []),
248
+ ]),
249
+ ];
250
+ if (isInitialHello) helloReceived.add(socket.data.connectionId);
239
251
  negotiatedCapabilities.set(socket.data.connectionId, new Set(capabilities));
240
252
  capabilitiesHandler?.(socket.data.connectionId, capabilities);
241
253
  }
@@ -101,6 +101,10 @@ export type SessionCreateTarget = SessionLifecycleCoordinatorTarget & {
101
101
  readonly body?: string;
102
102
  readonly modelPreset?: string;
103
103
  readonly mcpServers?: readonly Record<string, unknown>[];
104
+ /** Per-session environment for the hosted session; `GJC_*` names are reserved (#6735). */
105
+ readonly env?: Readonly<Record<string, string>>;
106
+ /** Inherited broker environment names removed from the hosted session (#6735). */
107
+ readonly unsetEnv?: readonly string[];
104
108
  readonly worktree?: SessionLifecycleWorktreeTarget;
105
109
  readonly readiness?: "immediate" | "deferred";
106
110
  readonly readinessTimeoutMs?: number;
@@ -115,6 +119,10 @@ export type SessionForkTarget = SessionLifecycleCoordinatorTarget & {
115
119
  readonly body?: string;
116
120
  readonly modelPreset?: string;
117
121
  readonly mcpServers?: readonly Record<string, unknown>[];
122
+ /** Per-session environment for the hosted session; `GJC_*` names are reserved (#6735). */
123
+ readonly env?: Readonly<Record<string, string>>;
124
+ /** Inherited broker environment names removed from the hosted session (#6735). */
125
+ readonly unsetEnv?: readonly string[];
118
126
  readonly worktree?: SessionLifecycleWorktreeTarget;
119
127
  readonly readinessTimeoutMs?: number;
120
128
  };
@@ -128,6 +136,10 @@ export type SessionResumeTarget = SessionLifecycleCoordinatorTarget & {
128
136
  readonly body?: string;
129
137
  readonly modelPreset?: string;
130
138
  readonly mcpServers?: readonly Record<string, unknown>[];
139
+ /** Per-session environment for the hosted session; `GJC_*` names are reserved (#6735). */
140
+ readonly env?: Readonly<Record<string, string>>;
141
+ /** Inherited broker environment names removed from the hosted session (#6735). */
142
+ readonly unsetEnv?: readonly string[];
131
143
  readonly worktree?: SessionLifecycleWorktreeTarget;
132
144
  readonly readinessTimeoutMs?: number;
133
145
  };
@@ -550,7 +562,7 @@ export function validateSessionLifecycleMutationRequest(request: unknown): Sessi
550
562
  }
551
563
 
552
564
  function certaintyForBrokerCode(code: string): SessionLifecycleCertainty {
553
- if (code === "terminal_uncertain") return "uncertain";
565
+ if (code === "terminal_uncertain" || code === "legacy_lifecycle_ambiguous") return "uncertain";
554
566
  if (code === "cleanup_pending") return "cleanup_pending";
555
567
  if (RETRYABLE_BROKER_ERRORS.has(code)) return "retryable";
556
568
  return "terminal";
@@ -701,6 +713,7 @@ const savedSessionCandidateDetailCodes = new Set([
701
713
  "cwd_not_utf8",
702
714
  "cwd_network_unsupported",
703
715
  "cwd_identity_unavailable",
716
+ "permission_denied",
704
717
  "cwd_io_error",
705
718
  ]);
706
719
 
@@ -40,12 +40,14 @@ export interface TurnPromptImageInput {
40
40
  mimeType?: string;
41
41
  }
42
42
 
43
- /** Public input contract for ordered `turn.prompt`. */
44
- export interface TurnPromptInput {
43
+ /** Public input contract for ordered `turn.prompt`; direct and staged images cannot be mixed. */
44
+ export type TurnPromptInput = {
45
45
  text: string;
46
- images?: TurnPromptImageInput[];
47
46
  clientRef?: string;
48
- }
47
+ } & (
48
+ | { images?: TurnPromptImageInput[]; stagedImages?: never }
49
+ | { images?: never; stagedImages: Array<{ id: string }> }
50
+ );
49
51
 
50
52
  /**
51
53
  * Terminal outcome is preserved exactly; active records never age into terminal. An
@@ -1,3 +1,5 @@
1
+ import { MAX_STAGED_PROMPT_IMAGES } from "../../utils/image-limits";
2
+
1
3
  const RELOAD_COMPONENTS = new Set(["config", "models", "skills", "extensions", "tools"]);
2
4
  const SERVICE_TIERS = new Set([
3
5
  "none",
@@ -73,10 +75,35 @@ function hasUsablePromptImage(value: unknown): boolean {
73
75
  );
74
76
  }
75
77
 
78
+ function hasValidStagedPromptImages(value: unknown): boolean {
79
+ if (!Array.isArray(value) || value.length === 0 || value.length > MAX_STAGED_PROMPT_IMAGES) return false;
80
+ const ids = new Set<string>();
81
+ return value.every(descriptor => {
82
+ if (!descriptor || typeof descriptor !== "object" || Array.isArray(descriptor)) return false;
83
+ const image = descriptor as Record<string, unknown>;
84
+ if (Object.keys(image).some(key => key !== "id") || typeof image.id !== "string" || image.id.trim().length === 0)
85
+ return false;
86
+ if (ids.has(image.id)) return false;
87
+ ids.add(image.id);
88
+ return true;
89
+ });
90
+ }
91
+
76
92
  /** Rejects instruction-bearing controls before correlation or provider work. */
77
93
  export function validateRequiredPromptText(operation: string, input: Input): AdapterValidationError | undefined {
94
+ if (operation === "turn.prompt" && input.stagedImages !== undefined) {
95
+ if (input.images !== undefined)
96
+ return { code: "invalid_input", message: "Direct and staged images cannot be mixed." };
97
+ if (!hasValidStagedPromptImages(input.stagedImages))
98
+ return {
99
+ code: "invalid_input",
100
+ message: `stagedImages must contain 1–${MAX_STAGED_PROMPT_IMAGES} valid image IDs.`,
101
+ };
102
+ }
78
103
  const hasUsableImage =
79
- operation === "turn.prompt" && Array.isArray(input.images) && input.images.some(hasUsablePromptImage);
104
+ operation === "turn.prompt" &&
105
+ ((Array.isArray(input.images) && input.images.some(hasUsablePromptImage)) ||
106
+ hasValidStagedPromptImages(input.stagedImages));
80
107
  if (
81
108
  PROMPT_OPERATIONS.has(operation) &&
82
109
  (typeof input.text !== "string" || (input.text.trim().length === 0 && !hasUsableImage))
@@ -953,6 +953,78 @@
953
953
  "packages/coding-agent/test/sdk-operation-inventory.test.ts"
954
954
  ]
955
955
  },
956
+ {
957
+ "sourceId": "registry:C54",
958
+ "sourceFile": "packages/coding-agent/src/sdk/protocol/operation-registry.ts",
959
+ "sourceKind": "registry",
960
+ "decision": "include",
961
+ "sdkId": "turn.image.begin",
962
+ "adapterMappings": {
963
+ "telegram": "prohibited",
964
+ "discord": "prohibited",
965
+ "slack": "prohibited",
966
+ "mcp": "prohibited",
967
+ "acp": "prohibited",
968
+ "daemonCli": "machine_only"
969
+ },
970
+ "testIds": [
971
+ "packages/coding-agent/test/sdk-operation-inventory.test.ts"
972
+ ]
973
+ },
974
+ {
975
+ "sourceId": "registry:C55",
976
+ "sourceFile": "packages/coding-agent/src/sdk/protocol/operation-registry.ts",
977
+ "sourceKind": "registry",
978
+ "decision": "include",
979
+ "sdkId": "turn.image.append",
980
+ "adapterMappings": {
981
+ "telegram": "prohibited",
982
+ "discord": "prohibited",
983
+ "slack": "prohibited",
984
+ "mcp": "prohibited",
985
+ "acp": "prohibited",
986
+ "daemonCli": "machine_only"
987
+ },
988
+ "testIds": [
989
+ "packages/coding-agent/test/sdk-operation-inventory.test.ts"
990
+ ]
991
+ },
992
+ {
993
+ "sourceId": "registry:C56",
994
+ "sourceFile": "packages/coding-agent/src/sdk/protocol/operation-registry.ts",
995
+ "sourceKind": "registry",
996
+ "decision": "include",
997
+ "sdkId": "turn.image.finish",
998
+ "adapterMappings": {
999
+ "telegram": "prohibited",
1000
+ "discord": "prohibited",
1001
+ "slack": "prohibited",
1002
+ "mcp": "prohibited",
1003
+ "acp": "prohibited",
1004
+ "daemonCli": "machine_only"
1005
+ },
1006
+ "testIds": [
1007
+ "packages/coding-agent/test/sdk-operation-inventory.test.ts"
1008
+ ]
1009
+ },
1010
+ {
1011
+ "sourceId": "registry:C57",
1012
+ "sourceFile": "packages/coding-agent/src/sdk/protocol/operation-registry.ts",
1013
+ "sourceKind": "registry",
1014
+ "decision": "include",
1015
+ "sdkId": "turn.image.discard",
1016
+ "adapterMappings": {
1017
+ "telegram": "prohibited",
1018
+ "discord": "prohibited",
1019
+ "slack": "prohibited",
1020
+ "mcp": "prohibited",
1021
+ "acp": "prohibited",
1022
+ "daemonCli": "machine_only"
1023
+ },
1024
+ "testIds": [
1025
+ "packages/coding-agent/test/sdk-operation-inventory.test.ts"
1026
+ ]
1027
+ },
956
1028
  {
957
1029
  "sourceId": "registry:G01",
958
1030
  "sourceFile": "packages/coding-agent/src/sdk/protocol/operation-registry.ts",
@@ -2642,6 +2714,17 @@
2642
2714
  "testIds": "not_applicable"
2643
2715
  }
2644
2716
  },
2717
+ {
2718
+ "sourceId": "agent_session:refreshEffectiveActiveWorkflowSkillState",
2719
+ "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
2720
+ "sourceKind": "agent_session",
2721
+ "decision": "exclude",
2722
+ "rationale": "internal durable workflow identity refresh before session safety checks, not an independent public SDK operation",
2723
+ "exclusionMetadata": {
2724
+ "adapterMappings": "not_applicable",
2725
+ "testIds": "not_applicable"
2726
+ }
2727
+ },
2645
2728
  {
2646
2729
  "sourceId": "agent_session:replaceOwnedMcpManager",
2647
2730
  "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
@@ -2891,6 +2974,17 @@
2891
2974
  "testIds": "not_applicable"
2892
2975
  }
2893
2976
  },
2977
+ {
2978
+ "sourceId": "agent_session:notifySessionIdentityChanged",
2979
+ "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
2980
+ "sourceKind": "agent_session",
2981
+ "decision": "exclude",
2982
+ "rationale": "internal session-identity listener fan-out for in-process session surfaces; not a user-facing SDK control seam",
2983
+ "exclusionMetadata": {
2984
+ "adapterMappings": "not_applicable",
2985
+ "testIds": "not_applicable"
2986
+ }
2987
+ },
2894
2988
  {
2895
2989
  "sourceId": "agent_session:emitNotice",
2896
2990
  "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
@@ -2924,6 +3018,17 @@
2924
3018
  "testIds": "not_applicable"
2925
3019
  }
2926
3020
  },
3021
+ {
3022
+ "sourceId": "agent_session:subscribeSessionIdentityChanges",
3023
+ "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
3024
+ "sourceKind": "agent_session",
3025
+ "decision": "exclude",
3026
+ "rationale": "internal session-identity subscription used by in-process adapters to follow session replacement; not a user-facing SDK control seam",
3027
+ "exclusionMetadata": {
3028
+ "adapterMappings": "not_applicable",
3029
+ "testIds": "not_applicable"
3030
+ }
3031
+ },
2927
3032
  {
2928
3033
  "sourceId": "agent_session:dispose",
2929
3034
  "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
@@ -3111,6 +3216,17 @@
3111
3216
  "testIds": "not_applicable"
3112
3217
  }
3113
3218
  },
3219
+ {
3220
+ "sourceId": "agent_session:waitForAgentEndHandlingForTests",
3221
+ "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
3222
+ "sourceKind": "agent_session",
3223
+ "decision": "exclude",
3224
+ "rationale": "test-only SDK terminal-event handler completion barrier, not a user-facing SDK control seam",
3225
+ "exclusionMetadata": {
3226
+ "adapterMappings": "not_applicable",
3227
+ "testIds": "not_applicable"
3228
+ }
3229
+ },
3114
3230
  {
3115
3231
  "sourceId": "agent_session:drainAsyncJobDeliveriesForAcp",
3116
3232
  "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
@@ -3333,6 +3449,39 @@
3333
3449
  "testIds": "not_applicable"
3334
3450
  }
3335
3451
  },
3452
+ {
3453
+ "sourceId": "agent_session:hasCommittedMCPToolSelectionAuthority",
3454
+ "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
3455
+ "sourceKind": "agent_session",
3456
+ "decision": "exclude",
3457
+ "rationale": "internal committed MCP-selection authority predicate used by catalog reconciliation; not a user-facing SDK control seam",
3458
+ "exclusionMetadata": {
3459
+ "adapterMappings": "not_applicable",
3460
+ "testIds": "not_applicable"
3461
+ }
3462
+ },
3463
+ {
3464
+ "sourceId": "agent_session:hasMCPToolSelectionAuthority",
3465
+ "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
3466
+ "sourceKind": "agent_session",
3467
+ "decision": "exclude",
3468
+ "rationale": "internal MCP-selection authority predicate used by catalog and mode-transition reconciliation; not a user-facing SDK control seam",
3469
+ "exclusionMetadata": {
3470
+ "adapterMappings": "not_applicable",
3471
+ "testIds": "not_applicable"
3472
+ }
3473
+ },
3474
+ {
3475
+ "sourceId": "agent_session:getActiveMCPToolNames",
3476
+ "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
3477
+ "sourceKind": "agent_session",
3478
+ "decision": "exclude",
3479
+ "rationale": "internal MCP bridge subset used by mode controllers to preserve live selections across tool swaps; not a user-facing SDK control seam",
3480
+ "exclusionMetadata": {
3481
+ "adapterMappings": "not_applicable",
3482
+ "testIds": "not_applicable"
3483
+ }
3484
+ },
3336
3485
  {
3337
3486
  "sourceId": "agent_session:getSelectedMCPToolNames",
3338
3487
  "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
@@ -4524,6 +4673,17 @@
4524
4673
  "testIds": "not_applicable"
4525
4674
  }
4526
4675
  },
4676
+ {
4677
+ "sourceId": "agent_session:getActivatedModelProfile",
4678
+ "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
4679
+ "sourceKind": "agent_session",
4680
+ "decision": "exclude",
4681
+ "rationale": "internal model-profile activation provenance used to gate role-only materialization, not a user-facing SDK control seam",
4682
+ "exclusionMetadata": {
4683
+ "adapterMappings": "not_applicable",
4684
+ "testIds": "not_applicable"
4685
+ }
4686
+ },
4527
4687
  {
4528
4688
  "sourceId": "agent_session:setUnavailableModelProfile",
4529
4689
  "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
@@ -125,6 +125,10 @@ const controls = [
125
125
  ["retry.now", "Immediately retry pending backoff."],
126
126
  ["bash.background", "Move active managed bash to the background."],
127
127
  ["model.profile.set", "Activate a model profile for the current session."],
128
+ ["turn.image.begin", "Begin a bounded host-owned image upload."],
129
+ ["turn.image.append", "Append a canonical base64 image chunk."],
130
+ ["turn.image.finish", "Verify and stage a complete image."],
131
+ ["turn.image.discard", "Discard an unfinished or staged image."],
128
132
  ] as const;
129
133
 
130
134
  const globals = [
@@ -235,6 +239,15 @@ const reverse = [
235
239
  ] as const;
236
240
 
237
241
  function controlDisposition(id: string): Record<Adapter, AdapterDisposition> {
242
+ if (["C54", "C55", "C56", "C57"].includes(id))
243
+ return dispositions({
244
+ telegram: "prohibited",
245
+ discord: "prohibited",
246
+ slack: "prohibited",
247
+ mcp: "prohibited",
248
+ acp: "prohibited",
249
+ daemonCli: "machine_only",
250
+ });
238
251
  if (["C25", "C26", "C27", "C28", "C29", "C30", "C31", "C32", "C34", "C48"].includes(id))
239
252
  return dispositions({
240
253
  telegram: "prohibited",
@@ -271,7 +284,13 @@ function controlErrors(id: string): string[] {
271
284
  // C01/C05 submit a prompt and therefore run the prompt preflight, which
272
285
  // refuses a session with no selected model before admission. The code is
273
286
  // appended: ACP machine-only mapping reads errorCodes[0].
274
- C01: ["client_ref_conflict", "reconciliation_capacity", "reconciliation_persist_failed", "model_not_selected"],
287
+ C01: [
288
+ "client_ref_conflict",
289
+ "reconciliation_capacity",
290
+ "reconciliation_persist_failed",
291
+ "model_not_selected",
292
+ "image_upload_unavailable",
293
+ ],
275
294
  C02: ["turn_not_active", "client_ref_conflict", "reconciliation_capacity", "reconciliation_persist_failed"],
276
295
  C09: ["client_ref_conflict", "reconciliation_capacity", "reconciliation_persist_failed"],
277
296
  C06: ["action_claimed"],
@@ -294,6 +313,10 @@ function controlErrors(id: string): string[] {
294
313
  C50: ["nothing_to_retry", "busy"],
295
314
  C51: ["retry_not_pending"],
296
315
  C52: ["not_foldable", "already_backgrounded", "no_active_bash"],
316
+ C54: ["invalid_input", "busy", "resource_gone", "operation_prohibited"],
317
+ C55: ["invalid_input", "busy", "resource_gone", "operation_prohibited"],
318
+ C56: ["invalid_input", "busy", "resource_gone", "operation_prohibited"],
319
+ C57: ["invalid_input", "resource_gone", "operation_prohibited"],
297
320
  };
298
321
  return errors[id] ?? ["invalid_request", "busy"];
299
322
  }
@@ -354,8 +377,15 @@ export const OPERATIONS: readonly Operation[] = [
354
377
  : id === "G10"
355
378
  ? ["invalid_input", "not_found", "idempotency_conflict", "lifecycle_pending", "terminal_uncertain"]
356
379
  : ["G03", "G04", "G05"].includes(id)
357
- ? ["invalid_request", "unknown_model_profile", "model_profile_registry_error"]
358
- : ["invalid_request"],
380
+ ? [
381
+ "invalid_request",
382
+ "unknown_model_profile",
383
+ "model_profile_registry_error",
384
+ "legacy_lifecycle_ambiguous",
385
+ ]
386
+ : ["G06", "G07", "G08"].includes(id)
387
+ ? ["invalid_request", "legacy_lifecycle_ambiguous"]
388
+ : ["invalid_request"],
359
389
  adapterDispositions:
360
390
  id === "G02"
361
391
  ? dispositions({