@ours.network/fleet 1.2.0-nightly.7 → 1.2.0-nightly.71

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 (423) hide show
  1. package/README.md +279 -68
  2. package/dist/account-origin.d.ts +2 -0
  3. package/dist/account-origin.js +6 -0
  4. package/dist/agent-ours/bridge.js +26 -9
  5. package/dist/agent-ours/correspondence.d.ts +10 -0
  6. package/dist/agent-ours/correspondence.js +1 -0
  7. package/dist/agent-ours/file-rpc.d.ts +12 -0
  8. package/dist/agent-ours/file-rpc.js +18 -4
  9. package/dist/agent-ours/harness.js +9 -1
  10. package/dist/agent-ours/mcp-endpoint.d.ts +19 -0
  11. package/dist/agent-ours/mcp-endpoint.js +98 -25
  12. package/dist/agent-ours/runtime.d.ts +9 -1
  13. package/dist/agent-ours/runtime.js +50 -2
  14. package/dist/agent-ours/service.d.ts +24 -1
  15. package/dist/agent-ours/service.js +97 -13
  16. package/dist/application/codex-models.d.ts +15 -0
  17. package/dist/application/codex-models.js +56 -0
  18. package/dist/application/conversation-history.d.ts +34 -0
  19. package/dist/application/conversation-history.js +280 -0
  20. package/dist/application/conversation-role-observer.d.ts +62 -0
  21. package/dist/application/conversation-role-observer.js +206 -0
  22. package/dist/application/fleet-query-service.d.ts +1 -1
  23. package/dist/application/fleet-query-service.js +3 -3
  24. package/dist/application/log-service.js +8 -8
  25. package/dist/application/model-catalog.d.ts +1 -1
  26. package/dist/application/model-catalog.js +5 -2
  27. package/dist/application/preset-provenance.d.ts +19 -0
  28. package/dist/application/preset-provenance.js +59 -0
  29. package/dist/application/resource-observer.d.ts +40 -0
  30. package/dist/application/resource-observer.js +278 -0
  31. package/dist/application/role-creation-service.js +3 -2
  32. package/dist/application/role-removal-service.js +17 -3
  33. package/dist/application/role-repository.d.ts +1 -1
  34. package/dist/application/role-repository.js +30 -7
  35. package/dist/application/room-layout-definitions.d.ts +45 -0
  36. package/dist/application/room-layout-definitions.js +130 -0
  37. package/dist/application/session-control.d.ts +61 -17
  38. package/dist/application/session-control.js +207 -23
  39. package/dist/application/supervisor-ours-tools.js +5 -11
  40. package/dist/application/task-layouts.d.ts +91 -0
  41. package/dist/application/task-layouts.js +261 -0
  42. package/dist/application/task-room-service.d.ts +101 -3
  43. package/dist/application/task-room-service.js +286 -33
  44. package/dist/application/types.d.ts +2 -0
  45. package/dist/atomic-file.d.ts +34 -1
  46. package/dist/atomic-file.js +161 -18
  47. package/dist/briefing.d.ts +3 -1
  48. package/dist/briefing.js +97 -31
  49. package/dist/build-info.json +9 -4
  50. package/dist/capabilities.d.ts +9 -1
  51. package/dist/capabilities.js +13 -0
  52. package/dist/cli.js +400 -37
  53. package/dist/client-profile.d.ts +5 -17
  54. package/dist/client-profile.js +4 -127
  55. package/dist/config.d.ts +45 -0
  56. package/dist/config.js +57 -6
  57. package/dist/creation.d.ts +1 -1
  58. package/dist/creation.js +4 -4
  59. package/dist/daemon-recovery.d.ts +14 -9
  60. package/dist/daemon-recovery.js +124 -115
  61. package/dist/docs.d.ts +1 -1
  62. package/dist/docs.js +207 -19
  63. package/dist/doctor.d.ts +4 -1
  64. package/dist/doctor.js +75 -60
  65. package/dist/erased-resources.d.ts +9 -0
  66. package/dist/erased-resources.js +87 -0
  67. package/dist/file-delivery/reader.d.ts +15 -0
  68. package/dist/file-delivery/reader.js +63 -0
  69. package/dist/file-delivery/store.d.ts +15 -0
  70. package/dist/file-delivery/store.js +124 -0
  71. package/dist/file-delivery/types.d.ts +19 -0
  72. package/dist/file-delivery/types.js +1 -0
  73. package/dist/fleet-command-audit.d.ts +7 -0
  74. package/dist/fleet-command-audit.js +24 -8
  75. package/dist/harness/agent-session.d.ts +4 -0
  76. package/dist/harness/claude-code-session.js +1 -1
  77. package/dist/harness/claude-code.js +21 -11
  78. package/dist/harness/claude-runtime.d.ts +12 -0
  79. package/dist/harness/claude-runtime.js +43 -0
  80. package/dist/harness/codex-app-server-proxy.d.ts +4 -1
  81. package/dist/harness/codex-app-server-proxy.js +41 -5
  82. package/dist/harness/codex-reasoning.d.ts +5 -0
  83. package/dist/harness/codex-reasoning.js +12 -0
  84. package/dist/harness/codex-runtime.d.ts +11 -1
  85. package/dist/harness/codex-runtime.js +31 -4
  86. package/dist/harness/codex-session.js +2 -2
  87. package/dist/harness/codex.js +24 -12
  88. package/dist/init-wizard.d.ts +2 -0
  89. package/dist/init-wizard.js +38 -19
  90. package/dist/isolation/policy.js +6 -1
  91. package/dist/isolation/types.d.ts +5 -0
  92. package/dist/managed-cli.d.ts +253 -0
  93. package/dist/managed-cli.js +923 -0
  94. package/dist/managed-recovery.d.ts +13 -0
  95. package/dist/managed-recovery.js +31 -0
  96. package/dist/minimal-setup.d.ts +2 -0
  97. package/dist/minimal-setup.js +44 -0
  98. package/dist/monitor.d.ts +9 -34
  99. package/dist/monitor.js +90 -153
  100. package/dist/notifications/fleet-producer.d.ts +22 -0
  101. package/dist/notifications/fleet-producer.js +237 -0
  102. package/dist/notifications/outbox.d.ts +46 -0
  103. package/dist/notifications/outbox.js +158 -0
  104. package/dist/notifications/target-cleanup.d.ts +11 -0
  105. package/dist/notifications/target-cleanup.js +63 -0
  106. package/dist/notifications/task-producer.d.ts +20 -0
  107. package/dist/notifications/task-producer.js +100 -0
  108. package/dist/ops.d.ts +2 -0
  109. package/dist/ops.js +20 -3
  110. package/dist/owner-channel/channel.js +17 -6
  111. package/dist/owner-channel/commands.d.ts +4 -0
  112. package/dist/owner-channel/commands.js +8 -0
  113. package/dist/owner-channel/lifecycle-outbox.js +4 -3
  114. package/dist/owner-channel/ours-client.js +2 -17
  115. package/dist/paths.d.ts +2 -0
  116. package/dist/paths.js +2 -0
  117. package/dist/preset-migration.js +43 -0
  118. package/dist/process-incarnation.d.ts +23 -0
  119. package/dist/process-incarnation.js +42 -0
  120. package/dist/reminders/manager.d.ts +75 -0
  121. package/dist/reminders/manager.js +278 -0
  122. package/dist/reminders/runtime.d.ts +27 -0
  123. package/dist/reminders/runtime.js +32 -0
  124. package/dist/reminders/schedule.d.ts +37 -0
  125. package/dist/reminders/schedule.js +104 -0
  126. package/dist/reminders/store.d.ts +341 -0
  127. package/dist/reminders/store.js +762 -0
  128. package/dist/reminders/tools.d.ts +20 -0
  129. package/dist/reminders/tools.js +114 -0
  130. package/dist/resolved-plan.js +1 -0
  131. package/dist/rooms-tasks/add-member.d.ts +48 -0
  132. package/dist/rooms-tasks/add-member.js +84 -0
  133. package/dist/rooms-tasks/archived-absence.d.ts +8 -0
  134. package/dist/rooms-tasks/archived-absence.js +48 -0
  135. package/dist/rooms-tasks/cli.js +65 -5
  136. package/dist/rooms-tasks/close.d.ts +6 -2
  137. package/dist/rooms-tasks/close.js +246 -37
  138. package/dist/rooms-tasks/config.d.ts +1 -1
  139. package/dist/rooms-tasks/config.js +11 -4
  140. package/dist/rooms-tasks/cowork-adapter.d.ts +12 -5
  141. package/dist/rooms-tasks/cowork-adapter.js +15 -121
  142. package/dist/rooms-tasks/cowork-http.js +56 -6
  143. package/dist/rooms-tasks/deletion.d.ts +1 -1
  144. package/dist/rooms-tasks/deletion.js +84 -5
  145. package/dist/rooms-tasks/erasure.d.ts +6 -0
  146. package/dist/rooms-tasks/erasure.js +173 -0
  147. package/dist/rooms-tasks/external-worker.d.ts +1 -1
  148. package/dist/rooms-tasks/external-worker.js +3 -4
  149. package/dist/rooms-tasks/layout-binding-client.d.ts +11 -0
  150. package/dist/rooms-tasks/layout-binding-client.js +56 -0
  151. package/dist/rooms-tasks/layout-binding-grants.d.ts +21 -0
  152. package/dist/rooms-tasks/layout-binding-grants.js +128 -0
  153. package/dist/rooms-tasks/layout-cli.d.ts +4 -0
  154. package/dist/rooms-tasks/layout-cli.js +107 -0
  155. package/dist/rooms-tasks/layout-config.d.ts +11 -0
  156. package/dist/rooms-tasks/layout-config.js +89 -0
  157. package/dist/rooms-tasks/layout-control.d.ts +21 -0
  158. package/dist/rooms-tasks/layout-control.js +52 -0
  159. package/dist/rooms-tasks/layout-member-retirement.d.ts +10 -0
  160. package/dist/rooms-tasks/layout-member-retirement.js +90 -0
  161. package/dist/rooms-tasks/layout-service.d.ts +43 -0
  162. package/dist/rooms-tasks/layout-service.js +203 -0
  163. package/dist/rooms-tasks/layout.d.ts +121 -0
  164. package/dist/rooms-tasks/layout.js +286 -0
  165. package/dist/rooms-tasks/legacy-task-member.d.ts +19 -0
  166. package/dist/rooms-tasks/legacy-task-member.js +116 -0
  167. package/dist/rooms-tasks/live-readiness.d.ts +18 -0
  168. package/dist/rooms-tasks/live-readiness.js +85 -0
  169. package/dist/rooms-tasks/member-ownership.d.ts +5 -0
  170. package/dist/rooms-tasks/member-ownership.js +40 -0
  171. package/dist/rooms-tasks/member-startup.d.ts +1 -0
  172. package/dist/rooms-tasks/member-startup.js +2 -0
  173. package/dist/rooms-tasks/provision.d.ts +3 -0
  174. package/dist/rooms-tasks/provision.js +101 -49
  175. package/dist/rooms-tasks/recovery.d.ts +19 -0
  176. package/dist/rooms-tasks/recovery.js +110 -0
  177. package/dist/rooms-tasks/room-state.d.ts +4 -2
  178. package/dist/rooms-tasks/room-state.js +47 -8
  179. package/dist/rooms-tasks/task-service-retirement.d.ts +11 -0
  180. package/dist/rooms-tasks/task-service-retirement.js +21 -0
  181. package/dist/rooms-tasks/task-state.d.ts +52 -8
  182. package/dist/rooms-tasks/task-state.js +251 -26
  183. package/dist/rooms-tasks/types.d.ts +40 -0
  184. package/dist/rooms-tasks/workspace-artifacts.d.ts +6 -0
  185. package/dist/rooms-tasks/workspace-artifacts.js +93 -0
  186. package/dist/rooms-tasks/workspace.d.ts +35 -0
  187. package/dist/rooms-tasks/workspace.js +325 -0
  188. package/dist/runner.d.ts +33 -4
  189. package/dist/runner.js +410 -62
  190. package/dist/session/acp.d.ts +75 -2
  191. package/dist/session/acp.js +345 -82
  192. package/dist/session/arbiter.d.ts +98 -0
  193. package/dist/session/arbiter.js +272 -3
  194. package/dist/session/codex-app-server.d.ts +45 -1
  195. package/dist/session/codex-app-server.js +225 -32
  196. package/dist/session/control.d.ts +17 -3
  197. package/dist/session/control.js +213 -23
  198. package/dist/session/conversation-normalizer.d.ts +2 -1
  199. package/dist/session/conversation-normalizer.js +1 -1
  200. package/dist/session/conversation-observation.d.ts +25 -0
  201. package/dist/session/conversation-observation.js +100 -0
  202. package/dist/session/conversation-replay.d.ts +50 -0
  203. package/dist/session/conversation-replay.js +203 -0
  204. package/dist/session/conversation-store.d.ts +15 -1
  205. package/dist/session/conversation-store.js +206 -26
  206. package/dist/session/conversation-types.d.ts +57 -4
  207. package/dist/session/prompt-batch.d.ts +79 -0
  208. package/dist/session/prompt-batch.js +120 -0
  209. package/dist/session/task-notice.d.ts +14 -0
  210. package/dist/session/task-notice.js +13 -0
  211. package/dist/session/types.d.ts +42 -1
  212. package/dist/setup-tunnel-preflight.d.ts +34 -0
  213. package/dist/setup-tunnel-preflight.js +62 -0
  214. package/dist/socket-path.d.ts +2 -0
  215. package/dist/socket-path.js +22 -0
  216. package/dist/spawn.d.ts +5 -1
  217. package/dist/spawn.js +40 -4
  218. package/dist/startup-prompt.d.ts +15 -0
  219. package/dist/startup-prompt.js +71 -0
  220. package/dist/startup-readiness.d.ts +32 -0
  221. package/dist/startup-readiness.js +101 -0
  222. package/dist/startup-telemetry.d.ts +16 -0
  223. package/dist/startup-telemetry.js +46 -0
  224. package/dist/subscriptions/cli.d.ts +91 -0
  225. package/dist/subscriptions/cli.js +223 -0
  226. package/dist/subscriptions/launch.d.ts +37 -0
  227. package/dist/subscriptions/launch.js +93 -0
  228. package/dist/subscriptions/login.d.ts +77 -0
  229. package/dist/subscriptions/login.js +215 -0
  230. package/dist/subscriptions/observed.d.ts +7 -0
  231. package/dist/subscriptions/observed.js +44 -0
  232. package/dist/subscriptions/probe.d.ts +10 -0
  233. package/dist/subscriptions/probe.js +73 -0
  234. package/dist/subscriptions/service.d.ts +102 -0
  235. package/dist/subscriptions/service.js +364 -0
  236. package/dist/subscriptions/store.d.ts +71 -0
  237. package/dist/subscriptions/store.js +143 -0
  238. package/dist/supervisor/adoption.d.ts +8 -0
  239. package/dist/supervisor/adoption.js +78 -0
  240. package/dist/supervisor/catalog.d.ts +62 -0
  241. package/dist/supervisor/catalog.js +254 -0
  242. package/dist/supervisor/fleet.d.ts +8 -0
  243. package/dist/supervisor/fleet.js +89 -0
  244. package/dist/supervisor/index.js +3 -6
  245. package/dist/supervisor/launchd.d.ts +1 -1
  246. package/dist/supervisor/launchd.js +26 -13
  247. package/dist/supervisor/legacy.d.ts +35 -0
  248. package/dist/supervisor/legacy.js +524 -0
  249. package/dist/supervisor/manager.d.ts +15 -0
  250. package/dist/supervisor/manager.js +270 -0
  251. package/dist/supervisor/registration-refresh.d.ts +45 -0
  252. package/dist/supervisor/registration-refresh.js +266 -0
  253. package/dist/supervisor/scope.d.ts +4 -0
  254. package/dist/supervisor/scope.js +10 -0
  255. package/dist/supervisor/systemd.d.ts +2 -2
  256. package/dist/supervisor/systemd.js +19 -33
  257. package/dist/task-supervision.d.ts +9 -0
  258. package/dist/task-supervision.js +145 -0
  259. package/dist/temp-idle.d.ts +17 -0
  260. package/dist/temp-idle.js +42 -0
  261. package/dist/temp-lifecycle.d.ts +23 -8
  262. package/dist/temp-lifecycle.js +123 -66
  263. package/dist/temp-supervisor-recovery.d.ts +1 -1
  264. package/dist/temp-supervisor-recovery.js +2 -2
  265. package/dist/tunnel-setup-completion.d.ts +7 -0
  266. package/dist/tunnel-setup-completion.js +13 -0
  267. package/dist/tunnel-setup-input.d.ts +19 -0
  268. package/dist/tunnel-setup-input.js +124 -0
  269. package/dist/watchdog/query.d.ts +3 -1
  270. package/dist/watchdog/query.js +2 -1
  271. package/dist/web/agent-attachments.d.ts +29 -0
  272. package/dist/web/agent-attachments.js +162 -0
  273. package/dist/web/auth.d.ts +65 -2
  274. package/dist/web/auth.js +201 -11
  275. package/dist/web/available-port.d.ts +2 -0
  276. package/dist/web/available-port.js +23 -0
  277. package/dist/web/control.d.ts +3 -3
  278. package/dist/web/control.js +10 -8
  279. package/dist/web/conversation-stream-codec.d.ts +23 -0
  280. package/dist/web/conversation-stream-codec.js +110 -0
  281. package/dist/web/conversation-stream.d.ts +25 -0
  282. package/dist/web/conversation-stream.js +231 -0
  283. package/dist/web/events.d.ts +2 -0
  284. package/dist/web/events.js +9 -0
  285. package/dist/web/fleet-config-service.d.ts +4 -1
  286. package/dist/web/fleet-config-service.js +46 -15
  287. package/dist/web/prefix-gateway.d.ts +32 -0
  288. package/dist/web/prefix-gateway.js +248 -0
  289. package/dist/web/resource-views.d.ts +124 -0
  290. package/dist/web/resource-views.js +424 -0
  291. package/dist/web/runtime.d.ts +3 -1
  292. package/dist/web/runtime.js +132 -34
  293. package/dist/web/server.d.ts +19 -0
  294. package/dist/web/server.js +802 -67
  295. package/dist/web/service.d.ts +11 -2
  296. package/dist/web/service.js +30 -4
  297. package/dist/web/workspace-devices.d.ts +107 -0
  298. package/dist/web/workspace-devices.js +277 -0
  299. package/dist/web/workspace-tunnel.d.ts +1 -0
  300. package/dist/web/workspace-tunnel.js +34 -0
  301. package/dist/workspace-enrollment.d.ts +83 -0
  302. package/dist/workspace-enrollment.js +580 -0
  303. package/dist/workspace-replacement.d.ts +66 -0
  304. package/dist/workspace-replacement.js +220 -0
  305. package/docs/acp-files.md +146 -0
  306. package/docs/conversation-stream.md +196 -0
  307. package/docs/fleet-migration.md +54 -0
  308. package/docs/live-voice.md +13 -0
  309. package/docs/room-layouts.md +227 -0
  310. package/docs/self-reminders.md +374 -0
  311. package/docs/task-workspaces.md +225 -0
  312. package/docs/validation/managed-cli-permissions.md +421 -0
  313. package/examples/room-layouts/fresh.yaml +27 -0
  314. package/examples/room-layouts/scoped.yaml +21 -0
  315. package/examples/room-layouts/shared.yaml +19 -0
  316. package/package.json +24 -20
  317. package/presets/README.md +78 -0
  318. package/presets/brain-catalog.json +8 -2
  319. package/presets/fleet/agent_templates/Critic.yaml +1 -1
  320. package/presets/fleet/agent_templates/Developer.yaml +1 -1
  321. package/presets/fleet/agent_templates/Engineer.yaml +5 -0
  322. package/presets/fleet/agent_templates/LocalCoordinator.yaml +4 -2
  323. package/presets/fleet/agents/FleetCoordinator.yaml +1 -1
  324. package/presets/fleet/brains/claude-fable-5-1-high.yaml +5 -0
  325. package/presets/fleet/brains/claude-fable-5-1-low.yaml +5 -0
  326. package/presets/fleet/brains/claude-fable-5-1-max.yaml +5 -0
  327. package/presets/fleet/brains/claude-fable-5-1-medium.yaml +5 -0
  328. package/presets/fleet/brains/claude-fable-5-1-xhigh.yaml +5 -0
  329. package/presets/fleet/brains/claude-fable-5-high.yaml +1 -1
  330. package/presets/fleet/brains/claude-fable-5-low.yaml +1 -1
  331. package/presets/fleet/brains/claude-fable-5-max.yaml +1 -1
  332. package/presets/fleet/brains/claude-fable-5-medium.yaml +1 -1
  333. package/presets/fleet/brains/claude-fable-5-xhigh.yaml +1 -1
  334. package/presets/fleet/brains/claude-haiku-4-5-20251001-default.yaml +4 -0
  335. package/presets/fleet/brains/claude-opus-5-5-high.yaml +5 -0
  336. package/presets/fleet/brains/claude-opus-5-5-low.yaml +5 -0
  337. package/presets/fleet/brains/claude-opus-5-5-max.yaml +5 -0
  338. package/presets/fleet/brains/claude-opus-5-5-medium.yaml +5 -0
  339. package/presets/fleet/brains/claude-opus-5-5-xhigh.yaml +5 -0
  340. package/presets/fleet/brains/claude-opus-5-high.yaml +1 -1
  341. package/presets/fleet/brains/claude-opus-5-low.yaml +1 -1
  342. package/presets/fleet/brains/claude-opus-5-max.yaml +1 -1
  343. package/presets/fleet/brains/claude-opus-5-medium.yaml +1 -1
  344. package/presets/fleet/brains/claude-opus-5-xhigh.yaml +1 -1
  345. package/presets/fleet/brains/claude-sonnet-5-high.yaml +1 -1
  346. package/presets/fleet/brains/claude-sonnet-5-low.yaml +1 -1
  347. package/presets/fleet/brains/claude-sonnet-5-max.yaml +1 -1
  348. package/presets/fleet/brains/claude-sonnet-5-medium.yaml +1 -1
  349. package/presets/fleet/brains/claude-sonnet-5-xhigh.yaml +1 -1
  350. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-high.yaml +1 -1
  351. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-low.yaml +1 -1
  352. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-medium.yaml +1 -1
  353. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-xhigh.yaml +1 -1
  354. package/presets/fleet/brains/codex-gpt-5-4-high.yaml +1 -1
  355. package/presets/fleet/brains/codex-gpt-5-4-low.yaml +1 -1
  356. package/presets/fleet/brains/codex-gpt-5-4-medium.yaml +1 -1
  357. package/presets/fleet/brains/codex-gpt-5-4-mini-high.yaml +1 -1
  358. package/presets/fleet/brains/codex-gpt-5-4-mini-low.yaml +1 -1
  359. package/presets/fleet/brains/codex-gpt-5-4-mini-medium.yaml +1 -1
  360. package/presets/fleet/brains/codex-gpt-5-4-mini-xhigh.yaml +1 -1
  361. package/presets/fleet/brains/codex-gpt-5-4-xhigh.yaml +1 -1
  362. package/presets/fleet/brains/codex-gpt-5-5-high.yaml +1 -1
  363. package/presets/fleet/brains/codex-gpt-5-5-low.yaml +1 -1
  364. package/presets/fleet/brains/codex-gpt-5-5-medium.yaml +1 -1
  365. package/presets/fleet/brains/codex-gpt-5-5-xhigh.yaml +1 -1
  366. package/presets/fleet/brains/codex-gpt-5-6-luna-high.yaml +1 -1
  367. package/presets/fleet/brains/codex-gpt-5-6-luna-low.yaml +1 -1
  368. package/presets/fleet/brains/codex-gpt-5-6-luna-max.yaml +1 -1
  369. package/presets/fleet/brains/codex-gpt-5-6-luna-medium.yaml +1 -1
  370. package/presets/fleet/brains/codex-gpt-5-6-luna-xhigh.yaml +1 -1
  371. package/presets/fleet/brains/codex-gpt-5-6-sol-high.yaml +1 -1
  372. package/presets/fleet/brains/codex-gpt-5-6-sol-low.yaml +1 -1
  373. package/presets/fleet/brains/codex-gpt-5-6-sol-max.yaml +1 -1
  374. package/presets/fleet/brains/codex-gpt-5-6-sol-medium.yaml +1 -1
  375. package/presets/fleet/brains/codex-gpt-5-6-sol-ultra.yaml +1 -1
  376. package/presets/fleet/brains/codex-gpt-5-6-sol-xhigh.yaml +1 -1
  377. package/presets/fleet/brains/codex-gpt-5-6-terra-high.yaml +1 -1
  378. package/presets/fleet/brains/codex-gpt-5-6-terra-low.yaml +1 -1
  379. package/presets/fleet/brains/codex-gpt-5-6-terra-max.yaml +1 -1
  380. package/presets/fleet/brains/codex-gpt-5-6-terra-medium.yaml +1 -1
  381. package/presets/fleet/brains/codex-gpt-5-6-terra-ultra.yaml +1 -1
  382. package/presets/fleet/brains/codex-gpt-5-6-terra-xhigh.yaml +1 -1
  383. package/presets/fleet/brains/codex-gpt-6-1-sol-high.yaml +5 -0
  384. package/presets/fleet/brains/codex-gpt-6-1-sol-low.yaml +5 -0
  385. package/presets/fleet/brains/codex-gpt-6-1-sol-max.yaml +5 -0
  386. package/presets/fleet/brains/codex-gpt-6-1-sol-medium.yaml +5 -0
  387. package/presets/fleet/brains/codex-gpt-6-1-sol-ultra.yaml +5 -0
  388. package/presets/fleet/brains/codex-gpt-6-1-sol-xhigh.yaml +5 -0
  389. package/presets/fleet/brains/codex-gpt-6-astra-high.yaml +1 -1
  390. package/presets/fleet/brains/codex-gpt-6-astra-low.yaml +1 -1
  391. package/presets/fleet/brains/codex-gpt-6-astra-max.yaml +1 -1
  392. package/presets/fleet/brains/codex-gpt-6-astra-medium.yaml +1 -1
  393. package/presets/fleet/brains/codex-gpt-6-astra-ultra.yaml +1 -1
  394. package/presets/fleet/brains/codex-gpt-6-astra-xhigh.yaml +1 -1
  395. package/presets/fleet/brains/codex-gpt-6-luna-high.yaml +5 -0
  396. package/presets/fleet/brains/codex-gpt-6-luna-low.yaml +5 -0
  397. package/presets/fleet/brains/codex-gpt-6-luna-max.yaml +5 -0
  398. package/presets/fleet/brains/codex-gpt-6-luna-medium.yaml +5 -0
  399. package/presets/fleet/brains/codex-gpt-6-luna-xhigh.yaml +5 -0
  400. package/presets/fleet/brains/codex-gpt-6-sol-high.yaml +5 -0
  401. package/presets/fleet/brains/codex-gpt-6-sol-low.yaml +5 -0
  402. package/presets/fleet/brains/codex-gpt-6-sol-max.yaml +5 -0
  403. package/presets/fleet/brains/codex-gpt-6-sol-medium.yaml +5 -0
  404. package/presets/fleet/brains/codex-gpt-6-sol-ultra.yaml +5 -0
  405. package/presets/fleet/brains/codex-gpt-6-sol-xhigh.yaml +5 -0
  406. package/presets/fleet/roles/Coordinator.yaml +12 -11
  407. package/presets/fleet/roles/Critic.yaml +13 -0
  408. package/presets/fleet/roles/Developer.yaml +13 -0
  409. package/presets/fleet/roles/Engineer.yaml +53 -0
  410. package/presets/fleet/room_layouts/engineering.yaml +25 -0
  411. package/presets/fleet/room_layouts/pair.yaml +24 -0
  412. package/presets/fleet/room_layouts/single.yaml +17 -0
  413. package/presets/fleet/room_layouts/team.yaml +30 -0
  414. package/presets/fleet/room_templates/engineering.yaml +19 -0
  415. package/presets/manifest.json +2 -2
  416. package/dist/web-app/assets/index-59GF-gsZ.css +0 -1
  417. package/dist/web-app/assets/index-C0h3ALvs.js +0 -10
  418. package/dist/web-app/icons/ours-fleet-maskable.svg +0 -4
  419. package/dist/web-app/icons/ours-fleet.svg +0 -4
  420. package/dist/web-app/index.html +0 -17
  421. package/dist/web-app/manifest.webmanifest +0 -15
  422. package/dist/web-app/offline.html +0 -18
  423. package/dist/web-app/sw.js +0 -51
@@ -1,5 +1,53 @@
1
1
  import type { ConversationHandlePage, ExitRecord, InterruptOutcome, PromptOrigin, QueuedPrompt, SessionEvent, AgentSession, SessionSnapshot, SubmitPromptOptions, TurnCancellationSource, TurnResult } from './types.js';
2
2
  import type { ConversationEventV1, ConversationSnapshot, PromptReceipt, SubmitPromptCommand } from './conversation-types.js';
3
+ export type ReminderAttempt =
4
+ /** Admitted; `queued.completion` settles when the turn (or its refusal) ends. */
5
+ {
6
+ state: 'admitted';
7
+ queued: QueuedPrompt;
8
+ } | {
9
+ state: 'busy';
10
+ } | {
11
+ state: 'unavailable';
12
+ error: string;
13
+ admitted: false;
14
+ };
15
+ /**
16
+ * The single interruption an urgent reminder may request, as the arbiter saw
17
+ * it. `target` names the exact checked turn; `outcome` is what the session
18
+ * and the target's own terminal result actually reported.
19
+ */
20
+ export interface UrgentInterruptReport {
21
+ target: UrgentInterruptTarget;
22
+ outcome: 'cancelled' | 'ended' | 'forced' | 'failed';
23
+ reason?: string;
24
+ }
25
+ export interface UrgentInterruptTarget {
26
+ source: NonNullable<SessionSnapshot['activePromptSource']>;
27
+ sessionId?: string;
28
+ generation: string;
29
+ promptId: string;
30
+ }
31
+ /** The urgent path's durable seams; every one is synchronous and owned by the reminder store. */
32
+ export interface UrgentReminderHooks {
33
+ /** The durable `admitting` claim (as for `tryReminder`). False: nothing is queued. */
34
+ beforeQueue(): boolean;
35
+ /** Release fence; the only way the prompt reaches the model. */
36
+ releaseGuard(): boolean;
37
+ /** Whether this event may still request its one interruption. */
38
+ mayInterrupt(): boolean;
39
+ /** Durable mark written BEFORE the session is asked to cancel. False: do not cancel. */
40
+ markRequested(target: UrgentInterruptTarget): boolean;
41
+ /** How the requested interruption ended. */
42
+ recordOutcome(report: UrgentInterruptReport): void;
43
+ /** The busy turn was not interruptible this time, and why. */
44
+ deferred(reason: UrgentDeferral): void;
45
+ /** Still this caller's current, undispatched claim? Re-checked after every await. */
46
+ stillAdmitting(): boolean;
47
+ /** The wake text, built once the interruption (if any) is known. */
48
+ text(report?: UrgentInterruptReport): string;
49
+ }
50
+ export type UrgentDeferral = 'protected_turn' | 'untracked_turn' | 'permission_pending' | 'queued_work' | 'session_starting' | 'interrupt_unsupported' | 'uncorrelatable' | 'interrupt_already_used';
3
51
  export type ScheduledAttempt = {
4
52
  state: 'started';
5
53
  queued: QueuedPrompt;
@@ -22,7 +70,12 @@ export declare class RoleTurnArbiter implements AgentSession {
22
70
  readonly capabilities: import("./types.js").AgentSessionCapabilities | undefined;
23
71
  private tail;
24
72
  private unsettled;
73
+ /** Admissions waiting for the boundary; an urgent interruption yields to them. */
74
+ private waiting;
75
+ /** Terminal results of prompts this arbiter admitted and that have not settled yet. */
76
+ private readonly live;
25
77
  private stopping;
78
+ private retiring;
26
79
  /** Bumped by `retireStalledAdmission`; every claim carries the one it was made under. */
27
80
  private generation;
28
81
  /** Resolves the instant the CURRENT generation is retired. */
@@ -53,6 +106,11 @@ export declare class RoleTurnArbiter implements AgentSession {
53
106
  */
54
107
  retireStalledAdmission(): void;
55
108
  queuePrompt(text: string, options?: SubmitPromptOptions): Promise<QueuedPrompt>;
109
+ /** Inbox traffic must not cancel or steer an active human console/voice turn.
110
+ * Queue it once; the monitor commits its cursor after that turn succeeds.
111
+ * Other origins retain their configured monitor policy.
112
+ */
113
+ private monitorAdmissionOptions;
56
114
  submitPrompt(text: string, options?: SubmitPromptOptions): Promise<TurnResult>;
57
115
  /**
58
116
  * Do not hold `exclusive` while ACP waits for a tool boundary: permission
@@ -62,6 +120,40 @@ export declare class RoleTurnArbiter implements AgentSession {
62
120
  tryScheduled(text: string, origin: Extract<PromptOrigin, {
63
121
  kind: 'scheduled-loop';
64
122
  }>, beforeQueue?: () => void | Promise<void>): Promise<ScheduledAttempt>;
123
+ /**
124
+ * Admit a self-reminder wake only into an idle role, at the same boundary
125
+ * every producer uses. It never interrupts or steers, and never joins a
126
+ * queue behind other work: a busy role answers `busy` and the caller tries
127
+ * again later. `beforeQueue` makes the caller's durable claim; if it
128
+ * declines, nothing is queued. `releaseGuard` is the session's last-moment
129
+ * fence and is the only way the prompt can reach the model.
130
+ */
131
+ tryReminder(text: string, origin: Extract<PromptOrigin, {
132
+ kind: 'self-reminder';
133
+ }>, beforeQueue: () => boolean, releaseGuard: () => boolean): Promise<ReminderAttempt>;
134
+ /**
135
+ * Admit an URGENT self-reminder wake. Idle: exactly `tryReminder`. Busy: the
136
+ * reminder may ask the exact checked turn to stop — once per event — and is
137
+ * then admitted at the next boundary like any other reminder.
138
+ *
139
+ * The check and the cancel request happen in one synchronous step inside the
140
+ * admission boundary, so the turn asked to stop is the turn that was checked.
141
+ * Only a running, correlatable, interruptible turn with nothing queued behind
142
+ * it and no admission waiting is ever asked to stop; anything else is a
143
+ * reported deferral (`busy`). After the cancellation the boundary is given up
144
+ * before the wake is queued, so an owner prompt (or any producer) that
145
+ * arrived meanwhile is admitted first and the wake simply finds the role
146
+ * busy. A forced, failed or uncertain cancellation never queues the wake.
147
+ */
148
+ tryUrgentReminder(origin: Extract<PromptOrigin, {
149
+ kind: 'self-reminder';
150
+ }>, hooks: UrgentReminderHooks): Promise<ReminderAttempt>;
151
+ /** The exact interruptible turn, or why there is none. Synchronous by design. */
152
+ private urgentTarget;
153
+ private queueReminder;
154
+ /** Retire only at the same admission boundary used by all prompt producers. */
155
+ retireIfIdle(expired: (snapshot: SessionSnapshot, queueDepth: number) => boolean): Promise<boolean>;
156
+ sharedTurnId(promptId: string): string | undefined;
65
157
  stopScheduledAdmission(): void;
66
158
  isAlive(): boolean;
67
159
  snapshot(): SessionSnapshot;
@@ -70,8 +162,14 @@ export declare class RoleTurnArbiter implements AgentSession {
70
162
  limit?: number;
71
163
  }): ConversationHandlePage;
72
164
  conversationSnapshot(): ConversationSnapshot;
165
+ subscribeConversationFailure(listener: (generation: string) => void): () => void;
166
+ conversationReplayAvailable(expectedGeneration: string): boolean;
167
+ replayConversation(request: import('./conversation-replay.js').ConversationReplayRequest): AsyncIterable<import("./conversation-replay.js").ConversationReplayPage>;
168
+ observeConversation(listener: (state: import('./conversation-types.js').ConversationObservationState) => void): import('./conversation-types.js').ConversationObservation;
73
169
  subscribeConversation(listener: (event: ConversationEventV1) => void): () => void;
74
170
  submitPromptBrowser(command: SubmitPromptCommand): Promise<PromptReceipt>;
171
+ get liveVoiceSupported(): boolean;
172
+ interruptPrompt(generation: string, promptId: string): Promise<InterruptOutcome>;
75
173
  interrupt(source?: TurnCancellationSource): Promise<InterruptOutcome>;
76
174
  respondPermission(permissionId: string, optionId: string): boolean;
77
175
  respondPermissionV2(permissionId: string, optionId: string, sessionGeneration: string): 'accepted' | 'stale';
@@ -1,4 +1,14 @@
1
1
  import { ACP_CANCEL_DEADLINE_EXCEEDED, SessionControlError, interruptOutcome, } from './types.js';
2
+ /**
3
+ * Turn sources an urgent reminder may cancel. Owner-channel requests and the
4
+ * owner console are owner commands: cancelling one finalizes the request and
5
+ * its reply route (owner-channel/channel.ts), which is an owner-visible
6
+ * effect. Startup is the readiness gate, stall-watchdog is mid-recovery, and
7
+ * another self-reminder's turn must not be cancelled by a sibling.
8
+ */
9
+ const URGENT_INTERRUPTIBLE = new Set(['fleet-monitor', 'scheduled-loop', 'local-console']);
10
+ /** How long a settled cancellation may take to surface the target's own terminal result. */
11
+ const URGENT_CORRELATION_MS = 2_000;
2
12
  /**
3
13
  * Raised for admissions that were still waiting on a generation which had to be
4
14
  * retired. It carries `ACP_CANCEL_DEADLINE_EXCEEDED` because that is the only
@@ -28,7 +38,12 @@ export class RoleTurnArbiter {
28
38
  capabilities;
29
39
  tail = Promise.resolve();
30
40
  unsettled = 0;
41
+ /** Admissions waiting for the boundary; an urgent interruption yields to them. */
42
+ waiting = 0;
43
+ /** Terminal results of prompts this arbiter admitted and that have not settled yet. */
44
+ live = new Map();
31
45
  stopping = false;
46
+ retiring = false;
32
47
  /** Bumped by `retireStalledAdmission`; every claim carries the one it was made under. */
33
48
  generation = 0;
34
49
  /** Resolves the instant the CURRENT generation is retired. */
@@ -48,11 +63,18 @@ export class RoleTurnArbiter {
48
63
  */
49
64
  exclusive(operation) {
50
65
  const generation = this.generation;
66
+ this.waiting++;
67
+ let counted = true;
68
+ const uncount = () => { if (counted) {
69
+ counted = false;
70
+ this.waiting = Math.max(0, this.waiting - 1);
71
+ } };
51
72
  const run = Promise.race([this.tail, this.retirement.promise]).then(() => {
73
+ uncount();
52
74
  if (generation !== this.generation)
53
75
  throw new AdmissionRetiredError();
54
76
  return operation();
55
- });
77
+ }, error => { uncount(); throw error; });
56
78
  this.tail = run.then(() => undefined, () => undefined);
57
79
  return run;
58
80
  }
@@ -60,10 +82,12 @@ export class RoleTurnArbiter {
60
82
  const generation = this.generation;
61
83
  this.unsettled++;
62
84
  const completion = queued.completion.finally(() => {
85
+ this.live.delete(queued.promptId);
63
86
  // A retired generation's claims were released in one step already.
64
87
  if (generation === this.generation)
65
88
  this.unsettled = Math.max(0, this.unsettled - 1);
66
89
  });
90
+ this.live.set(queued.promptId, completion);
67
91
  return { ...queued, completion };
68
92
  }
69
93
  /**
@@ -86,10 +110,29 @@ export class RoleTurnArbiter {
86
110
  this.retirement = retirementSignal();
87
111
  this.tail = Promise.resolve();
88
112
  this.unsettled = 0;
113
+ this.waiting = 0;
89
114
  retired.retire();
90
115
  }
91
116
  queuePrompt(text, options = {}) {
92
- return this.exclusive(async () => this.track(await this.session.queuePrompt(text, options)));
117
+ return this.exclusive(async () => {
118
+ if (this.retiring)
119
+ throw new Error('Chat is closing');
120
+ return this.track(await this.session.queuePrompt(text, this.monitorAdmissionOptions(options)));
121
+ });
122
+ }
123
+ /** Inbox traffic must not cancel or steer an active human console/voice turn.
124
+ * Queue it once; the monitor commits its cursor after that turn succeeds.
125
+ * Other origins retain their configured monitor policy.
126
+ */
127
+ monitorAdmissionOptions(options) {
128
+ if (options.origin?.kind !== 'fleet-monitor')
129
+ return options;
130
+ const active = this.session.snapshot().activePromptSource;
131
+ // A self-reminder turn is protected the same way: a retried wake (say the
132
+ // one an urgent reminder just interrupted) queues behind it instead of
133
+ // cancelling it before the agent could inspect and acknowledge.
134
+ return active === 'owner-admin-console' || active === 'self-reminder'
135
+ ? { ...options, interrupt: false, steer: false } : options;
93
136
  }
94
137
  async submitPrompt(text, options = {}) {
95
138
  return (await this.queuePrompt(text, options)).completion;
@@ -99,6 +142,10 @@ export class RoleTurnArbiter {
99
142
  * answers and explicit interrupts must remain able to pass immediately.
100
143
  */
101
144
  submitPromptAfterTool(text, options = {}) {
145
+ if (this.retiring)
146
+ return Promise.reject(new Error('Chat is closing'));
147
+ if (this.monitorAdmissionOptions(options) !== options)
148
+ return this.submitPrompt(text, options);
102
149
  return this.session.submitPromptAfterTool?.(text, options)
103
150
  ?? this.session.submitPrompt(text, { ...options, interrupt: false, steer: false });
104
151
  }
@@ -136,6 +183,179 @@ export class RoleTurnArbiter {
136
183
  throw error;
137
184
  });
138
185
  }
186
+ /**
187
+ * Admit a self-reminder wake only into an idle role, at the same boundary
188
+ * every producer uses. It never interrupts or steers, and never joins a
189
+ * queue behind other work: a busy role answers `busy` and the caller tries
190
+ * again later. `beforeQueue` makes the caller's durable claim; if it
191
+ * declines, nothing is queued. `releaseGuard` is the session's last-moment
192
+ * fence and is the only way the prompt can reach the model.
193
+ */
194
+ async tryReminder(text, origin, beforeQueue, releaseGuard) {
195
+ await new Promise(resolve => setImmediate(resolve));
196
+ return this.exclusive(async () => {
197
+ const snapshot = this.session.snapshot();
198
+ if (this.stopping || this.retiring || !snapshot.alive || snapshot.readiness === 'failed')
199
+ return { state: 'unavailable', error: this.stopping ? 'role is stopping' : 'session is unavailable', admitted: false };
200
+ if (snapshot.readiness !== 'idle' || this.unsettled > 0)
201
+ return { state: 'busy' };
202
+ if (!beforeQueue())
203
+ return { state: 'unavailable', error: 'claim declined', admitted: false };
204
+ try {
205
+ const queued = await this.session.queuePrompt(text, {
206
+ interrupt: false, steer: false, origin, releaseGuard,
207
+ });
208
+ return { state: 'admitted', queued: this.track(queued) };
209
+ }
210
+ catch (error) {
211
+ return { state: 'unavailable', error: error?.message ?? String(error), admitted: false };
212
+ }
213
+ }).catch(error => {
214
+ if (error instanceof AdmissionRetiredError)
215
+ return { state: 'unavailable', error: error.message, admitted: false };
216
+ throw error;
217
+ });
218
+ }
219
+ /**
220
+ * Admit an URGENT self-reminder wake. Idle: exactly `tryReminder`. Busy: the
221
+ * reminder may ask the exact checked turn to stop — once per event — and is
222
+ * then admitted at the next boundary like any other reminder.
223
+ *
224
+ * The check and the cancel request happen in one synchronous step inside the
225
+ * admission boundary, so the turn asked to stop is the turn that was checked.
226
+ * Only a running, correlatable, interruptible turn with nothing queued behind
227
+ * it and no admission waiting is ever asked to stop; anything else is a
228
+ * reported deferral (`busy`). After the cancellation the boundary is given up
229
+ * before the wake is queued, so an owner prompt (or any producer) that
230
+ * arrived meanwhile is admitted first and the wake simply finds the role
231
+ * busy. A forced, failed or uncertain cancellation never queues the wake.
232
+ */
233
+ async tryUrgentReminder(origin, hooks) {
234
+ await new Promise(resolve => setImmediate(resolve));
235
+ const unavailable = (error) => ({ state: 'unavailable', error, admitted: false });
236
+ const first = await this.exclusive(async () => {
237
+ const snapshot = this.session.snapshot();
238
+ if (this.stopping || this.retiring || !snapshot.alive || snapshot.readiness === 'failed')
239
+ return unavailable(this.stopping ? 'role is stopping' : 'session is unavailable');
240
+ if (snapshot.readiness === 'idle' && this.unsettled === 0)
241
+ return this.queueReminder(hooks, origin);
242
+ const deferral = this.urgentTarget(snapshot);
243
+ if (typeof deferral === 'string' || !hooks.mayInterrupt()) {
244
+ hooks.deferred(typeof deferral === 'string' ? deferral : 'interrupt_already_used');
245
+ return { state: 'busy' };
246
+ }
247
+ if (!hooks.beforeQueue())
248
+ return unavailable('claim declined');
249
+ if (!hooks.markRequested(deferral))
250
+ return unavailable('interrupt request not recorded');
251
+ const terminal = this.live.get(deferral.promptId);
252
+ // No await between the check above and this call: the session cancels
253
+ // the turn that was checked, never a successor.
254
+ let report;
255
+ try {
256
+ const outcome = interruptOutcome(await this.session.interrupt('self-reminder'));
257
+ report = outcome.state === 'forced'
258
+ ? { target: deferral, outcome: 'forced', ...(outcome.reasonCode ? { reason: outcome.reasonCode } : {}) }
259
+ : { target: deferral, outcome: await correlate(terminal) };
260
+ }
261
+ catch (error) {
262
+ report = { target: deferral, outcome: 'failed', reason: controlReason(error) };
263
+ }
264
+ hooks.recordOutcome(report);
265
+ return report;
266
+ }).catch(error => {
267
+ if (error instanceof AdmissionRetiredError)
268
+ return unavailable(error.message);
269
+ throw error;
270
+ });
271
+ if ('state' in first)
272
+ return first;
273
+ if (first.outcome === 'forced' || first.outcome === 'failed')
274
+ return unavailable(`interruption ${first.outcome}; the wake was not queued`);
275
+ // Give up the boundary: anything that queued during the cancellation —
276
+ // owner input first among them — is admitted before the wake.
277
+ await new Promise(resolve => setImmediate(resolve));
278
+ return this.exclusive(async () => {
279
+ const snapshot = this.session.snapshot();
280
+ if (this.stopping || this.retiring || !snapshot.alive || snapshot.readiness === 'failed')
281
+ return unavailable(this.stopping ? 'role is stopping' : 'session is unavailable');
282
+ if (!hooks.stillAdmitting())
283
+ return unavailable('reminder changed during the interruption');
284
+ if (snapshot.readiness !== 'idle' || this.unsettled > 0 || this.waiting > 0)
285
+ return { state: 'busy' };
286
+ return this.queueReminder(hooks, origin, first, false);
287
+ }).catch(error => {
288
+ if (error instanceof AdmissionRetiredError)
289
+ return unavailable(error.message);
290
+ throw error;
291
+ });
292
+ }
293
+ /** The exact interruptible turn, or why there is none. Synchronous by design. */
294
+ urgentTarget(snapshot) {
295
+ if (snapshot.readiness === 'starting')
296
+ return 'session_starting';
297
+ if (snapshot.readiness === 'awaiting_permission' || snapshot.pendingPermissionId)
298
+ return 'permission_pending';
299
+ if (snapshot.readiness !== 'running')
300
+ return 'untracked_turn';
301
+ const source = snapshot.activePromptSource;
302
+ if (!source)
303
+ return 'untracked_turn';
304
+ if (!URGENT_INTERRUPTIBLE.has(source))
305
+ return 'protected_turn';
306
+ if (!this.session.capabilities?.interrupt)
307
+ return 'interrupt_unsupported';
308
+ if (this.waiting > 0 || this.unsettled > 1)
309
+ return 'queued_work';
310
+ if (!this.session.observeConversation)
311
+ return 'uncorrelatable';
312
+ let state;
313
+ try {
314
+ const observation = this.session.observeConversation(() => { });
315
+ state = observation.snapshot;
316
+ observation.unsubscribe();
317
+ }
318
+ catch {
319
+ return 'uncorrelatable';
320
+ }
321
+ if (state.pendingPermissions.length || state.pendingPermissionIds.length)
322
+ return 'permission_pending';
323
+ if (state.pendingPromptCount > 0 || state.queueDepth > 1)
324
+ return 'queued_work';
325
+ if (state.activePromptIds.length < 1)
326
+ return 'untracked_turn';
327
+ return {
328
+ source, generation: state.sessionGeneration, promptId: state.activePromptIds[0],
329
+ ...(snapshot.sessionId ? { sessionId: snapshot.sessionId } : {}),
330
+ };
331
+ }
332
+ async queueReminder(hooks, origin, report, claim = true) {
333
+ if (claim && !hooks.beforeQueue())
334
+ return { state: 'unavailable', error: 'claim declined', admitted: false };
335
+ try {
336
+ const queued = await this.session.queuePrompt(hooks.text(report), {
337
+ interrupt: false, steer: false, origin, releaseGuard: () => hooks.releaseGuard(),
338
+ });
339
+ return { state: 'admitted', queued: this.track(queued) };
340
+ }
341
+ catch (error) {
342
+ return { state: 'unavailable', error: error?.message ?? String(error), admitted: false };
343
+ }
344
+ }
345
+ /** Retire only at the same admission boundary used by all prompt producers. */
346
+ retireIfIdle(expired) {
347
+ return this.exclusive(async () => {
348
+ const snapshot = this.session.snapshot();
349
+ const queue = this.session.conversationSnapshot?.().queueDepth ?? -1;
350
+ if (this.retiring || this.unsettled > 0 || snapshot.readiness !== 'idle' || !expired(snapshot, queue))
351
+ return false;
352
+ this.retiring = true;
353
+ this.stopping = true;
354
+ await this.session.close();
355
+ return true;
356
+ });
357
+ }
358
+ sharedTurnId(promptId) { return this.session.sharedTurnId?.(promptId); }
139
359
  stopScheduledAdmission() { this.stopping = true; }
140
360
  isAlive() { return this.session.isAlive(); }
141
361
  snapshot() { return this.session.snapshot(); }
@@ -149,6 +369,24 @@ export class RoleTurnArbiter {
149
369
  throw new Error('conversation snapshot is unavailable');
150
370
  return this.session.conversationSnapshot();
151
371
  }
372
+ subscribeConversationFailure(listener) {
373
+ if (!this.session.subscribeConversationFailure)
374
+ throw new Error('conversation durability observation is unavailable');
375
+ return this.session.subscribeConversationFailure(listener);
376
+ }
377
+ conversationReplayAvailable(expectedGeneration) {
378
+ return this.session.conversationReplayAvailable?.(expectedGeneration) ?? false;
379
+ }
380
+ replayConversation(request) {
381
+ if (!this.session.replayConversation)
382
+ throw new Error('conversation replay is unavailable');
383
+ return this.session.replayConversation(request);
384
+ }
385
+ observeConversation(listener) {
386
+ if (!this.session.observeConversation)
387
+ throw new Error('conversation observation is unavailable');
388
+ return this.session.observeConversation(listener);
389
+ }
152
390
  subscribeConversation(listener) {
153
391
  if (!this.session.subscribeConversation)
154
392
  throw new Error('conversation subscription is unavailable');
@@ -157,7 +395,16 @@ export class RoleTurnArbiter {
157
395
  submitPromptBrowser(command) {
158
396
  if (!this.session.submitPromptBrowser)
159
397
  return Promise.reject(new Error('browser prompt admission is unavailable'));
160
- return this.exclusive(() => this.session.submitPromptBrowser(command));
398
+ return this.exclusive(() => { if (this.retiring)
399
+ throw new Error('Chat is closing'); return this.session.submitPromptBrowser(command); });
400
+ }
401
+ get liveVoiceSupported() { return this.session.liveVoiceSupported === true; }
402
+ interruptPrompt(generation, promptId) {
403
+ return this.exclusive(async () => {
404
+ if (!this.session.interruptPrompt)
405
+ throw new Error('targeted voice interrupt is unavailable');
406
+ return interruptOutcome(await this.session.interruptPrompt(generation, promptId));
407
+ });
161
408
  }
162
409
  interrupt(source = 'local-console') {
163
410
  return this.exclusive(async () => interruptOutcome(await this.session.interrupt(source)));
@@ -175,3 +422,25 @@ export class RoleTurnArbiter {
175
422
  exitResult() { return this.session.exitResult(); }
176
423
  close() { return this.session.close(); }
177
424
  }
425
+ /**
426
+ * Whether the target's own terminal result proves this request cancelled it.
427
+ * A settled interrupt says only that the turn (or nothing) ended; without the
428
+ * target's correlated result the honest answer is `ended`.
429
+ */
430
+ async function correlate(terminal) {
431
+ if (!terminal)
432
+ return 'ended';
433
+ let timer;
434
+ const result = await Promise.race([
435
+ terminal,
436
+ new Promise(resolve => { timer = setTimeout(() => resolve(undefined), URGENT_CORRELATION_MS); timer.unref?.(); }),
437
+ ]);
438
+ if (timer)
439
+ clearTimeout(timer);
440
+ return result?.outcome === 'cancelled' && result.cancellationSource === 'self-reminder' ? 'cancelled' : 'ended';
441
+ }
442
+ function controlReason(error) {
443
+ if (error instanceof SessionControlError)
444
+ return error.reasonCode ?? error.kind;
445
+ return 'control_error';
446
+ }
@@ -1,5 +1,7 @@
1
+ import { type TaskNoticeBinding, type TaskCreatedNotice } from './task-notice.js';
1
2
  import type { CommonPermissions } from '../config.js';
2
- import type { ConversationEventV1, ConversationSnapshot, PromptOrigin, PromptReceipt, SubmitPromptCommand } from './conversation-types.js';
3
+ import type { ConversationEventV1, ConversationObservationState, ConversationSnapshot, PromptOrigin, PromptReceipt, SubmitPromptCommand } from './conversation-types.js';
4
+ import { type PendingPrompt } from './prompt-batch.js';
3
5
  import type { CodexAppServerTransportFactory } from './codex-app-server-transport.js';
4
6
  import type { AgentSession, ConversationHandlePage, ExitRecord, InterruptOutcome, QueuedPrompt, SessionEvent, SessionSnapshot, SubmitPromptOptions, TurnCancellationSource, TurnResult } from './types.js';
5
7
  type JsonObject = Record<string, unknown>;
@@ -10,6 +12,9 @@ export interface CodexAppServerSessionOptions {
10
12
  env: Record<string, string>;
11
13
  stateDir: string;
12
14
  mode: 'fresh' | 'resume';
15
+ requireResume?: boolean;
16
+ /** Hold recovered never-started prompts until activateRecoveredPrompts(). */
17
+ deferRecoveredPrompts?: boolean;
13
18
  permissions: CommonPermissions;
14
19
  permissionMode: NonNullable<SessionSnapshot['permissionMode']>;
15
20
  model?: string | null;
@@ -28,6 +33,16 @@ export interface CodexAppServerSessionOptions {
28
33
  }
29
34
  /** Server-generated application provenance for authenticated browser prompts only. */
30
35
  export declare function nativePromptAdditionalContext(origin: PromptOrigin | undefined): JsonObject | undefined;
36
+ /**
37
+ * Application context for a turn that carries several admitted prompts.
38
+ *
39
+ * The single-prompt context says "the accompanying user text", which would
40
+ * cover every member. A shared turn therefore carries this one entry instead:
41
+ * each member is its own user text item, in order, and its route and exact
42
+ * bytes are stated here by the server. Text imitating this wording is still
43
+ * only user text; it cannot add an application-context entry.
44
+ */
45
+ export declare function nativeBatchAdditionalContext(members: ReadonlyArray<Pick<PendingPrompt, 'text' | 'origin'>>): JsonObject | undefined;
31
46
  /** Native Codex session implementing Fleet's provider-neutral live-session contract. */
32
47
  export declare class CodexAppServerSession implements AgentSession {
33
48
  private readonly options;
@@ -53,7 +68,13 @@ export declare class CodexAppServerSession implements AgentSession {
53
68
  private lastError?;
54
69
  private exit;
55
70
  private queueDepth;
71
+ private readonly deferredRecovered;
72
+ private readonly observation;
56
73
  private promptTail;
74
+ /** Admitted prompts not yet handed to the app-server, in admission order. */
75
+ private readonly pendingPrompts;
76
+ /** Admitted prompt → the turn that carries it, while that turn is open. */
77
+ private readonly sharedTurns;
57
78
  private activeTurn?;
58
79
  private controllerCount;
59
80
  private controllerGrace?;
@@ -67,7 +88,20 @@ export declare class CodexAppServerSession implements AgentSession {
67
88
  isAlive(): boolean;
68
89
  snapshot(): SessionSnapshot;
69
90
  queuePrompt(text: string, options?: SubmitPromptOptions): Promise<QueuedPrompt>;
91
+ /** The turn whose events and result answer this admitted prompt; itself unless a release shared it. */
92
+ sharedTurnId(promptId: string): string | undefined;
93
+ /** Each prompt keeps its own step in the chain; the step it reaches releases a whole snapshot. */
94
+ private enqueue;
95
+ /**
96
+ * The turn boundary: the first waiting prompt to get here synchronously
97
+ * takes every pending prompt delivered with it into one turn. A prompt
98
+ * admitted afterwards stays pending for the next boundary, and a step whose
99
+ * prompt was already taken reports that turn's result.
100
+ */
101
+ private release;
70
102
  submitPrompt(text: string, options?: SubmitPromptOptions): Promise<TurnResult>;
103
+ readonly liveVoiceSupported = true;
104
+ interruptPrompt(generation: string, promptId: string): Promise<InterruptOutcome>;
71
105
  interrupt(source?: TurnCancellationSource): Promise<InterruptOutcome>;
72
106
  respondPermission(permissionId: string, optionId: string): boolean;
73
107
  respondPermissionV2(permissionId: string, optionId: string, sessionGeneration: string): 'accepted' | 'stale';
@@ -76,15 +110,25 @@ export declare class CodexAppServerSession implements AgentSession {
76
110
  setControllerAttached(attached: boolean): void;
77
111
  exitResult(): ExitRecord | null;
78
112
  close(): Promise<void>;
113
+ taskNoticeBinding(): TaskNoticeBinding | undefined;
114
+ recordTaskCreated(binding: TaskNoticeBinding, notice: TaskCreatedNotice): void;
79
115
  conversationPage(request?: {
80
116
  after?: string;
81
117
  limit?: number;
82
118
  }): ConversationHandlePage;
119
+ subscribeConversationFailure(listener: (generation: string) => void): () => void;
120
+ conversationReplayAvailable(expectedGeneration: string): boolean;
121
+ replayConversation(request: import('./conversation-replay.js').ConversationReplayRequest): AsyncGenerator<import("./conversation-replay.js").ConversationReplayPage, any, any>;
122
+ observeConversation(listener: (state: ConversationObservationState) => void): import("./conversation-types.js").ConversationObservation;
123
+ private captureObservation;
83
124
  conversationSnapshot(): ConversationSnapshot;
84
125
  subscribeConversation(listener: (event: ConversationEventV1) => void): () => void;
85
126
  submitPromptBrowser(command: SubmitPromptCommand): Promise<PromptReceipt>;
86
127
  private initialize;
87
128
  private recoverOpenPrompts;
129
+ /** Dispatch recovered prompts once the caller's control plane is listening. */
130
+ activateRecoveredPrompts(): void;
131
+ private dispatchRecovered;
88
132
  private admit;
89
133
  private runPrompt;
90
134
  private steer;