@ours.network/fleet 1.2.0-nightly.9 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (429) hide show
  1. package/README.md +280 -68
  2. package/dist/account-origin.d.ts +5 -0
  3. package/dist/account-origin.js +31 -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 +22 -0
  11. package/dist/agent-ours/mcp-endpoint.js +101 -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 +27 -1
  15. package/dist/agent-ours/service.js +107 -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 +31 -0
  19. package/dist/application/conversation-history.js +339 -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 +43 -0
  30. package/dist/application/resource-observer.js +323 -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 +3 -1
  34. package/dist/application/role-repository.js +89 -54
  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 +63 -17
  38. package/dist/application/session-control.js +221 -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 +120 -31
  49. package/dist/build-info.json +10 -5
  50. package/dist/capabilities.d.ts +9 -1
  51. package/dist/capabilities.js +13 -0
  52. package/dist/cli.js +391 -38
  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 +214 -20
  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 +13 -0
  74. package/dist/fleet-command-audit.js +31 -9
  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 +31 -0
  101. package/dist/notifications/fleet-producer.js +351 -0
  102. package/dist/notifications/outbox.d.ts +59 -0
  103. package/dist/notifications/outbox.js +199 -0
  104. package/dist/notifications/target-cleanup.d.ts +16 -0
  105. package/dist/notifications/target-cleanup.js +75 -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 +5 -0
  116. package/dist/paths.js +5 -0
  117. package/dist/preset-migration.js +55 -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 +4 -0
  134. package/dist/rooms-tasks/archived-absence.js +11 -0
  135. package/dist/rooms-tasks/cli.js +182 -5
  136. package/dist/rooms-tasks/close.d.ts +5 -2
  137. package/dist/rooms-tasks/close.js +224 -36
  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 +66 -10
  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-review.d.ts +113 -0
  180. package/dist/rooms-tasks/task-review.js +561 -0
  181. package/dist/rooms-tasks/task-service-retirement.d.ts +11 -0
  182. package/dist/rooms-tasks/task-service-retirement.js +21 -0
  183. package/dist/rooms-tasks/task-state.d.ts +51 -5
  184. package/dist/rooms-tasks/task-state.js +358 -50
  185. package/dist/rooms-tasks/task-tools.d.ts +35 -0
  186. package/dist/rooms-tasks/task-tools.js +134 -0
  187. package/dist/rooms-tasks/types.d.ts +78 -0
  188. package/dist/rooms-tasks/workspace-artifacts.d.ts +6 -0
  189. package/dist/rooms-tasks/workspace-artifacts.js +93 -0
  190. package/dist/rooms-tasks/workspace.d.ts +35 -0
  191. package/dist/rooms-tasks/workspace.js +325 -0
  192. package/dist/runner.d.ts +23 -4
  193. package/dist/runner.js +409 -61
  194. package/dist/session/acp.d.ts +75 -2
  195. package/dist/session/acp.js +345 -82
  196. package/dist/session/arbiter.d.ts +98 -0
  197. package/dist/session/arbiter.js +272 -3
  198. package/dist/session/codex-app-server.d.ts +45 -1
  199. package/dist/session/codex-app-server.js +225 -32
  200. package/dist/session/control.d.ts +17 -3
  201. package/dist/session/control.js +219 -23
  202. package/dist/session/conversation-normalizer.d.ts +2 -1
  203. package/dist/session/conversation-normalizer.js +1 -1
  204. package/dist/session/conversation-observation.d.ts +25 -0
  205. package/dist/session/conversation-observation.js +100 -0
  206. package/dist/session/conversation-replay.d.ts +50 -0
  207. package/dist/session/conversation-replay.js +203 -0
  208. package/dist/session/conversation-store.d.ts +15 -1
  209. package/dist/session/conversation-store.js +213 -26
  210. package/dist/session/conversation-types.d.ts +57 -4
  211. package/dist/session/prompt-batch.d.ts +79 -0
  212. package/dist/session/prompt-batch.js +120 -0
  213. package/dist/session/task-notice.d.ts +14 -0
  214. package/dist/session/task-notice.js +13 -0
  215. package/dist/session/types.d.ts +42 -1
  216. package/dist/setup-tunnel-preflight.d.ts +34 -0
  217. package/dist/setup-tunnel-preflight.js +62 -0
  218. package/dist/socket-path.d.ts +2 -0
  219. package/dist/socket-path.js +22 -0
  220. package/dist/spawn.d.ts +5 -1
  221. package/dist/spawn.js +40 -4
  222. package/dist/startup-prompt.d.ts +15 -0
  223. package/dist/startup-prompt.js +71 -0
  224. package/dist/startup-readiness.d.ts +20 -1
  225. package/dist/startup-readiness.js +66 -3
  226. package/dist/startup-telemetry.d.ts +16 -0
  227. package/dist/startup-telemetry.js +46 -0
  228. package/dist/subscriptions/cli.d.ts +91 -0
  229. package/dist/subscriptions/cli.js +223 -0
  230. package/dist/subscriptions/launch.d.ts +37 -0
  231. package/dist/subscriptions/launch.js +93 -0
  232. package/dist/subscriptions/login.d.ts +77 -0
  233. package/dist/subscriptions/login.js +215 -0
  234. package/dist/subscriptions/observed.d.ts +7 -0
  235. package/dist/subscriptions/observed.js +44 -0
  236. package/dist/subscriptions/probe.d.ts +10 -0
  237. package/dist/subscriptions/probe.js +73 -0
  238. package/dist/subscriptions/service.d.ts +102 -0
  239. package/dist/subscriptions/service.js +364 -0
  240. package/dist/subscriptions/store.d.ts +71 -0
  241. package/dist/subscriptions/store.js +143 -0
  242. package/dist/supervisor/adoption.d.ts +8 -0
  243. package/dist/supervisor/adoption.js +78 -0
  244. package/dist/supervisor/catalog.d.ts +62 -0
  245. package/dist/supervisor/catalog.js +254 -0
  246. package/dist/supervisor/fleet.d.ts +8 -0
  247. package/dist/supervisor/fleet.js +89 -0
  248. package/dist/supervisor/index.js +3 -6
  249. package/dist/supervisor/launchd.d.ts +1 -1
  250. package/dist/supervisor/launchd.js +26 -13
  251. package/dist/supervisor/legacy.d.ts +35 -0
  252. package/dist/supervisor/legacy.js +524 -0
  253. package/dist/supervisor/manager.d.ts +15 -0
  254. package/dist/supervisor/manager.js +270 -0
  255. package/dist/supervisor/registration-refresh.d.ts +45 -0
  256. package/dist/supervisor/registration-refresh.js +266 -0
  257. package/dist/supervisor/scope.d.ts +4 -0
  258. package/dist/supervisor/scope.js +10 -0
  259. package/dist/supervisor/systemd.d.ts +2 -2
  260. package/dist/supervisor/systemd.js +18 -37
  261. package/dist/task-supervision.d.ts +9 -0
  262. package/dist/task-supervision.js +145 -0
  263. package/dist/temp-idle.d.ts +17 -0
  264. package/dist/temp-idle.js +42 -0
  265. package/dist/temp-lifecycle.d.ts +23 -8
  266. package/dist/temp-lifecycle.js +123 -66
  267. package/dist/temp-supervisor-recovery.d.ts +1 -1
  268. package/dist/temp-supervisor-recovery.js +2 -2
  269. package/dist/tunnel-setup-completion.d.ts +7 -0
  270. package/dist/tunnel-setup-completion.js +13 -0
  271. package/dist/tunnel-setup-input.d.ts +19 -0
  272. package/dist/tunnel-setup-input.js +130 -0
  273. package/dist/watchdog/query.d.ts +3 -1
  274. package/dist/watchdog/query.js +2 -1
  275. package/dist/web/agent-attachments.d.ts +29 -0
  276. package/dist/web/agent-attachments.js +162 -0
  277. package/dist/web/auth.d.ts +65 -2
  278. package/dist/web/auth.js +201 -11
  279. package/dist/web/available-port.d.ts +2 -0
  280. package/dist/web/available-port.js +23 -0
  281. package/dist/web/control.d.ts +3 -3
  282. package/dist/web/control.js +10 -8
  283. package/dist/web/conversation-stream-codec.d.ts +23 -0
  284. package/dist/web/conversation-stream-codec.js +110 -0
  285. package/dist/web/conversation-stream.d.ts +26 -0
  286. package/dist/web/conversation-stream.js +239 -0
  287. package/dist/web/events.d.ts +2 -0
  288. package/dist/web/events.js +9 -0
  289. package/dist/web/fleet-config-service.d.ts +7 -1
  290. package/dist/web/fleet-config-service.js +61 -16
  291. package/dist/web/prefix-gateway.d.ts +32 -0
  292. package/dist/web/prefix-gateway.js +248 -0
  293. package/dist/web/resource-views.d.ts +138 -0
  294. package/dist/web/resource-views.js +519 -0
  295. package/dist/web/runtime.d.ts +3 -1
  296. package/dist/web/runtime.js +132 -34
  297. package/dist/web/server.d.ts +19 -0
  298. package/dist/web/server.js +893 -71
  299. package/dist/web/service.d.ts +11 -2
  300. package/dist/web/service.js +30 -4
  301. package/dist/web/workspace-devices.d.ts +107 -0
  302. package/dist/web/workspace-devices.js +277 -0
  303. package/dist/web/workspace-tunnel.d.ts +1 -0
  304. package/dist/web/workspace-tunnel.js +34 -0
  305. package/dist/workspace-enrollment.d.ts +83 -0
  306. package/dist/workspace-enrollment.js +605 -0
  307. package/dist/workspace-replacement.d.ts +66 -0
  308. package/dist/workspace-replacement.js +238 -0
  309. package/docs/acp-files.md +146 -0
  310. package/docs/conversation-stream.md +216 -0
  311. package/docs/fleet-migration.md +54 -0
  312. package/docs/live-voice.md +13 -0
  313. package/docs/room-layouts.md +227 -0
  314. package/docs/self-reminders.md +374 -0
  315. package/docs/task-progress-review.md +143 -0
  316. package/docs/task-workspaces.md +225 -0
  317. package/docs/validation/managed-cli-permissions.md +421 -0
  318. package/examples/room-layouts/fresh.yaml +27 -0
  319. package/examples/room-layouts/scoped.yaml +21 -0
  320. package/examples/room-layouts/shared.yaml +19 -0
  321. package/package.json +25 -20
  322. package/presets/README.md +78 -0
  323. package/presets/brain-catalog.json +8 -2
  324. package/presets/fleet/agent_templates/Critic.yaml +1 -1
  325. package/presets/fleet/agent_templates/Developer.yaml +1 -1
  326. package/presets/fleet/agent_templates/Engineer.yaml +5 -0
  327. package/presets/fleet/agent_templates/LocalCoordinator.yaml +6 -3
  328. package/presets/fleet/agents/FleetCoordinator.yaml +1 -1
  329. package/presets/fleet/brains/claude-fable-5-1-high.yaml +5 -0
  330. package/presets/fleet/brains/claude-fable-5-1-low.yaml +5 -0
  331. package/presets/fleet/brains/claude-fable-5-1-max.yaml +5 -0
  332. package/presets/fleet/brains/claude-fable-5-1-medium.yaml +5 -0
  333. package/presets/fleet/brains/claude-fable-5-1-xhigh.yaml +5 -0
  334. package/presets/fleet/brains/claude-fable-5-high.yaml +1 -1
  335. package/presets/fleet/brains/claude-fable-5-low.yaml +1 -1
  336. package/presets/fleet/brains/claude-fable-5-max.yaml +1 -1
  337. package/presets/fleet/brains/claude-fable-5-medium.yaml +1 -1
  338. package/presets/fleet/brains/claude-fable-5-xhigh.yaml +1 -1
  339. package/presets/fleet/brains/claude-haiku-4-5-20251001-default.yaml +4 -0
  340. package/presets/fleet/brains/claude-opus-5-5-high.yaml +5 -0
  341. package/presets/fleet/brains/claude-opus-5-5-low.yaml +5 -0
  342. package/presets/fleet/brains/claude-opus-5-5-max.yaml +5 -0
  343. package/presets/fleet/brains/claude-opus-5-5-medium.yaml +5 -0
  344. package/presets/fleet/brains/claude-opus-5-5-xhigh.yaml +5 -0
  345. package/presets/fleet/brains/claude-opus-5-high.yaml +1 -1
  346. package/presets/fleet/brains/claude-opus-5-low.yaml +1 -1
  347. package/presets/fleet/brains/claude-opus-5-max.yaml +1 -1
  348. package/presets/fleet/brains/claude-opus-5-medium.yaml +1 -1
  349. package/presets/fleet/brains/claude-opus-5-xhigh.yaml +1 -1
  350. package/presets/fleet/brains/claude-sonnet-5-high.yaml +1 -1
  351. package/presets/fleet/brains/claude-sonnet-5-low.yaml +1 -1
  352. package/presets/fleet/brains/claude-sonnet-5-max.yaml +1 -1
  353. package/presets/fleet/brains/claude-sonnet-5-medium.yaml +1 -1
  354. package/presets/fleet/brains/claude-sonnet-5-xhigh.yaml +1 -1
  355. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-high.yaml +1 -1
  356. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-low.yaml +1 -1
  357. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-medium.yaml +1 -1
  358. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-xhigh.yaml +1 -1
  359. package/presets/fleet/brains/codex-gpt-5-4-high.yaml +1 -1
  360. package/presets/fleet/brains/codex-gpt-5-4-low.yaml +1 -1
  361. package/presets/fleet/brains/codex-gpt-5-4-medium.yaml +1 -1
  362. package/presets/fleet/brains/codex-gpt-5-4-mini-high.yaml +1 -1
  363. package/presets/fleet/brains/codex-gpt-5-4-mini-low.yaml +1 -1
  364. package/presets/fleet/brains/codex-gpt-5-4-mini-medium.yaml +1 -1
  365. package/presets/fleet/brains/codex-gpt-5-4-mini-xhigh.yaml +1 -1
  366. package/presets/fleet/brains/codex-gpt-5-4-xhigh.yaml +1 -1
  367. package/presets/fleet/brains/codex-gpt-5-5-high.yaml +1 -1
  368. package/presets/fleet/brains/codex-gpt-5-5-low.yaml +1 -1
  369. package/presets/fleet/brains/codex-gpt-5-5-medium.yaml +1 -1
  370. package/presets/fleet/brains/codex-gpt-5-5-xhigh.yaml +1 -1
  371. package/presets/fleet/brains/codex-gpt-5-6-luna-high.yaml +1 -1
  372. package/presets/fleet/brains/codex-gpt-5-6-luna-low.yaml +1 -1
  373. package/presets/fleet/brains/codex-gpt-5-6-luna-max.yaml +1 -1
  374. package/presets/fleet/brains/codex-gpt-5-6-luna-medium.yaml +1 -1
  375. package/presets/fleet/brains/codex-gpt-5-6-luna-xhigh.yaml +1 -1
  376. package/presets/fleet/brains/codex-gpt-5-6-sol-high.yaml +1 -1
  377. package/presets/fleet/brains/codex-gpt-5-6-sol-low.yaml +1 -1
  378. package/presets/fleet/brains/codex-gpt-5-6-sol-max.yaml +1 -1
  379. package/presets/fleet/brains/codex-gpt-5-6-sol-medium.yaml +1 -1
  380. package/presets/fleet/brains/codex-gpt-5-6-sol-ultra.yaml +1 -1
  381. package/presets/fleet/brains/codex-gpt-5-6-sol-xhigh.yaml +1 -1
  382. package/presets/fleet/brains/codex-gpt-5-6-terra-high.yaml +1 -1
  383. package/presets/fleet/brains/codex-gpt-5-6-terra-low.yaml +1 -1
  384. package/presets/fleet/brains/codex-gpt-5-6-terra-max.yaml +1 -1
  385. package/presets/fleet/brains/codex-gpt-5-6-terra-medium.yaml +1 -1
  386. package/presets/fleet/brains/codex-gpt-5-6-terra-ultra.yaml +1 -1
  387. package/presets/fleet/brains/codex-gpt-5-6-terra-xhigh.yaml +1 -1
  388. package/presets/fleet/brains/codex-gpt-6-1-sol-high.yaml +5 -0
  389. package/presets/fleet/brains/codex-gpt-6-1-sol-low.yaml +5 -0
  390. package/presets/fleet/brains/codex-gpt-6-1-sol-max.yaml +5 -0
  391. package/presets/fleet/brains/codex-gpt-6-1-sol-medium.yaml +5 -0
  392. package/presets/fleet/brains/codex-gpt-6-1-sol-ultra.yaml +5 -0
  393. package/presets/fleet/brains/codex-gpt-6-1-sol-xhigh.yaml +5 -0
  394. package/presets/fleet/brains/codex-gpt-6-astra-high.yaml +1 -1
  395. package/presets/fleet/brains/codex-gpt-6-astra-low.yaml +1 -1
  396. package/presets/fleet/brains/codex-gpt-6-astra-max.yaml +1 -1
  397. package/presets/fleet/brains/codex-gpt-6-astra-medium.yaml +1 -1
  398. package/presets/fleet/brains/codex-gpt-6-astra-ultra.yaml +1 -1
  399. package/presets/fleet/brains/codex-gpt-6-astra-xhigh.yaml +1 -1
  400. package/presets/fleet/brains/codex-gpt-6-luna-high.yaml +5 -0
  401. package/presets/fleet/brains/codex-gpt-6-luna-low.yaml +5 -0
  402. package/presets/fleet/brains/codex-gpt-6-luna-max.yaml +5 -0
  403. package/presets/fleet/brains/codex-gpt-6-luna-medium.yaml +5 -0
  404. package/presets/fleet/brains/codex-gpt-6-luna-xhigh.yaml +5 -0
  405. package/presets/fleet/brains/codex-gpt-6-sol-high.yaml +5 -0
  406. package/presets/fleet/brains/codex-gpt-6-sol-low.yaml +5 -0
  407. package/presets/fleet/brains/codex-gpt-6-sol-max.yaml +5 -0
  408. package/presets/fleet/brains/codex-gpt-6-sol-medium.yaml +5 -0
  409. package/presets/fleet/brains/codex-gpt-6-sol-ultra.yaml +5 -0
  410. package/presets/fleet/brains/codex-gpt-6-sol-xhigh.yaml +5 -0
  411. package/presets/fleet/roles/Coordinator.yaml +21 -13
  412. package/presets/fleet/roles/Critic.yaml +24 -0
  413. package/presets/fleet/roles/Developer.yaml +32 -0
  414. package/presets/fleet/roles/Engineer.yaml +72 -0
  415. package/presets/fleet/roles/LocalCoordinator.yaml +17 -0
  416. package/presets/fleet/room_layouts/engineering.yaml +25 -0
  417. package/presets/fleet/room_layouts/pair.yaml +24 -0
  418. package/presets/fleet/room_layouts/single.yaml +17 -0
  419. package/presets/fleet/room_layouts/team.yaml +30 -0
  420. package/presets/fleet/room_templates/engineering.yaml +19 -0
  421. package/presets/manifest.json +2 -2
  422. package/dist/web-app/assets/index-59GF-gsZ.css +0 -1
  423. package/dist/web-app/assets/index-C0h3ALvs.js +0 -10
  424. package/dist/web-app/icons/ours-fleet-maskable.svg +0 -4
  425. package/dist/web-app/icons/ours-fleet.svg +0 -4
  426. package/dist/web-app/index.html +0 -17
  427. package/dist/web-app/manifest.webmanifest +0 -15
  428. package/dist/web-app/offline.html +0 -18
  429. package/dist/web-app/sw.js +0 -51
@@ -0,0 +1,20 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { type ReminderStore } from './store.js';
3
+ /**
4
+ * What the agent's managed MCP endpoint needs from its runner. Absent until
5
+ * the runner has bound the store to this exact runtime instance and identity.
6
+ */
7
+ export interface ReminderToolBackend {
8
+ store: ReminderStore;
9
+ /** Re-arm the dispatcher after a schedule change. */
10
+ changed(): void;
11
+ }
12
+ export declare const REMINDER_TOOL_NAMES: readonly ["fleet_reminder_create", "fleet_reminder_list", "fleet_reminder_update", "fleet_reminder_cancel", "fleet_reminder_inspect", "fleet_reminder_ack"];
13
+ /**
14
+ * Register the self-reminder tools on the agent's own fixed-identity MCP
15
+ * server. No argument names an agent, identity or recipient: the server is the
16
+ * caller's own supervisor, so every operation is implicitly self-scoped.
17
+ */
18
+ export declare function registerReminderTools(server: McpServer, backend: () => ReminderToolBackend | undefined,
19
+ /** The endpoint's runtime admission; nothing is read or changed unless it admits. */
20
+ admit: () => Promise<() => void>): void;
@@ -0,0 +1,114 @@
1
+ import { z } from 'zod';
2
+ import { ReminderError } from './store.js';
3
+ export const REMINDER_TOOL_NAMES = Object.freeze([
4
+ 'fleet_reminder_create', 'fleet_reminder_list', 'fleet_reminder_update',
5
+ 'fleet_reminder_cancel', 'fleet_reminder_inspect', 'fleet_reminder_ack',
6
+ ]);
7
+ const schedule = {
8
+ local_time: z.string().describe('Calendar date and wall-clock time WITHOUT an offset, e.g. "2027-01-20T16:00". Always a real date: resolve "tomorrow" yourself.'),
9
+ time_zone: z.string().describe('IANA zone the time is meant in, e.g. "Europe/London", "America/New_York" or "UTC". Use the zone of the person or task, not a guess.'),
10
+ fold: z.union([z.literal(0), z.literal(1)]).optional().describe('Only for a wall time that occurs twice when clocks go back: 0 = first occurrence, 1 = second.'),
11
+ late_window_seconds: z.number().int().optional().describe('How late the wake may still be delivered if this agent or the host was offline or busy at the due time (60..604800, default 3600). After it the reminder expires without a wake.'),
12
+ interrupt: z.boolean().optional().describe('Default false: the wake waits until you are idle. true only for a return that is genuinely time-bound: '
13
+ + 'when due and you are busy with interruptible work, Fleet asks your current turn to stop (session and context are kept) and wakes you with this reminder instead of waiting. '
14
+ + 'At most one interruption per reminder revision. It never pre-empts owner requests, the owner console, startup, a pending permission, queued work or another reminder; '
15
+ + 'then it waits like an ordinary reminder. Not a hard real-time alarm: no wake while the host or agent is down, and model start-up still takes time.'),
16
+ };
17
+ function result(value) {
18
+ return {
19
+ content: [{ type: 'text', text: JSON.stringify(value, null, 2) }],
20
+ structuredContent: value,
21
+ isError: false,
22
+ };
23
+ }
24
+ function failure(code, message) {
25
+ const value = { error: code, message };
26
+ return { content: [{ type: 'text', text: JSON.stringify(value) }], isError: true };
27
+ }
28
+ /**
29
+ * Register the self-reminder tools on the agent's own fixed-identity MCP
30
+ * server. No argument names an agent, identity or recipient: the server is the
31
+ * caller's own supervisor, so every operation is implicitly self-scoped.
32
+ */
33
+ export function registerReminderTools(server, backend,
34
+ /** The endpoint's runtime admission; nothing is read or changed unless it admits. */
35
+ admit) {
36
+ const run = async (operation, mutates) => {
37
+ let release;
38
+ try {
39
+ release = await admit();
40
+ }
41
+ catch {
42
+ return failure('runtime_not_ready', 'the managed runtime is not admitting tool calls right now; nothing was read or changed');
43
+ }
44
+ try {
45
+ const target = backend();
46
+ if (!target)
47
+ return failure('reminders_unavailable', 'self-reminders are not available in this session (the supervisor has not bound them, or this session cannot take scheduled prompts)');
48
+ try {
49
+ const value = operation(target);
50
+ if (mutates)
51
+ target.changed();
52
+ return result(value);
53
+ }
54
+ catch (error) {
55
+ if (error instanceof ReminderError)
56
+ return failure(error.code, error.message);
57
+ return failure('reminder_store_failed', 'the reminder could not be recorded; nothing was changed');
58
+ }
59
+ }
60
+ finally {
61
+ release();
62
+ }
63
+ };
64
+ server.registerTool('fleet_reminder_create', {
65
+ description: 'Schedule a one-time reminder that wakes YOU (this agent) at a future date and time. '
66
+ + 'It sends nothing to anyone: when due, Fleet starts a turn for you with the reminder, and you decide what to do. '
67
+ + 'Use it to come back to something later instead of polling or waiting. Repeating a call with the same request_key '
68
+ + 'and input returns the existing reminder instead of creating another.',
69
+ inputSchema: {
70
+ request_key: z.string().describe('Stable key for this scheduling decision, so a retried call cannot create a duplicate (e.g. "release-check-2027-01-20").'),
71
+ title: z.string().describe('Short label shown in the wake (max 200 characters).'),
72
+ note: z.string().optional().describe('Private context for your future self: what to check and why (max 4000 characters). Returned by inspect, not in the wake text.'),
73
+ ...schedule,
74
+ },
75
+ }, async (args) => run(({ store }) => store.create(args.request_key, args), true));
76
+ server.registerTool('fleet_reminder_list', {
77
+ description: 'List your own reminders. state: "open" (default: scheduled or delivered but not acknowledged), "closed", or "all". '
78
+ + 'Pages with limit (1..100, default 50) and after (the id from the previous page).',
79
+ inputSchema: {
80
+ state: z.enum(['open', 'closed', 'all']).optional(),
81
+ limit: z.number().int().optional(),
82
+ after: z.string().optional(),
83
+ },
84
+ }, async (args) => run(({ store }) => store.list(args), false));
85
+ server.registerTool('fleet_reminder_update', {
86
+ description: 'Change one of your reminders, e.g. to postpone it. Pass the id and the revision you last saw '
87
+ + '(expected_revision) plus only the fields to change. Any wake already issued for the old revision becomes void.',
88
+ inputSchema: {
89
+ id: z.string(),
90
+ expected_revision: z.number().int(),
91
+ title: z.string().optional(),
92
+ note: z.string().optional(),
93
+ local_time: schedule.local_time.optional(),
94
+ time_zone: schedule.time_zone.optional(),
95
+ fold: schedule.fold,
96
+ late_window_seconds: schedule.late_window_seconds,
97
+ interrupt: schedule.interrupt,
98
+ },
99
+ }, async ({ id, expected_revision, ...changes }) => run(({ store }) => store.update(id, expected_revision, changes), true));
100
+ server.registerTool('fleet_reminder_cancel', {
101
+ description: 'Cancel one of your reminders (id + expected_revision). A wake already waiting for it will not be delivered.',
102
+ inputSchema: { id: z.string(), expected_revision: z.number().int() },
103
+ }, async ({ id, expected_revision }) => run(({ store }) => store.cancel(id, expected_revision), true));
104
+ server.registerTool('fleet_reminder_inspect', {
105
+ description: 'Read the reminder behind a [fleet-reminder] wake, including its note, whether the wake is still current and eligible, '
106
+ + 'and for an urgent reminder what its interruption request did (interrupt.state).',
107
+ inputSchema: { event_id: z.string() },
108
+ }, async ({ event_id }) => run(({ store }) => store.inspect(event_id), false));
109
+ server.registerTool('fleet_reminder_ack', {
110
+ description: 'Record that you handled a [fleet-reminder] wake (event_id + revision from the wake). '
111
+ + 'It closes the reminder and sends nothing; it does not claim any external action happened. Safe to repeat.',
112
+ inputSchema: { event_id: z.string(), expected_revision: z.number().int() },
113
+ }, async ({ event_id, expected_revision }) => run(({ store }) => store.ack(event_id, expected_revision), true));
114
+ }
@@ -103,6 +103,7 @@ export function resolvedRolePlan(role, manifestDir = dirname(role.sourceFile)) {
103
103
  isolation: role.isolation ?? null,
104
104
  worklog: role.worklog ?? null,
105
105
  authProxy: role.auth_proxy ?? null,
106
+ managedCli: role.managed_cli ?? [],
106
107
  oversee: role.oversee ?? [],
107
108
  harnessOptions: redactSensitive(role.harness_options ?? null),
108
109
  env: {
@@ -0,0 +1,48 @@
1
+ import type { FleetConfig } from '../config.js';
2
+ import { TaskStateError } from './task-state.js';
3
+ import { provisionMembers } from './provision.js';
4
+ import type { CoworkAdapter } from './cowork-adapter.js';
5
+ export declare class MemberAdditionRejected extends TaskStateError {
6
+ readonly accepted = false;
7
+ }
8
+ export interface AddMemberRequest {
9
+ requestId: string;
10
+ slot: string;
11
+ role: string;
12
+ brain: string;
13
+ agentTemplate: string;
14
+ }
15
+ export declare function memberAddition(taskId: string, requestId: string): {
16
+ requestId: string;
17
+ taskId: string;
18
+ roleId: string;
19
+ state: "running" | "succeeded" | "attention" | "failed";
20
+ error?: string;
21
+ } | {
22
+ state: string;
23
+ error: string;
24
+ requestId: string;
25
+ taskId: string;
26
+ roleId: string;
27
+ };
28
+ export declare function requestMemberAddition(input: {
29
+ taskId: string;
30
+ request: AddMemberRequest;
31
+ cfg: FleetConfig;
32
+ cowork: CoworkAdapter;
33
+ configPath?: string;
34
+ binPath: string;
35
+ provision?: typeof provisionMembers;
36
+ }): Promise<{
37
+ requestId: string;
38
+ taskId: string;
39
+ roleId: string;
40
+ state: "running" | "succeeded" | "attention" | "failed";
41
+ error?: string;
42
+ } | {
43
+ state: string;
44
+ error: string;
45
+ requestId: string;
46
+ taskId: string;
47
+ roleId: string;
48
+ }>;
@@ -0,0 +1,84 @@
1
+ import { publishFleetResourceCommit } from '../application/resource-observer.js';
2
+ import { createHash } from 'node:crypto';
3
+ import { existsSync, mkdirSync, readFileSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { replaceFileAtomically, withFileLock } from '../atomic-file.js';
6
+ import { canonicalJson } from '../canonical-json.js';
7
+ import { stateRoot } from '../paths.js';
8
+ import { getTask, TaskStateError } from './task-state.js';
9
+ import { getRoomRecord } from './room-state.js';
10
+ import { prepareExecutionPlan } from './member-overrides.js';
11
+ import { sealTemplateSnapshot } from './templates.js';
12
+ import { provisionMembers } from './provision.js';
13
+ export class MemberAdditionRejected extends TaskStateError {
14
+ accepted = false;
15
+ }
16
+ const running = new Set();
17
+ function pathFor(taskId, requestId) {
18
+ if (!/^[a-z0-9]{10,40}$/.test(taskId) || !/^[a-zA-Z0-9_-]{8,80}$/.test(requestId))
19
+ throw new TaskStateError('Invalid task or request ID');
20
+ return join(stateRoot(), 'member-additions', taskId, requestId + '.json');
21
+ }
22
+ export function memberAddition(taskId, requestId) {
23
+ getTask(taskId);
24
+ const path = pathFor(taskId, requestId);
25
+ if (!existsSync(path))
26
+ throw new TaskStateError('Member request not found');
27
+ const receipt = JSON.parse(readFileSync(path, 'utf8'));
28
+ const { hash, ...view } = receipt;
29
+ return receipt.state === 'running' && !running.has(path) ? { ...view, state: 'attention', error: 'The server stopped observing this launch. Inspect the existing agent before any recovery.' } : view;
30
+ }
31
+ export async function requestMemberAddition(input) {
32
+ const { request: r, taskId } = input;
33
+ if (!r || typeof r.slot !== 'string' || !/^[A-Za-z][A-Za-z0-9_-]{0,31}$/.test(r.slot)
34
+ || ![r.role, r.brain, r.agentTemplate].every(v => typeof v === 'string' && v.length > 0 && v.length <= 128))
35
+ // No receipt lookup has happened yet: this request ID may already be accepted.
36
+ throw new TaskStateError('Slot, Role, Brain and Agent Template are required');
37
+ const path = pathFor(taskId, r.requestId);
38
+ const hash = createHash('sha256').update(canonicalJson(r)).digest('hex');
39
+ mkdirSync(join(stateRoot(), 'member-additions', taskId), { recursive: true, mode: 0o700 });
40
+ return withFileLock(path + '.lock', async () => {
41
+ if (existsSync(path)) {
42
+ const old = JSON.parse(readFileSync(path, 'utf8'));
43
+ if (old.hash !== hash)
44
+ throw new TaskStateError('Request ID was already used with different settings');
45
+ return memberAddition(taskId, r.requestId);
46
+ }
47
+ const task = getTask(taskId);
48
+ const room = task.room_id && getRoomRecord(task.room_id);
49
+ if (!room || !['active', 'review'].includes(task.state) || task.terminal_intent || room.state !== 'active'
50
+ || room.task_id !== taskId || room.room_identity_cid !== task.room_identity_cid)
51
+ throw new MemberAdditionRejected('Adding an agent requires an active task room');
52
+ const roleId = `${taskId.slice(0, 8)}-${r.slot}-1`;
53
+ if (room.member_seats.some(s => s.role_name === roleId))
54
+ throw new MemberAdditionRejected('This member slot already exists');
55
+ const plan = (() => {
56
+ try {
57
+ return prepareExecutionPlan({ name: 'additional-member', version: 1, description: 'Additional task participant',
58
+ contract: room.template_snapshot?.contract, members: [{ slot: r.slot, role: r.role, count: 1, agent_template: r.agentTemplate }] }, input.cfg, { [r.slot]: { role: r.role, brain: r.brain } });
59
+ }
60
+ catch (error) {
61
+ throw new MemberAdditionRejected(error instanceof Error ? error.message : 'Invalid member configuration');
62
+ }
63
+ })();
64
+ const template = sealTemplateSnapshot(plan.snapshot, input.cfg.agentTemplates ?? {}, plan.launchDefinitions);
65
+ const receipt = { taskId, requestId: r.requestId, roleId, hash, state: 'running' };
66
+ const save = () => { replaceFileAtomically(path, JSON.stringify(receipt) + '\n', 0o600); publishFleetResourceCommit(path); };
67
+ save();
68
+ running.add(path);
69
+ void (input.provision ?? provisionMembers)({ cfg: input.cfg, cowork: input.cowork, configPath: input.configPath, binPath: input.binPath,
70
+ taskId, roomId: room.room_id, template, goal: task.title, brief: task.brief, append: true }).then(result => {
71
+ const seat = result.member_seats.find(s => s.role_name === roleId);
72
+ receipt.state = seat?.seat_state === 'active' && getTask(taskId).member_roles.some(m => m.name === roleId) ? 'succeeded' : 'attention';
73
+ if (receipt.state === 'attention')
74
+ receipt.error = 'Admission is not confirmed. Inspect the existing launch; no automatic retry was made.';
75
+ }).catch(() => { receipt.state = 'failed'; receipt.error = 'Member launch failed. Inspect the task and agent logs before recovery.'; })
76
+ .finally(() => { try {
77
+ save();
78
+ }
79
+ finally {
80
+ running.delete(path);
81
+ } }).catch(() => { running.delete(path); });
82
+ return memberAddition(taskId, r.requestId);
83
+ });
84
+ }
@@ -1,4 +1,8 @@
1
1
  import type { ArchivedMemberAbsence, RoomMemberSeat } from './types.js';
2
2
  /** Revalidate live facts; a persisted timestamp is never cleanup authority. */
3
3
  export declare function verifyArchivedAbsence(proof: ArchivedMemberAbsence): Promise<void>;
4
+ /** After the verified archive has been consumed by explicit workspace deletion,
5
+ * still fence replacement live state and a recreated daemon identity on every retry.
6
+ */
7
+ export declare function verifyArchivedMemberStillAbsent(proof: ArchivedMemberAbsence): Promise<void>;
4
8
  export declare function proveArchivedAbsence(seat: RoomMemberSeat): Promise<ArchivedMemberAbsence>;
@@ -18,6 +18,17 @@ export async function verifyArchivedAbsence(proof) {
18
18
  throw new Error('Archived member absence ownership proof mismatch');
19
19
  if (await tempSupervisorLiveness(archive) !== 'stopped')
20
20
  throw new Error('Archived member supervisor absence is not proven');
21
+ await verifyArchivedMemberStillAbsent(proof);
22
+ }
23
+ /** After the verified archive has been consumed by explicit workspace deletion,
24
+ * still fence replacement live state and a recreated daemon identity on every retry.
25
+ */
26
+ export async function verifyArchivedMemberStillAbsent(proof) {
27
+ const absent = () => {
28
+ if (existsSync(agentDir(proof.name, true)))
29
+ throw new Error('Archived member has replacement live state');
30
+ };
31
+ absent();
21
32
  await assertMemberIdentityAbsent({
22
33
  role_name: proof.name, slot: 'archived', cowork_role: 'archived', seat_state: 'removed',
23
34
  });
@@ -45,6 +45,8 @@ import { createCoworkAdapter } from './cowork-adapter.js';
45
45
  import { markdownCode, markdownProse, renderMarkdownFailure, renderMarkdownList, renderMarkdownResult, roomStatus, taskStatus, } from './markdown.js';
46
46
  import { recordTaskProvisioningOutcome, TaskRoomApplicationError, TaskRoomApplicationService, } from '../application/task-room-service.js';
47
47
  import { TaskListError } from './task-lists.js';
48
+ import { appendTaskProgress, attachTaskReviewArtifact, detachTaskReviewArtifact, getTaskReview, listTaskProgress, openTaskWorkspaceFile, publicProgressEntry, publicReview, setTaskReviewMarkdown, TaskReviewError, } from './task-review.js';
49
+ import { verifiedFleetCaller } from '../fleet-command-audit.js';
48
50
  import { beginFleetAuditCollection, consumeFleetAuditCollection, recordFleetAuditFailure, recordFleetAuditPresentation, recordFleetAuditResource, } from '../fleet-command-audit.js';
49
51
  import { renderAgentConfiguration } from '../lifecycle-summary.js';
50
52
  import { withFileLock } from '../atomic-file.js';
@@ -75,6 +77,11 @@ async function presentDetachedProvisioningOutcome(outcome) {
75
77
  function taskRoomPublicFailure(error) {
76
78
  const f = error.fields;
77
79
  switch (error.code) {
80
+ case 'task_not_ready': return {
81
+ legacy: `task readiness ${f.readiness}: ${f.reason}`, kind: 'state',
82
+ detail: `Task ${f.task} readiness is ${f.readiness}: ${f.reason}${f.member ? ` (${f.member})` : ''}.`,
83
+ action: 'Ask Fleet Coordinator to inspect room and member status and choose supported recovery. Do not blindly relaunch agents or reuse invites.',
84
+ };
78
85
  case 'task_confirmation_mismatch': return {
79
86
  legacy: 'confirmation ID must match task ID', kind: 'usage',
80
87
  detail: 'The two task IDs must match.', action: 'Repeat the same task ID twice.',
@@ -130,6 +137,28 @@ function taskRoomPublicFailure(error) {
130
137
  };
131
138
  }
132
139
  }
140
+ /** A supervisor-verified managed agent is attributed as itself; otherwise the local operator. */
141
+ function cliContributionAuthor(taskId) {
142
+ const verified = verifiedFleetCaller();
143
+ if (!verified)
144
+ return { kind: 'local_control', surface: 'cli' };
145
+ // The same identity CID the agent's MCP tools use, so retries match across both surfaces.
146
+ const cid = getTask(taskId).member_roles.find(item => item.name === verified.caller)?.identity_cid ?? bridgeIdentityCid(verified.stateDir);
147
+ return { kind: 'agent', role: verified.caller, ...(cid ? { identity_cid: cid } : {}), surface: 'cli' };
148
+ }
149
+ /** The managed runtime CID its supervisor recorded for the agent's MCP bridge, when present. */
150
+ function bridgeIdentityCid(stateDir) {
151
+ try {
152
+ const cid = JSON.parse(readFileSync(join(stateDir, '.ours-bridge', 'descriptor.json'), 'utf8')).cid;
153
+ return typeof cid === 'string' && /^[A-Fa-f0-9]{64}$/.test(cid) ? cid : undefined;
154
+ }
155
+ catch {
156
+ return undefined;
157
+ }
158
+ }
159
+ function contributionAuthorLabel(author) {
160
+ return author.kind === 'agent' ? `${author.role} (agent, ${author.surface})` : `local ${author.surface}`;
161
+ }
133
162
  function die(e) {
134
163
  const msg = e instanceof TaskRoomPublicError
135
164
  ? taskRoomPublicFailure(e).legacy : e instanceof Error ? e.message : String(e);
@@ -196,6 +225,19 @@ function dieTaskRoom(e) {
196
225
  recordFleetAuditFailure({ class: 'validation', effect: 'not_started' });
197
226
  process.exit(1);
198
227
  }
228
+ if (e instanceof TaskReviewError) {
229
+ const output = renderMarkdownFailure({
230
+ kind: e.code === 'not_found' ? 'not_found' : e.code === 'conflict' || e.code === 'idempotency_conflict' ? 'state' : 'usage',
231
+ subject: 'ours-fleet task progress/review-package',
232
+ detail: e.message,
233
+ action: e.code === 'conflict' ? 'Show the current review package and retry against it.'
234
+ : e.code === 'idempotency_conflict' ? 'Use a new --request-key for different content.'
235
+ : 'Correct the request and retry.',
236
+ });
237
+ process.stderr.write(`${output}\n`);
238
+ recordFleetAuditFailure({ class: 'validation', effect: 'not_started' });
239
+ process.exit(1);
240
+ }
199
241
  if (e instanceof TaskListError) {
200
242
  const notFound = e.code === 'list_not_found';
201
243
  const conflict = ['duplicate_name', 'reserved_name', 'default_immutable',
@@ -242,6 +284,8 @@ const taskListMarkdown = (tasks, title = 'Tasks') => renderMarkdownList({
242
284
  icon: '📋', title, empty: 'No tasks found.',
243
285
  records: tasks.map(t => `${taskStatus(t.state)} ${markdownCode(t.task_id)} — ${markdownProse(t.title)}`
244
286
  + ` — List ${markdownCode(t.list_name ?? 'default')}`
287
+ + (t.deletion?.status === 'pending' ? ' — Deletion pending'
288
+ + (t.deletion.error ? `: ${markdownProse(t.deletion.error)}` : '') : '')
245
289
  + (t.blocked ? ` — 🚧 Blocked: ${markdownProse(t.blocked.reason)}` : '')),
246
290
  });
247
291
  const taskActionMarkdown = (title, task, fields = []) => {
@@ -515,10 +559,10 @@ function taskRoomService(configuration) {
515
559
  function allTemplates(cfg) {
516
560
  return cfg.roomTemplates ?? {};
517
561
  }
518
- function coworkFor(cfg) {
562
+ function coworkFor(cfg, options) {
519
563
  if (!cfg.rooms)
520
564
  throw new ConfigError('rooms: configuration is required before creating or querying rooms');
521
- return createCoworkAdapter({ configPath: cfg.rooms.cowork?.config });
565
+ return createCoworkAdapter({ configPath: cfg.rooms.cowork?.config, ...options });
522
566
  }
523
567
  function resolveRoomTemplate(cfg, name) {
524
568
  if (!name)
@@ -709,6 +753,7 @@ export function registerTaskCommands(parent, cOpt) {
709
753
  .option('--state <state>', 'filter by state (backlog|active|provisioning|review|done|cancelled|failed|all)')
710
754
  .option('--list <name>', 'filter by task list')
711
755
  .option('--group-by-list', 'group deterministic results by list (JSON)')
756
+ .option('--include-deleting', 'include tasks whose accepted deletion is still pending')
712
757
  .option('--json', 'JSON output')
713
758
  .action(async (opts) => {
714
759
  try {
@@ -717,7 +762,8 @@ export function registerTaskCommands(parent, cOpt) {
717
762
  stateFilter = opts.state;
718
763
  }
719
764
  const service = taskRoomService(opts.configuration);
720
- const filter = { ...(stateFilter ? { state: stateFilter } : {}), ...(opts.list ? { list: opts.list } : {}) };
765
+ const filter = { ...(stateFilter ? { state: stateFilter } : {}), ...(opts.list ? { list: opts.list } : {}),
766
+ ...(opts.includeDeleting ? { includeDeleting: true } : {}) };
721
767
  const tasks = service.listTasks(filter);
722
768
  if (opts.json) {
723
769
  console.log(JSON.stringify(opts.groupByList
@@ -827,16 +873,19 @@ export function registerTaskCommands(parent, cOpt) {
827
873
  dieTaskRoom(e);
828
874
  }
829
875
  });
830
- taskCmd.command('show <id>')
876
+ cOpt(taskCmd.command('show <id>'))
831
877
  .description('show task details')
832
878
  .option('--json', 'JSON output')
833
879
  .action(async (id, opts) => {
834
880
  try {
835
- const service = taskRoomService();
881
+ const service = taskRoomService(opts.configuration);
836
882
  const { task: t, orchestration: room } = service.getTask(id);
883
+ const readiness = t.state === 'active' && t.deletion?.status !== 'pending'
884
+ ? await service.observeTaskReadiness(id) : undefined;
837
885
  if (opts.json) {
838
886
  console.log(JSON.stringify({
839
887
  schema_version: 1, task: t, orchestration: room ?? null,
888
+ ...(readiness ? { readiness } : {}),
840
889
  }, null, 2));
841
890
  return;
842
891
  }
@@ -846,6 +895,13 @@ export function registerTaskCommands(parent, cOpt) {
846
895
  { label: 'ID', value: t.task_id, kind: 'code' },
847
896
  { label: 'Title', value: t.title },
848
897
  { label: 'Status', value: taskStatus(t.state), kind: 'markdown' },
898
+ ...(t.deletion?.status === 'pending' ? [
899
+ { label: 'Deletion', value: 'Pending — cleanup is not complete' },
900
+ ...(t.deletion.error ? [{ label: 'Cleanup error', value: t.deletion.error }] : []),
901
+ { label: 'Retry', value: `ours-fleet task delete ${t.task_id} ${t.task_id}`, kind: 'code' },
902
+ ] : []),
903
+ ...(readiness ? [{ label: 'Readiness', value: readiness.state },
904
+ ...('reason' in readiness ? [{ label: 'Reason', value: readiness.reason }] : [])] : []),
849
905
  ...(t.blocked ? [{ label: 'Blocked', value: t.blocked.reason }] : []),
850
906
  ...(t.template ? [{ label: 'Template', value: `${t.template.name}@${t.template.version}`, kind: 'code' }] : []),
851
907
  ...(t.room_id ? [{ label: 'Room', value: t.room_id, kind: 'code' }] : []),
@@ -872,6 +928,27 @@ export function registerTaskCommands(parent, cOpt) {
872
928
  dieTaskRoom(e);
873
929
  }
874
930
  });
931
+ cOpt(taskCmd.command('recover-members <id>'))
932
+ .description('resume proven stopped task members in-place; never create identities or replay invites')
933
+ .option('--json', 'JSON output')
934
+ .action(async (id, opts) => {
935
+ try {
936
+ const { recoverTaskMembers } = await import('./recovery.js');
937
+ const task = getTask(id), cfg = loadConfig(opts.configuration);
938
+ const members = await recoverTaskMembers({ taskId: id, binPath: getBinPath(),
939
+ cowork: task.layout ? undefined : createCoworkAdapter({ configPath: cfg.rooms?.cowork?.config }) });
940
+ if (opts.json)
941
+ console.log(JSON.stringify({ schema_version: 1, task_id: id, members }, null, 2));
942
+ else
943
+ for (const member of members)
944
+ console.log(`${member.name}: ${member.status}`);
945
+ }
946
+ catch (e) {
947
+ if (opts.json)
948
+ die(e);
949
+ dieTaskRoom(e);
950
+ }
951
+ });
875
952
  cOpt(taskCmd.command('start <id>'))
876
953
  .description('idempotently select a plan, provision, and start a task')
877
954
  .option('--template <name>', 'room template')
@@ -988,6 +1065,86 @@ export function registerTaskCommands(parent, cOpt) {
988
1065
  dieTaskRoom(e);
989
1066
  }
990
1067
  });
1068
+ taskCmd.command('progress <id>')
1069
+ .description('read the task Progress log, or append one significant milestone with --text')
1070
+ .option('--text <text>', 'milestone text to append, kept exactly as written')
1071
+ .option('--text-file <path>', 'milestone text to append, from a file')
1072
+ .option('--request-key <key>', 'retry key: repeating the same key and text returns the original entry')
1073
+ .option('--json', 'JSON output')
1074
+ .action((id, opts) => {
1075
+ try {
1076
+ if (opts.text !== undefined && opts.textFile !== undefined)
1077
+ throw new Error('use --text or --text-file, not both');
1078
+ const text = opts.textFile !== undefined ? readFileSync(opts.textFile, 'utf8') : opts.text;
1079
+ if (text === undefined) {
1080
+ if (opts.requestKey !== undefined)
1081
+ throw new Error('--request-key applies only when appending');
1082
+ const progress = listTaskProgress(id).map(publicProgressEntry);
1083
+ if (opts.json) {
1084
+ console.log(JSON.stringify({ schema_version: 1, task_id: id, progress }, null, 2));
1085
+ return;
1086
+ }
1087
+ console.log(progress.length ? progress.map(entry => `- ${entry.at} — ${contributionAuthorLabel(entry.author)}\n\n${entry.text}\n`).join('\n')
1088
+ : `Task ${id} has no progress entries.`);
1089
+ return;
1090
+ }
1091
+ const result = appendTaskProgress(id, { text, requestKey: opts.requestKey, author: cliContributionAuthor(id) });
1092
+ if (opts.json) {
1093
+ console.log(JSON.stringify({ schema_version: 1, task_id: id, entry: publicProgressEntry(result.entry), replayed: result.replayed }, null, 2));
1094
+ return;
1095
+ }
1096
+ console.log(result.replayed ? `Progress entry ${result.entry.id} was already recorded.` : `Progress entry ${result.entry.id} added to task ${id}.`);
1097
+ }
1098
+ catch (e) {
1099
+ if (opts.json)
1100
+ die(e);
1101
+ dieTaskRoom(e);
1102
+ }
1103
+ });
1104
+ taskCmd.command('review-package <id>')
1105
+ .description('show or prepare the task To review package (Markdown and retained files)')
1106
+ .option('--markdown <text>', 'replace the review Markdown')
1107
+ .option('--markdown-file <path>', 'replace the review Markdown from a file')
1108
+ .option('--attach <path>', 'retain a file from the task workspace in the package (repeatable)', (value, all) => [...all, value], [])
1109
+ .option('--detach <artifact-id>', 'remove a file from the package (repeatable)', (value, all) => [...all, value], [])
1110
+ .option('--request-key <key>', 'retry key for a single --attach: repeating it with the same file returns the original artifact')
1111
+ .option('--json', 'JSON output')
1112
+ .action(async (id, opts) => {
1113
+ try {
1114
+ if (opts.markdown !== undefined && opts.markdownFile !== undefined)
1115
+ throw new Error('use --markdown or --markdown-file, not both');
1116
+ if (opts.requestKey !== undefined && opts.attach.length !== 1)
1117
+ throw new Error('--request-key needs exactly one --attach');
1118
+ const markdown = opts.markdownFile !== undefined ? readFileSync(opts.markdownFile, 'utf8') : opts.markdown;
1119
+ const author = markdown !== undefined || opts.attach.length || opts.detach.length ? cliContributionAuthor(id) : undefined;
1120
+ const attached = [];
1121
+ if (markdown !== undefined)
1122
+ setTaskReviewMarkdown(id, { markdown, expectedMarkdown: getTaskReview(id)?.markdown ?? '', author: author });
1123
+ for (const artifactId of opts.detach)
1124
+ detachTaskReviewArtifact(id, artifactId, { author: author });
1125
+ for (const path of opts.attach) {
1126
+ const source = await openTaskWorkspaceFile(getTask(id), path);
1127
+ attached.push(await attachTaskReviewArtifact(id, { name: source.name, source, author: author, requestKey: opts.requestKey }));
1128
+ }
1129
+ const review = getTaskReview(id);
1130
+ if (opts.json) {
1131
+ console.log(JSON.stringify({ schema_version: 1, task_id: id, review: review ? publicReview(review) : null }, null, 2));
1132
+ return;
1133
+ }
1134
+ if (!review) {
1135
+ console.log(`Task ${id} has no To review package yet.`);
1136
+ return;
1137
+ }
1138
+ const files = review.artifacts.map(artifact => `- \`${artifact.id}\` ${artifact.name} (${artifact.mime}, ${artifact.size} bytes)`).join('\n');
1139
+ console.log(`## To review — task ${id}\n\n${review.markdown || '_No review Markdown yet._'}\n\n### Files\n\n${files || '_No files._'}`
1140
+ + (attached.some(item => item.replayed) ? '\n\n(The attached file was already recorded.)' : ''));
1141
+ }
1142
+ catch (e) {
1143
+ if (opts.json)
1144
+ die(e);
1145
+ dieTaskRoom(e);
1146
+ }
1147
+ });
991
1148
  cOpt(taskCmd.command('done <id>'))
992
1149
  .description('complete a task')
993
1150
  .option('--summary <text>', 'completion summary')
@@ -1176,6 +1333,26 @@ export function registerTaskCommands(parent, cOpt) {
1176
1333
  dieTaskRoom(e);
1177
1334
  }
1178
1335
  });
1336
+ cOpt(taskCmd.command('_layout <id> <operation> [room]', { hidden: true }))
1337
+ .description('internal: run an accepted layout room operation (open, close-room, close)')
1338
+ .option('--json', 'JSON output')
1339
+ .option('--operation-id <id>', 'accepted operation ID; status updates apply only while it is current')
1340
+ .action(async (id, operation, room, opts) => {
1341
+ try {
1342
+ if (!['open', 'close-room', 'close'].includes(operation))
1343
+ throw new Error(`unknown layout operation: ${operation}`);
1344
+ const view = await taskRoomService(opts.configuration).runTaskLayoutOperation({
1345
+ actor: { kind: 'internal_worker', surface: 'cli' }, taskId: id,
1346
+ operation: operation, room, operationId: opts.operationId,
1347
+ });
1348
+ console.log(JSON.stringify({ schema_version: 1, layout: view }, null, 2));
1349
+ }
1350
+ catch (e) {
1351
+ if (opts.json)
1352
+ die(e);
1353
+ dieTaskRoom(e);
1354
+ }
1355
+ });
1179
1356
  cOpt(taskCmd.command('_settle_delete <id>', { hidden: true }))
1180
1357
  .description('internal: settle a previously accepted task deletion')
1181
1358
  .option('--json', 'JSON output')
@@ -1,9 +1,12 @@
1
+ import { retireTaskMemberService } from './task-service-retirement.js';
1
2
  import { withFileLock } from '../atomic-file.js';
2
3
  import { type TempLifecycleDeps } from '../temp-lifecycle.js';
3
4
  import { type CoworkAdapter } from './cowork-adapter.js';
4
5
  import type { RoomMemberSeat, RoomOrchestrationRecord } from './types.js';
6
+ export declare const CLOSE_LOCK_STALE_MS: number;
5
7
  export declare function roomCloseLockPath(roomId: string): string;
6
8
  export interface RoomCloseDeps {
9
+ retireTaskService?: typeof retireTaskMemberService;
7
10
  inspectMember?(seat: RoomMemberSeat): Promise<{
8
11
  launchId: string;
9
12
  }>;
@@ -26,7 +29,7 @@ export declare function acceptManagedRoomClose(roomId: string): Promise<RoomOrch
26
29
  export declare function recordManagedRoomCloseError(roomId: string, error: string, recoveryHint: string): Promise<RoomOrchestrationRecord>;
27
30
  export declare function closeManagedRoom(input: {
28
31
  roomId: string;
29
- cowork: Pick<CoworkAdapter, 'closeRoom'>;
32
+ cowork: Pick<CoworkAdapter, 'closeRoom'> & Partial<Pick<CoworkAdapter, 'getRoom'>>;
30
33
  deps?: RoomCloseDeps;
31
34
  }): Promise<RoomOrchestrationRecord>;
32
35
  export interface ManagedRoomDeleteResult {
@@ -40,6 +43,6 @@ export declare function deleteLegacyClosedRooms(input: {
40
43
  /** Retire live resources through the existing cursor, then delete retained state. */
41
44
  export declare function deleteManagedRoom(input: {
42
45
  roomId: string;
43
- cowork: Pick<CoworkAdapter, 'closeRoom' | 'deleteRoom'>;
46
+ cowork: Pick<CoworkAdapter, 'closeRoom' | 'deleteRoom'> & Partial<Pick<CoworkAdapter, 'getRoom'>>;
44
47
  deps?: RoomCloseDeps;
45
48
  }): Promise<ManagedRoomDeleteResult>;