@ours.network/fleet 1.2.0-nightly.8 → 1.2.0-nightly.80

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (423) hide show
  1. package/README.md +279 -68
  2. package/dist/account-origin.d.ts +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 +19 -0
  11. package/dist/agent-ours/mcp-endpoint.js +98 -25
  12. package/dist/agent-ours/runtime.d.ts +9 -1
  13. package/dist/agent-ours/runtime.js +50 -2
  14. package/dist/agent-ours/service.d.ts +24 -1
  15. package/dist/agent-ours/service.js +97 -13
  16. package/dist/application/codex-models.d.ts +15 -0
  17. package/dist/application/codex-models.js +56 -0
  18. package/dist/application/conversation-history.d.ts +34 -0
  19. package/dist/application/conversation-history.js +294 -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 +1 -1
  34. package/dist/application/role-repository.js +30 -7
  35. package/dist/application/room-layout-definitions.d.ts +45 -0
  36. package/dist/application/room-layout-definitions.js +130 -0
  37. package/dist/application/session-control.d.ts +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 +97 -31
  49. package/dist/build-info.json +9 -4
  50. package/dist/capabilities.d.ts +9 -1
  51. package/dist/capabilities.js +13 -0
  52. package/dist/cli.js +400 -37
  53. package/dist/client-profile.d.ts +5 -17
  54. package/dist/client-profile.js +4 -127
  55. package/dist/config.d.ts +45 -0
  56. package/dist/config.js +57 -6
  57. package/dist/creation.d.ts +1 -1
  58. package/dist/creation.js +4 -4
  59. package/dist/daemon-recovery.d.ts +14 -9
  60. package/dist/daemon-recovery.js +124 -115
  61. package/dist/docs.d.ts +1 -1
  62. package/dist/docs.js +207 -19
  63. package/dist/doctor.d.ts +4 -1
  64. package/dist/doctor.js +75 -60
  65. package/dist/erased-resources.d.ts +9 -0
  66. package/dist/erased-resources.js +87 -0
  67. package/dist/file-delivery/reader.d.ts +15 -0
  68. package/dist/file-delivery/reader.js +63 -0
  69. package/dist/file-delivery/store.d.ts +15 -0
  70. package/dist/file-delivery/store.js +124 -0
  71. package/dist/file-delivery/types.d.ts +19 -0
  72. package/dist/file-delivery/types.js +1 -0
  73. package/dist/fleet-command-audit.d.ts +7 -0
  74. package/dist/fleet-command-audit.js +24 -8
  75. package/dist/harness/agent-session.d.ts +4 -0
  76. package/dist/harness/claude-code-session.js +1 -1
  77. package/dist/harness/claude-code.js +21 -11
  78. package/dist/harness/claude-runtime.d.ts +12 -0
  79. package/dist/harness/claude-runtime.js +43 -0
  80. package/dist/harness/codex-app-server-proxy.d.ts +4 -1
  81. package/dist/harness/codex-app-server-proxy.js +41 -5
  82. package/dist/harness/codex-reasoning.d.ts +5 -0
  83. package/dist/harness/codex-reasoning.js +12 -0
  84. package/dist/harness/codex-runtime.d.ts +11 -1
  85. package/dist/harness/codex-runtime.js +31 -4
  86. package/dist/harness/codex-session.js +2 -2
  87. package/dist/harness/codex.js +24 -12
  88. package/dist/init-wizard.d.ts +2 -0
  89. package/dist/init-wizard.js +38 -19
  90. package/dist/isolation/policy.js +6 -1
  91. package/dist/isolation/types.d.ts +5 -0
  92. package/dist/managed-cli.d.ts +253 -0
  93. package/dist/managed-cli.js +923 -0
  94. package/dist/managed-recovery.d.ts +13 -0
  95. package/dist/managed-recovery.js +31 -0
  96. package/dist/minimal-setup.d.ts +2 -0
  97. package/dist/minimal-setup.js +44 -0
  98. package/dist/monitor.d.ts +9 -34
  99. package/dist/monitor.js +90 -153
  100. package/dist/notifications/fleet-producer.d.ts +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 +43 -0
  118. package/dist/process-incarnation.d.ts +23 -0
  119. package/dist/process-incarnation.js +42 -0
  120. package/dist/reminders/manager.d.ts +75 -0
  121. package/dist/reminders/manager.js +278 -0
  122. package/dist/reminders/runtime.d.ts +27 -0
  123. package/dist/reminders/runtime.js +32 -0
  124. package/dist/reminders/schedule.d.ts +37 -0
  125. package/dist/reminders/schedule.js +104 -0
  126. package/dist/reminders/store.d.ts +341 -0
  127. package/dist/reminders/store.js +762 -0
  128. package/dist/reminders/tools.d.ts +20 -0
  129. package/dist/reminders/tools.js +114 -0
  130. package/dist/resolved-plan.js +1 -0
  131. package/dist/rooms-tasks/add-member.d.ts +48 -0
  132. package/dist/rooms-tasks/add-member.js +84 -0
  133. package/dist/rooms-tasks/archived-absence.d.ts +4 -0
  134. package/dist/rooms-tasks/archived-absence.js +11 -0
  135. package/dist/rooms-tasks/cli.js +65 -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 +63 -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-service-retirement.d.ts +11 -0
  180. package/dist/rooms-tasks/task-service-retirement.js +21 -0
  181. package/dist/rooms-tasks/task-state.d.ts +43 -5
  182. package/dist/rooms-tasks/task-state.js +244 -22
  183. package/dist/rooms-tasks/types.d.ts +35 -0
  184. package/dist/rooms-tasks/workspace-artifacts.d.ts +6 -0
  185. package/dist/rooms-tasks/workspace-artifacts.js +93 -0
  186. package/dist/rooms-tasks/workspace.d.ts +35 -0
  187. package/dist/rooms-tasks/workspace.js +325 -0
  188. package/dist/runner.d.ts +33 -4
  189. package/dist/runner.js +410 -62
  190. package/dist/session/acp.d.ts +75 -2
  191. package/dist/session/acp.js +345 -82
  192. package/dist/session/arbiter.d.ts +98 -0
  193. package/dist/session/arbiter.js +272 -3
  194. package/dist/session/codex-app-server.d.ts +45 -1
  195. package/dist/session/codex-app-server.js +225 -32
  196. package/dist/session/control.d.ts +17 -3
  197. package/dist/session/control.js +219 -23
  198. package/dist/session/conversation-normalizer.d.ts +2 -1
  199. package/dist/session/conversation-normalizer.js +1 -1
  200. package/dist/session/conversation-observation.d.ts +25 -0
  201. package/dist/session/conversation-observation.js +100 -0
  202. package/dist/session/conversation-replay.d.ts +50 -0
  203. package/dist/session/conversation-replay.js +203 -0
  204. package/dist/session/conversation-store.d.ts +15 -1
  205. package/dist/session/conversation-store.js +213 -26
  206. package/dist/session/conversation-types.d.ts +57 -4
  207. package/dist/session/prompt-batch.d.ts +79 -0
  208. package/dist/session/prompt-batch.js +120 -0
  209. package/dist/session/task-notice.d.ts +14 -0
  210. package/dist/session/task-notice.js +13 -0
  211. package/dist/session/types.d.ts +42 -1
  212. package/dist/setup-tunnel-preflight.d.ts +34 -0
  213. package/dist/setup-tunnel-preflight.js +62 -0
  214. package/dist/socket-path.d.ts +2 -0
  215. package/dist/socket-path.js +22 -0
  216. package/dist/spawn.d.ts +5 -1
  217. package/dist/spawn.js +40 -4
  218. package/dist/startup-prompt.d.ts +15 -0
  219. package/dist/startup-prompt.js +71 -0
  220. package/dist/startup-readiness.d.ts +32 -0
  221. package/dist/startup-readiness.js +101 -0
  222. package/dist/startup-telemetry.d.ts +16 -0
  223. package/dist/startup-telemetry.js +46 -0
  224. package/dist/subscriptions/cli.d.ts +91 -0
  225. package/dist/subscriptions/cli.js +223 -0
  226. package/dist/subscriptions/launch.d.ts +37 -0
  227. package/dist/subscriptions/launch.js +93 -0
  228. package/dist/subscriptions/login.d.ts +77 -0
  229. package/dist/subscriptions/login.js +215 -0
  230. package/dist/subscriptions/observed.d.ts +7 -0
  231. package/dist/subscriptions/observed.js +44 -0
  232. package/dist/subscriptions/probe.d.ts +10 -0
  233. package/dist/subscriptions/probe.js +73 -0
  234. package/dist/subscriptions/service.d.ts +102 -0
  235. package/dist/subscriptions/service.js +364 -0
  236. package/dist/subscriptions/store.d.ts +71 -0
  237. package/dist/subscriptions/store.js +143 -0
  238. package/dist/supervisor/adoption.d.ts +8 -0
  239. package/dist/supervisor/adoption.js +78 -0
  240. package/dist/supervisor/catalog.d.ts +62 -0
  241. package/dist/supervisor/catalog.js +254 -0
  242. package/dist/supervisor/fleet.d.ts +8 -0
  243. package/dist/supervisor/fleet.js +89 -0
  244. package/dist/supervisor/index.js +3 -6
  245. package/dist/supervisor/launchd.d.ts +1 -1
  246. package/dist/supervisor/launchd.js +26 -13
  247. package/dist/supervisor/legacy.d.ts +35 -0
  248. package/dist/supervisor/legacy.js +524 -0
  249. package/dist/supervisor/manager.d.ts +15 -0
  250. package/dist/supervisor/manager.js +270 -0
  251. package/dist/supervisor/registration-refresh.d.ts +45 -0
  252. package/dist/supervisor/registration-refresh.js +266 -0
  253. package/dist/supervisor/scope.d.ts +4 -0
  254. package/dist/supervisor/scope.js +10 -0
  255. package/dist/supervisor/systemd.d.ts +2 -2
  256. package/dist/supervisor/systemd.js +19 -33
  257. package/dist/task-supervision.d.ts +9 -0
  258. package/dist/task-supervision.js +145 -0
  259. package/dist/temp-idle.d.ts +17 -0
  260. package/dist/temp-idle.js +42 -0
  261. package/dist/temp-lifecycle.d.ts +23 -8
  262. package/dist/temp-lifecycle.js +123 -66
  263. package/dist/temp-supervisor-recovery.d.ts +1 -1
  264. package/dist/temp-supervisor-recovery.js +2 -2
  265. package/dist/tunnel-setup-completion.d.ts +7 -0
  266. package/dist/tunnel-setup-completion.js +13 -0
  267. package/dist/tunnel-setup-input.d.ts +19 -0
  268. package/dist/tunnel-setup-input.js +130 -0
  269. package/dist/watchdog/query.d.ts +3 -1
  270. package/dist/watchdog/query.js +2 -1
  271. package/dist/web/agent-attachments.d.ts +29 -0
  272. package/dist/web/agent-attachments.js +162 -0
  273. package/dist/web/auth.d.ts +65 -2
  274. package/dist/web/auth.js +201 -11
  275. package/dist/web/available-port.d.ts +2 -0
  276. package/dist/web/available-port.js +23 -0
  277. package/dist/web/control.d.ts +3 -3
  278. package/dist/web/control.js +10 -8
  279. package/dist/web/conversation-stream-codec.d.ts +23 -0
  280. package/dist/web/conversation-stream-codec.js +110 -0
  281. package/dist/web/conversation-stream.d.ts +26 -0
  282. package/dist/web/conversation-stream.js +239 -0
  283. package/dist/web/events.d.ts +2 -0
  284. package/dist/web/events.js +9 -0
  285. package/dist/web/fleet-config-service.d.ts +7 -1
  286. package/dist/web/fleet-config-service.js +61 -16
  287. package/dist/web/prefix-gateway.d.ts +32 -0
  288. package/dist/web/prefix-gateway.js +248 -0
  289. package/dist/web/resource-views.d.ts +135 -0
  290. package/dist/web/resource-views.js +486 -0
  291. package/dist/web/runtime.d.ts +3 -1
  292. package/dist/web/runtime.js +132 -34
  293. package/dist/web/server.d.ts +19 -0
  294. package/dist/web/server.js +821 -68
  295. package/dist/web/service.d.ts +11 -2
  296. package/dist/web/service.js +30 -4
  297. package/dist/web/workspace-devices.d.ts +107 -0
  298. package/dist/web/workspace-devices.js +277 -0
  299. package/dist/web/workspace-tunnel.d.ts +1 -0
  300. package/dist/web/workspace-tunnel.js +34 -0
  301. package/dist/workspace-enrollment.d.ts +83 -0
  302. package/dist/workspace-enrollment.js +605 -0
  303. package/dist/workspace-replacement.d.ts +66 -0
  304. package/dist/workspace-replacement.js +238 -0
  305. package/docs/acp-files.md +146 -0
  306. package/docs/conversation-stream.md +216 -0
  307. package/docs/fleet-migration.md +54 -0
  308. package/docs/live-voice.md +13 -0
  309. package/docs/room-layouts.md +227 -0
  310. package/docs/self-reminders.md +374 -0
  311. package/docs/task-workspaces.md +225 -0
  312. package/docs/validation/managed-cli-permissions.md +421 -0
  313. package/examples/room-layouts/fresh.yaml +27 -0
  314. package/examples/room-layouts/scoped.yaml +21 -0
  315. package/examples/room-layouts/shared.yaml +19 -0
  316. package/package.json +24 -20
  317. package/presets/README.md +78 -0
  318. package/presets/brain-catalog.json +8 -2
  319. package/presets/fleet/agent_templates/Critic.yaml +1 -1
  320. package/presets/fleet/agent_templates/Developer.yaml +1 -1
  321. package/presets/fleet/agent_templates/Engineer.yaml +5 -0
  322. package/presets/fleet/agent_templates/LocalCoordinator.yaml +4 -2
  323. package/presets/fleet/agents/FleetCoordinator.yaml +1 -1
  324. package/presets/fleet/brains/claude-fable-5-1-high.yaml +5 -0
  325. package/presets/fleet/brains/claude-fable-5-1-low.yaml +5 -0
  326. package/presets/fleet/brains/claude-fable-5-1-max.yaml +5 -0
  327. package/presets/fleet/brains/claude-fable-5-1-medium.yaml +5 -0
  328. package/presets/fleet/brains/claude-fable-5-1-xhigh.yaml +5 -0
  329. package/presets/fleet/brains/claude-fable-5-high.yaml +1 -1
  330. package/presets/fleet/brains/claude-fable-5-low.yaml +1 -1
  331. package/presets/fleet/brains/claude-fable-5-max.yaml +1 -1
  332. package/presets/fleet/brains/claude-fable-5-medium.yaml +1 -1
  333. package/presets/fleet/brains/claude-fable-5-xhigh.yaml +1 -1
  334. package/presets/fleet/brains/claude-haiku-4-5-20251001-default.yaml +4 -0
  335. package/presets/fleet/brains/claude-opus-5-5-high.yaml +5 -0
  336. package/presets/fleet/brains/claude-opus-5-5-low.yaml +5 -0
  337. package/presets/fleet/brains/claude-opus-5-5-max.yaml +5 -0
  338. package/presets/fleet/brains/claude-opus-5-5-medium.yaml +5 -0
  339. package/presets/fleet/brains/claude-opus-5-5-xhigh.yaml +5 -0
  340. package/presets/fleet/brains/claude-opus-5-high.yaml +1 -1
  341. package/presets/fleet/brains/claude-opus-5-low.yaml +1 -1
  342. package/presets/fleet/brains/claude-opus-5-max.yaml +1 -1
  343. package/presets/fleet/brains/claude-opus-5-medium.yaml +1 -1
  344. package/presets/fleet/brains/claude-opus-5-xhigh.yaml +1 -1
  345. package/presets/fleet/brains/claude-sonnet-5-high.yaml +1 -1
  346. package/presets/fleet/brains/claude-sonnet-5-low.yaml +1 -1
  347. package/presets/fleet/brains/claude-sonnet-5-max.yaml +1 -1
  348. package/presets/fleet/brains/claude-sonnet-5-medium.yaml +1 -1
  349. package/presets/fleet/brains/claude-sonnet-5-xhigh.yaml +1 -1
  350. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-high.yaml +1 -1
  351. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-low.yaml +1 -1
  352. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-medium.yaml +1 -1
  353. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-xhigh.yaml +1 -1
  354. package/presets/fleet/brains/codex-gpt-5-4-high.yaml +1 -1
  355. package/presets/fleet/brains/codex-gpt-5-4-low.yaml +1 -1
  356. package/presets/fleet/brains/codex-gpt-5-4-medium.yaml +1 -1
  357. package/presets/fleet/brains/codex-gpt-5-4-mini-high.yaml +1 -1
  358. package/presets/fleet/brains/codex-gpt-5-4-mini-low.yaml +1 -1
  359. package/presets/fleet/brains/codex-gpt-5-4-mini-medium.yaml +1 -1
  360. package/presets/fleet/brains/codex-gpt-5-4-mini-xhigh.yaml +1 -1
  361. package/presets/fleet/brains/codex-gpt-5-4-xhigh.yaml +1 -1
  362. package/presets/fleet/brains/codex-gpt-5-5-high.yaml +1 -1
  363. package/presets/fleet/brains/codex-gpt-5-5-low.yaml +1 -1
  364. package/presets/fleet/brains/codex-gpt-5-5-medium.yaml +1 -1
  365. package/presets/fleet/brains/codex-gpt-5-5-xhigh.yaml +1 -1
  366. package/presets/fleet/brains/codex-gpt-5-6-luna-high.yaml +1 -1
  367. package/presets/fleet/brains/codex-gpt-5-6-luna-low.yaml +1 -1
  368. package/presets/fleet/brains/codex-gpt-5-6-luna-max.yaml +1 -1
  369. package/presets/fleet/brains/codex-gpt-5-6-luna-medium.yaml +1 -1
  370. package/presets/fleet/brains/codex-gpt-5-6-luna-xhigh.yaml +1 -1
  371. package/presets/fleet/brains/codex-gpt-5-6-sol-high.yaml +1 -1
  372. package/presets/fleet/brains/codex-gpt-5-6-sol-low.yaml +1 -1
  373. package/presets/fleet/brains/codex-gpt-5-6-sol-max.yaml +1 -1
  374. package/presets/fleet/brains/codex-gpt-5-6-sol-medium.yaml +1 -1
  375. package/presets/fleet/brains/codex-gpt-5-6-sol-ultra.yaml +1 -1
  376. package/presets/fleet/brains/codex-gpt-5-6-sol-xhigh.yaml +1 -1
  377. package/presets/fleet/brains/codex-gpt-5-6-terra-high.yaml +1 -1
  378. package/presets/fleet/brains/codex-gpt-5-6-terra-low.yaml +1 -1
  379. package/presets/fleet/brains/codex-gpt-5-6-terra-max.yaml +1 -1
  380. package/presets/fleet/brains/codex-gpt-5-6-terra-medium.yaml +1 -1
  381. package/presets/fleet/brains/codex-gpt-5-6-terra-ultra.yaml +1 -1
  382. package/presets/fleet/brains/codex-gpt-5-6-terra-xhigh.yaml +1 -1
  383. package/presets/fleet/brains/codex-gpt-6-1-sol-high.yaml +5 -0
  384. package/presets/fleet/brains/codex-gpt-6-1-sol-low.yaml +5 -0
  385. package/presets/fleet/brains/codex-gpt-6-1-sol-max.yaml +5 -0
  386. package/presets/fleet/brains/codex-gpt-6-1-sol-medium.yaml +5 -0
  387. package/presets/fleet/brains/codex-gpt-6-1-sol-ultra.yaml +5 -0
  388. package/presets/fleet/brains/codex-gpt-6-1-sol-xhigh.yaml +5 -0
  389. package/presets/fleet/brains/codex-gpt-6-astra-high.yaml +1 -1
  390. package/presets/fleet/brains/codex-gpt-6-astra-low.yaml +1 -1
  391. package/presets/fleet/brains/codex-gpt-6-astra-max.yaml +1 -1
  392. package/presets/fleet/brains/codex-gpt-6-astra-medium.yaml +1 -1
  393. package/presets/fleet/brains/codex-gpt-6-astra-ultra.yaml +1 -1
  394. package/presets/fleet/brains/codex-gpt-6-astra-xhigh.yaml +1 -1
  395. package/presets/fleet/brains/codex-gpt-6-luna-high.yaml +5 -0
  396. package/presets/fleet/brains/codex-gpt-6-luna-low.yaml +5 -0
  397. package/presets/fleet/brains/codex-gpt-6-luna-max.yaml +5 -0
  398. package/presets/fleet/brains/codex-gpt-6-luna-medium.yaml +5 -0
  399. package/presets/fleet/brains/codex-gpt-6-luna-xhigh.yaml +5 -0
  400. package/presets/fleet/brains/codex-gpt-6-sol-high.yaml +5 -0
  401. package/presets/fleet/brains/codex-gpt-6-sol-low.yaml +5 -0
  402. package/presets/fleet/brains/codex-gpt-6-sol-max.yaml +5 -0
  403. package/presets/fleet/brains/codex-gpt-6-sol-medium.yaml +5 -0
  404. package/presets/fleet/brains/codex-gpt-6-sol-ultra.yaml +5 -0
  405. package/presets/fleet/brains/codex-gpt-6-sol-xhigh.yaml +5 -0
  406. package/presets/fleet/roles/Coordinator.yaml +12 -11
  407. package/presets/fleet/roles/Critic.yaml +13 -0
  408. package/presets/fleet/roles/Developer.yaml +13 -0
  409. package/presets/fleet/roles/Engineer.yaml +53 -0
  410. package/presets/fleet/room_layouts/engineering.yaml +25 -0
  411. package/presets/fleet/room_layouts/pair.yaml +24 -0
  412. package/presets/fleet/room_layouts/single.yaml +17 -0
  413. package/presets/fleet/room_layouts/team.yaml +30 -0
  414. package/presets/fleet/room_templates/engineering.yaml +19 -0
  415. package/presets/manifest.json +2 -2
  416. package/dist/web-app/assets/index-59GF-gsZ.css +0 -1
  417. package/dist/web-app/assets/index-C0h3ALvs.js +0 -10
  418. package/dist/web-app/icons/ours-fleet-maskable.svg +0 -4
  419. package/dist/web-app/icons/ours-fleet.svg +0 -4
  420. package/dist/web-app/index.html +0 -17
  421. package/dist/web-app/manifest.webmanifest +0 -15
  422. package/dist/web-app/offline.html +0 -18
  423. package/dist/web-app/sw.js +0 -51
package/dist/docs.js CHANGED
@@ -172,34 +172,29 @@ rollback; inspect host integration and private init stage/recovery evidence.
172
172
  Attachment also accepts \`/permit <permission-id> <option-id>\`, \`/interrupt\`,
173
173
  and \`/detach\`.
174
174
 
175
- ## Local web console
175
+ ## Local HTTP service
176
176
 
177
- The npm package includes the web console; installed users do not clone the repo
178
- or run \`npm run build\`:
177
+ Fleet runs an HTTP service for the App. It serves no pages and opens no
178
+ browser; every screen is in the App.
179
179
 
180
180
  \`\`\`sh
181
181
  npm i -g @ours.network/fleet
182
- ours-fleet init
183
- ours-fleet doctor
184
- ours-fleet web # install/update service, start, pair browser
182
+ ours-fleet setup-tunnel --file /private/setup.txt # connect host; prints QR and connection code
183
+ ours-fleet link-device # connect another browser or device
185
184
  \`\`\`
186
185
 
187
- The normal command uses stable \`http://127.0.0.1:49271/\`, installs an
188
- owner-level systemd user service (Linux) or LaunchAgent (macOS), and opens a
189
- five-minute one-use pairing link in the local browser. After pairing, bookmark
190
- the plain URL or install the PWA. To pair a new, signed-out, or revoked browser,
191
- run \`ours-fleet web open\`.
186
+ The service listens on \`http://127.0.0.1:49271/\` and is installed as an
187
+ owner-level systemd user service (Linux) or LaunchAgent (macOS).
192
188
 
193
189
  \`\`\`sh
194
190
  ours-fleet web status
195
191
  ours-fleet web start|stop|restart
196
- ours-fleet web open
197
- ours-fleet web revoke-all # revoke every browser and active session
192
+ ours-fleet web revoke-all # revoke every device and active session
198
193
  ours-fleet web uninstall
199
- ours-fleet web serve --port 0 --no-open # isolated foreground/testing mode
194
+ ours-fleet web serve --port 0 # isolated foreground/testing mode
200
195
  \`\`\`
201
196
 
202
- The console is IPv4-loopback-only by default. Both \`localhost\` and
197
+ The service is IPv4-loopback-only by default. Both \`localhost\` and
203
198
  \`127.0.0.1\` are accepted locally. For an nginx/TLS reverse proxy, keep the
204
199
  default bind and declare the exact browser origin:
205
200
 
@@ -271,6 +266,88 @@ the executor inside the role's existing OS sandbox, and ordinary CLI validation
271
266
  the source of truth. Hidden worker entry points remain internal; public lifecycle and
272
267
  operator commands are not restricted by the proxy.
273
268
 
269
+ ### Fleet commands from a command sandbox (\`managed_cli\`)
270
+
271
+ That supervisor connection is a Unix socket. A harness command sandbox (Codex
272
+ \`workspace-write\`, Claude's OS sandbox) can refuse it with \`connect EPERM\`
273
+ before any command, even \`--help\`, is parsed. Fleet prepares the native
274
+ harness policy for one declared workflow; you never write Codex rules or Claude
275
+ sandbox settings by hand.
276
+
277
+ Opt an Agent (or Agent Template) in explicitly. It is never inferred from a
278
+ role's name or persona and is not inherited by agents it spawns:
279
+
280
+ \`\`\`yaml
281
+ # fleet/agents/FleetCoordinator.yaml
282
+ role: { ref: Coordinator }
283
+ brain: { ref: codex-gpt-5-4-medium }
284
+ permissions: { approval: auto, filesystem: workspace, unattended: deny }
285
+ managed_cli: [task-workflow]
286
+ \`\`\`
287
+
288
+ \`ours-fleet managed-cli setup --enable FleetCoordinator\` adds that one key to
289
+ an existing Agent file and changes nothing else, permissions included.
290
+ \`ours-fleet managed-cli setup\` generates the policy for every declaring agent
291
+ and \`ours-fleet managed-cli status\` compares without writing. Neither starts a
292
+ session or a model. The same preparation runs at every agent start, so spawned
293
+ and task-room agents need no separate step.
294
+
295
+ \`task-workflow\` prepares: \`task create|start|finish|block|unblock|review\`,
296
+ \`task list|show\`, \`room show|members\`, \`template list|show|validate\`,
297
+ \`config\`, \`docs\` and \`--help\`. \`task start\` and \`task finish\`
298
+ provision and retire rooms and agents: this is real authority. Not prepared, and
299
+ still sandboxed: \`spawn\`, \`ours tools|call\`, \`status|peek|send\`, room
300
+ create/delete/close, task cancel/delete and service administration.
301
+
302
+ The agent invokes a prepared command through the pinned entry form shown in its
303
+ briefing:
304
+
305
+ \`\`\`sh
306
+ /abs/node /abs/fleet/dist/cli.js --managed-configuration /abs/fleet.yaml task create --title "..." --backlog --no-room
307
+ \`\`\`
308
+
309
+ What the native policy does and does not do:
310
+
311
+ - A rule fixes the Node executable, this Fleet CLI, the configuration and the
312
+ command. It matches an argv prefix and admits every trailing option and
313
+ argument. It is not argument validation, target authorization or per-agent
314
+ isolation.
315
+ - A later \`-c\`/\`--configuration\` naming another file is refused by the
316
+ Fleet CLI itself, after the process has started outside the sandbox. That is
317
+ Fleet validation, not a native policy denial.
318
+ - The supervisor audit and ordinary CLI validation are unchanged. The pinned
319
+ form is refused outside a managed session, where no supervisor would audit it.
320
+ - Compound, piped, redirected, \`$(...)\` and \`VAR=value\`-prefixed command
321
+ lines do not match and stay sandboxed.
322
+ - Codex: a Fleet-owned \`.codex/rules/ours-fleet-<id>.rules\` in the agent's
323
+ workspace. It applies to every trusted Codex session in that workspace, and
324
+ Codex must trust the workspace; Fleet does not change trust. Other files in
325
+ that directory are never touched.
326
+ - Claude: entries in the agent's own Fleet settings overlay
327
+ (\`permissions.allow\` and \`sandbox.excludedCommands\`). Your Claude settings
328
+ are not modified and Fleet never enables or disables Claude's OS sandbox.
329
+ - A Fleet CLI or configuration path containing spaces is spelled in single
330
+ quotes (Codex >= 0.160.0). The Node executable itself must be at a path that
331
+ needs no quoting: neither harness matches a quoted executable against a rule.
332
+ A path containing anything but letters, digits, spaces and \`_@%+=:,./-\`
333
+ (quotes, backslashes, \`*\` and other pattern characters), or located inside
334
+ the agent's workspace or a \`harness_options.add_dirs\` directory (also through
335
+ a symlink), is reported as unsupported; so is a Codex role with
336
+ \`harness_options.config\` or \`profile\`, whose sandbox Fleet does not inspect.
337
+ - Prepared for: Codex native app-server and bundled ACP, Claude bundled ACP, on
338
+ Linux and macOS. The generated setup was qualified end to end on Linux
339
+ (Codex 0.160.0, Claude Code 2.1.289); the macOS run of that matrix is
340
+ outstanding and \`managed-cli status\` says so there. Custom session
341
+ commands, other harnesses, roles declaring \`isolation:\` and other
342
+ platforms are reported as unsupported and left exactly as sandboxed as before.
343
+
344
+ \`ours-fleet doctor\` reports three separate facts per declaring agent: the
345
+ generated setup (static), whether the last launch loaded the current policy, and
346
+ what the supervisor audit ledger recorded since. A prepared setup is not
347
+ evidence of supervisor access, and a successful \`--help\` proves only its own
348
+ audited path, not the task lifecycle. See
349
+ \`docs/validation/managed-cli-permissions.md\`.
350
+
274
351
  Command invocation, raw argv, read-only work, validation failures, and generic
275
352
  outcomes are never forwarded to the Owner-visible channel. Fleet announces only
276
353
  confirmed Agent, Task, and Room lifecycle changes. Local diagnostics retain
@@ -492,6 +569,17 @@ Messenger-bound results are capped at 3,500 Unicode code points and 12,000 UTF-8
492
569
  bytes with structural omission notices. \`--json\` bypasses this presentation layer
493
570
  and retains the versioned machine schema and serialization order.
494
571
 
572
+ Active task \`show\` reports current readiness separately from lifecycle, also in
573
+ Owner commands. Start/work preserve the fail-closed \`task_not_ready\` behavior.
574
+ Unknown control health does not prove a dead agent or authorize replacement.
575
+ Before deliberate recovery, Fleet Coordinator inspects current seats and exact
576
+ old-launch worklogs/termination evidence in \`recovery/temporary\`, preserves
577
+ original records, and privately records verified old/new launch provenance.
578
+ A new inbox is not complete history: page scoped history to the end, authenticate
579
+ historical Owner authors, and compare completed actions and replies before resuming.
580
+ Do not restore archived identity state, reuse invites, adopt same-role seats or
581
+ blindly replay instructions. Ask the Owner if authority/completion is uncertain.
582
+
495
583
  Every task belongs to a named list. The built-in \`default\` list always exists,
496
584
  and legacy tasks or create calls without \`--list\` resolve to it. Use \`task lists\`,
497
585
  \`task list-create <name>\`, \`task list-rename <name> <new-name>\`, and
@@ -738,6 +826,32 @@ Override an adapter only when necessary with \`session_options.acp.command\`
738
826
  ours-fleet falls back to a compatible globally installed \`codex-acp\` or
739
827
  \`claude-agent-acp\`. \`ours-fleet doctor -c FILE\` verifies the resolved adapter.
740
828
 
829
+ ## Boot-time daemon readiness
830
+
831
+ Linux permanent-agent services wait for their configured daemon before launching
832
+ Fleet's runner. This uses the role's saved manifest path and environment, including
833
+ host profiles, gateway endpoints and expected daemon identity; no Docker container
834
+ names or default ports are assumed. The read-only probe requires verified startup
835
+ readiness and an available identity index. Unavailable or unauthorized daemons leave
836
+ the service waiting, with a diagnostic code in the journal. Each wait is bounded
837
+ and systemd retries it until the daemon is ready; stopping the service cancels it.
838
+ This does not consume the agent crash budget or discard its session context.
839
+ Once the runner starts, its normal crash circuit breaker still applies.
840
+ After upgrading Fleet, run \`ours-fleet service refresh\` (\`ours-install\` does it for
841
+ you). Service definitions start the exact release tree that wrote them, so an
842
+ unrefreshed one starts the previous release after the next reboot.
843
+ \`ours-fleet service check\` reports each supervisor, web and watchdog definition,
844
+ and whether its running process uses another release, without changing anything.
845
+ \`refresh\` only re-points the release paths in definitions Fleet generated, runs
846
+ \`daemon-reload\`, and never creates, starts, stops or restarts a service. A running
847
+ supervisor keeps its code until it is restarted.
848
+ Temporary agents and macOS services retain their existing lifecycle behavior.
849
+
850
+ After a supervisor restart or reboot, prompts a role had admitted but never
851
+ started are dispatched only once its control socket is listening, so recovered
852
+ work cannot reach the previous run's socket (\`connect ECONNREFUSED\`). Turns that
853
+ had already started are closed as \`unknown_after_restart\` and never replayed.
854
+
741
855
  ## Reliable mail wake
742
856
 
743
857
  \`monitor.mode\` selects exactly one wake owner:
@@ -749,10 +863,12 @@ ours-fleet falls back to a compatible globally installed \`codex-acp\` or
749
863
  - \`native\`: ours-fleet starts no supervisor monitor; the generated briefing
750
864
  instructs Claude Code or Codex to arm its harness-native wake mechanism.
751
865
 
752
- Set \`monitor.interrupt: true\` in fleet mode to cancel active work before every
753
- configured wake. Set it to \`after_tool\` to preserve an active ACP tool (and any
754
- pending permission), then steer the wake at the first tool-terminal boundary
755
- without cancellation. A hung boundary is bounded at 120 seconds and falls back
866
+ \`monitor.interrupt\` defaults to \`after_tool\` for every harness except Hermes,
867
+ which defaults to \`false\`; an explicit value always wins, and temporary snapshots
868
+ written without one keep \`false\`. Set \`monitor.interrupt: true\` in fleet mode to
869
+ cancel active work before every configured wake. \`after_tool\` preserves an active
870
+ ACP tool (and any pending permission), then steers the wake at the first
871
+ tool-terminal boundary without cancellation. A hung boundary is bounded at 120 seconds and falls back
756
872
  to non-cancelling steering/queueing; adapters without authenticated tool events
757
873
  use the same conservative fallback. Explicit human/control interrupts remain
758
874
  immediate. The policy is content-blind because the supervisor cannot inspect
@@ -773,6 +889,78 @@ selection.
773
889
  Inspect \`ours-fleet status Name\`, \`peek Name\`, role logs, and
774
890
  \`~/.ours-fleet/agents/Name/.monitor-status\` when diagnosing delivery.
775
891
 
892
+ ## Self-reminders
893
+
894
+ Every managed agent (\`session: acp\` or \`codex-app-server\`, Claude or Codex,
895
+ persistent, temporary or task-owned) can schedule one-time wakes for ITSELF.
896
+ The tools are on the agent's own fixed-identity ours MCP server, so there is no
897
+ agent, identity or recipient argument and no setup, worker, service, chat or key:
898
+
899
+ - \`fleet_reminder_create\` — \`request_key\` (stable per decision; a repeat with
900
+ the same input returns the same reminder, different input is refused),
901
+ \`title\`, optional \`note\`, \`local_time\` (date and time WITHOUT an offset, e.g.
902
+ \`2027-01-20T16:00\`), \`time_zone\` (IANA, e.g. \`Europe/London\`, \`UTC\`), optional
903
+ \`fold\` (0/1, required only for a time that occurs twice when clocks go back;
904
+ times skipped by a spring-forward gap are refused), \`late_window_seconds\`
905
+ (60..604800, default 3600) and \`interrupt\` (default false; see below).
906
+ - \`fleet_reminder_list\` — \`state\` \`open\` (default) | \`closed\` | \`all\`, \`limit\`, \`after\`.
907
+ - \`fleet_reminder_update\` / \`fleet_reminder_cancel\` — \`id\` + \`expected_revision\`;
908
+ every change bumps the revision and voids any wake issued for the old one.
909
+ - \`fleet_reminder_inspect\` — \`event_id\` from a wake: the note, whether the
910
+ wake is still current and eligible, and for an urgent one \`interrupt.state\`.
911
+ - \`fleet_reminder_ack\` — \`event_id\` + \`expected_revision\`: records that the
912
+ wake was handled. Idempotent; sends nothing and claims no external action.
913
+
914
+ When a reminder is due the supervisor starts one turn beginning \`[fleet-reminder]\`
915
+ with the event id. It is the agent's own stored reminder, not an owner
916
+ instruction or ours mail, and grants no authority. Fleet never sends anything
917
+ on the agent's behalf; whether to message anyone is the agent's own decision
918
+ under its existing tools and authorization.
919
+
920
+ Delivery: the supervisor process that runs the agent owns the timer — an idle
921
+ agent with no open reminders costs nothing, and only a due reminder creates a
922
+ model turn. By default a wake never interrupts or queues behind work: it is
923
+ admitted at the next idle turn boundary after its due time and after the agent's
924
+ startup turn.
925
+
926
+ Urgent (\`interrupt: true\`), only for a return genuinely bound to a time: when
927
+ due and the agent is busy with an interruptible turn (mail wake, scheduled loop,
928
+ local console), the supervisor durably records the request, asks that exact turn
929
+ to stop once per revision, keeps the session and context, and releases the wake
930
+ through the same fence. It never stops owner-channel or owner-console work,
931
+ startup, stall recovery, another reminder, a pending permission, queued work or a
932
+ turn it cannot identify; then it waits like an ordinary reminder and \`inspect\`
933
+ shows \`interrupt_deferred\`. Due, interruption requested, its terminal
934
+ (\`cancelled\` only when correlated; else \`ended\`/\`forced\`/\`failed\`/\`unknown\`),
935
+ release, ack and any external action are separate facts. A forced or failed stop
936
+ never queues the wake. It is not a hard real-time alarm and does nothing while
937
+ the host or agent is down.
938
+ If the host, Fleet or the agent is down, paused or busy, a reminder is still
939
+ delivered when it comes back within its late window, and otherwise expires
940
+ without a turn. Reminders survive supervisor, Fleet and host restarts and
941
+ ordinary stop/start. They do not survive the agent: removing or retiring an
942
+ agent or its task cancels them and deletes their state, and a replaced identity
943
+ or same-named successor never inherits them.
944
+
945
+ Guarantees are at most once per reminder revision. Queue acceptance, release to
946
+ the model, the agent's ack, and any external action are distinct facts. A wake
947
+ is marked dispatched durably at the moment it is handed to the model; if the
948
+ supervisor stops before that, the same event is retried. If it stops after, the
949
+ event is held \`uncertain\` (shown by \`list\`/\`inspect\`, never re-sent): check your
950
+ own records, then ack it or schedule something new.
951
+
952
+ Waiting on a peer (Developer/Critic/Engineer): before waiting on a specific
953
+ review, answer or artifact, schedule ONE idle-only reminder about 20 minutes out
954
+ naming the task/room and the expectation; cancel or reschedule it (with its
955
+ revision) when the state changes; on the wake re-check, ack if resolved, else one
956
+ follow-up in the same room and at most one more reminder, then report the
957
+ nonresponse once. No polling, recurring chains, repeated follow-ups or automatic
958
+ done.
959
+
960
+ Operators can read an agent's reminders with
961
+ \`ours-fleet ours call Name fleet_reminder_list\`. Full guide, examples and the
962
+ migration from the standalone \`self-reminders\` worker skill: \`docs/self-reminders.md\`.
963
+
776
964
  ## Trusted owner channel
777
965
 
778
966
  Any managed role may declare a separate ours identity which fleet — never the agent —
package/dist/doctor.d.ts CHANGED
@@ -1,9 +1,10 @@
1
+ import { type RefreshOptions } from './supervisor/registration-refresh.js';
1
2
  import { type AttachOursClientOptions, type OursClient } from '@ours.network/sdk/client';
2
3
  import { type Exec } from './exec.js';
3
4
  import type { YamlMode } from './config-yaml.js';
4
5
  import { type FetchLike } from './monitor.js';
5
6
  import type { PrereqReport } from './harness/types.js';
6
- type DoctorDaemonClient = Pick<OursClient, 'version' | 'close'>;
7
+ type DoctorDaemonClient = Pick<OursClient, 'version' | 'close'> & Partial<Pick<OursClient, 'identities'>>;
7
8
  type AttachDoctorDaemon = (options: AttachOursClientOptions) => Promise<DoctorDaemonClient>;
8
9
  /** Host-level + per-harness prerequisite report with actionable messages. */
9
10
  export declare function doctor(opts?: {
@@ -17,5 +18,7 @@ export declare function doctor(opts?: {
17
18
  };
18
19
  /** Override the local Codex model cache path (tests). */
19
20
  codexCatalogPath?: string;
21
+ /** Compare installed service definitions with this release (read-only). */
22
+ serviceRegistration?: Pick<RefreshOptions, 'binPath' | 'homeDir' | 'exists' | 'processArgv'>;
20
23
  }, exec?: Exec, platform?: NodeJS.Platform, fetchImpl?: FetchLike, attachDaemon?: AttachDoctorDaemon): Promise<PrereqReport>;
21
24
  export {};
package/dist/doctor.js CHANGED
@@ -1,17 +1,17 @@
1
- import { join } from 'node:path';
2
- import { userInfo, homedir } from 'node:os';
1
+ import { describeRegistration, refreshServiceRegistrations, registrationDrift } from './supervisor/registration-refresh.js';
2
+ import { userInfo } from 'node:os';
3
3
  import { existsSync, readFileSync } from 'node:fs';
4
4
  import { attachOursClient, } from '@ours.network/sdk/client';
5
5
  import { realExec } from './exec.js';
6
6
  import { isolationContextFor, loadConfig } from './config.js';
7
7
  import { getAdapter, productionAdapters } from './harness/registry.js';
8
8
  import { analyzeFleetPermissions, formatNative } from './permissions.js';
9
+ import { managedCliReport } from './managed-cli.js';
9
10
  import { resolveBundledAcpAgent } from './harness/acp-agent.js';
10
11
  import { agentDir, deriveXdgRuntimeDir } from './paths.js';
11
12
  import { resolveIsolation, harnessRuntimeDir } from './isolation/policy.js';
12
13
  import { hermesConfiguredProvider } from './harness/hermes-startup.js';
13
14
  import { makeBubblewrapBackend } from './isolation/bubblewrap.js';
14
- import { authResolutionHint, resolveEndpoint, } from './monitor.js';
15
15
  import { readClientProfile } from './client-profile.js';
16
16
  import { readScheduledLoops, storedLoopHealth } from './loops/state.js';
17
17
  import { controlSocketPath } from './session/control.js';
@@ -37,25 +37,21 @@ function resolveMonitorProfiles(roles) {
37
37
  const profiles = [];
38
38
  for (const role of roles.filter(r => r.monitor?.mode === 'fleet')) {
39
39
  const env = { ...process.env, ...(role.env ?? {}) };
40
- const client = readClientProfile(env);
41
- if (client) {
42
- const existing = profiles.find(p => p.client?.endpoint === client.endpoint
43
- && p.client.expectedInstanceId === client.expectedInstanceId
44
- && p.client.credentialPath === client.credentialPath);
45
- if (existing)
46
- existing.roles.push(role.name);
47
- else
48
- profiles.push({ client, roles: [role.name] });
40
+ let client;
41
+ try {
42
+ client = readClientProfile(env);
43
+ }
44
+ catch (error) {
45
+ profiles.push({ roles: [role.name], error: error instanceof Error ? error.message : 'Invalid gateway profile' });
49
46
  continue;
50
47
  }
51
- const endpoint = resolveEndpoint(env);
52
- const token = endpoint.headers['x-ours-api-token'];
53
- const existing = profiles.find(p => p.endpoint?.origin === endpoint.origin
54
- && p.endpoint.headers['x-ours-api-token'] === token);
48
+ const existing = profiles.find(p => p.client?.endpoint === client.endpoint
49
+ && p.client.expectedInstanceId === client.expectedInstanceId
50
+ && p.client.credentialPath === client.credentialPath);
55
51
  if (existing)
56
52
  existing.roles.push(role.name);
57
53
  else
58
- profiles.push({ endpoint, roles: [role.name] });
54
+ profiles.push({ client, roles: [role.name] });
59
55
  }
60
56
  return profiles;
61
57
  }
@@ -101,6 +97,25 @@ export async function doctor(opts = {}, exec = realExec, platform = process.plat
101
97
  // trustworthy as the answer, and a second install with the same semver and
102
98
  // different behaviour is invisible to `--version`.
103
99
  checks.push(...installChecks(opts.installScan));
100
+ if (opts.serviceRegistration) {
101
+ try {
102
+ const reports = await refreshServiceRegistrations({
103
+ ...opts.serviceRegistration, write: false, exec, platform,
104
+ });
105
+ for (const report of reports.filter(report => report.state !== 'absent'))
106
+ checks.push({
107
+ name: `service: ${report.service}`,
108
+ // Same predicate as `service check`, so a pending reload is drift here too.
109
+ ok: registrationDrift([report]).length === 0,
110
+ detail: describeRegistration(report).replace(/^\S+\s+/, '')
111
+ + (report.state === 'stale' ? '; run: ours-fleet service refresh' : ''),
112
+ });
113
+ }
114
+ catch (error) {
115
+ checks.push({ name: 'service definitions', ok: false,
116
+ detail: `could not inspect: ${error?.message ?? String(error)}` });
117
+ }
118
+ }
104
119
  const major = Number(process.versions.node.split('.')[0]);
105
120
  checks.push({
106
121
  name: 'node', ok: major >= 20,
@@ -156,7 +171,7 @@ export async function doctor(opts = {}, exec = realExec, platform = process.plat
156
171
  // ── Rooms/tasks checks ────────────────────────────────────────
157
172
  if (loaded.ok && loaded.rooms) {
158
173
  const rooms = loaded.rooms;
159
- // Cowork socket reachability
174
+ // Cowork gateway reachability
160
175
  const coworkConfig = rooms.cowork?.config;
161
176
  try {
162
177
  const { createCoworkAdapter } = await import('./rooms-tasks/cowork-adapter.js');
@@ -165,14 +180,14 @@ export async function doctor(opts = {}, exec = realExec, platform = process.plat
165
180
  checks.push({
166
181
  name: 'cowork', ok: reachable,
167
182
  detail: reachable
168
- ? 'management socket reachable'
169
- : `management socket unreachable${coworkConfig ? ` (config: ${coworkConfig})` : ''}`,
183
+ ? 'gateway management reachable'
184
+ : `gateway management unreachable${coworkConfig ? ` (config: ${coworkConfig})` : ''}`,
170
185
  });
171
186
  }
172
187
  catch (e) {
173
188
  checks.push({
174
189
  name: 'cowork', ok: false,
175
- detail: `management socket error${coworkConfig ? ` (config: ${coworkConfig})` : ''}: ${e?.message ?? e}`,
190
+ detail: `gateway management error${coworkConfig ? ` (config: ${coworkConfig})` : ''}: ${e?.message ?? e}`,
176
191
  });
177
192
  }
178
193
  // Owner CID shape
@@ -219,17 +234,6 @@ export async function doctor(opts = {}, exec = realExec, platform = process.plat
219
234
  : `template '${defaultTemplate}' not found`,
220
235
  });
221
236
  }
222
- // Shared-daemon selection coherence
223
- if (rooms.cowork?.config) {
224
- const { existsSync: exists } = await import('node:fs');
225
- const configOk = exists(rooms.cowork.config);
226
- checks.push({
227
- name: 'rooms: cowork config', ok: configOk,
228
- detail: configOk
229
- ? `cowork config at ${rooms.cowork.config}`
230
- : `cowork config not found: ${rooms.cowork.config}`,
231
- });
232
- }
233
237
  // Hard room-management capability check
234
238
  try {
235
239
  const { createCoworkAdapter } = await import('./rooms-tasks/cowork-adapter.js');
@@ -273,20 +277,17 @@ export async function doctor(opts = {}, exec = realExec, platform = process.plat
273
277
  }
274
278
  catch { /* state dir may not exist yet */ }
275
279
  }
276
- let managedSelection = false;
280
+ let managedSelection = true;
277
281
  try {
278
282
  // Mark explicit selection before validation so a damaged managed profile does
279
283
  // not produce advice to start an unrelated local daemon.
280
- managedSelection = process.env.OURS_CONFIG !== undefined
281
- || existsSync(join(process.env.HOME || homedir(), '.ours-client', 'profile.json'));
284
+ managedSelection = true;
282
285
  const selected = readClientProfile(process.env);
283
286
  managedSelection = selected !== undefined;
284
- const client = await attachDaemon(selected ? {
287
+ const client = await attachDaemon({
285
288
  endpoint: selected.endpoint, expectedInstanceId: selected.expectedInstanceId,
286
289
  credentialPath: selected.credentialPath, env: {}, sessionMode: 'external',
287
290
  leaseToken: `ours-fleet-doctor-${process.pid}`,
288
- } : {
289
- env: process.env, leaseToken: `ours-fleet-doctor-${process.pid}`, clientPid: process.pid,
290
291
  });
291
292
  let daemonVersion;
292
293
  try {
@@ -368,6 +369,32 @@ export async function doctor(opts = {}, exec = realExec, platform = process.plat
368
369
  + `grants only ${analysis.capabilities.join(', ') || '(nothing)'}`,
369
370
  });
370
371
  }
372
+ // Managed CLI policy. Three separate rows on purpose: what Fleet generated
373
+ // (static), what the running session loaded, and what the supervisor audit
374
+ // ledger actually recorded. The first two never stand in for the third.
375
+ if (roles.some(role => role.managed_cli?.length)) {
376
+ const report = managedCliReport({ roles }, opts.configPath, { write: false, platform });
377
+ for (const role of report.roles.filter(item => item.setup.state !== 'not-declared')) {
378
+ checks.push({
379
+ name: `managed CLI setup: ${role.role}`,
380
+ ok: ['prepared', 'generated-at-launch', 'not-required'].includes(role.setup.state),
381
+ detail: `static: ${role.setup.state} — ${role.setup.detail}`
382
+ + (['missing', 'stale'].includes(role.setup.state) ? '; run: ours-fleet managed-cli setup' : '')
383
+ + (role.warnings.length ? `; ${role.warnings.join('; ')}` : ''),
384
+ });
385
+ if (role.session_policy !== 'not-applicable')
386
+ checks.push({
387
+ name: `managed CLI session: ${role.role}`, ok: true,
388
+ detail: role.session_policy === 'restart-required'
389
+ ? 'the last launch loaded a different policy — restart this agent to load the current one'
390
+ : role.session_policy === 'never-launched' ? 'not launched since setup; the policy loads at its next start'
391
+ : 'the last launch loaded the current policy',
392
+ });
393
+ checks.push({
394
+ name: `managed CLI observed: ${role.role}`, ok: true, detail: role.observed.summary,
395
+ });
396
+ }
397
+ }
371
398
  for (const role of roles.filter(candidate => candidate.auth_proxy !== undefined)) {
372
399
  const proxy = role.auth_proxy;
373
400
  const credentialKeys = Object.keys(role.env ?? {}).filter(key => /^(ANTHROPIC_API_KEY|ANTHROPIC_AUTH_TOKEN|AUTHORIZATION)$/i.test(key)
@@ -448,14 +475,18 @@ export async function doctor(opts = {}, exec = realExec, platform = process.plat
448
475
  // shared-mode misconfig (401) surfaces here rather than as a silent deaf monitor.
449
476
  const monitorProfiles = resolveMonitorProfiles(roles);
450
477
  for (const profile of monitorProfiles) {
451
- const { endpoint, client: selected } = profile;
478
+ const selected = profile.client;
452
479
  const checkName = monitorProfiles.length === 1
453
480
  ? 'monitor: daemon API'
454
481
  : `monitor: daemon API (${profile.roles.join(', ')})`;
455
- let ok = false, detail;
482
+ let ok = false, detail = 'gateway profile unavailable';
483
+ if (profile.error) {
484
+ checks.push({ name: checkName, ok: false, detail: profile.error });
485
+ continue;
486
+ }
456
487
  try {
457
488
  if (selected) {
458
- const daemon = await attachOursClient({
489
+ const daemon = await attachDaemon({
459
490
  endpoint: selected.endpoint,
460
491
  expectedInstanceId: selected.expectedInstanceId,
461
492
  credentialPath: selected.credentialPath,
@@ -464,7 +495,7 @@ export async function doctor(opts = {}, exec = realExec, platform = process.plat
464
495
  });
465
496
  try {
466
497
  const [info, identities] = await Promise.all([
467
- daemon.version(), daemon.identities(),
498
+ daemon.version(), daemon.identities?.(),
468
499
  ]);
469
500
  if (info.name !== 'ours' || !Array.isArray(identities))
470
501
  throw new Error('selected daemon metadata is invalid');
@@ -477,27 +508,11 @@ export async function doctor(opts = {}, exec = realExec, platform = process.plat
477
508
  checks.push({ name: checkName, ok, detail });
478
509
  continue;
479
510
  }
480
- const live = await fetchImpl(`${endpoint.origin}/state-dir`, {});
481
- if (!live.ok) {
482
- detail = `daemon on :${endpoint.port} answered /state-dir with HTTP ${live.status} — not the ours daemon?`;
483
- }
484
- else {
485
- const auth = await fetchImpl(`${endpoint.origin}/identities`, { headers: endpoint.headers });
486
- if (auth.status === 401)
487
- detail = `reachable on :${endpoint.port} but the API token was rejected (401) — ` +
488
- authResolutionHint(endpoint);
489
- else if (!auth.ok)
490
- detail = `reachable on :${endpoint.port} but /identities returned HTTP ${auth.status}`;
491
- else {
492
- ok = true;
493
- detail = `reachable on :${endpoint.port}, authorized — supervisor wake stream available`;
494
- }
495
- }
496
511
  }
497
512
  catch (e) {
498
- const target = selected?.endpoint ?? `:${endpoint.port}`;
513
+ const target = selected.endpoint;
499
514
  detail = `unreachable on ${target} — monitored roles run degraded until it is up ` +
500
- `(start it: ours-daemon start) [${e?.message ?? e}]`;
515
+ `(check the configured gateway and issued credential) [${e?.message ?? e}]`;
501
516
  }
502
517
  checks.push({ name: checkName, ok, detail });
503
518
  }
@@ -0,0 +1,9 @@
1
+ export declare const erasedArg: (value: string) => string;
2
+ export declare function redactErasedContent<T>(value: T): T;
3
+ /** Every cooperative writer filters stale in-memory snapshots under the same lock as erasure. */
4
+ export declare function writePrivacyFilteredLedger(path: string, value: unknown): void;
5
+ /** Content-free resource IDs persist to prevent active writers resurrecting erased labels. */
6
+ export declare function eraseResourcePresentations(resources: ReadonlyArray<{
7
+ kind: 'task' | 'room' | 'agent';
8
+ id: string;
9
+ }>): void;
@@ -0,0 +1,87 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { existsSync, lstatSync, readFileSync, readdirSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { replaceFileAtomically, withSynchronousFileLock } from './atomic-file.js';
5
+ import { stateRoot } from './paths.js';
6
+ const registryPath = () => join(stateRoot(), 'erased-resources.json');
7
+ const lockPath = () => join(stateRoot(), 'locks', 'audit-erasure');
8
+ const ledgerNames = ['.fleet-command-audit.json', '.owner-channel-command-audit.json', '.owner-channel-lifecycle-outbox.json'];
9
+ export const erasedArg = (value) => `[erased:${createHash('sha256').update(value).digest('hex')}]`;
10
+ function registry() {
11
+ if (!existsSync(registryPath()))
12
+ return new Set();
13
+ const value = JSON.parse(readFileSync(registryPath(), 'utf8'));
14
+ if (!Array.isArray(value) || value.some(v => typeof v !== 'string'))
15
+ throw new Error('Invalid erasure registry');
16
+ return new Set(value);
17
+ }
18
+ /** Preserve delivery/deduplication metadata while removing owned presentation content. */
19
+ function redact(value, erased) {
20
+ if (Array.isArray(value))
21
+ return value.map(item => redact(item, erased));
22
+ if (!value || typeof value !== 'object')
23
+ return value;
24
+ const next = { ...value };
25
+ const kind = value.kind === 'lifecycle_failure' ? value.resource?.toLowerCase() : value.kind === 'agent_started' ? 'agent' : value.kind;
26
+ if (typeof value.id === 'string' && erased.has(`${kind}:${value.id}`)) {
27
+ for (const key of ['title', 'reason', 'roomName', 'label', 'template', 'configuration', 'model', 'permissions'])
28
+ delete next[key];
29
+ if (kind === 'task')
30
+ next.agents = [];
31
+ if (kind === 'room') {
32
+ delete next.name;
33
+ next.participants = [];
34
+ }
35
+ if (kind === 'agent') {
36
+ next.name = 'erased';
37
+ next.brain = '[erased]';
38
+ next.role = '[erased]';
39
+ next.inherited = [];
40
+ }
41
+ }
42
+ if (typeof value.roomId === 'string' && erased.has(`room:${value.roomId}`)) {
43
+ delete next.roomName;
44
+ if (kind === 'task')
45
+ next.agents = [];
46
+ }
47
+ const resources = value.outcome?.resourceIds;
48
+ const ownsAttempt = resources && Object.entries(resources).some(([key, id]) => erased.has(`${key}:${id}`));
49
+ const ownsPresentation = value.outcome?.presentations?.some((p) => erased.has(`${p.kind === 'agent_started' ? 'agent' : p.kind}:${p.id}`));
50
+ if ((ownsAttempt || ownsPresentation) && Array.isArray(value.argv) && !value.erased) {
51
+ next.argv = value.argv.map(erasedArg);
52
+ next.erased = true;
53
+ }
54
+ for (const key of Object.keys(next))
55
+ if (typeof next[key] === 'object')
56
+ next[key] = redact(next[key], erased);
57
+ return next;
58
+ }
59
+ export function redactErasedContent(value) { return redact(value, registry()); }
60
+ /** Every cooperative writer filters stale in-memory snapshots under the same lock as erasure. */
61
+ export function writePrivacyFilteredLedger(path, value) {
62
+ withSynchronousFileLock(lockPath(), () => replaceFileAtomically(path, JSON.stringify(redact(value, registry())) + '\n'));
63
+ }
64
+ /** Content-free resource IDs persist to prevent active writers resurrecting erased labels. */
65
+ export function eraseResourcePresentations(resources) {
66
+ withSynchronousFileLock(lockPath(), () => {
67
+ const erased = registry();
68
+ for (const resource of resources)
69
+ erased.add(`${resource.kind}:${resource.id}`);
70
+ replaceFileAtomically(registryPath(), JSON.stringify([...erased]));
71
+ for (const root of [join(stateRoot(), 'agents'), join(stateRoot(), 'tmp'), join(stateRoot(), 'recovery', 'temporary')]) {
72
+ if (!existsSync(root))
73
+ continue;
74
+ for (const entry of readdirSync(root, { withFileTypes: true })) {
75
+ if (!entry.isDirectory() || entry.isSymbolicLink())
76
+ continue;
77
+ for (const name of ledgerNames) {
78
+ const path = join(root, entry.name, name);
79
+ if (!existsSync(path) || !lstatSync(path).isFile() || lstatSync(path).isSymbolicLink())
80
+ continue;
81
+ const old = JSON.parse(readFileSync(path, 'utf8'));
82
+ replaceFileAtomically(path, JSON.stringify(redact(old, erased)) + '\n');
83
+ }
84
+ }
85
+ }
86
+ });
87
+ }