@gajae-code/coding-agent 0.16.7 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (321) hide show
  1. package/CHANGELOG.md +180 -1
  2. package/dist/types/capability/fs.d.ts +37 -4
  3. package/dist/types/capability/index.d.ts +19 -0
  4. package/dist/types/capability/types.d.ts +9 -0
  5. package/dist/types/cli/doctor/args.d.ts +36 -0
  6. package/dist/types/cli/doctor/checks.d.ts +18 -0
  7. package/dist/types/cli/doctor/config-repairs.d.ts +38 -0
  8. package/dist/types/cli/doctor/context.d.ts +89 -0
  9. package/dist/types/cli/doctor/files.d.ts +27 -0
  10. package/dist/types/cli/doctor/ids.d.ts +20 -0
  11. package/dist/types/cli/doctor/install-repairs.d.ts +94 -0
  12. package/dist/types/cli/doctor/journal.d.ts +43 -0
  13. package/dist/types/cli/doctor/managed-link.d.ts +39 -0
  14. package/dist/types/cli/doctor/native-probe.d.ts +2 -0
  15. package/dist/types/cli/doctor/permission-repairs.d.ts +25 -0
  16. package/dist/types/cli/doctor/plugin-quarantine.d.ts +77 -0
  17. package/dist/types/cli/doctor/plugin-restore.d.ts +40 -0
  18. package/dist/types/cli/doctor/plugin-targets.d.ts +11 -0
  19. package/dist/types/cli/doctor/probe-client.d.ts +9 -0
  20. package/dist/types/cli/doctor/probe-types.d.ts +18 -0
  21. package/dist/types/cli/doctor/probe.d.ts +3 -0
  22. package/dist/types/cli/doctor/projection-probe.d.ts +2 -0
  23. package/dist/types/cli/doctor/repairs.d.ts +28 -0
  24. package/dist/types/cli/doctor/report.d.ts +27 -0
  25. package/dist/types/cli/doctor/runner.d.ts +4 -0
  26. package/dist/types/cli/doctor/safety.d.ts +10 -0
  27. package/dist/types/cli/doctor/service-repairs.d.ts +8 -0
  28. package/dist/types/cli/doctor/service-targets.d.ts +41 -0
  29. package/dist/types/cli/doctor/types.d.ts +145 -0
  30. package/dist/types/cli/doctor-cli.d.ts +7 -0
  31. package/dist/types/cli/doctor-supervisor.d.ts +121 -0
  32. package/dist/types/cli/doctor-worker.d.ts +29 -0
  33. package/dist/types/cli/install-activation.d.ts +158 -0
  34. package/dist/types/cli/macos-community-app.d.ts +41 -0
  35. package/dist/types/cli/mcp-cli.d.ts +0 -11
  36. package/dist/types/cli/update-cli.d.ts +41 -4
  37. package/dist/types/cli-main.d.ts +174 -0
  38. package/dist/types/cli.d.ts +1 -171
  39. package/dist/types/commands/doctor.d.ts +7 -0
  40. package/dist/types/commands/sdk.d.ts +17 -8
  41. package/dist/types/config/autorouting-tier-map.d.ts +19 -0
  42. package/dist/types/config/file-lock.d.ts +27 -3
  43. package/dist/types/config/model-preset-registry.d.ts +1 -0
  44. package/dist/types/config/model-registry.d.ts +12 -5
  45. package/dist/types/config/model-resolver.d.ts +16 -3
  46. package/dist/types/config/models-config-schema.d.ts +2 -0
  47. package/dist/types/config/settings-schema.d.ts +1 -1
  48. package/dist/types/coordinator-mcp/question-gate-codec.d.ts +1 -1
  49. package/dist/types/coordinator-mcp/session-reaper.d.ts +15 -5
  50. package/dist/types/cursor.d.ts +9 -9
  51. package/dist/types/discovery/agents-md.d.ts +6 -1
  52. package/dist/types/discovery/helpers.d.ts +36 -7
  53. package/dist/types/discovery/index.d.ts +1 -1
  54. package/dist/types/discovery/mcp-json.d.ts +2 -0
  55. package/dist/types/extensibility/extensions/loader.d.ts +22 -1
  56. package/dist/types/extensibility/gjc-plugins/lifecycle.d.ts +14 -1
  57. package/dist/types/extensibility/gjc-plugins/paths.d.ts +2 -1
  58. package/dist/types/extensibility/gjc-plugins/types.d.ts +25 -0
  59. package/dist/types/extensibility/plugins/manager.d.ts +33 -4
  60. package/dist/types/extensibility/plugins/marketplace/cache.d.ts +6 -0
  61. package/dist/types/extensibility/plugins/marketplace/manager.d.ts +186 -0
  62. package/dist/types/extensibility/plugins/marketplace/registry.d.ts +27 -0
  63. package/dist/types/extensibility/plugins/marketplace/source-resolver.d.ts +16 -1
  64. package/dist/types/extensibility/runtime-skill-discovery.d.ts +16 -3
  65. package/dist/types/gjc-runtime/autoresearch-runtime.d.ts +6 -0
  66. package/dist/types/gjc-runtime/launch-worktree.d.ts +53 -0
  67. package/dist/types/gjc-runtime/session-layout.d.ts +8 -0
  68. package/dist/types/gjc-runtime/session-state-lock.d.ts +15 -0
  69. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +13 -0
  70. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +6 -0
  71. package/dist/types/main.d.ts +19 -1
  72. package/dist/types/modes/acp/acp-agent.d.ts +40 -0
  73. package/dist/types/modes/components/agent-dashboard.d.ts +1 -0
  74. package/dist/types/modes/components/model-selector.d.ts +2 -0
  75. package/dist/types/modes/interactive-mode.d.ts +1 -1
  76. package/dist/types/runtime-mcp/config-writer.d.ts +47 -0
  77. package/dist/types/runtime-mcp/policy-json-edit.d.ts +60 -0
  78. package/dist/types/runtime-mcp/startup-policy.d.ts +4 -0
  79. package/dist/types/runtime-mcp/types.d.ts +2 -2
  80. package/dist/types/sdk/acp/adapter.d.ts +5 -1
  81. package/dist/types/sdk/broker/broker.d.ts +51 -0
  82. package/dist/types/sdk/broker/daemon-entry.d.ts +39 -0
  83. package/dist/types/sdk/broker/discovery.d.ts +38 -0
  84. package/dist/types/sdk/broker/doctor-restart.d.ts +79 -0
  85. package/dist/types/sdk/broker/endpoint-authority.d.ts +7 -0
  86. package/dist/types/sdk/broker/ensure.d.ts +14 -0
  87. package/dist/types/sdk/broker/lifecycle.d.ts +2 -0
  88. package/dist/types/sdk/broker/process-incarnation.d.ts +50 -0
  89. package/dist/types/sdk/broker/runtime.d.ts +26 -0
  90. package/dist/types/sdk/broker/session-index.d.ts +13 -4
  91. package/dist/types/sdk/broker/worktree-occupancy.d.ts +14 -0
  92. package/dist/types/sdk/bus/chat-daemon-cli.d.ts +16 -0
  93. package/dist/types/sdk/bus/chat-daemon-control.d.ts +101 -6
  94. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +16 -0
  95. package/dist/types/sdk/bus/daemon-startup-exclusion.d.ts +43 -0
  96. package/dist/types/sdk/bus/doctor-daemon-restart-client.d.ts +51 -0
  97. package/dist/types/sdk/bus/doctor-daemon-restart.d.ts +39 -0
  98. package/dist/types/sdk/bus/index.d.ts +2 -0
  99. package/dist/types/sdk/bus/notification-service.d.ts +3 -0
  100. package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +11 -0
  101. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +1 -1
  102. package/dist/types/sdk/bus/telegram-daemon-control.d.ts +5 -0
  103. package/dist/types/sdk/bus/telegram-daemon-owner-registry.d.ts +1 -0
  104. package/dist/types/sdk/bus/telegram-daemon.d.ts +36 -5
  105. package/dist/types/sdk/cli/session-cli.d.ts +1 -0
  106. package/dist/types/sdk/host/session-runtime.d.ts +4 -0
  107. package/dist/types/sdk/host/surface-policy.d.ts +3 -1
  108. package/dist/types/sdk/lifecycle/service.d.ts +44 -10
  109. package/dist/types/sdk/prompt-deadline-lease.d.ts +6 -3
  110. package/dist/types/sdk/prompt-deadline-manager.d.ts +2 -2
  111. package/dist/types/sdk/prompt-failure.d.ts +47 -0
  112. package/dist/types/sdk/prompt-status.d.ts +19 -0
  113. package/dist/types/sdk/router/session-router.d.ts +3 -4
  114. package/dist/types/sdk/service-artifact-paths.d.ts +16 -0
  115. package/dist/types/sdk/session-authority.d.ts +9 -0
  116. package/dist/types/sdk/session.d.ts +3 -1
  117. package/dist/types/session/agent-session.d.ts +1 -1
  118. package/dist/types/session/blob-store.d.ts +1 -1
  119. package/dist/types/session/fallback-chain-controller.d.ts +3 -6
  120. package/dist/types/session/internal/managed-session-scope.d.ts +44 -0
  121. package/dist/types/session/primary-control-surface.d.ts +4 -0
  122. package/dist/types/session/session-manager.d.ts +6 -0
  123. package/dist/types/system-prompt.d.ts +6 -0
  124. package/dist/types/tools/ask.d.ts +25 -0
  125. package/dist/types/tools/image-gen.d.ts +0 -4
  126. package/dist/types/tools/skill-discovery.d.ts +7 -5
  127. package/dist/types/tools/ultragoal-ask-guard.d.ts +7 -4
  128. package/dist/types/utils/changelog.d.ts +0 -9
  129. package/dist/types/utils/mupdf-wasm.d.ts +1 -0
  130. package/package.json +9 -8
  131. package/scripts/compile-args.ts +8 -4
  132. package/src/capability/fs.ts +395 -17
  133. package/src/capability/index.ts +273 -10
  134. package/src/capability/types.ts +9 -0
  135. package/src/cli/customize-doctor.ts +18 -12
  136. package/src/cli/doctor/args.ts +236 -0
  137. package/src/cli/doctor/checks.ts +431 -0
  138. package/src/cli/doctor/config-repairs.ts +517 -0
  139. package/src/cli/doctor/context.ts +149 -0
  140. package/src/cli/doctor/files.ts +149 -0
  141. package/src/cli/doctor/ids.ts +115 -0
  142. package/src/cli/doctor/install-repairs.ts +335 -0
  143. package/src/cli/doctor/journal.ts +423 -0
  144. package/src/cli/doctor/managed-link.ts +514 -0
  145. package/src/cli/doctor/native-probe.ts +13 -0
  146. package/src/cli/doctor/permission-repairs.ts +242 -0
  147. package/src/cli/doctor/plugin-quarantine.ts +377 -0
  148. package/src/cli/doctor/plugin-restore.ts +59 -0
  149. package/src/cli/doctor/plugin-targets.ts +373 -0
  150. package/src/cli/doctor/probe-client.ts +195 -0
  151. package/src/cli/doctor/probe-types.ts +21 -0
  152. package/src/cli/doctor/probe.ts +42 -0
  153. package/src/cli/doctor/projection-probe.ts +249 -0
  154. package/src/cli/doctor/repairs.ts +1157 -0
  155. package/src/cli/doctor/report.ts +176 -0
  156. package/src/cli/doctor/runner.ts +342 -0
  157. package/src/cli/doctor/safety.ts +40 -0
  158. package/src/cli/doctor/service-repairs.ts +452 -0
  159. package/src/cli/doctor/service-targets.ts +274 -0
  160. package/src/cli/doctor/types.ts +164 -0
  161. package/src/cli/doctor-cli.ts +62 -0
  162. package/src/cli/doctor-supervisor.ts +571 -0
  163. package/src/cli/doctor-worker.ts +181 -0
  164. package/src/cli/install-activation.ts +666 -0
  165. package/src/cli/macos-community-app.ts +1449 -0
  166. package/src/cli/mcp-cli.ts +11 -21
  167. package/src/cli/nofile-limit.ts +5 -1
  168. package/src/cli/plugin-cli.ts +6 -1
  169. package/src/cli/update-cli.ts +362 -264
  170. package/src/cli-main.ts +517 -0
  171. package/src/cli.ts +64 -433
  172. package/src/commands/autoresearch.ts +11 -5
  173. package/src/commands/completion.ts +1 -1
  174. package/src/commands/doctor.ts +13 -0
  175. package/src/commands/sdk.ts +58 -10
  176. package/src/commands/ultragoal.ts +11 -5
  177. package/src/config/autorouting-tier-map.ts +7 -0
  178. package/src/config/file-lock.ts +736 -71
  179. package/src/config/mcp-schema.json +3 -3
  180. package/src/config/model-preset-registry.ts +1 -0
  181. package/src/config/model-registry.ts +80 -27
  182. package/src/config/model-resolver.ts +33 -4
  183. package/src/config/models-config-schema.ts +2 -0
  184. package/src/config/settings-schema.ts +6 -2
  185. package/src/coordinator-mcp/question-gate-codec.ts +1 -0
  186. package/src/coordinator-mcp/server.ts +534 -51
  187. package/src/coordinator-mcp/session-reaper.ts +64 -8
  188. package/src/cursor.ts +223 -53
  189. package/src/discovery/agents-md.ts +74 -8
  190. package/src/discovery/agents.ts +32 -7
  191. package/src/discovery/builtin.ts +184 -75
  192. package/src/discovery/claude-plugins.ts +85 -17
  193. package/src/discovery/cline.ts +38 -10
  194. package/src/discovery/cursor.ts +19 -6
  195. package/src/discovery/gemini.ts +62 -22
  196. package/src/discovery/github.ts +13 -3
  197. package/src/discovery/helpers.ts +483 -89
  198. package/src/discovery/index.ts +1 -0
  199. package/src/discovery/mcp-json.ts +36 -10
  200. package/src/discovery/opencode.ts +36 -19
  201. package/src/discovery/ssh.ts +11 -8
  202. package/src/discovery/windsurf.ts +12 -3
  203. package/src/exec/bash-executor.ts +10 -3
  204. package/src/exec/isolated-shell.ts +15 -2
  205. package/src/extensibility/extensions/loader.ts +88 -26
  206. package/src/extensibility/gjc-plugins/lifecycle.ts +189 -0
  207. package/src/extensibility/gjc-plugins/paths.ts +4 -1
  208. package/src/extensibility/gjc-plugins/types.ts +27 -0
  209. package/src/extensibility/plugins/manager.ts +200 -22
  210. package/src/extensibility/plugins/marketplace/cache.ts +55 -2
  211. package/src/extensibility/plugins/marketplace/manager.ts +1262 -162
  212. package/src/extensibility/plugins/marketplace/registry.ts +153 -0
  213. package/src/extensibility/plugins/marketplace/source-resolver.ts +116 -10
  214. package/src/extensibility/runtime-skill-discovery.ts +61 -9
  215. package/src/extensibility/skill-management.ts +7 -1
  216. package/src/gjc-runtime/autoresearch-runtime.ts +10 -1
  217. package/src/gjc-runtime/launch-worktree.test.ts +248 -0
  218. package/src/gjc-runtime/launch-worktree.ts +275 -38
  219. package/src/gjc-runtime/repository-binding.ts +26 -1
  220. package/src/gjc-runtime/session-layout.ts +10 -0
  221. package/src/gjc-runtime/session-state-lock.ts +330 -23
  222. package/src/gjc-runtime/session-state-sidecar.ts +328 -80
  223. package/src/gjc-runtime/ultragoal-runtime.ts +10 -1
  224. package/src/harness-control-plane/session-lease.ts +2 -2
  225. package/src/internal-urls/docs-index.generated.ts +28 -26
  226. package/src/main.ts +150 -29
  227. package/src/memories/index.ts +24 -2
  228. package/src/modes/acp/acp-agent.ts +522 -68
  229. package/src/modes/components/agent-dashboard.ts +3 -1
  230. package/src/modes/components/model-selector.ts +28 -19
  231. package/src/modes/components/plugin-settings.ts +2 -1
  232. package/src/modes/controllers/selector-controller.ts +15 -9
  233. package/src/modes/interactive-mode.ts +21 -3
  234. package/src/prompts/system/system-prompt.md +5 -1
  235. package/src/prompts/tools/browser.md +1 -1
  236. package/src/prompts/tools/move-session.md +4 -0
  237. package/src/prompts/tools/read.md +2 -1
  238. package/src/prompts/tools/skill-discovery.md +6 -5
  239. package/src/prompts/tools/task.md +1 -0
  240. package/src/runtime-mcp/config-writer.ts +228 -0
  241. package/src/runtime-mcp/oauth-discovery.ts +114 -14
  242. package/src/runtime-mcp/policy-json-edit.ts +129 -0
  243. package/src/runtime-mcp/startup-policy.ts +14 -0
  244. package/src/runtime-mcp/types.ts +2 -2
  245. package/src/sdk/acp/adapter.ts +27 -12
  246. package/src/sdk/broker/broker.ts +273 -44
  247. package/src/sdk/broker/daemon-entry.ts +119 -0
  248. package/src/sdk/broker/discovery.ts +173 -20
  249. package/src/sdk/broker/doctor-restart.ts +206 -0
  250. package/src/sdk/broker/endpoint-authority.ts +36 -0
  251. package/src/sdk/broker/ensure.ts +49 -14
  252. package/src/sdk/broker/lifecycle.ts +174 -42
  253. package/src/sdk/broker/process-incarnation.ts +86 -2
  254. package/src/sdk/broker/runtime.ts +145 -21
  255. package/src/sdk/broker/session-index.ts +136 -22
  256. package/src/sdk/broker/spawn-substrate.ts +4 -1
  257. package/src/sdk/broker/transport.ts +5 -0
  258. package/src/sdk/broker/worktree-occupancy.ts +21 -1
  259. package/src/sdk/bus/chat-daemon-cli.ts +63 -0
  260. package/src/sdk/bus/chat-daemon-control.ts +260 -64
  261. package/src/sdk/bus/chat-daemon-runtime.ts +141 -25
  262. package/src/sdk/bus/daemon-startup-exclusion.ts +119 -0
  263. package/src/sdk/bus/doctor-daemon-restart-client.ts +291 -0
  264. package/src/sdk/bus/doctor-daemon-restart.ts +92 -0
  265. package/src/sdk/bus/index.ts +252 -51
  266. package/src/sdk/bus/kind-aware-reconciliation.ts +76 -41
  267. package/src/sdk/bus/notification-service.ts +21 -3
  268. package/src/sdk/bus/reconciliation-store.ts +17 -11
  269. package/src/sdk/bus/telegram-daemon-cli.ts +91 -5
  270. package/src/sdk/bus/telegram-daemon-contract.ts +1 -1
  271. package/src/sdk/bus/telegram-daemon-control.ts +47 -0
  272. package/src/sdk/bus/telegram-daemon-owner-registry.ts +1 -1
  273. package/src/sdk/bus/telegram-daemon.ts +178 -13
  274. package/src/sdk/cli/session-cli.ts +100 -12
  275. package/src/sdk/host/host.ts +2 -7
  276. package/src/sdk/host/session-runtime.test.ts +329 -8
  277. package/src/sdk/host/session-runtime.ts +202 -50
  278. package/src/sdk/host/surface-policy.ts +8 -1
  279. package/src/sdk/lifecycle/service.ts +199 -22
  280. package/src/sdk/mcp/server.ts +1 -1
  281. package/src/sdk/prompt-deadline-lease.ts +12 -4
  282. package/src/sdk/prompt-deadline-manager.ts +5 -7
  283. package/src/sdk/prompt-failure.ts +148 -0
  284. package/src/sdk/prompt-status.ts +30 -1
  285. package/src/sdk/prompt-watchdog.ts +11 -3
  286. package/src/sdk/protocol/operation-inventory.generated.json +18 -0
  287. package/src/sdk/protocol/operation-registry.ts +20 -8
  288. package/src/sdk/router/session-router.ts +8 -3
  289. package/src/sdk/service-artifact-paths.ts +26 -0
  290. package/src/sdk/session-authority.ts +10 -0
  291. package/src/sdk/session.ts +361 -194
  292. package/src/session/agent-session.ts +398 -93
  293. package/src/session/blob-store.ts +9 -9
  294. package/src/session/fallback-chain-controller.ts +3 -7
  295. package/src/session/internal/managed-session-scope.ts +445 -29
  296. package/src/session/internal/managed-session-storage.ts +38 -6
  297. package/src/session/primary-control-surface.ts +12 -0
  298. package/src/session/session-manager.ts +11 -3
  299. package/src/session/session-storage.ts +1 -1
  300. package/src/session-import/codex.ts +6 -1
  301. package/src/session-import/redact.ts +7 -0
  302. package/src/skill-state/workflow-mutation-guard.ts +645 -39
  303. package/src/slash-commands/builtin-registry.ts +7 -3
  304. package/src/system-prompt.ts +8 -0
  305. package/src/task/executor.ts +36 -3
  306. package/src/task/types.ts +27 -5
  307. package/src/tools/ask.ts +114 -34
  308. package/src/tools/browser/actions.ts +2 -2
  309. package/src/tools/browser/tab-worker.ts +11 -8
  310. package/src/tools/descriptors.ts +6 -1
  311. package/src/tools/fetch.ts +7 -2
  312. package/src/tools/image-gen.ts +33 -34
  313. package/src/tools/read.ts +78 -32
  314. package/src/tools/skill-discovery.ts +17 -7
  315. package/src/tools/tool-catalog.generated.ts +8 -8
  316. package/src/tools/ultragoal-ask-guard.ts +16 -26
  317. package/src/utils/changelog.ts +7 -1
  318. package/src/utils/git.ts +3 -1
  319. package/src/utils/markit.ts +24 -2
  320. package/src/utils/mupdf-wasm.ts +26 -0
  321. package/src/web/search/providers/openai-compatible.ts +191 -14
@@ -47,6 +47,7 @@ import {
47
47
  type MasterRoleAttestationV2,
48
48
  resolveSessionLocator,
49
49
  SessionIndex,
50
+ type SessionIndexEvent,
50
51
  type SessionLocatorV2,
51
52
  } from "../broker/session-index";
52
53
  import {
@@ -58,7 +59,16 @@ import {
58
59
  } from "../model-profile-model";
59
60
  import { projectQ10Models } from "../models.js";
60
61
  import { PromptDeadlineManager, type PromptTerminalTransitionEvidence } from "../prompt-deadline-manager";
61
- import { formatPromptFailureForLocalLog, sanitizePromptFailure } from "../prompt-failure";
62
+ import {
63
+ assistantFailureCode,
64
+ failedPromptOutcome,
65
+ failureEvidence,
66
+ formatPromptFailureForLocalLog,
67
+ PROMPT_FAILURE_MESSAGE_SUBMISSION,
68
+ type PromptFailureEvidence,
69
+ rephaseFailedOutcome,
70
+ sanitizePromptFailure,
71
+ } from "../prompt-failure";
62
72
  import type { SdkPromptTerminalOutcome } from "../prompt-status";
63
73
  import { validateRequiredPromptText } from "../protocol/adapter-validation";
64
74
  import { OPERATIONS } from "../protocol/operation-registry";
@@ -524,6 +534,8 @@ export interface CreateSdkSessionRuntimeOptions {
524
534
  brokerRegistrationRequired?: boolean;
525
535
  /** Trusted broker-issued lifecycle marker bound to lifecycle host index events. */
526
536
  lifecycleRequestId?: string;
537
+ /** Startup surface that owns host-level permission and lifecycle authority. */
538
+ primaryControlSurface?: "cli" | "sdk";
527
539
  createTransport(input: {
528
540
  sessionId: string;
529
541
  stateRoot: string;
@@ -597,24 +609,39 @@ const isPreservedProviderFailure = (code: string | undefined): boolean =>
597
609
  * classifier so a failed terminal can never be quarantined on reload.
598
610
  */
599
611
  function canonicalFailedOutcome(
600
- failure?: { code?: unknown; message?: unknown },
612
+ failure?: { code?: unknown; message?: unknown; providerCode?: unknown },
601
613
  provenance: "agent_failed" | "deadline" = "agent_failed",
614
+ evidence: PromptFailureEvidence = {},
615
+ providerCode?: string,
602
616
  ): InvocationOutcome {
603
617
  const deadline = provenance === "deadline" || failure?.code === "prompt_deadline_exceeded";
604
- return {
605
- kind: "failed",
618
+ const known = typeof failure?.code === "string" ? failure.code : undefined;
619
+ const explicit = providerCode ?? (typeof failure?.providerCode === "string" ? failure.providerCode : undefined);
620
+ return failedPromptOutcome({
606
621
  code: deadline ? "prompt_deadline_exceeded" : "prompt_failed",
607
- message: deadline ? "Prompt deadline exceeded." : EMPTY_PROMPT_FAILURE.message,
608
622
  provenance: deadline ? "deadline" : "agent_failed",
609
- };
623
+ ...(explicit !== undefined
624
+ ? { providerCode: explicit }
625
+ : known !== undefined && known !== "prompt_failed" && known !== "prompt_deadline_exceeded"
626
+ ? { providerCode: known }
627
+ : {}),
628
+ evidence,
629
+ });
610
630
  }
611
631
 
612
632
  function canonicalTerminalOutcome(
613
633
  outcome: unknown,
614
- failure?: { code?: unknown; message?: unknown },
634
+ failure?: { code?: unknown; message?: unknown; providerCode?: unknown },
635
+ evidence: PromptFailureEvidence = {},
615
636
  ): InvocationOutcome | undefined {
616
637
  if (outcome && typeof outcome === "object") {
617
- const candidate = outcome as { kind?: unknown; reason?: unknown; provenance?: unknown; code?: unknown };
638
+ const candidate = outcome as {
639
+ kind?: unknown;
640
+ reason?: unknown;
641
+ provenance?: unknown;
642
+ code?: unknown;
643
+ providerCode?: unknown;
644
+ };
618
645
  if (candidate.kind === "stopped") {
619
646
  if (candidate.reason === "cancelled" && candidate.provenance === "client_cancel")
620
647
  return { kind: "stopped", reason: "cancelled", provenance: "client_cancel" };
@@ -626,9 +653,11 @@ function canonicalTerminalOutcome(
626
653
  return canonicalFailedOutcome(
627
654
  { code: candidate.code, message: (outcome as { message?: unknown }).message },
628
655
  candidate.provenance === "deadline" ? "deadline" : "agent_failed",
656
+ evidence,
657
+ typeof candidate.providerCode === "string" ? candidate.providerCode : undefined,
629
658
  );
630
659
  }
631
- if (failure !== undefined) return canonicalFailedOutcome(failure);
660
+ if (failure !== undefined) return canonicalFailedOutcome(failure, "agent_failed", evidence);
632
661
  return undefined;
633
662
  }
634
663
  interface InvocationRecord extends InvocationCorrelation {
@@ -1183,7 +1212,9 @@ export function createInvocationReconciliation(
1183
1212
  delete (next as unknown as { pendingOutcome?: unknown }).pendingOutcome;
1184
1213
  delete (next as unknown as { pendingReceiptState?: unknown }).pendingReceiptState;
1185
1214
  next.content = reduceTurnResultContent(next.content, frame.content);
1186
- const incomingOutcome = canonicalTerminalOutcome(frame.outcome) ?? canonicalTerminalOutcome(pendingOutcome);
1215
+ const incomingOutcome =
1216
+ canonicalTerminalOutcome(frame.outcome, undefined, failureEvidence(next, frame.hasActivity)) ??
1217
+ canonicalTerminalOutcome(pendingOutcome, undefined, failureEvidence(next, frame.hasActivity));
1187
1218
  if (
1188
1219
  incomingOutcome?.kind === "stopped" &&
1189
1220
  (next.error === undefined || next.error.code === "prompt_deadline_exceeded")
@@ -1192,9 +1223,21 @@ export function createInvocationReconciliation(
1192
1223
  if (next.error?.code === "prompt_deadline_exceeded") delete next.error;
1193
1224
  next.status = "terminal_ok";
1194
1225
  } else if (incomingOutcome?.kind === "failed") {
1195
- next.outcome = incomingOutcome;
1226
+ // The provider diagnostic recorded before the boundary carries the
1227
+ // bounded classifier; prefer it over a generic frame outcome that lost
1228
+ // the provider code.
1229
+ const recordErrorOutcome =
1230
+ next.error !== undefined && next.error.code !== "prompt_deadline_exceeded"
1231
+ ? canonicalFailedOutcome(next.error, "agent_failed", failureEvidence(next))
1232
+ : undefined;
1233
+ const preferRecordError =
1234
+ recordErrorOutcome?.kind === "failed" &&
1235
+ recordErrorOutcome.providerCode !== undefined &&
1236
+ incomingOutcome.providerCode === undefined;
1237
+ next.outcome = preferRecordError ? recordErrorOutcome : incomingOutcome;
1196
1238
  if (next.error === undefined)
1197
1239
  next.error = { code: incomingOutcome.code, message: incomingOutcome.message };
1240
+ else next.error = { code: next.error.code, message: incomingOutcome.message };
1198
1241
  next.status = "failed";
1199
1242
  } else if (next.error !== undefined) {
1200
1243
  next.outcome = canonicalFailedOutcome(next.error);
@@ -1209,6 +1252,15 @@ export function createInvocationReconciliation(
1209
1252
  next.error = EMPTY_PROMPT_FAILURE;
1210
1253
  next.outcome = canonicalFailedOutcome(EMPTY_PROMPT_FAILURE);
1211
1254
  } else next.status = "terminal_ok";
1255
+ if (next.outcome !== undefined)
1256
+ next.outcome = rephaseFailedOutcome(
1257
+ next.outcome as SdkPromptTerminalOutcome,
1258
+ failureEvidence(next, frame.hasActivity),
1259
+ );
1260
+ if ((next.outcome as SdkPromptTerminalOutcome | undefined)?.kind === "failed") {
1261
+ const failed = next.outcome as Extract<SdkPromptTerminalOutcome, { kind: "failed" }>;
1262
+ next.error = { code: next.error?.code ?? failed.code, message: failed.message };
1263
+ }
1212
1264
  next.receiptState = reduceReceiptState(
1213
1265
  next.receiptState,
1214
1266
  reportableTurnResultContent(next.content) ? "present" : "missing",
@@ -1270,11 +1322,12 @@ export function createInvocationReconciliation(
1270
1322
  hydrate,
1271
1323
  async claimPendingOutcome(kind, correlation, outcome) {
1272
1324
  const record = records.get(key(kind, correlation));
1273
- const normalized = canonicalTerminalOutcome(outcome);
1325
+ const normalized = canonicalTerminalOutcome(outcome, undefined, failureEvidence(record ?? {}));
1274
1326
  if (normalized === undefined) throw new Error("Invalid terminal outcome.");
1275
1327
  if (!record || record.terminalAt !== undefined || record.kind !== kind) return normalized;
1276
1328
  const pending = (record as unknown as { pendingOutcome?: unknown }).pendingOutcome;
1277
- if (pending !== undefined) return canonicalTerminalOutcome(pending) ?? normalized;
1329
+ if (pending !== undefined)
1330
+ return canonicalTerminalOutcome(pending, undefined, failureEvidence(record)) ?? normalized;
1278
1331
  const next = { ...record, revision: ++mutationRevision } as InvocationRecord & { pendingOutcome?: unknown };
1279
1332
  next.pendingOutcome = normalized;
1280
1333
  records.set(key(kind, correlation), next);
@@ -1318,14 +1371,22 @@ export function createInvocationReconciliation(
1318
1371
  if (!record || record.terminalAt !== undefined || record.kind !== kind) return;
1319
1372
  const requestedOutcome = canonicalTerminalOutcome(
1320
1373
  outcome ?? (record as unknown as { pendingOutcome?: unknown }).pendingOutcome,
1374
+ undefined,
1375
+ failureEvidence(record, evidence?.hasActivity),
1321
1376
  );
1322
1377
  const priorFailure = record.error;
1378
+ const requestedProviderCode = requestedOutcome?.kind === "failed" ? requestedOutcome.providerCode : undefined;
1323
1379
  // A provider diagnostic recorded before a deadline finalization is stronger
1324
1380
  // than the synthetic deadline claim. Preserve it as the terminal failure
1325
1381
  // intent instead of allowing a later agent_end to look successful.
1326
1382
  const finalOutcome =
1327
1383
  priorFailure !== undefined && priorFailure.code !== "prompt_deadline_exceeded"
1328
- ? canonicalFailedOutcome(priorFailure)
1384
+ ? canonicalFailedOutcome(
1385
+ priorFailure,
1386
+ "agent_failed",
1387
+ failureEvidence(record, evidence?.hasActivity),
1388
+ requestedProviderCode,
1389
+ )
1329
1390
  : requestedOutcome?.kind === "stopped"
1330
1391
  ? requestedOutcome
1331
1392
  : priorFailure !== undefined &&
@@ -1333,12 +1394,22 @@ export function createInvocationReconciliation(
1333
1394
  (requestedOutcome.kind === "failed" &&
1334
1395
  (requestedOutcome.code === "prompt_deadline_exceeded" ||
1335
1396
  priorFailure.code !== "prompt_deadline_exceeded")))
1336
- ? canonicalFailedOutcome(priorFailure)
1397
+ ? canonicalFailedOutcome(
1398
+ priorFailure,
1399
+ "agent_failed",
1400
+ failureEvidence(record, evidence?.hasActivity),
1401
+ requestedProviderCode,
1402
+ )
1337
1403
  : requestedOutcome;
1338
1404
  const previousRecord = { ...record };
1339
1405
  const finalizedRecord: InvocationRecord = { ...record, revision: ++mutationRevision, terminalAt: Date.now() };
1340
1406
  finalizedRecord.content = reduceTurnResultContent(finalizedRecord.content, evidence?.content);
1341
1407
  let resolvedOutcome = finalOutcome;
1408
+ if (resolvedOutcome !== undefined)
1409
+ resolvedOutcome = rephaseFailedOutcome(
1410
+ resolvedOutcome,
1411
+ failureEvidence(record, evidence?.hasActivity),
1412
+ ) as InvocationOutcome;
1342
1413
  if (resolvedOutcome?.kind === "stopped") {
1343
1414
  // Stopped is a successful terminal boundary: it must never coexist with
1344
1415
  // an earlier diagnostic failure.
@@ -1348,11 +1419,11 @@ export function createInvocationReconciliation(
1348
1419
  finalizedRecord.status = "failed";
1349
1420
  finalizedRecord.error =
1350
1421
  recordError !== undefined
1351
- ? { code: recordError.code, message: recordError.message }
1422
+ ? { code: recordError.code, message: resolvedOutcome.message }
1352
1423
  : priorFailure !== undefined &&
1353
1424
  (resolvedOutcome.code === "prompt_deadline_exceeded" ||
1354
1425
  priorFailure.code !== "prompt_deadline_exceeded")
1355
- ? priorFailure
1426
+ ? { code: priorFailure.code, message: resolvedOutcome.message }
1356
1427
  : { code: resolvedOutcome.code, message: resolvedOutcome.message };
1357
1428
  } else if (kind === "prompt") {
1358
1429
  // Evidence-based empty predicate (exact-head review P1/P2): the same
@@ -1361,9 +1432,14 @@ export function createInvocationReconciliation(
1361
1432
  // only a genuinely empty, no-activity completion fails closed.
1362
1433
  const terminalText = evidence?.content?.text.trim() ?? "";
1363
1434
  if (terminalText === "" && !evidence?.hasActivity && evidence?.outcomeKind !== "stopped") {
1364
- resolvedOutcome = canonicalFailedOutcome(EMPTY_PROMPT_FAILURE);
1435
+ const emptyOutcome = canonicalFailedOutcome(
1436
+ EMPTY_PROMPT_FAILURE,
1437
+ "agent_failed",
1438
+ failureEvidence(finalizedRecord, evidence?.hasActivity),
1439
+ ) as Extract<InvocationOutcome, { kind: "failed" }>;
1440
+ resolvedOutcome = emptyOutcome;
1365
1441
  finalizedRecord.status = "failed";
1366
- finalizedRecord.error = EMPTY_PROMPT_FAILURE;
1442
+ finalizedRecord.error = { code: emptyOutcome.code, message: emptyOutcome.message };
1367
1443
  } else finalizedRecord.status = "terminal_ok";
1368
1444
  } else finalizedRecord.status = "terminal_ok";
1369
1445
  finalizedRecord.receiptState = reduceReceiptState(
@@ -1454,6 +1530,8 @@ export interface SdkSurfaceFactoryOptions {
1454
1530
  ctx: ExtensionContext;
1455
1531
  id: string;
1456
1532
  api: ExtensionAPI;
1533
+ /** Startup surface that owns host-level permission and lifecycle authority. */
1534
+ primaryControlSurface?: "cli" | "sdk";
1457
1535
  policy?: SdkSurfacePolicy;
1458
1536
  getInstalledDefinitions?: (capability: string) => unknown | undefined;
1459
1537
  getLiveState?: () => { isStreaming: boolean; steeringQueueDepth: number; followupQueueDepth: number };
@@ -1499,6 +1577,7 @@ function createQuerySurface(
1499
1577
  steerStatusLookup?: (selector: { commandId?: string; turnId?: string; clientRef?: string }) => unknown;
1500
1578
  hostTools?: boolean | (() => boolean);
1501
1579
  getRuntimeHost?: () => SessionSdkHost | undefined;
1580
+ primaryControlSurface?: "cli" | "sdk";
1502
1581
  } = {},
1503
1582
  ): SessionSurface {
1504
1583
  const policy =
@@ -1881,7 +1960,7 @@ function createQuerySurface(
1881
1960
  getStats: () => ctx.sessionManager.getUsageStatistics(),
1882
1961
  getBranchCandidates: () => ctx.getBranchCandidates(),
1883
1962
  getLastAssistant: lastAssistant,
1884
- getCapabilities: () => createSdkCapabilities(policy, hasHostTools()),
1963
+ getCapabilities: () => createSdkCapabilities(policy, hasHostTools(), options.primaryControlSurface),
1885
1964
  getAuthProviders: () => [...new Set(ctx.modelRegistry.getAll().map(model => model.provider))],
1886
1965
  getActiveProviders: () => ctx.modelRegistry.getActiveProviders(),
1887
1966
  getTools: () => {
@@ -1974,6 +2053,7 @@ export function createSdkSurfaceFactory(
1974
2053
  steerStatusLookup: options.steerStatusLookup,
1975
2054
  hostTools: options.hostTools,
1976
2055
  getRuntimeHost: options.getRuntimeHost,
2056
+ primaryControlSurface: options.primaryControlSurface,
1977
2057
  });
1978
2058
  return {
1979
2059
  policy,
@@ -2121,7 +2201,9 @@ function rejectionRecoveryIntent(error: unknown): { code: string; message: strin
2121
2201
  * after retry/fallback policy has settled, so this is the safe boundary at which
2122
2202
  * to publish the additive failure diagnostic before terminal reconciliation.
2123
2203
  */
2124
- function providerFailureFromAgentEnd(event: unknown): { code: string; message: string } | undefined {
2204
+ function providerFailureFromAgentEnd(
2205
+ event: unknown,
2206
+ ): { code: string; message: string; providerCode?: string } | undefined {
2125
2207
  try {
2126
2208
  if (!event || typeof event !== "object") return undefined;
2127
2209
  const messages = (event as { messages?: unknown }).messages;
@@ -2137,7 +2219,8 @@ function providerFailureFromAgentEnd(event: unknown): { code: string; message: s
2137
2219
  errorMessage?: unknown;
2138
2220
  errorKind?: unknown;
2139
2221
  errorStatus?: unknown;
2140
- transportFailure?: { status?: unknown };
2222
+ errorCode?: unknown;
2223
+ transportFailure?: { status?: unknown; providerCode?: unknown };
2141
2224
  };
2142
2225
  let stopReason: unknown;
2143
2226
  try {
@@ -2183,10 +2266,24 @@ function providerFailureFromAgentEnd(event: unknown): { code: string; message: s
2183
2266
  // A throwing transport metadata accessor is also statusless.
2184
2267
  }
2185
2268
  }
2269
+ const providerCode = assistantFailureCode(assistant);
2186
2270
  if (status === 402 || status === 429)
2187
- return { code: `provider_http_${status}`, message: "Prompt submission failed." };
2188
- if (status !== undefined) return { code: "provider_rejected", message: "Prompt submission failed." };
2189
- return { code: "provider_rejected", message: "Prompt submission failed." };
2271
+ return {
2272
+ code: `provider_http_${status}`,
2273
+ message: PROMPT_FAILURE_MESSAGE_SUBMISSION,
2274
+ ...(providerCode !== undefined ? { providerCode } : {}),
2275
+ };
2276
+ if (status !== undefined)
2277
+ return {
2278
+ code: "provider_rejected",
2279
+ message: PROMPT_FAILURE_MESSAGE_SUBMISSION,
2280
+ ...(providerCode !== undefined ? { providerCode } : {}),
2281
+ };
2282
+ return {
2283
+ code: "provider_rejected",
2284
+ message: PROMPT_FAILURE_MESSAGE_SUBMISSION,
2285
+ ...(providerCode !== undefined ? { providerCode } : {}),
2286
+ };
2190
2287
  } catch {
2191
2288
  // Provider metadata is untrusted: an SDK/provider adapter may expose a
2192
2289
  // throwing getter while the lifecycle boundary still needs to terminalize.
@@ -2199,32 +2296,76 @@ interface PromptTerminalEvidence {
2199
2296
  hasActivity: boolean;
2200
2297
  }
2201
2298
 
2299
+ function assistantMessageHasPromptActivity(assistant: object): boolean {
2300
+ const hasUsage = Object.hasOwn(assistant, "usage");
2301
+ const usage = hasUsage ? (assistant as { usage?: unknown }).usage : undefined;
2302
+ const hasTokenActivity =
2303
+ hasUsage &&
2304
+ usage !== null &&
2305
+ typeof usage === "object" &&
2306
+ !Array.isArray(usage) &&
2307
+ typeof (usage as { totalTokens?: unknown }).totalTokens === "number" &&
2308
+ Number.isFinite((usage as { totalTokens: number }).totalTokens) &&
2309
+ (usage as { totalTokens: number }).totalTokens > 0;
2310
+ if (hasTokenActivity) return true;
2311
+ const content = (assistant as { content?: unknown }).content;
2312
+ if (typeof content === "string") return content.trim().length > 0;
2313
+ if (!Array.isArray(content)) return false;
2314
+ return content.some(block => {
2315
+ if (block === null || typeof block !== "object") return false;
2316
+ const type = (block as { type?: unknown }).type;
2317
+ if (type === "text") {
2318
+ const text = (block as { text?: unknown }).text;
2319
+ return typeof text === "string" && text.trim().length > 0;
2320
+ }
2321
+ if (type === "thinking") {
2322
+ const thinking = (block as { thinking?: unknown }).thinking;
2323
+ return typeof thinking === "string" && thinking.trim().length > 0;
2324
+ }
2325
+ if (type === "redactedThinking") {
2326
+ const data = (block as { data?: unknown }).data;
2327
+ return typeof data === "string" && data.trim().length > 0;
2328
+ }
2329
+ if (type !== "toolCall") return false;
2330
+ const toolCall = block as {
2331
+ id?: unknown;
2332
+ name?: unknown;
2333
+ arguments?: unknown;
2334
+ incompleteArguments?: unknown;
2335
+ incompleteArgumentsReason?: unknown;
2336
+ };
2337
+ return (
2338
+ typeof toolCall.id === "string" &&
2339
+ toolCall.id.trim().length > 0 &&
2340
+ typeof toolCall.name === "string" &&
2341
+ toolCall.name.trim().length > 0 &&
2342
+ toolCall.arguments !== null &&
2343
+ typeof toolCall.arguments === "object" &&
2344
+ !Array.isArray(toolCall.arguments) &&
2345
+ (toolCall.incompleteArguments === undefined || toolCall.incompleteArguments === false) &&
2346
+ toolCall.incompleteArgumentsReason === undefined
2347
+ );
2348
+ });
2349
+ }
2350
+
2202
2351
  function promptTerminalEvidenceFromAgentEnd(event: unknown): PromptTerminalEvidence {
2203
2352
  try {
2204
2353
  if (!event || typeof event !== "object") return { hasActivity: false };
2205
2354
  const messages = (event as { messages?: unknown }).messages;
2206
2355
  if (!Array.isArray(messages)) return { hasActivity: false };
2207
- const assistant = [...messages]
2208
- .reverse()
2209
- .find(
2210
- message => message && typeof message === "object" && (message as { role?: unknown }).role === "assistant",
2211
- );
2212
- if (!assistant || typeof assistant !== "object") return { hasActivity: false };
2356
+ const assistants = messages.filter(
2357
+ (message): message is object =>
2358
+ message !== null && typeof message === "object" && (message as { role?: unknown }).role === "assistant",
2359
+ );
2360
+ const assistant = assistants.at(-1);
2361
+ if (!assistant) return { hasActivity: false };
2362
+ const hasActivity = assistants.some(assistantMessageHasPromptActivity);
2213
2363
  const content = (assistant as { content?: unknown }).content;
2214
2364
  if (typeof content === "string") {
2215
2365
  const bounded = sanitizeTurnResultContent(content);
2216
- return { content: bounded, hasActivity: content.trim().length > 0 };
2366
+ return { content: bounded, hasActivity };
2217
2367
  }
2218
2368
  if (Array.isArray(content)) {
2219
- const hasActivity = content.some(block => {
2220
- if (block === null || typeof block !== "object") return false;
2221
- const type = (block as { type?: unknown }).type;
2222
- if (type === "text") {
2223
- const text = (block as { text?: unknown }).text;
2224
- return typeof text === "string" && text.trim().length > 0;
2225
- }
2226
- return typeof type === "string" && type.length > 0;
2227
- });
2228
2369
  const text = content
2229
2370
  .filter(
2230
2371
  (block): block is { type: "text"; text: string } =>
@@ -2237,7 +2378,7 @@ function promptTerminalEvidenceFromAgentEnd(event: unknown): PromptTerminalEvide
2237
2378
  .join("");
2238
2379
  return { content: sanitizeTurnResultContent(text), hasActivity };
2239
2380
  }
2240
- return { content: sanitizeTurnResultContent(""), hasActivity: false };
2381
+ return { content: sanitizeTurnResultContent(""), hasActivity };
2241
2382
  } catch {
2242
2383
  return { hasActivity: false };
2243
2384
  }
@@ -5028,6 +5169,9 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
5028
5169
  api.on("tool_execution_start", async (_event, ctx) => {
5029
5170
  renewAttributableProgress("tool_execution_start", ctx);
5030
5171
  });
5172
+ api.on("tool_execution_update", async (_event, ctx) => {
5173
+ renewAttributableProgress("tool_execution_update", ctx);
5174
+ });
5031
5175
  api.on("tool_execution_end", async (_event, ctx) => {
5032
5176
  renewAttributableProgress("tool_execution_end", ctx);
5033
5177
  });
@@ -5131,6 +5275,9 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
5131
5275
  configOverrides: options.configOverrides,
5132
5276
  settings: options.settings,
5133
5277
  getRuntimeHost: () => runtime?.host,
5278
+ // Origin is explicit at the session bootstrap boundary. The low-level
5279
+ // runtime defaults to SDK for existing embedders; CLI roots pass cli.
5280
+ primaryControlSurface: options.primaryControlSurface ?? "sdk",
5134
5281
  });
5135
5282
  const queryHandlers = new QueryHandlers(surfaceFactory.query, sessionId, revisions, cursors);
5136
5283
  const inputGate = { quiescing: false };
@@ -5730,6 +5877,7 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
5730
5877
  pid: process.pid,
5731
5878
  processIncarnation: effectiveIncarnation,
5732
5879
  });
5880
+ let registration: SessionIndexEvent | undefined;
5733
5881
  await runtime.registerWithBroker({
5734
5882
  register: async input => {
5735
5883
  if (publishedEndpointUrl === undefined)
@@ -5756,7 +5904,7 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
5756
5904
  processIncarnation: effectiveIncarnation,
5757
5905
  direct,
5758
5906
  });
5759
- await index.append({
5907
+ registration = await index.append({
5760
5908
  type: "host_registered",
5761
5909
  ...input,
5762
5910
  locator,
@@ -5768,13 +5916,17 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
5768
5916
  });
5769
5917
  },
5770
5918
  unregister: async input => {
5771
- await index.append({
5772
- type: "host_unregistered",
5773
- ...input,
5774
- locator,
5775
- pid: process.pid,
5776
- ...(options.lifecycleRequestId ? { lifecycleRequestId: options.lifecycleRequestId } : {}),
5777
- });
5919
+ const expected = registration;
5920
+ if (
5921
+ !expected ||
5922
+ expected.sessionId !== input.sessionId ||
5923
+ expected.endpointGeneration !== input.endpointGeneration ||
5924
+ path.resolve(expected.locator.stateRoot) !== path.resolve(input.stateRoot)
5925
+ )
5926
+ return;
5927
+ // Use the successful publication's proof, never a teardown-time file read.
5928
+ await index.unregisterIfCurrent(expected);
5929
+ if (registration === expected) registration = undefined;
5778
5930
  },
5779
5931
  });
5780
5932
  brokerRegistered = true;
@@ -107,13 +107,20 @@ export interface SdkCapabilities {
107
107
  operations: string[];
108
108
  hostTools: boolean;
109
109
  promptTerminalOutcomeVersion: 1;
110
+ /** Startup surface that owns host-level permission and lifecycle authority. */
111
+ primaryControlSurface: "cli" | "sdk";
110
112
  }
111
113
 
112
- export function createSdkCapabilities(policy: SdkSurfacePolicy, hostTools = false): SdkCapabilities {
114
+ export function createSdkCapabilities(
115
+ policy: SdkSurfacePolicy,
116
+ hostTools = false,
117
+ primaryControlSurface: SdkCapabilities["primaryControlSurface"] = "sdk",
118
+ ): SdkCapabilities {
113
119
  return {
114
120
  operations: [...policy.installedControls, ...policy.installedQueries],
115
121
  hostTools,
116
122
  promptTerminalOutcomeVersion: 1,
123
+ primaryControlSurface,
117
124
  };
118
125
  }
119
126