@ours.network/fleet 1.2.0-nightly.6 → 1.2.0-nightly.61

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 (389) hide show
  1. package/README.md +287 -65
  2. package/dist/account-origin.d.ts +2 -0
  3. package/dist/account-origin.js +6 -0
  4. package/dist/agent-ours/bridge.js +35 -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 +4 -0
  11. package/dist/agent-ours/mcp-endpoint.js +5 -0
  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 +21 -1
  15. package/dist/agent-ours/service.js +94 -14
  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 +27 -0
  19. package/dist/application/conversation-history.js +212 -0
  20. package/dist/application/fleet-query-service.d.ts +1 -1
  21. package/dist/application/fleet-query-service.js +2 -2
  22. package/dist/application/legacy-supervisor-identity.d.ts +7 -0
  23. package/dist/application/legacy-supervisor-identity.js +43 -0
  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/role-creation-service.js +3 -2
  30. package/dist/application/role-removal-service.js +9 -1
  31. package/dist/application/role-repository.js +19 -2
  32. package/dist/application/room-layout-definitions.d.ts +45 -0
  33. package/dist/application/room-layout-definitions.js +130 -0
  34. package/dist/application/session-control.d.ts +30 -0
  35. package/dist/application/session-control.js +72 -3
  36. package/dist/application/supervisor-ours-tools.d.ts +159 -0
  37. package/dist/application/supervisor-ours-tools.js +115 -0
  38. package/dist/application/task-layouts.d.ts +91 -0
  39. package/dist/application/task-layouts.js +259 -0
  40. package/dist/application/task-room-service.d.ts +99 -3
  41. package/dist/application/task-room-service.js +285 -32
  42. package/dist/application/types.d.ts +2 -0
  43. package/dist/atomic-file.d.ts +5 -0
  44. package/dist/atomic-file.js +62 -1
  45. package/dist/briefing.d.ts +3 -1
  46. package/dist/briefing.js +70 -30
  47. package/dist/build-info.json +7 -4
  48. package/dist/capabilities.d.ts +6 -1
  49. package/dist/capabilities.js +8 -0
  50. package/dist/cli.js +407 -37
  51. package/dist/client-profile.d.ts +5 -17
  52. package/dist/client-profile.js +4 -127
  53. package/dist/config.d.ts +45 -0
  54. package/dist/config.js +57 -6
  55. package/dist/creation.d.ts +1 -1
  56. package/dist/creation.js +4 -4
  57. package/dist/daemon-recovery.d.ts +1 -8
  58. package/dist/daemon-recovery.js +8 -113
  59. package/dist/docs.d.ts +1 -1
  60. package/dist/docs.js +123 -19
  61. package/dist/doctor.d.ts +1 -1
  62. package/dist/doctor.js +55 -60
  63. package/dist/erased-resources.d.ts +9 -0
  64. package/dist/erased-resources.js +87 -0
  65. package/dist/file-delivery/reader.d.ts +15 -0
  66. package/dist/file-delivery/reader.js +63 -0
  67. package/dist/file-delivery/store.d.ts +15 -0
  68. package/dist/file-delivery/store.js +124 -0
  69. package/dist/file-delivery/types.d.ts +19 -0
  70. package/dist/file-delivery/types.js +1 -0
  71. package/dist/fleet-command-audit.d.ts +7 -0
  72. package/dist/fleet-command-audit.js +26 -9
  73. package/dist/harness/agent-session.d.ts +2 -0
  74. package/dist/harness/claude-code-session.js +1 -1
  75. package/dist/harness/claude-code.js +20 -11
  76. package/dist/harness/claude-runtime.d.ts +12 -0
  77. package/dist/harness/claude-runtime.js +43 -0
  78. package/dist/harness/codex-app-server-proxy.d.ts +4 -1
  79. package/dist/harness/codex-app-server-proxy.js +41 -5
  80. package/dist/harness/codex-reasoning.d.ts +5 -0
  81. package/dist/harness/codex-reasoning.js +12 -0
  82. package/dist/harness/codex-runtime.d.ts +11 -1
  83. package/dist/harness/codex-runtime.js +31 -4
  84. package/dist/harness/codex-session.js +2 -2
  85. package/dist/harness/codex.js +23 -12
  86. package/dist/init-wizard.d.ts +2 -0
  87. package/dist/init-wizard.js +38 -19
  88. package/dist/isolation/policy.js +6 -1
  89. package/dist/isolation/types.d.ts +5 -0
  90. package/dist/managed-cli.d.ts +253 -0
  91. package/dist/managed-cli.js +923 -0
  92. package/dist/managed-recovery.d.ts +13 -0
  93. package/dist/managed-recovery.js +31 -0
  94. package/dist/minimal-setup.d.ts +2 -0
  95. package/dist/minimal-setup.js +44 -0
  96. package/dist/monitor.d.ts +8 -34
  97. package/dist/monitor.js +89 -152
  98. package/dist/notifications/fleet-producer.d.ts +19 -0
  99. package/dist/notifications/fleet-producer.js +208 -0
  100. package/dist/notifications/outbox.d.ts +46 -0
  101. package/dist/notifications/outbox.js +158 -0
  102. package/dist/notifications/target-cleanup.d.ts +8 -0
  103. package/dist/notifications/target-cleanup.js +41 -0
  104. package/dist/notifications/task-producer.d.ts +18 -0
  105. package/dist/notifications/task-producer.js +67 -0
  106. package/dist/ops.d.ts +2 -0
  107. package/dist/ops.js +20 -3
  108. package/dist/owner-channel/channel.js +17 -6
  109. package/dist/owner-channel/commands.d.ts +4 -0
  110. package/dist/owner-channel/commands.js +8 -0
  111. package/dist/owner-channel/lifecycle-outbox.js +4 -3
  112. package/dist/owner-channel/ours-client.js +2 -17
  113. package/dist/paths.d.ts +2 -0
  114. package/dist/paths.js +2 -0
  115. package/dist/preset-migration.js +25 -0
  116. package/dist/resolved-plan.js +1 -0
  117. package/dist/rooms-tasks/add-member.d.ts +48 -0
  118. package/dist/rooms-tasks/add-member.js +83 -0
  119. package/dist/rooms-tasks/archived-absence.d.ts +8 -0
  120. package/dist/rooms-tasks/archived-absence.js +48 -0
  121. package/dist/rooms-tasks/cli.js +65 -5
  122. package/dist/rooms-tasks/close.d.ts +6 -2
  123. package/dist/rooms-tasks/close.js +246 -37
  124. package/dist/rooms-tasks/config.d.ts +1 -1
  125. package/dist/rooms-tasks/config.js +11 -4
  126. package/dist/rooms-tasks/cowork-adapter.d.ts +2 -4
  127. package/dist/rooms-tasks/cowork-adapter.js +7 -121
  128. package/dist/rooms-tasks/cowork-http.js +29 -1
  129. package/dist/rooms-tasks/deletion.d.ts +1 -1
  130. package/dist/rooms-tasks/deletion.js +84 -5
  131. package/dist/rooms-tasks/erasure.d.ts +6 -0
  132. package/dist/rooms-tasks/erasure.js +173 -0
  133. package/dist/rooms-tasks/external-worker.d.ts +1 -1
  134. package/dist/rooms-tasks/external-worker.js +3 -4
  135. package/dist/rooms-tasks/layout-binding-client.d.ts +11 -0
  136. package/dist/rooms-tasks/layout-binding-client.js +56 -0
  137. package/dist/rooms-tasks/layout-binding-grants.d.ts +21 -0
  138. package/dist/rooms-tasks/layout-binding-grants.js +128 -0
  139. package/dist/rooms-tasks/layout-cli.d.ts +4 -0
  140. package/dist/rooms-tasks/layout-cli.js +107 -0
  141. package/dist/rooms-tasks/layout-config.d.ts +11 -0
  142. package/dist/rooms-tasks/layout-config.js +89 -0
  143. package/dist/rooms-tasks/layout-control.d.ts +21 -0
  144. package/dist/rooms-tasks/layout-control.js +52 -0
  145. package/dist/rooms-tasks/layout-member-retirement.d.ts +10 -0
  146. package/dist/rooms-tasks/layout-member-retirement.js +90 -0
  147. package/dist/rooms-tasks/layout-service.d.ts +43 -0
  148. package/dist/rooms-tasks/layout-service.js +203 -0
  149. package/dist/rooms-tasks/layout.d.ts +121 -0
  150. package/dist/rooms-tasks/layout.js +285 -0
  151. package/dist/rooms-tasks/legacy-task-member.d.ts +19 -0
  152. package/dist/rooms-tasks/legacy-task-member.js +116 -0
  153. package/dist/rooms-tasks/live-readiness.d.ts +18 -0
  154. package/dist/rooms-tasks/live-readiness.js +85 -0
  155. package/dist/rooms-tasks/member-ownership.d.ts +5 -0
  156. package/dist/rooms-tasks/member-ownership.js +40 -0
  157. package/dist/rooms-tasks/member-startup.d.ts +1 -0
  158. package/dist/rooms-tasks/member-startup.js +2 -0
  159. package/dist/rooms-tasks/provision.d.ts +3 -0
  160. package/dist/rooms-tasks/provision.js +101 -49
  161. package/dist/rooms-tasks/recovery.d.ts +19 -0
  162. package/dist/rooms-tasks/recovery.js +110 -0
  163. package/dist/rooms-tasks/room-state.d.ts +4 -2
  164. package/dist/rooms-tasks/room-state.js +47 -8
  165. package/dist/rooms-tasks/task-service-retirement.d.ts +11 -0
  166. package/dist/rooms-tasks/task-service-retirement.js +21 -0
  167. package/dist/rooms-tasks/task-state.d.ts +51 -8
  168. package/dist/rooms-tasks/task-state.js +245 -25
  169. package/dist/rooms-tasks/types.d.ts +40 -0
  170. package/dist/rooms-tasks/workspace-artifacts.d.ts +6 -0
  171. package/dist/rooms-tasks/workspace-artifacts.js +93 -0
  172. package/dist/rooms-tasks/workspace.d.ts +35 -0
  173. package/dist/rooms-tasks/workspace.js +325 -0
  174. package/dist/runner.d.ts +25 -3
  175. package/dist/runner.js +291 -49
  176. package/dist/session/acp.d.ts +53 -1
  177. package/dist/session/acp.js +216 -40
  178. package/dist/session/arbiter.d.ts +11 -0
  179. package/dist/session/arbiter.js +43 -2
  180. package/dist/session/codex-app-server.d.ts +32 -0
  181. package/dist/session/codex-app-server.js +137 -23
  182. package/dist/session/control.d.ts +12 -1
  183. package/dist/session/control.js +68 -3
  184. package/dist/session/conversation-normalizer.d.ts +2 -1
  185. package/dist/session/conversation-normalizer.js +1 -1
  186. package/dist/session/conversation-store.d.ts +1 -1
  187. package/dist/session/conversation-store.js +7 -11
  188. package/dist/session/conversation-types.d.ts +28 -3
  189. package/dist/session/prompt-batch.d.ts +63 -0
  190. package/dist/session/prompt-batch.js +86 -0
  191. package/dist/session/task-notice.d.ts +14 -0
  192. package/dist/session/task-notice.js +13 -0
  193. package/dist/session/types.d.ts +14 -0
  194. package/dist/setup-tunnel-preflight.d.ts +34 -0
  195. package/dist/setup-tunnel-preflight.js +62 -0
  196. package/dist/socket-path.d.ts +2 -0
  197. package/dist/socket-path.js +22 -0
  198. package/dist/spawn.d.ts +5 -1
  199. package/dist/spawn.js +40 -4
  200. package/dist/startup-prompt.d.ts +4 -0
  201. package/dist/startup-prompt.js +36 -0
  202. package/dist/startup-readiness.d.ts +13 -0
  203. package/dist/startup-readiness.js +38 -0
  204. package/dist/startup-telemetry.d.ts +16 -0
  205. package/dist/startup-telemetry.js +46 -0
  206. package/dist/subscriptions/cli.d.ts +91 -0
  207. package/dist/subscriptions/cli.js +223 -0
  208. package/dist/subscriptions/launch.d.ts +37 -0
  209. package/dist/subscriptions/launch.js +93 -0
  210. package/dist/subscriptions/login.d.ts +75 -0
  211. package/dist/subscriptions/login.js +182 -0
  212. package/dist/subscriptions/observed.d.ts +7 -0
  213. package/dist/subscriptions/observed.js +44 -0
  214. package/dist/subscriptions/probe.d.ts +10 -0
  215. package/dist/subscriptions/probe.js +73 -0
  216. package/dist/subscriptions/service.d.ts +102 -0
  217. package/dist/subscriptions/service.js +364 -0
  218. package/dist/subscriptions/store.d.ts +71 -0
  219. package/dist/subscriptions/store.js +140 -0
  220. package/dist/supervisor/adoption.d.ts +8 -0
  221. package/dist/supervisor/adoption.js +78 -0
  222. package/dist/supervisor/catalog.d.ts +62 -0
  223. package/dist/supervisor/catalog.js +254 -0
  224. package/dist/supervisor/fleet.d.ts +8 -0
  225. package/dist/supervisor/fleet.js +89 -0
  226. package/dist/supervisor/index.js +3 -6
  227. package/dist/supervisor/launchd.d.ts +1 -1
  228. package/dist/supervisor/launchd.js +26 -13
  229. package/dist/supervisor/legacy.d.ts +35 -0
  230. package/dist/supervisor/legacy.js +524 -0
  231. package/dist/supervisor/manager.d.ts +15 -0
  232. package/dist/supervisor/manager.js +270 -0
  233. package/dist/supervisor/scope.d.ts +4 -0
  234. package/dist/supervisor/scope.js +10 -0
  235. package/dist/supervisor/systemd.d.ts +2 -2
  236. package/dist/supervisor/systemd.js +19 -33
  237. package/dist/task-supervision.d.ts +9 -0
  238. package/dist/task-supervision.js +145 -0
  239. package/dist/temp-idle.d.ts +17 -0
  240. package/dist/temp-idle.js +42 -0
  241. package/dist/temp-lifecycle.d.ts +23 -8
  242. package/dist/temp-lifecycle.js +113 -65
  243. package/dist/temp-supervisor-recovery.d.ts +1 -1
  244. package/dist/temp-supervisor-recovery.js +2 -2
  245. package/dist/tunnel-setup-completion.d.ts +7 -0
  246. package/dist/tunnel-setup-completion.js +13 -0
  247. package/dist/tunnel-setup-input.d.ts +19 -0
  248. package/dist/tunnel-setup-input.js +124 -0
  249. package/dist/web/agent-attachments.d.ts +29 -0
  250. package/dist/web/agent-attachments.js +162 -0
  251. package/dist/web/auth.d.ts +63 -2
  252. package/dist/web/auth.js +191 -10
  253. package/dist/web/available-port.d.ts +2 -0
  254. package/dist/web/available-port.js +23 -0
  255. package/dist/web/control.d.ts +3 -3
  256. package/dist/web/control.js +10 -8
  257. package/dist/web/fleet-config-service.d.ts +4 -1
  258. package/dist/web/fleet-config-service.js +46 -15
  259. package/dist/web/prefix-gateway.d.ts +32 -0
  260. package/dist/web/prefix-gateway.js +238 -0
  261. package/dist/web/runtime.d.ts +3 -1
  262. package/dist/web/runtime.js +116 -31
  263. package/dist/web/server.d.ts +16 -0
  264. package/dist/web/server.js +654 -55
  265. package/dist/web/service.d.ts +11 -2
  266. package/dist/web/service.js +30 -4
  267. package/dist/web/workspace-devices.d.ts +107 -0
  268. package/dist/web/workspace-devices.js +277 -0
  269. package/dist/web/workspace-tunnel.d.ts +1 -0
  270. package/dist/web/workspace-tunnel.js +34 -0
  271. package/dist/workspace-enrollment.d.ts +82 -0
  272. package/dist/workspace-enrollment.js +566 -0
  273. package/dist/workspace-replacement.d.ts +66 -0
  274. package/dist/workspace-replacement.js +220 -0
  275. package/docs/acp-files.md +146 -0
  276. package/docs/fleet-migration.md +54 -0
  277. package/docs/live-voice.md +13 -0
  278. package/docs/room-layouts.md +227 -0
  279. package/docs/task-workspaces.md +225 -0
  280. package/docs/validation/managed-cli-permissions.md +421 -0
  281. package/examples/room-layouts/fresh.yaml +27 -0
  282. package/examples/room-layouts/scoped.yaml +21 -0
  283. package/examples/room-layouts/shared.yaml +19 -0
  284. package/package.json +20 -19
  285. package/presets/README.md +78 -0
  286. package/presets/brain-catalog.json +8 -2
  287. package/presets/fleet/agent_templates/Critic.yaml +1 -1
  288. package/presets/fleet/agent_templates/Developer.yaml +1 -1
  289. package/presets/fleet/agent_templates/Engineer.yaml +5 -0
  290. package/presets/fleet/agent_templates/LocalCoordinator.yaml +1 -1
  291. package/presets/fleet/agents/FleetCoordinator.yaml +1 -1
  292. package/presets/fleet/brains/claude-fable-5-1-high.yaml +5 -0
  293. package/presets/fleet/brains/claude-fable-5-1-low.yaml +5 -0
  294. package/presets/fleet/brains/claude-fable-5-1-max.yaml +5 -0
  295. package/presets/fleet/brains/claude-fable-5-1-medium.yaml +5 -0
  296. package/presets/fleet/brains/claude-fable-5-1-xhigh.yaml +5 -0
  297. package/presets/fleet/brains/claude-fable-5-high.yaml +1 -1
  298. package/presets/fleet/brains/claude-fable-5-low.yaml +1 -1
  299. package/presets/fleet/brains/claude-fable-5-max.yaml +1 -1
  300. package/presets/fleet/brains/claude-fable-5-medium.yaml +1 -1
  301. package/presets/fleet/brains/claude-fable-5-xhigh.yaml +1 -1
  302. package/presets/fleet/brains/claude-haiku-4-5-20251001-default.yaml +4 -0
  303. package/presets/fleet/brains/claude-opus-5-5-high.yaml +5 -0
  304. package/presets/fleet/brains/claude-opus-5-5-low.yaml +5 -0
  305. package/presets/fleet/brains/claude-opus-5-5-max.yaml +5 -0
  306. package/presets/fleet/brains/claude-opus-5-5-medium.yaml +5 -0
  307. package/presets/fleet/brains/claude-opus-5-5-xhigh.yaml +5 -0
  308. package/presets/fleet/brains/claude-opus-5-high.yaml +1 -1
  309. package/presets/fleet/brains/claude-opus-5-low.yaml +1 -1
  310. package/presets/fleet/brains/claude-opus-5-max.yaml +1 -1
  311. package/presets/fleet/brains/claude-opus-5-medium.yaml +1 -1
  312. package/presets/fleet/brains/claude-opus-5-xhigh.yaml +1 -1
  313. package/presets/fleet/brains/claude-sonnet-5-high.yaml +1 -1
  314. package/presets/fleet/brains/claude-sonnet-5-low.yaml +1 -1
  315. package/presets/fleet/brains/claude-sonnet-5-max.yaml +1 -1
  316. package/presets/fleet/brains/claude-sonnet-5-medium.yaml +1 -1
  317. package/presets/fleet/brains/claude-sonnet-5-xhigh.yaml +1 -1
  318. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-high.yaml +1 -1
  319. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-low.yaml +1 -1
  320. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-medium.yaml +1 -1
  321. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-xhigh.yaml +1 -1
  322. package/presets/fleet/brains/codex-gpt-5-4-high.yaml +1 -1
  323. package/presets/fleet/brains/codex-gpt-5-4-low.yaml +1 -1
  324. package/presets/fleet/brains/codex-gpt-5-4-medium.yaml +1 -1
  325. package/presets/fleet/brains/codex-gpt-5-4-mini-high.yaml +1 -1
  326. package/presets/fleet/brains/codex-gpt-5-4-mini-low.yaml +1 -1
  327. package/presets/fleet/brains/codex-gpt-5-4-mini-medium.yaml +1 -1
  328. package/presets/fleet/brains/codex-gpt-5-4-mini-xhigh.yaml +1 -1
  329. package/presets/fleet/brains/codex-gpt-5-4-xhigh.yaml +1 -1
  330. package/presets/fleet/brains/codex-gpt-5-5-high.yaml +1 -1
  331. package/presets/fleet/brains/codex-gpt-5-5-low.yaml +1 -1
  332. package/presets/fleet/brains/codex-gpt-5-5-medium.yaml +1 -1
  333. package/presets/fleet/brains/codex-gpt-5-5-xhigh.yaml +1 -1
  334. package/presets/fleet/brains/codex-gpt-5-6-luna-high.yaml +1 -1
  335. package/presets/fleet/brains/codex-gpt-5-6-luna-low.yaml +1 -1
  336. package/presets/fleet/brains/codex-gpt-5-6-luna-max.yaml +1 -1
  337. package/presets/fleet/brains/codex-gpt-5-6-luna-medium.yaml +1 -1
  338. package/presets/fleet/brains/codex-gpt-5-6-luna-xhigh.yaml +1 -1
  339. package/presets/fleet/brains/codex-gpt-5-6-sol-high.yaml +1 -1
  340. package/presets/fleet/brains/codex-gpt-5-6-sol-low.yaml +1 -1
  341. package/presets/fleet/brains/codex-gpt-5-6-sol-max.yaml +1 -1
  342. package/presets/fleet/brains/codex-gpt-5-6-sol-medium.yaml +1 -1
  343. package/presets/fleet/brains/codex-gpt-5-6-sol-ultra.yaml +1 -1
  344. package/presets/fleet/brains/codex-gpt-5-6-sol-xhigh.yaml +1 -1
  345. package/presets/fleet/brains/codex-gpt-5-6-terra-high.yaml +1 -1
  346. package/presets/fleet/brains/codex-gpt-5-6-terra-low.yaml +1 -1
  347. package/presets/fleet/brains/codex-gpt-5-6-terra-max.yaml +1 -1
  348. package/presets/fleet/brains/codex-gpt-5-6-terra-medium.yaml +1 -1
  349. package/presets/fleet/brains/codex-gpt-5-6-terra-ultra.yaml +1 -1
  350. package/presets/fleet/brains/codex-gpt-5-6-terra-xhigh.yaml +1 -1
  351. package/presets/fleet/brains/codex-gpt-6-1-sol-high.yaml +5 -0
  352. package/presets/fleet/brains/codex-gpt-6-1-sol-low.yaml +5 -0
  353. package/presets/fleet/brains/codex-gpt-6-1-sol-max.yaml +5 -0
  354. package/presets/fleet/brains/codex-gpt-6-1-sol-medium.yaml +5 -0
  355. package/presets/fleet/brains/codex-gpt-6-1-sol-ultra.yaml +5 -0
  356. package/presets/fleet/brains/codex-gpt-6-1-sol-xhigh.yaml +5 -0
  357. package/presets/fleet/brains/codex-gpt-6-astra-high.yaml +1 -1
  358. package/presets/fleet/brains/codex-gpt-6-astra-low.yaml +1 -1
  359. package/presets/fleet/brains/codex-gpt-6-astra-max.yaml +1 -1
  360. package/presets/fleet/brains/codex-gpt-6-astra-medium.yaml +1 -1
  361. package/presets/fleet/brains/codex-gpt-6-astra-ultra.yaml +1 -1
  362. package/presets/fleet/brains/codex-gpt-6-astra-xhigh.yaml +1 -1
  363. package/presets/fleet/brains/codex-gpt-6-luna-high.yaml +5 -0
  364. package/presets/fleet/brains/codex-gpt-6-luna-low.yaml +5 -0
  365. package/presets/fleet/brains/codex-gpt-6-luna-max.yaml +5 -0
  366. package/presets/fleet/brains/codex-gpt-6-luna-medium.yaml +5 -0
  367. package/presets/fleet/brains/codex-gpt-6-luna-xhigh.yaml +5 -0
  368. package/presets/fleet/brains/codex-gpt-6-sol-high.yaml +5 -0
  369. package/presets/fleet/brains/codex-gpt-6-sol-low.yaml +5 -0
  370. package/presets/fleet/brains/codex-gpt-6-sol-max.yaml +5 -0
  371. package/presets/fleet/brains/codex-gpt-6-sol-medium.yaml +5 -0
  372. package/presets/fleet/brains/codex-gpt-6-sol-ultra.yaml +5 -0
  373. package/presets/fleet/brains/codex-gpt-6-sol-xhigh.yaml +5 -0
  374. package/presets/fleet/roles/Coordinator.yaml +34 -11
  375. package/presets/fleet/roles/Engineer.yaml +40 -0
  376. package/presets/fleet/room_layouts/engineering.yaml +25 -0
  377. package/presets/fleet/room_layouts/pair.yaml +24 -0
  378. package/presets/fleet/room_layouts/single.yaml +17 -0
  379. package/presets/fleet/room_layouts/team.yaml +30 -0
  380. package/presets/fleet/room_templates/engineering.yaml +19 -0
  381. package/presets/manifest.json +2 -2
  382. package/dist/web-app/assets/index-59GF-gsZ.css +0 -1
  383. package/dist/web-app/assets/index-C0h3ALvs.js +0 -10
  384. package/dist/web-app/icons/ours-fleet-maskable.svg +0 -4
  385. package/dist/web-app/icons/ours-fleet.svg +0 -4
  386. package/dist/web-app/index.html +0 -17
  387. package/dist/web-app/manifest.webmanifest +0 -15
  388. package/dist/web-app/offline.html +0 -18
  389. package/dist/web-app/sw.js +0 -51
@@ -1,5 +1,5 @@
1
1
  import type * as acp from '@agentclientprotocol/sdk';
2
- import type { AdapterMeta, ConversationEventKind, ConversationPayload } from './conversation-types.js';
2
+ import type { AdapterMeta, BoundedJson, ConversationEventKind, ConversationPayload } from './conversation-types.js';
3
3
  /**
4
4
  * Reduce one ACP v1 `session/update` into one conversation-domain event draft.
5
5
  *
@@ -43,4 +43,5 @@ export interface NormalizedUpdate {
43
43
  toolCallId?: string;
44
44
  adapterMeta?: AdapterMeta[];
45
45
  }
46
+ export declare function boundedJson(value: unknown): BoundedJson;
46
47
  export declare function normalizeSessionUpdate(update: acp.SessionUpdate, options?: NormalizeOptions): NormalizedUpdate;
@@ -246,7 +246,7 @@ function redactSensitiveJson(value) {
246
246
  };
247
247
  return { value: visit(value, 0), redacted };
248
248
  }
249
- function boundedJson(value) {
249
+ export function boundedJson(value) {
250
250
  let serialized;
251
251
  let safe;
252
252
  let redacted = false;
@@ -29,6 +29,7 @@ type EventDraft = Omit<ConversationEventV1, 'schemaVersion' | 'roleId' | 'eventI
29
29
  export declare class ConversationEventStore {
30
30
  private readonly dir;
31
31
  private nextSeq;
32
+ private firstAvailableSeq?;
32
33
  private segments;
33
34
  private tail;
34
35
  private readonly listeners;
@@ -81,7 +82,6 @@ export declare class ConversationEventStore {
81
82
  private trackPromptState;
82
83
  private segmentFd;
83
84
  private writeManifest;
84
- private firstStoredSeq;
85
85
  private eventsAfter;
86
86
  private markDegraded;
87
87
  }
@@ -24,6 +24,7 @@ export class IdempotencyConflictError extends Error {
24
24
  export class ConversationEventStore {
25
25
  dir;
26
26
  nextSeq = 1;
27
+ firstAvailableSeq;
27
28
  segments = [];
28
29
  tail = [];
29
30
  listeners = new Set();
@@ -72,6 +73,7 @@ export class ConversationEventStore {
72
73
  const fd = this.segmentFd(Buffer.byteLength(line));
73
74
  writeSync(fd, line);
74
75
  fsyncSync(fd);
76
+ this.firstAvailableSeq ??= event.seq;
75
77
  this.nextSeq++;
76
78
  this.activeBytes += Buffer.byteLength(line);
77
79
  this.tail.push(event);
@@ -101,7 +103,10 @@ export class ConversationEventStore {
101
103
  const events = this.eventsAfter(after, limit + 1);
102
104
  const hasMore = events.length > limit;
103
105
  const pageEvents = hasMore ? events.slice(0, limit) : events;
104
- const firstStored = this.firstStoredSeq();
106
+ // This single-writer store never removes retained segments. Recovery and
107
+ // append already know the first readable sequence; paging the memory tail
108
+ // must not parse the first segment again, especially while skipping replay.
109
+ const firstStored = this.firstAvailableSeq;
105
110
  return {
106
111
  events: pageEvents,
107
112
  ...(firstStored !== undefined ? { firstAvailableCursor: String(firstStored) } : {}),
@@ -159,6 +164,7 @@ export class ConversationEventStore {
159
164
  let maxSeq = 0;
160
165
  for (const segment of this.segments) {
161
166
  for (const event of this.readSegment(segment)) {
167
+ this.firstAvailableSeq ??= event.seq;
162
168
  maxSeq = Math.max(maxSeq, event.seq);
163
169
  this.tail.push(event);
164
170
  if (this.tail.length > TAIL_EVENTS)
@@ -308,16 +314,6 @@ export class ConversationEventStore {
308
314
  }
309
315
  }
310
316
  // ── reads ──────────────────────────────────────────────────────────────────
311
- firstStoredSeq() {
312
- if (this.tail.length && this.tail[0].seq === 1)
313
- return 1;
314
- for (const segment of this.segments) {
315
- const events = this.readSegment(segment);
316
- if (events.length)
317
- return events[0].seq;
318
- }
319
- return this.tail[0]?.seq;
320
- }
321
317
  eventsAfter(after, limit) {
322
318
  // Serve from the in-memory tail whenever the range allows it.
323
319
  if (this.tail.length && after >= this.tail[0].seq - 1)
@@ -1,3 +1,4 @@
1
+ import type { TaskCreatedNotice } from './task-notice.js';
1
2
  import type { PromptOrigin, TurnCancellationSource, TurnOutcome } from './types.js';
2
3
  /**
3
4
  * Durable conversation domain schema for managed-session consoles.
@@ -7,11 +8,11 @@ import type { PromptOrigin, TurnCancellationSource, TurnOutcome } from './types.
7
8
  * file touches the wire: transport updates are reduced into these shapes by a
8
9
  * session adapter, and the store assigns `seq`/`eventId`/timestamps.
9
10
  */
10
- export type ConversationEventKind = 'prompt.admitted' | 'prompt.started' | 'prompt.interrupt_requested' | 'message.chunk' | 'message.replace' | 'thought.chunk' | 'thought.replace' | 'plan.replace' | 'tool.upsert' | 'tool.content_chunk' | 'permission.requested' | 'permission.resolved' | 'monitor.delivery' | 'usage.updated' | 'turn.state' | 'turn.completed' | 'session.state' | 'session.info' | 'capabilities.updated' | 'error'
11
+ export type ConversationEventKind = 'prompt.admitted' | 'prompt.started' | 'prompt.interrupt_requested' | 'message.chunk' | 'message.replace' | 'thought.chunk' | 'thought.replace' | 'plan.replace' | 'tool.upsert' | 'tool.content_chunk' | 'permission.requested' | 'permission.resolved' | 'file.attached' | 'fleet.task_created' | 'monitor.delivery' | 'usage.updated' | 'turn.state' | 'turn.completed' | 'session.state' | 'session.info' | 'capabilities.updated' | 'error'
11
12
  /** A well-formed transport update this version cannot represent. Bounded, never a crash. */
12
13
  | 'unsupported';
13
14
  /** Where a conversation record came from. Typed provenance, never prompt text. */
14
- export type ConversationSource = 'owner_admin_console' | 'owner_channel' | 'fleet_monitor' | 'scheduled_loop' | 'startup' | 'local_console' | 'agent' | 'agent_replay';
15
+ export type ConversationSource = 'owner_admin_console' | 'owner_channel' | 'fleet_monitor' | 'scheduled_loop' | 'startup' | 'local_console' | 'agent' | 'agent_replay' | 'fleet_lifecycle';
15
16
  export interface NormalizedText {
16
17
  type: 'text';
17
18
  text: string;
@@ -175,6 +176,12 @@ export interface PromptAdmittedPayload {
175
176
  }
176
177
  export interface PromptStartedPayload {
177
178
  queuedBehind?: number;
179
+ /** Present when one adapter turn carries several admitted prompts; `turnId` is the shared turn. */
180
+ batch?: {
181
+ turnId: string;
182
+ index: number;
183
+ size: number;
184
+ };
178
185
  }
179
186
  export interface PromptInterruptRequestedPayload {
180
187
  commandId?: string;
@@ -227,7 +234,9 @@ export interface BoundedJson {
227
234
  digest?: string;
228
235
  redacted?: true;
229
236
  }
230
- export type ConversationPayload = MessageChunkPayload | ThoughtChunkPayload | PlanReplacePayload | ToolUpsertPayload | UsageUpdatedPayload | SessionStatePayload | SessionInfoPayload | CapabilitiesUpdatedPayload | UnsupportedPayload | PromptAdmittedPayload | PromptStartedPayload | PromptInterruptRequestedPayload | PermissionRequestedPayload | PermissionResolvedPayload | TurnStatePayload | TurnCompletedPayload | MonitorDeliveryPayload | SessionLifecyclePayload | ErrorPayload;
237
+ export type ConversationPayload = {
238
+ attachment: import('../file-delivery/types.js').DeliveredFile;
239
+ } | MessageChunkPayload | ThoughtChunkPayload | PlanReplacePayload | ToolUpsertPayload | UsageUpdatedPayload | SessionStatePayload | SessionInfoPayload | CapabilitiesUpdatedPayload | UnsupportedPayload | PromptAdmittedPayload | PromptStartedPayload | PromptInterruptRequestedPayload | PermissionRequestedPayload | PermissionResolvedPayload | TurnStatePayload | TurnCompletedPayload | MonitorDeliveryPayload | SessionLifecyclePayload | ErrorPayload | TaskCreatedNotice;
231
240
  export interface ConversationEventV1 {
232
241
  schemaVersion: 1;
233
242
  roleId: string;
@@ -262,6 +271,9 @@ export interface ConversationEventV1 {
262
271
  adapterMeta?: AdapterMeta[];
263
272
  }
264
273
  export interface SubmitPromptCommand {
274
+ expectedSessionGeneration?: string;
275
+ /** Live speech must not silently queue behind an unrelated turn. */
276
+ requireIdle?: boolean;
265
277
  /** Idempotency-Key / clientRequestId. Reuse with a different body is a conflict. */
266
278
  commandId: string;
267
279
  text: string;
@@ -283,12 +295,25 @@ export interface PermissionDecisionCommand {
283
295
  sessionGeneration: string;
284
296
  optionId: string;
285
297
  }
298
+ /** One admitted prompt not yet handed to the agent, as reported by the queue that owns it. */
299
+ export interface PendingPromptSummary {
300
+ promptId: string;
301
+ source: ConversationSource;
302
+ admittedAt: string;
303
+ bytes: number;
304
+ /** A bounded preview, present only for a body the ledger already holds. */
305
+ text?: string;
306
+ textTruncated?: boolean;
307
+ }
286
308
  export interface ConversationSnapshot {
287
309
  sessionGeneration: string;
288
310
  readiness: 'starting' | 'idle' | 'running' | 'awaiting_permission' | 'failed' | 'offline';
289
311
  queueDepth: number;
290
312
  pendingPermissionIds: string[];
291
313
  historyDegraded?: boolean;
314
+ /** Every waiting prompt, in delivery order; `pendingPromptCount` equals its length. */
315
+ pendingPrompts?: PendingPromptSummary[];
316
+ pendingPromptCount?: number;
292
317
  }
293
318
  export interface ConversationPage {
294
319
  events: ConversationEventV1[];
@@ -0,0 +1,63 @@
1
+ import type { ConversationSource, PendingPromptSummary } from './conversation-types.js';
2
+ import type { PromptOrigin, TurnResult } from './types.js';
3
+ /**
4
+ * A prompt the session has admitted and not yet handed to the adapter.
5
+ *
6
+ * Every admitted prompt keeps its own id, ledger records and completion. What
7
+ * changes at a turn boundary is how many of them one adapter turn carries.
8
+ */
9
+ export interface PendingPrompt {
10
+ promptId: string;
11
+ text: string;
12
+ origin?: PromptOrigin;
13
+ source: ConversationSource;
14
+ /** Whether the ledger already holds this body; an external body is never copied out of the queue. */
15
+ persistBody: boolean;
16
+ admittedAt: string;
17
+ /** Whether the session recognised the text, at admission, as one of its own control operations. */
18
+ command?: boolean;
19
+ /** Set when a release takes this prompt; every member of that turn shares it. */
20
+ released?: Promise<TurnResult>;
21
+ }
22
+ /**
23
+ * How a waiting prompt takes part in a release.
24
+ *
25
+ * - `message`: something a person or a peer route submitted for the agent to
26
+ * read — the paired console, the owner channel, the local console, a
27
+ * monitor wake. Every waiting message is delivered at one boundary, in
28
+ * admission order, whatever its route.
29
+ * - `command`: a control operation the session itself supports — the native
30
+ * `/compact`, a command the ACP adapter advertised. It must reach the
31
+ * adapter as the entire prompt, so it is its own turn and a boundary
32
+ * between the messages before and after it. The session decides this at
33
+ * admission; text that merely starts with a slash is an ordinary message.
34
+ * - `internal`: startup, scheduled-loop and stall-watchdog prompts. They own
35
+ * their turn's lifecycle (and, for a loop, the redaction of its whole
36
+ * transcript), run alone, and never split the messages around them.
37
+ */
38
+ export type PromptClass = 'message' | 'command' | 'internal';
39
+ export declare function promptClass(prompt: Pick<PendingPrompt, 'origin' | 'command'>): PromptClass;
40
+ /** The command name a prompt invokes, when its whole text has the shape of one. */
41
+ export declare function commandName(text: string): string | undefined;
42
+ /**
43
+ * Detach, in admission order, every pending prompt that is delivered with
44
+ * `head`. Synchronous on purpose: this is the snapshot boundary, and a prompt
45
+ * admitted after it returns belongs to the next release.
46
+ */
47
+ export declare function takeBatch(pending: PendingPrompt[], head: PendingPrompt): PendingPrompt[];
48
+ /** Exact, server-computed identity of one member's body inside a shared turn. */
49
+ export interface MemberBinding {
50
+ index: number;
51
+ of: number;
52
+ source: ConversationSource;
53
+ bytes: number;
54
+ sha256: string;
55
+ }
56
+ export declare function memberBindings(members: ReadonlyArray<Pick<PendingPrompt, 'text' | 'origin'>>, sourceOf: (origin: PromptOrigin | undefined) => ConversationSource): MemberBinding[];
57
+ /** What the server asserts about a member's route; never derived from the member's text. */
58
+ export declare function memberAuthority(source: ConversationSource): string;
59
+ /** What a client may show for prompts still waiting: all of them, in order, and never an unpersisted body. */
60
+ export declare function pendingInventory(pending: readonly PendingPrompt[]): {
61
+ pendingPrompts: PendingPromptSummary[];
62
+ pendingPromptCount: number;
63
+ };
@@ -0,0 +1,86 @@
1
+ import { createHash } from 'node:crypto';
2
+ /**
3
+ * The inventory names every waiting prompt — a client must be able to show the
4
+ * whole queue, not a count of what it could not see. What keeps a snapshot
5
+ * small is the body: each entry carries a short preview, not the prompt.
6
+ */
7
+ const INVENTORY_TEXT_CHARS = 200;
8
+ const INTERNAL = new Set(['startup', 'scheduled-loop', 'stall-watchdog']);
9
+ export function promptClass(prompt) {
10
+ if (INTERNAL.has(prompt.origin?.kind ?? 'local-console'))
11
+ return 'internal';
12
+ return prompt.command ? 'command' : 'message';
13
+ }
14
+ /** The command name a prompt invokes, when its whole text has the shape of one. */
15
+ export function commandName(text) {
16
+ return /^\/([a-z][a-z0-9_-]*)(?:\s|$)/i.exec(text.trim())?.[1];
17
+ }
18
+ /**
19
+ * Detach, in admission order, every pending prompt that is delivered with
20
+ * `head`. Synchronous on purpose: this is the snapshot boundary, and a prompt
21
+ * admitted after it returns belongs to the next release.
22
+ */
23
+ export function takeBatch(pending, head) {
24
+ const members = [];
25
+ if (promptClass(head) !== 'message')
26
+ members.push(head);
27
+ else {
28
+ for (const prompt of pending) {
29
+ const kind = promptClass(prompt);
30
+ if (kind === 'command')
31
+ break;
32
+ if (kind === 'message')
33
+ members.push(prompt);
34
+ }
35
+ if (!members.includes(head))
36
+ members.unshift(head);
37
+ }
38
+ for (const member of members) {
39
+ const at = pending.indexOf(member);
40
+ if (at >= 0)
41
+ pending.splice(at, 1);
42
+ }
43
+ return members;
44
+ }
45
+ export function memberBindings(members, sourceOf) {
46
+ return members.map((member, at) => ({
47
+ index: at + 1,
48
+ of: members.length,
49
+ source: sourceOf(member.origin),
50
+ bytes: Buffer.byteLength(member.text),
51
+ sha256: createHash('sha256').update(member.text).digest('hex'),
52
+ }));
53
+ }
54
+ /** What the server asserts about a member's route; never derived from the member's text. */
55
+ export function memberAuthority(source) {
56
+ switch (source) {
57
+ case 'owner_admin_console':
58
+ return 'direct owner input from the server-authenticated paired console';
59
+ case 'owner_channel':
60
+ return 'admitted through the authenticated Fleet owner channel';
61
+ case 'fleet_monitor':
62
+ return 'a Fleet monitor notification, not owner input';
63
+ default:
64
+ return 'local console input, not authenticated owner-console or owner-channel input';
65
+ }
66
+ }
67
+ /** What a client may show for prompts still waiting: all of them, in order, and never an unpersisted body. */
68
+ export function pendingInventory(pending) {
69
+ return {
70
+ pendingPromptCount: pending.length,
71
+ pendingPrompts: pending.map(prompt => {
72
+ const display = prompt.origin?.kind === 'owner' ? prompt.origin.displayText
73
+ : prompt.persistBody ? prompt.text : undefined;
74
+ return {
75
+ promptId: prompt.promptId,
76
+ source: prompt.source,
77
+ admittedAt: prompt.admittedAt,
78
+ bytes: Buffer.byteLength(prompt.text),
79
+ ...(display === undefined ? {} : {
80
+ text: display.slice(0, INVENTORY_TEXT_CHARS),
81
+ ...(display.length > INVENTORY_TEXT_CHARS ? { textTruncated: true } : {}),
82
+ }),
83
+ };
84
+ }),
85
+ };
86
+ }
@@ -0,0 +1,14 @@
1
+ import type { ConversationEventStore } from './conversation-store.js';
2
+ export interface TaskNoticeBinding {
3
+ sessionGeneration: string;
4
+ acpSessionId: string;
5
+ promptId: string;
6
+ }
7
+ export interface TaskCreatedNotice {
8
+ operationId: string;
9
+ taskId: string;
10
+ title: string;
11
+ state: string;
12
+ }
13
+ /** Only the trusted Fleet audit completion calls this, never model output. */
14
+ export declare function appendTaskCreated(store: ConversationEventStore, binding: TaskNoticeBinding, notice: TaskCreatedNotice): void;
@@ -0,0 +1,13 @@
1
+ /** Only the trusted Fleet audit completion calls this, never model output. */
2
+ export function appendTaskCreated(store, binding, notice) {
3
+ let after;
4
+ do {
5
+ const page = store.page({ after, limit: 1000 });
6
+ if (page.events.some(e => e.kind === 'fleet.task_created' && e.payload.operationId === notice.operationId))
7
+ return;
8
+ if (!page.hasMore)
9
+ break;
10
+ after = page.nextCursor;
11
+ } while (after);
12
+ store.append({ kind: 'fleet.task_created', source: 'fleet_lifecycle', ...binding, turnId: binding.promptId, payload: notice });
13
+ }
@@ -1,3 +1,4 @@
1
+ import type { TaskCreatedNotice, TaskNoticeBinding } from './task-notice.js';
1
2
  import type { SessionBackendId } from '../config.js';
2
3
  import type { ConversationEventV1, ConversationSnapshot, PromptReceipt, SubmitPromptCommand } from './conversation-types.js';
3
4
  /**
@@ -185,6 +186,8 @@ export interface SessionSnapshot {
185
186
  backend: SessionBackendId;
186
187
  alive: boolean;
187
188
  readiness: SessionReadiness;
189
+ /** Typed source of the active prompt; excludes prompt bodies and command IDs. */
190
+ activePromptSource?: PromptOrigin['kind'];
188
191
  sessionId?: string;
189
192
  lastError?: string;
190
193
  pendingPermissionId?: string;
@@ -283,12 +286,15 @@ export interface ConversationHandlePage {
283
286
  * on any concrete transport which implements it.
284
287
  */
285
288
  export interface AgentSession {
289
+ sendFileToChat?: (input: import('../file-delivery/types.js').FileDeliveryInput, signal: AbortSignal, copy: import('../file-delivery/types.js').CopyChatFile, policy: import('../config.js').CommonPermissions) => Promise<import('../file-delivery/types.js').DeliveredFile>;
286
290
  readonly backend: SessionBackendId;
287
291
  readonly pid: number;
288
292
  /** Live capabilities; optional only for source compatibility with external adapters. */
289
293
  readonly capabilities?: AgentSessionCapabilities;
290
294
  isAlive(): boolean;
291
295
  snapshot(): SessionSnapshot;
296
+ taskNoticeBinding?(): TaskNoticeBinding | undefined;
297
+ recordTaskCreated?(binding: TaskNoticeBinding, notice: TaskCreatedNotice): void;
292
298
  conversationPage?(request: {
293
299
  after?: string;
294
300
  limit?: number;
@@ -301,6 +307,11 @@ export interface AgentSession {
301
307
  * Hand the session a prompt and return as soon as it has accepted
302
308
  * responsibility for it. Throws `SessionControlError` if it cannot.
303
309
  */
310
+ /**
311
+ * The turn that carries an admitted prompt when one adapter turn delivered
312
+ * several; absent means the prompt's own id is its turn id.
313
+ */
314
+ sharedTurnId?(promptId: string): string | undefined;
304
315
  queuePrompt(text: string, options?: SubmitPromptOptions): Promise<QueuedPrompt>;
305
316
  /** Queue a prompt and wait for its terminal result. */
306
317
  submitPrompt(text: string, options?: SubmitPromptOptions): Promise<TurnResult>;
@@ -316,6 +327,9 @@ export interface AgentSession {
316
327
  * keep compiling. Read it through `interruptOutcome`, never directly.
317
328
  */
318
329
  interrupt(source?: TurnCancellationSource): Promise<InterruptResult>;
330
+ /** Atomically bind cancellation to one voice-owned turn. */
331
+ readonly liveVoiceSupported?: boolean;
332
+ interruptPrompt?(generation: string, promptId: string): Promise<InterruptResult>;
319
333
  respondPermission(permissionId: string, optionId: string): boolean;
320
334
  /** Generation-bound browser decision; stale/settled/invalid all fail closed. */
321
335
  respondPermissionV2?(permissionId: string, optionId: string, sessionGeneration: string): 'accepted' | 'stale';
@@ -0,0 +1,34 @@
1
+ import { type Exec } from './exec.js';
2
+ import type { WorkspacePayload } from './workspace-enrollment.js';
3
+ /**
4
+ * Check what the steps after the one-time root proof depend on, before that
5
+ * proof is sent: a failure afterwards cannot be retried with a fresh command.
6
+ */
7
+ export declare function setupTunnelPreflight({ exec, platform, node }?: {
8
+ exec?: Exec;
9
+ platform?: NodeJS.Platform;
10
+ node?: string;
11
+ }): Promise<void>;
12
+ /** What the steps after the proof need, kept so they can be finished without a new command. */
13
+ export interface PendingTunnelSetup {
14
+ appOrigin: string;
15
+ origin: string;
16
+ hostWorkspaceId: string;
17
+ rootCid: string;
18
+ challenge: WorkspacePayload['challenge'];
19
+ /** Fleet configuration the setup started with; a resume must use the same one. */
20
+ configuration: string;
21
+ /** Every port sent to the account as the tunnel target. Without confirmedPort, the remote target may be any of these or the default. */
22
+ requestedPorts?: number[];
23
+ /** Last positively confirmed target; cleared before any new retarget request. */
24
+ confirmedPort?: number;
25
+ }
26
+ export declare function savePendingTunnelSetup(pending: PendingTunnelSetup): void;
27
+ export declare function clearPendingTunnelSetup(): void;
28
+ export declare function readPendingTunnelSetup(): PendingTunnelSetup;
29
+ export declare const DEFAULT_TUNNEL_PORT = 49271;
30
+ /**
31
+ * The port the web service must bind when the account can no longer retarget
32
+ * the tunnel. Unknown when a different port was requested and never confirmed.
33
+ */
34
+ export declare function requiredPortAfterExpiry(pending: PendingTunnelSetup): number;
@@ -0,0 +1,62 @@
1
+ import { existsSync, lstatSync, readFileSync, rmSync } from 'node:fs';
2
+ import { userInfo } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { replaceFileAtomically } from './atomic-file.js';
5
+ import { realExec } from './exec.js';
6
+ import { stateRoot } from './paths.js';
7
+ const UNCHANGED = 'Nothing was changed and this host was not bound.';
8
+ /**
9
+ * Check what the steps after the one-time root proof depend on, before that
10
+ * proof is sent: a failure afterwards cannot be retried with a fresh command.
11
+ */
12
+ export async function setupTunnelPreflight({ exec = realExec, platform = process.platform, node = process.versions.node } = {}) {
13
+ const [major, minor] = node.split('.').map(Number);
14
+ if (major < 22 || (major === 22 && minor < 13))
15
+ throw Error(`Tunnel setup requires Node.js 22.13 or newer; this is ${node}. Update Node.js, then run a fresh tunnel setup command. ${UNCHANGED}`);
16
+ if (platform === 'linux') {
17
+ const manager = await exec('systemctl', ['--user', 'show-environment'], { timeout: 10_000 });
18
+ if (manager.code !== 0)
19
+ throw Error(`The user service manager is not reachable from this shell (${manager.stderr.trim().split('\n')[0] || `systemctl --user exited ${manager.code}`}). `
20
+ + `Log in directly as ${userInfo().username} (not through su or sudo), or run: sudo loginctl enable-linger ${userInfo().username} && export XDG_RUNTIME_DIR=/run/user/${process.getuid?.()} `
21
+ + `Then run a fresh tunnel setup command. ${UNCHANGED}`);
22
+ }
23
+ const help = await exec('cloudflared', ['tunnel', 'run', '--help'], { timeout: 10_000 });
24
+ if (help.code === 127)
25
+ throw Error(`cloudflared is not installed or not on PATH. Install it, then run a fresh tunnel setup command. ${UNCHANGED}`);
26
+ if (help.code !== 0 || !`${help.stdout}\n${help.stderr}`.includes('--token-file'))
27
+ throw Error(`This cloudflared is too old for tunnel setup (no --token-file support). Update cloudflared, then run a fresh tunnel setup command. ${UNCHANGED}`);
28
+ }
29
+ const pendingPath = () => join(stateRoot(), 'workspace', 'pending-setup.json');
30
+ export function savePendingTunnelSetup(pending) {
31
+ replaceFileAtomically(pendingPath(), JSON.stringify(pending) + '\n', 0o600);
32
+ }
33
+ export function clearPendingTunnelSetup() { rmSync(pendingPath(), { force: true }); }
34
+ export function readPendingTunnelSetup() {
35
+ const path = pendingPath();
36
+ if (!existsSync(path))
37
+ throw Error('No unfinished tunnel setup on this host. Run the tunnel setup command from the App.');
38
+ const stat = lstatSync(path);
39
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.uid !== process.getuid?.() || (stat.mode & 0o077) !== 0)
40
+ throw Error('Unfinished tunnel setup record must be an owned private file');
41
+ const pending = JSON.parse(readFileSync(path, 'utf8'));
42
+ if (typeof pending?.appOrigin !== 'string' || typeof pending.origin !== 'string' || typeof pending.hostWorkspaceId !== 'string'
43
+ || typeof pending.rootCid !== 'string' || !pending.challenge || !Number.isSafeInteger(pending.challenge.expiresAt) || typeof pending.configuration !== 'string'
44
+ || (pending.requestedPorts !== undefined && (!Array.isArray(pending.requestedPorts) || !pending.requestedPorts.every(Number.isInteger))))
45
+ throw Error('Unfinished tunnel setup record is invalid');
46
+ if (pending.confirmedPort !== undefined && (!Number.isInteger(pending.confirmedPort) || pending.confirmedPort < 1024 || pending.confirmedPort > 65535))
47
+ throw Error('Unfinished tunnel setup record is invalid');
48
+ return pending;
49
+ }
50
+ export const DEFAULT_TUNNEL_PORT = 49_271;
51
+ /**
52
+ * The port the web service must bind when the account can no longer retarget
53
+ * the tunnel. Unknown when a different port was requested and never confirmed.
54
+ */
55
+ export function requiredPortAfterExpiry(pending) {
56
+ if (pending.confirmedPort !== undefined)
57
+ return pending.confirmedPort;
58
+ const other = [...new Set(pending.requestedPorts ?? [])].filter(port => port !== DEFAULT_TUNNEL_PORT);
59
+ if (!other.length)
60
+ return DEFAULT_TUNNEL_PORT;
61
+ throw Error(`The setup window has expired and it is unknown whether the tunnel points at port ${[...other, DEFAULT_TUNNEL_PORT].join(' or ')}: the account's answer to a port request was not received. This setup cannot be finished automatically`);
62
+ }
@@ -0,0 +1,2 @@
1
+ /** Optional private socket directory for deeply nested, isolated Fleet homes. */
2
+ export declare function socketPath(logicalPath: string): string;
@@ -0,0 +1,22 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { lstatSync, mkdirSync } from 'node:fs';
3
+ import { isAbsolute, join, resolve } from 'node:path';
4
+ /** Optional private socket directory for deeply nested, isolated Fleet homes. */
5
+ export function socketPath(logicalPath) {
6
+ const root = process.env.OURS_FLEET_SOCKET_ROOT;
7
+ if (!root) {
8
+ if (Buffer.byteLength(logicalPath) > 103)
9
+ throw new Error('Unix socket path is too long; configure a short private OURS_FLEET_SOCKET_ROOT');
10
+ return logicalPath;
11
+ }
12
+ if (!isAbsolute(root) || resolve(root) !== root)
13
+ throw new Error('OURS_FLEET_SOCKET_ROOT must be an absolute normalized path');
14
+ mkdirSync(root, { recursive: true, mode: 0o700 });
15
+ const stat = lstatSync(root);
16
+ if (!stat.isDirectory() || stat.isSymbolicLink() || stat.uid !== process.getuid?.() || (stat.mode & 0o777) !== 0o700)
17
+ throw new Error('OURS_FLEET_SOCKET_ROOT must be an owner-only 0700 directory');
18
+ const path = join(root, createHash('sha256').update(resolve(logicalPath)).digest('hex').slice(0, 24) + '.sock');
19
+ if (Buffer.byteLength(path) > 103)
20
+ throw new Error('OURS_FLEET_SOCKET_ROOT is too long');
21
+ return path;
22
+ }
package/dist/spawn.d.ts CHANGED
@@ -6,7 +6,7 @@ import { type CreationDeps, type CreationProvenance } from './creation.js';
6
6
  import './harness/claude-code.js';
7
7
  import './harness/codex.js';
8
8
  import './harness/hermes.js';
9
- import { type SupervisorLauncher } from './temp-lifecycle.js';
9
+ import { type SupervisorLauncher, type TaskSupervisorOwner } from './temp-lifecycle.js';
10
10
  /**
11
11
  * The provenance record written by the most recent spawn in this process, so
12
12
  * the CLI can print the same summary it persisted rather than rebuilding it.
@@ -15,6 +15,8 @@ export declare let lastProvenance: CreationProvenance | undefined;
15
15
  export interface SpawnOpts {
16
16
  name: string;
17
17
  temp?: boolean;
18
+ /** Internal exact task-layout ownership, never a standalone manifest entry. */
19
+ taskOwner?: TaskSupervisorOwner;
18
20
  brain?: AgentSelection;
19
21
  role?: AgentSelection;
20
22
  /** Trusted canonical definition used by room provisioning; never a second schema. */
@@ -85,3 +87,5 @@ export declare function spawnPermanent(o: SpawnOpts, deps: OpsDeps, creation?: C
85
87
  export type { SupervisorLauncher } from './temp-lifecycle.js';
86
88
  /** Temp spawn: live state under ~/.ours-fleet/tmp, independent transient supervision. */
87
89
  export declare function spawnTemp(o: SpawnOpts, binPath: string, launch?: SupervisorLauncher, creation?: CreationDeps): Promise<string>;
90
+ /** Resume the exact durable task launch; no creation, invite issuance or state rotation. */
91
+ export declare function resumeTaskSupervisor(name: string, binPath: string): Promise<void>;
package/dist/spawn.js CHANGED
@@ -1,5 +1,7 @@
1
+ import { taskSupervisorMayRun } from './task-supervision.js';
1
2
  import { randomUUID } from 'node:crypto';
2
3
  import { storeRoomSecret, storeTemporaryLaunch, preparePermanentAssignment } from './agent-ours/service.js';
4
+ import { ensureWorkspace } from './rooms-tasks/workspace.js';
3
5
  import { spawn as spawnChild } from 'node:child_process';
4
6
  import { closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
5
7
  import { join } from 'node:path';
@@ -15,7 +17,8 @@ import { recordGeneratedAgentSource } from './generated-agent-source.js';
15
17
  import './harness/claude-code.js';
16
18
  import './harness/codex.js';
17
19
  import './harness/hermes.js';
18
- import { archiveTempState, makeTempSupervisorLauncher, prepareTempSupervisor, reclaimStaleTempState, } from './temp-lifecycle.js';
20
+ import { getAdapter } from './harness/registry.js';
21
+ import { archiveTempState, makeTempSupervisorLauncher, prepareTempSupervisor, reclaimStaleTempState, stopTempSupervisor, secureStoppedTempArchive, readTempSupervisor, requestedTempStopReason, } from './temp-lifecycle.js';
19
22
  /**
20
23
  * The provenance record written by the most recent spawn in this process, so
21
24
  * the CLI can print the same summary it persisted rather than rebuilding it.
@@ -321,6 +324,14 @@ export async function spawnTemp(o, binPath, launch = independentSupervisor, crea
321
324
  if (o.isolationFile)
322
325
  readIsolationFile(o.isolationFile); // fail before reserving
323
326
  const prepared = resolvedSpawn(o); // canonical validation before mutation
327
+ if ((o.taskOwner || o.roomMemberStartup?.task_id) && !getAdapter(prepared.role.harness).supportsResume)
328
+ throw Error('TASK_HARNESS_RESUME_UNSUPPORTED: task agents require a resumable harness');
329
+ if (o.roomMemberStartup?.workspace) {
330
+ const workspace = o.roomMemberStartup.workspace;
331
+ if (prepared.role.cwd !== workspace.path)
332
+ throw new Error('room member cwd must equal its recorded owned workspace');
333
+ ensureWorkspace(workspace);
334
+ }
324
335
  // Retire only supervisors whose recorded owner is definitively stopped. This
325
336
  // bounded pass keeps the active roster clean without deleting old evidence.
326
337
  await reclaimStaleTempState();
@@ -351,7 +362,7 @@ async function spawnTempInner(o, preparedRole, binPath, launch, tx, onStage) {
351
362
  if (role.roomMemberStartup)
352
363
  role.roomMemberStartup = { ...role.roomMemberStartup, invite: '' };
353
364
  onStage?.('writing_role');
354
- const dir = applyRole(role, { temp: true, identityGuarantee: 'unverified' });
365
+ const dir = applyRole(role, { temp: true, identityGuarantee: 'unverified', configPath: o.configPath });
355
366
  const provenance = buildProvenance({
356
367
  role: o.name, lifetime: 'temporary', fleetVersion: VERSION,
357
368
  settings: provenanceSettings(o, cfg.defaults, preparedRole.temporaryLoops),
@@ -361,7 +372,14 @@ async function spawnTempInner(o, preparedRole, binPath, launch, tx, onStage) {
361
372
  lastProvenance = provenance;
362
373
  tx.record({
363
374
  stage: `temp state dir ${dir}`,
364
- undo: () => {
375
+ undo: async () => {
376
+ if (o.taskOwner || role.roomMemberStartup?.task_id) {
377
+ await stopTempSupervisor(o.name);
378
+ const supervisor = readTempSupervisor(dir);
379
+ if (supervisor)
380
+ await secureStoppedTempArchive(o.name, supervisor.launchId);
381
+ return;
382
+ }
365
383
  // A failed launch is still lifecycle evidence: briefing, provenance,
366
384
  // metadata and supervisor output explain what happened. Remove it from
367
385
  // the live roster by atomic archive, never recursive deletion.
@@ -374,7 +392,14 @@ async function spawnTempInner(o, preparedRole, binPath, launch, tx, onStage) {
374
392
  // out; a lone temp spawn still waits zero (time-based gate).
375
393
  if (cfg.startStaggerMs > 0)
376
394
  writeFileSync(join(dir, START_STAGGER_FILE), String(cfg.startStaggerMs));
377
- prepareTempSupervisor(dir, o.name);
395
+ prepareTempSupervisor(dir, o.name, o.taskOwner ?? (o.roomMemberStartup?.task_id ? {
396
+ taskId: o.roomMemberStartup.task_id,
397
+ roomId: o.roomMemberStartup.room_id,
398
+ roomIdentityCid: o.roomMemberStartup.room_identity_cid,
399
+ creationActionId: o.creationActionId,
400
+ } : undefined));
401
+ if (o.taskOwner || o.roomMemberStartup?.task_id)
402
+ taskSupervisorMayRun(o.name);
378
403
  // Run the supervisor independently. On a service-managed host the temp
379
404
  // runner gets its own transient unit/job, so stopping the coordinator's unit
380
405
  // cannot kill a live worker in the coordinator's cgroup.
@@ -382,3 +407,14 @@ async function spawnTempInner(o, preparedRole, binPath, launch, tx, onStage) {
382
407
  await launch(binPath, ['_run-temp', o.name], dir);
383
408
  return dir;
384
409
  }
410
+ /** Resume the exact durable task launch; no creation, invite issuance or state rotation. */
411
+ export async function resumeTaskSupervisor(name, binPath) {
412
+ if (!taskSupervisorMayRun(name))
413
+ throw Error('TASK_SUPERVISOR_RETIRED');
414
+ const dir = agentDir(name, true);
415
+ if (requestedTempStopReason(dir))
416
+ throw Error('TASK_SUPERVISOR_STOP_REQUESTED');
417
+ const launcher = readTempSupervisor(dir)?.kind === 'detached'
418
+ ? makeTempSupervisorLauncher({ spawnDetached, supervisor: 'none' }) : independentSupervisor;
419
+ await launcher(binPath, ['_run-temp', name], dir);
420
+ }
@@ -0,0 +1,4 @@
1
+ /** Readiness is a separate turn after identity/profile and room admission succeed. */
2
+ export declare function managedStartupPrompt(stateDir: string, mode: 'fresh' | 'resume', hasPriorBoot?: boolean): string;
3
+ /** Configured work/continuity runs after readiness, never inside the fast turn. */
4
+ export declare function managedTaskPrompt(stateDir: string, mode: 'fresh' | 'resume', hasPriorBoot?: boolean): string;