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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (389) hide show
  1. package/README.md +287 -65
  2. package/dist/account-origin.d.ts +2 -0
  3. package/dist/account-origin.js +6 -0
  4. package/dist/agent-ours/bridge.js +35 -9
  5. package/dist/agent-ours/correspondence.d.ts +10 -0
  6. package/dist/agent-ours/correspondence.js +1 -0
  7. package/dist/agent-ours/file-rpc.d.ts +12 -0
  8. package/dist/agent-ours/file-rpc.js +18 -4
  9. package/dist/agent-ours/harness.js +9 -1
  10. package/dist/agent-ours/mcp-endpoint.d.ts +4 -0
  11. package/dist/agent-ours/mcp-endpoint.js +5 -0
  12. package/dist/agent-ours/runtime.d.ts +9 -1
  13. package/dist/agent-ours/runtime.js +50 -2
  14. package/dist/agent-ours/service.d.ts +21 -1
  15. package/dist/agent-ours/service.js +94 -14
  16. package/dist/application/codex-models.d.ts +15 -0
  17. package/dist/application/codex-models.js +56 -0
  18. package/dist/application/conversation-history.d.ts +27 -0
  19. package/dist/application/conversation-history.js +212 -0
  20. package/dist/application/fleet-query-service.d.ts +1 -1
  21. package/dist/application/fleet-query-service.js +2 -2
  22. package/dist/application/legacy-supervisor-identity.d.ts +7 -0
  23. package/dist/application/legacy-supervisor-identity.js +43 -0
  24. package/dist/application/log-service.js +8 -8
  25. package/dist/application/model-catalog.d.ts +1 -1
  26. package/dist/application/model-catalog.js +5 -2
  27. package/dist/application/preset-provenance.d.ts +19 -0
  28. package/dist/application/preset-provenance.js +59 -0
  29. package/dist/application/role-creation-service.js +3 -2
  30. package/dist/application/role-removal-service.js +9 -1
  31. package/dist/application/role-repository.js +19 -2
  32. package/dist/application/room-layout-definitions.d.ts +45 -0
  33. package/dist/application/room-layout-definitions.js +130 -0
  34. package/dist/application/session-control.d.ts +30 -0
  35. package/dist/application/session-control.js +72 -3
  36. package/dist/application/supervisor-ours-tools.d.ts +159 -0
  37. package/dist/application/supervisor-ours-tools.js +115 -0
  38. package/dist/application/task-layouts.d.ts +91 -0
  39. package/dist/application/task-layouts.js +259 -0
  40. package/dist/application/task-room-service.d.ts +99 -3
  41. package/dist/application/task-room-service.js +285 -32
  42. package/dist/application/types.d.ts +2 -0
  43. package/dist/atomic-file.d.ts +5 -0
  44. package/dist/atomic-file.js +62 -1
  45. package/dist/briefing.d.ts +3 -1
  46. package/dist/briefing.js +70 -30
  47. package/dist/build-info.json +7 -4
  48. package/dist/capabilities.d.ts +6 -1
  49. package/dist/capabilities.js +8 -0
  50. package/dist/cli.js +407 -37
  51. package/dist/client-profile.d.ts +5 -17
  52. package/dist/client-profile.js +4 -127
  53. package/dist/config.d.ts +45 -0
  54. package/dist/config.js +57 -6
  55. package/dist/creation.d.ts +1 -1
  56. package/dist/creation.js +4 -4
  57. package/dist/daemon-recovery.d.ts +1 -8
  58. package/dist/daemon-recovery.js +8 -113
  59. package/dist/docs.d.ts +1 -1
  60. package/dist/docs.js +123 -19
  61. package/dist/doctor.d.ts +1 -1
  62. package/dist/doctor.js +55 -60
  63. package/dist/erased-resources.d.ts +9 -0
  64. package/dist/erased-resources.js +87 -0
  65. package/dist/file-delivery/reader.d.ts +15 -0
  66. package/dist/file-delivery/reader.js +63 -0
  67. package/dist/file-delivery/store.d.ts +15 -0
  68. package/dist/file-delivery/store.js +124 -0
  69. package/dist/file-delivery/types.d.ts +19 -0
  70. package/dist/file-delivery/types.js +1 -0
  71. package/dist/fleet-command-audit.d.ts +7 -0
  72. package/dist/fleet-command-audit.js +26 -9
  73. package/dist/harness/agent-session.d.ts +2 -0
  74. package/dist/harness/claude-code-session.js +1 -1
  75. package/dist/harness/claude-code.js +20 -11
  76. package/dist/harness/claude-runtime.d.ts +12 -0
  77. package/dist/harness/claude-runtime.js +43 -0
  78. package/dist/harness/codex-app-server-proxy.d.ts +4 -1
  79. package/dist/harness/codex-app-server-proxy.js +41 -5
  80. package/dist/harness/codex-reasoning.d.ts +5 -0
  81. package/dist/harness/codex-reasoning.js +12 -0
  82. package/dist/harness/codex-runtime.d.ts +11 -1
  83. package/dist/harness/codex-runtime.js +31 -4
  84. package/dist/harness/codex-session.js +2 -2
  85. package/dist/harness/codex.js +23 -12
  86. package/dist/init-wizard.d.ts +2 -0
  87. package/dist/init-wizard.js +38 -19
  88. package/dist/isolation/policy.js +6 -1
  89. package/dist/isolation/types.d.ts +5 -0
  90. package/dist/managed-cli.d.ts +253 -0
  91. package/dist/managed-cli.js +923 -0
  92. package/dist/managed-recovery.d.ts +13 -0
  93. package/dist/managed-recovery.js +31 -0
  94. package/dist/minimal-setup.d.ts +2 -0
  95. package/dist/minimal-setup.js +44 -0
  96. package/dist/monitor.d.ts +8 -34
  97. package/dist/monitor.js +89 -152
  98. package/dist/notifications/fleet-producer.d.ts +19 -0
  99. package/dist/notifications/fleet-producer.js +208 -0
  100. package/dist/notifications/outbox.d.ts +46 -0
  101. package/dist/notifications/outbox.js +158 -0
  102. package/dist/notifications/target-cleanup.d.ts +8 -0
  103. package/dist/notifications/target-cleanup.js +41 -0
  104. package/dist/notifications/task-producer.d.ts +18 -0
  105. package/dist/notifications/task-producer.js +67 -0
  106. package/dist/ops.d.ts +2 -0
  107. package/dist/ops.js +20 -3
  108. package/dist/owner-channel/channel.js +17 -6
  109. package/dist/owner-channel/commands.d.ts +4 -0
  110. package/dist/owner-channel/commands.js +8 -0
  111. package/dist/owner-channel/lifecycle-outbox.js +4 -3
  112. package/dist/owner-channel/ours-client.js +2 -17
  113. package/dist/paths.d.ts +2 -0
  114. package/dist/paths.js +2 -0
  115. package/dist/preset-migration.js +25 -0
  116. package/dist/resolved-plan.js +1 -0
  117. package/dist/rooms-tasks/add-member.d.ts +48 -0
  118. package/dist/rooms-tasks/add-member.js +83 -0
  119. package/dist/rooms-tasks/archived-absence.d.ts +8 -0
  120. package/dist/rooms-tasks/archived-absence.js +48 -0
  121. package/dist/rooms-tasks/cli.js +65 -5
  122. package/dist/rooms-tasks/close.d.ts +6 -2
  123. package/dist/rooms-tasks/close.js +246 -37
  124. package/dist/rooms-tasks/config.d.ts +1 -1
  125. package/dist/rooms-tasks/config.js +11 -4
  126. package/dist/rooms-tasks/cowork-adapter.d.ts +2 -4
  127. package/dist/rooms-tasks/cowork-adapter.js +7 -121
  128. package/dist/rooms-tasks/cowork-http.js +29 -1
  129. package/dist/rooms-tasks/deletion.d.ts +1 -1
  130. package/dist/rooms-tasks/deletion.js +84 -5
  131. package/dist/rooms-tasks/erasure.d.ts +6 -0
  132. package/dist/rooms-tasks/erasure.js +173 -0
  133. package/dist/rooms-tasks/external-worker.d.ts +1 -1
  134. package/dist/rooms-tasks/external-worker.js +3 -4
  135. package/dist/rooms-tasks/layout-binding-client.d.ts +11 -0
  136. package/dist/rooms-tasks/layout-binding-client.js +56 -0
  137. package/dist/rooms-tasks/layout-binding-grants.d.ts +21 -0
  138. package/dist/rooms-tasks/layout-binding-grants.js +128 -0
  139. package/dist/rooms-tasks/layout-cli.d.ts +4 -0
  140. package/dist/rooms-tasks/layout-cli.js +107 -0
  141. package/dist/rooms-tasks/layout-config.d.ts +11 -0
  142. package/dist/rooms-tasks/layout-config.js +89 -0
  143. package/dist/rooms-tasks/layout-control.d.ts +21 -0
  144. package/dist/rooms-tasks/layout-control.js +52 -0
  145. package/dist/rooms-tasks/layout-member-retirement.d.ts +10 -0
  146. package/dist/rooms-tasks/layout-member-retirement.js +90 -0
  147. package/dist/rooms-tasks/layout-service.d.ts +43 -0
  148. package/dist/rooms-tasks/layout-service.js +203 -0
  149. package/dist/rooms-tasks/layout.d.ts +121 -0
  150. package/dist/rooms-tasks/layout.js +285 -0
  151. package/dist/rooms-tasks/legacy-task-member.d.ts +19 -0
  152. package/dist/rooms-tasks/legacy-task-member.js +116 -0
  153. package/dist/rooms-tasks/live-readiness.d.ts +18 -0
  154. package/dist/rooms-tasks/live-readiness.js +85 -0
  155. package/dist/rooms-tasks/member-ownership.d.ts +5 -0
  156. package/dist/rooms-tasks/member-ownership.js +40 -0
  157. package/dist/rooms-tasks/member-startup.d.ts +1 -0
  158. package/dist/rooms-tasks/member-startup.js +2 -0
  159. package/dist/rooms-tasks/provision.d.ts +3 -0
  160. package/dist/rooms-tasks/provision.js +101 -49
  161. package/dist/rooms-tasks/recovery.d.ts +19 -0
  162. package/dist/rooms-tasks/recovery.js +110 -0
  163. package/dist/rooms-tasks/room-state.d.ts +4 -2
  164. package/dist/rooms-tasks/room-state.js +47 -8
  165. package/dist/rooms-tasks/task-service-retirement.d.ts +11 -0
  166. package/dist/rooms-tasks/task-service-retirement.js +21 -0
  167. package/dist/rooms-tasks/task-state.d.ts +51 -8
  168. package/dist/rooms-tasks/task-state.js +245 -25
  169. package/dist/rooms-tasks/types.d.ts +40 -0
  170. package/dist/rooms-tasks/workspace-artifacts.d.ts +6 -0
  171. package/dist/rooms-tasks/workspace-artifacts.js +93 -0
  172. package/dist/rooms-tasks/workspace.d.ts +35 -0
  173. package/dist/rooms-tasks/workspace.js +325 -0
  174. package/dist/runner.d.ts +25 -3
  175. package/dist/runner.js +291 -49
  176. package/dist/session/acp.d.ts +53 -1
  177. package/dist/session/acp.js +216 -40
  178. package/dist/session/arbiter.d.ts +11 -0
  179. package/dist/session/arbiter.js +43 -2
  180. package/dist/session/codex-app-server.d.ts +32 -0
  181. package/dist/session/codex-app-server.js +137 -23
  182. package/dist/session/control.d.ts +12 -1
  183. package/dist/session/control.js +68 -3
  184. package/dist/session/conversation-normalizer.d.ts +2 -1
  185. package/dist/session/conversation-normalizer.js +1 -1
  186. package/dist/session/conversation-store.d.ts +1 -1
  187. package/dist/session/conversation-store.js +7 -11
  188. package/dist/session/conversation-types.d.ts +28 -3
  189. package/dist/session/prompt-batch.d.ts +63 -0
  190. package/dist/session/prompt-batch.js +86 -0
  191. package/dist/session/task-notice.d.ts +14 -0
  192. package/dist/session/task-notice.js +13 -0
  193. package/dist/session/types.d.ts +14 -0
  194. package/dist/setup-tunnel-preflight.d.ts +34 -0
  195. package/dist/setup-tunnel-preflight.js +62 -0
  196. package/dist/socket-path.d.ts +2 -0
  197. package/dist/socket-path.js +22 -0
  198. package/dist/spawn.d.ts +5 -1
  199. package/dist/spawn.js +40 -4
  200. package/dist/startup-prompt.d.ts +4 -0
  201. package/dist/startup-prompt.js +36 -0
  202. package/dist/startup-readiness.d.ts +13 -0
  203. package/dist/startup-readiness.js +38 -0
  204. package/dist/startup-telemetry.d.ts +16 -0
  205. package/dist/startup-telemetry.js +46 -0
  206. package/dist/subscriptions/cli.d.ts +91 -0
  207. package/dist/subscriptions/cli.js +223 -0
  208. package/dist/subscriptions/launch.d.ts +37 -0
  209. package/dist/subscriptions/launch.js +93 -0
  210. package/dist/subscriptions/login.d.ts +75 -0
  211. package/dist/subscriptions/login.js +182 -0
  212. package/dist/subscriptions/observed.d.ts +7 -0
  213. package/dist/subscriptions/observed.js +44 -0
  214. package/dist/subscriptions/probe.d.ts +10 -0
  215. package/dist/subscriptions/probe.js +73 -0
  216. package/dist/subscriptions/service.d.ts +102 -0
  217. package/dist/subscriptions/service.js +364 -0
  218. package/dist/subscriptions/store.d.ts +71 -0
  219. package/dist/subscriptions/store.js +140 -0
  220. package/dist/supervisor/adoption.d.ts +8 -0
  221. package/dist/supervisor/adoption.js +78 -0
  222. package/dist/supervisor/catalog.d.ts +62 -0
  223. package/dist/supervisor/catalog.js +254 -0
  224. package/dist/supervisor/fleet.d.ts +8 -0
  225. package/dist/supervisor/fleet.js +89 -0
  226. package/dist/supervisor/index.js +3 -6
  227. package/dist/supervisor/launchd.d.ts +1 -1
  228. package/dist/supervisor/launchd.js +26 -13
  229. package/dist/supervisor/legacy.d.ts +35 -0
  230. package/dist/supervisor/legacy.js +524 -0
  231. package/dist/supervisor/manager.d.ts +15 -0
  232. package/dist/supervisor/manager.js +270 -0
  233. package/dist/supervisor/scope.d.ts +4 -0
  234. package/dist/supervisor/scope.js +10 -0
  235. package/dist/supervisor/systemd.d.ts +2 -2
  236. package/dist/supervisor/systemd.js +19 -33
  237. package/dist/task-supervision.d.ts +9 -0
  238. package/dist/task-supervision.js +145 -0
  239. package/dist/temp-idle.d.ts +17 -0
  240. package/dist/temp-idle.js +42 -0
  241. package/dist/temp-lifecycle.d.ts +23 -8
  242. package/dist/temp-lifecycle.js +113 -65
  243. package/dist/temp-supervisor-recovery.d.ts +1 -1
  244. package/dist/temp-supervisor-recovery.js +2 -2
  245. package/dist/tunnel-setup-completion.d.ts +7 -0
  246. package/dist/tunnel-setup-completion.js +13 -0
  247. package/dist/tunnel-setup-input.d.ts +19 -0
  248. package/dist/tunnel-setup-input.js +124 -0
  249. package/dist/web/agent-attachments.d.ts +29 -0
  250. package/dist/web/agent-attachments.js +162 -0
  251. package/dist/web/auth.d.ts +63 -2
  252. package/dist/web/auth.js +191 -10
  253. package/dist/web/available-port.d.ts +2 -0
  254. package/dist/web/available-port.js +23 -0
  255. package/dist/web/control.d.ts +3 -3
  256. package/dist/web/control.js +10 -8
  257. package/dist/web/fleet-config-service.d.ts +4 -1
  258. package/dist/web/fleet-config-service.js +46 -15
  259. package/dist/web/prefix-gateway.d.ts +32 -0
  260. package/dist/web/prefix-gateway.js +238 -0
  261. package/dist/web/runtime.d.ts +3 -1
  262. package/dist/web/runtime.js +116 -31
  263. package/dist/web/server.d.ts +16 -0
  264. package/dist/web/server.js +654 -55
  265. package/dist/web/service.d.ts +11 -2
  266. package/dist/web/service.js +30 -4
  267. package/dist/web/workspace-devices.d.ts +107 -0
  268. package/dist/web/workspace-devices.js +277 -0
  269. package/dist/web/workspace-tunnel.d.ts +1 -0
  270. package/dist/web/workspace-tunnel.js +34 -0
  271. package/dist/workspace-enrollment.d.ts +82 -0
  272. package/dist/workspace-enrollment.js +566 -0
  273. package/dist/workspace-replacement.d.ts +66 -0
  274. package/dist/workspace-replacement.js +220 -0
  275. package/docs/acp-files.md +146 -0
  276. package/docs/fleet-migration.md +54 -0
  277. package/docs/live-voice.md +13 -0
  278. package/docs/room-layouts.md +227 -0
  279. package/docs/task-workspaces.md +225 -0
  280. package/docs/validation/managed-cli-permissions.md +421 -0
  281. package/examples/room-layouts/fresh.yaml +27 -0
  282. package/examples/room-layouts/scoped.yaml +21 -0
  283. package/examples/room-layouts/shared.yaml +19 -0
  284. package/package.json +20 -19
  285. package/presets/README.md +78 -0
  286. package/presets/brain-catalog.json +8 -2
  287. package/presets/fleet/agent_templates/Critic.yaml +1 -1
  288. package/presets/fleet/agent_templates/Developer.yaml +1 -1
  289. package/presets/fleet/agent_templates/Engineer.yaml +5 -0
  290. package/presets/fleet/agent_templates/LocalCoordinator.yaml +1 -1
  291. package/presets/fleet/agents/FleetCoordinator.yaml +1 -1
  292. package/presets/fleet/brains/claude-fable-5-1-high.yaml +5 -0
  293. package/presets/fleet/brains/claude-fable-5-1-low.yaml +5 -0
  294. package/presets/fleet/brains/claude-fable-5-1-max.yaml +5 -0
  295. package/presets/fleet/brains/claude-fable-5-1-medium.yaml +5 -0
  296. package/presets/fleet/brains/claude-fable-5-1-xhigh.yaml +5 -0
  297. package/presets/fleet/brains/claude-fable-5-high.yaml +1 -1
  298. package/presets/fleet/brains/claude-fable-5-low.yaml +1 -1
  299. package/presets/fleet/brains/claude-fable-5-max.yaml +1 -1
  300. package/presets/fleet/brains/claude-fable-5-medium.yaml +1 -1
  301. package/presets/fleet/brains/claude-fable-5-xhigh.yaml +1 -1
  302. package/presets/fleet/brains/claude-haiku-4-5-20251001-default.yaml +4 -0
  303. package/presets/fleet/brains/claude-opus-5-5-high.yaml +5 -0
  304. package/presets/fleet/brains/claude-opus-5-5-low.yaml +5 -0
  305. package/presets/fleet/brains/claude-opus-5-5-max.yaml +5 -0
  306. package/presets/fleet/brains/claude-opus-5-5-medium.yaml +5 -0
  307. package/presets/fleet/brains/claude-opus-5-5-xhigh.yaml +5 -0
  308. package/presets/fleet/brains/claude-opus-5-high.yaml +1 -1
  309. package/presets/fleet/brains/claude-opus-5-low.yaml +1 -1
  310. package/presets/fleet/brains/claude-opus-5-max.yaml +1 -1
  311. package/presets/fleet/brains/claude-opus-5-medium.yaml +1 -1
  312. package/presets/fleet/brains/claude-opus-5-xhigh.yaml +1 -1
  313. package/presets/fleet/brains/claude-sonnet-5-high.yaml +1 -1
  314. package/presets/fleet/brains/claude-sonnet-5-low.yaml +1 -1
  315. package/presets/fleet/brains/claude-sonnet-5-max.yaml +1 -1
  316. package/presets/fleet/brains/claude-sonnet-5-medium.yaml +1 -1
  317. package/presets/fleet/brains/claude-sonnet-5-xhigh.yaml +1 -1
  318. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-high.yaml +1 -1
  319. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-low.yaml +1 -1
  320. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-medium.yaml +1 -1
  321. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-xhigh.yaml +1 -1
  322. package/presets/fleet/brains/codex-gpt-5-4-high.yaml +1 -1
  323. package/presets/fleet/brains/codex-gpt-5-4-low.yaml +1 -1
  324. package/presets/fleet/brains/codex-gpt-5-4-medium.yaml +1 -1
  325. package/presets/fleet/brains/codex-gpt-5-4-mini-high.yaml +1 -1
  326. package/presets/fleet/brains/codex-gpt-5-4-mini-low.yaml +1 -1
  327. package/presets/fleet/brains/codex-gpt-5-4-mini-medium.yaml +1 -1
  328. package/presets/fleet/brains/codex-gpt-5-4-mini-xhigh.yaml +1 -1
  329. package/presets/fleet/brains/codex-gpt-5-4-xhigh.yaml +1 -1
  330. package/presets/fleet/brains/codex-gpt-5-5-high.yaml +1 -1
  331. package/presets/fleet/brains/codex-gpt-5-5-low.yaml +1 -1
  332. package/presets/fleet/brains/codex-gpt-5-5-medium.yaml +1 -1
  333. package/presets/fleet/brains/codex-gpt-5-5-xhigh.yaml +1 -1
  334. package/presets/fleet/brains/codex-gpt-5-6-luna-high.yaml +1 -1
  335. package/presets/fleet/brains/codex-gpt-5-6-luna-low.yaml +1 -1
  336. package/presets/fleet/brains/codex-gpt-5-6-luna-max.yaml +1 -1
  337. package/presets/fleet/brains/codex-gpt-5-6-luna-medium.yaml +1 -1
  338. package/presets/fleet/brains/codex-gpt-5-6-luna-xhigh.yaml +1 -1
  339. package/presets/fleet/brains/codex-gpt-5-6-sol-high.yaml +1 -1
  340. package/presets/fleet/brains/codex-gpt-5-6-sol-low.yaml +1 -1
  341. package/presets/fleet/brains/codex-gpt-5-6-sol-max.yaml +1 -1
  342. package/presets/fleet/brains/codex-gpt-5-6-sol-medium.yaml +1 -1
  343. package/presets/fleet/brains/codex-gpt-5-6-sol-ultra.yaml +1 -1
  344. package/presets/fleet/brains/codex-gpt-5-6-sol-xhigh.yaml +1 -1
  345. package/presets/fleet/brains/codex-gpt-5-6-terra-high.yaml +1 -1
  346. package/presets/fleet/brains/codex-gpt-5-6-terra-low.yaml +1 -1
  347. package/presets/fleet/brains/codex-gpt-5-6-terra-max.yaml +1 -1
  348. package/presets/fleet/brains/codex-gpt-5-6-terra-medium.yaml +1 -1
  349. package/presets/fleet/brains/codex-gpt-5-6-terra-ultra.yaml +1 -1
  350. package/presets/fleet/brains/codex-gpt-5-6-terra-xhigh.yaml +1 -1
  351. package/presets/fleet/brains/codex-gpt-6-1-sol-high.yaml +5 -0
  352. package/presets/fleet/brains/codex-gpt-6-1-sol-low.yaml +5 -0
  353. package/presets/fleet/brains/codex-gpt-6-1-sol-max.yaml +5 -0
  354. package/presets/fleet/brains/codex-gpt-6-1-sol-medium.yaml +5 -0
  355. package/presets/fleet/brains/codex-gpt-6-1-sol-ultra.yaml +5 -0
  356. package/presets/fleet/brains/codex-gpt-6-1-sol-xhigh.yaml +5 -0
  357. package/presets/fleet/brains/codex-gpt-6-astra-high.yaml +1 -1
  358. package/presets/fleet/brains/codex-gpt-6-astra-low.yaml +1 -1
  359. package/presets/fleet/brains/codex-gpt-6-astra-max.yaml +1 -1
  360. package/presets/fleet/brains/codex-gpt-6-astra-medium.yaml +1 -1
  361. package/presets/fleet/brains/codex-gpt-6-astra-ultra.yaml +1 -1
  362. package/presets/fleet/brains/codex-gpt-6-astra-xhigh.yaml +1 -1
  363. package/presets/fleet/brains/codex-gpt-6-luna-high.yaml +5 -0
  364. package/presets/fleet/brains/codex-gpt-6-luna-low.yaml +5 -0
  365. package/presets/fleet/brains/codex-gpt-6-luna-max.yaml +5 -0
  366. package/presets/fleet/brains/codex-gpt-6-luna-medium.yaml +5 -0
  367. package/presets/fleet/brains/codex-gpt-6-luna-xhigh.yaml +5 -0
  368. package/presets/fleet/brains/codex-gpt-6-sol-high.yaml +5 -0
  369. package/presets/fleet/brains/codex-gpt-6-sol-low.yaml +5 -0
  370. package/presets/fleet/brains/codex-gpt-6-sol-max.yaml +5 -0
  371. package/presets/fleet/brains/codex-gpt-6-sol-medium.yaml +5 -0
  372. package/presets/fleet/brains/codex-gpt-6-sol-ultra.yaml +5 -0
  373. package/presets/fleet/brains/codex-gpt-6-sol-xhigh.yaml +5 -0
  374. package/presets/fleet/roles/Coordinator.yaml +34 -11
  375. package/presets/fleet/roles/Engineer.yaml +40 -0
  376. package/presets/fleet/room_layouts/engineering.yaml +25 -0
  377. package/presets/fleet/room_layouts/pair.yaml +24 -0
  378. package/presets/fleet/room_layouts/single.yaml +17 -0
  379. package/presets/fleet/room_layouts/team.yaml +30 -0
  380. package/presets/fleet/room_templates/engineering.yaml +19 -0
  381. package/presets/manifest.json +2 -2
  382. package/dist/web-app/assets/index-59GF-gsZ.css +0 -1
  383. package/dist/web-app/assets/index-C0h3ALvs.js +0 -10
  384. package/dist/web-app/icons/ours-fleet-maskable.svg +0 -4
  385. package/dist/web-app/icons/ours-fleet.svg +0 -4
  386. package/dist/web-app/index.html +0 -17
  387. package/dist/web-app/manifest.webmanifest +0 -15
  388. package/dist/web-app/offline.html +0 -18
  389. package/dist/web-app/sw.js +0 -51
@@ -1,130 +1,7 @@
1
- import { normalizeDaemonEndpoint } from '@ours.network/sdk/client';
2
- import { lstatSync, readFileSync, statSync } from 'node:fs';
3
- import { homedir } from 'node:os';
4
- import { isAbsolute, join } from 'node:path';
5
- const PROFILE_FIELDS = ['endpoint', 'expectedInstanceId', 'credentialPath'];
6
- const LOWERCASE_UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
7
- const LEGACY_CONFIG_FIELDS = ['apiToken', 'stateDir', 'port'];
8
- const LEGACY_ENV_FIELDS = ['OURS_API_TOKEN', 'OURS_STATE_DIR', 'OURS_PORT', 'OURS_DAEMON_ID'];
9
- export class ClientProfileError extends Error {
10
- constructor(message) {
11
- super(message);
12
- this.name = 'ClientProfileError';
13
- }
14
- }
15
- export function clientConfigPath(env) {
16
- if (env.OURS_CONFIG !== undefined)
17
- return env.OURS_CONFIG;
18
- const managedPath = join(env.HOME || homedir(), '.ours-client', 'profile.json');
19
- try {
20
- lstatSync(managedPath);
21
- return managedPath;
22
- }
23
- catch (error) {
24
- if (error.code !== 'ENOENT')
25
- throw invalid(managedPath, 'could not be read');
26
- return join(homedir(), '.ours', 'config.json');
27
- }
28
- }
29
- function invalid(path, detail) {
30
- return new ClientProfileError(`ours client profile ${JSON.stringify(path)} ${detail}`);
31
- }
32
- /**
33
- * Read Fleet's selected host-client profile without opening its credential.
34
- * A legacy daemon config remains legacy only when none of the profile fields is
35
- * present. Explicit and managed selections fail closed on invalid input.
36
- */
37
- export function readClientProfile(env) {
38
- const configPath = clientConfigPath(env);
39
- const managed = configPath === join(env.HOME || homedir(), '.ours-client', 'profile.json');
40
- const named = env.OURS_CONFIG !== undefined || managed;
41
- let text;
42
- try {
43
- text = readFileSync(configPath, 'utf8');
44
- }
45
- catch {
46
- if (named)
47
- throw invalid(configPath, 'could not be read');
48
- return undefined;
49
- }
50
- let parsed;
51
- try {
52
- parsed = JSON.parse(text);
53
- }
54
- catch {
55
- if (named)
56
- throw invalid(configPath, 'is not valid JSON');
57
- return undefined;
58
- }
59
- if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
60
- if (named)
61
- throw invalid(configPath, 'must contain a JSON object');
62
- return undefined;
63
- }
64
- const row = parsed;
65
- if (!PROFILE_FIELDS.some(field => Object.prototype.hasOwnProperty.call(row, field))) {
66
- if (managed)
67
- throw invalid(configPath, 'must contain a complete client profile');
68
- return undefined;
69
- }
70
- let metadata;
71
- try {
72
- metadata = statSync(configPath);
73
- }
74
- catch {
75
- throw invalid(configPath, 'could not be inspected');
76
- }
77
- if (!metadata.isFile())
78
- throw invalid(configPath, 'must be a regular file');
79
- const getuid = process.getuid;
80
- if (getuid && metadata.uid !== getuid())
81
- throw invalid(configPath, 'must be owned by this user');
82
- if ((metadata.mode & 0o077) !== 0)
83
- throw invalid(configPath, 'must not be accessible by group or other users');
84
- for (const field of PROFILE_FIELDS)
85
- if (typeof row[field] !== 'string' || !row[field].trim())
86
- throw invalid(configPath, `has an invalid or missing ${field}`);
87
- for (const field of LEGACY_CONFIG_FIELDS)
88
- if (Object.prototype.hasOwnProperty.call(row, field))
89
- throw invalid(configPath, `cannot combine ${field} with explicit profile selection`);
90
- for (const field of LEGACY_ENV_FIELDS)
91
- if (env[field]?.trim())
92
- throw invalid(configPath, `cannot combine ${field} with explicit profile selection`);
93
- const endpoint = row.endpoint.trim();
94
- let url;
95
- try {
96
- url = new URL(endpoint);
97
- }
98
- catch {
99
- throw invalid(configPath, 'has an invalid endpoint');
100
- }
101
- if ((url.protocol !== 'http:' && url.protocol !== 'https:') || url.username || url.password
102
- || url.search || url.hash)
103
- throw invalid(configPath, 'endpoint must be an HTTP or HTTPS base URL');
104
- const expectedInstanceId = row.expectedInstanceId.trim();
105
- if (!LOWERCASE_UUID.test(expectedInstanceId))
106
- throw invalid(configPath, 'expectedInstanceId must be a lowercase UUID');
107
- const credentialPath = row.credentialPath.trim();
108
- if (!isAbsolute(credentialPath))
109
- throw invalid(configPath, 'credentialPath must be absolute');
110
- let serverUrl;
111
- if (Object.hasOwn(row, 'serverUrl')) {
112
- if (typeof row.serverUrl !== 'string' || /[\s\\?#]/.test(row.serverUrl))
113
- throw invalid(configPath, 'serverUrl must be a safe HTTP or HTTPS base URL');
114
- try {
115
- serverUrl = normalizeDaemonEndpoint(row.serverUrl);
116
- }
117
- catch {
118
- throw invalid(configPath, 'serverUrl must be a safe HTTP or HTTPS base URL');
119
- }
120
- if (normalizeDaemonEndpoint(endpoint) !== serverUrl + '/daemon')
121
- throw invalid(configPath, 'endpoint must select serverUrl/daemon');
122
- }
123
- return Object.freeze({
124
- ...(serverUrl === undefined ? {} : { serverUrl }),
125
- endpoint: normalizeDaemonEndpoint(endpoint), expectedInstanceId, credentialPath, configPath,
126
- });
127
- }
1
+ import { clientProfilePath, readGatewayClientProfile } from '@ours.network/sdk/client';
2
+ export { ClientProfileError } from '@ours.network/sdk/client';
3
+ export const clientConfigPath = clientProfilePath;
4
+ export const readClientProfile = readGatewayClientProfile;
128
5
  export function clientProfileKey(profile) {
129
6
  return `${profile.endpoint}#${profile.expectedInstanceId}`;
130
7
  }
package/dist/config.d.ts CHANGED
@@ -2,6 +2,7 @@ import { type ConfigDiagnostic, type YamlMode } from './config-yaml.js';
2
2
  import type { IsolationConfig, WrapContext } from './isolation/types.js';
3
3
  import type { ResolvedWatchdog } from './watchdog/config.js';
4
4
  import type { AgentLoopsConfig, ResolvedLoop, ResolvedRoleLoop } from './loops/config.js';
5
+ import { validateRoomsConfig } from './rooms-tasks/config.js';
5
6
  export interface OverseeEntry {
6
7
  agent: string;
7
8
  interval: string;
@@ -35,6 +36,23 @@ export type FilesystemMode = 'read-only' | 'workspace' | 'unrestricted';
35
36
  export type UnattendedMode = 'deny' | 'wait';
36
37
  /** Monitor wake policy: preserve legacy booleans and add one explicit safe boundary. */
37
38
  export type MonitorInterrupt = boolean | 'after_tool';
39
+ /**
40
+ * Workflows Fleet prepares native harness execution policy for. Declared per
41
+ * Agent; never inferred from a role's name or persona, and never inherited.
42
+ */
43
+ export declare const MANAGED_CLI_WORKFLOW_IDS: readonly ["task-workflow"];
44
+ export type ManagedCliWorkflowId = (typeof MANAGED_CLI_WORKFLOW_IDS)[number];
45
+ /** Retired opt-in. Both keys are accepted so existing manifests load, and neither has any effect. */
46
+ export interface FileDeliveryConfig {
47
+ enabled?: boolean;
48
+ directory?: string;
49
+ }
50
+ /**
51
+ * Current-chat file delivery is on for every Agent and takes the path the Agent
52
+ * provides. A legacy block is shape-checked only: `enabled: false` does not turn
53
+ * delivery off and `directory` does not restrict or create anything.
54
+ */
55
+ export declare function validateFileDelivery(value: unknown): FileDeliveryConfig | undefined;
38
56
  export interface CommonPermissions {
39
57
  approval: ApprovalMode;
40
58
  filesystem: FilesystemMode;
@@ -145,6 +163,10 @@ export interface RoleConfig {
145
163
  owner_channel?: OwnerChannelConfigInput;
146
164
  worklog?: WorklogPolicyInput;
147
165
  auth_proxy?: Partial<AuthProxyConfig>;
166
+ /** Fleet-prepared CLI workflows this role may run outside its command sandbox. */
167
+ managed_cli?: ManagedCliWorkflowId[];
168
+ /** Retired and ignored; current-chat file delivery needs no Agent setting. */
169
+ file_delivery?: FileDeliveryConfig;
148
170
  }
149
171
  export type AgentSelection<T extends Record<string, unknown> = Record<string, unknown>> = {
150
172
  ref: string;
@@ -166,6 +188,10 @@ export interface AgentDefinition {
166
188
  owner_channel?: OwnerChannelConfigInput;
167
189
  worklog?: WorklogPolicyInput;
168
190
  auth_proxy?: Partial<AuthProxyConfig>;
191
+ /** Fleet-prepared CLI workflows this Agent may run outside its command sandbox. */
192
+ managed_cli?: ManagedCliWorkflowId[];
193
+ /** Retired and ignored; current-chat file delivery needs no Agent setting. */
194
+ file_delivery?: FileDeliveryConfig;
169
195
  /** Scheduled turns scoped only to temporary launches; persistent Agents reject this field. */
170
196
  loops?: AgentLoopsConfig;
171
197
  }
@@ -178,6 +204,9 @@ export interface AgentTemplateInstance {
178
204
  }
179
205
  /** Internal first-boot payload for a Fleet-provisioned Cowork room member. */
180
206
  export interface RoomMemberStartup {
207
+ /** Task ownership; absent for standalone rooms and legacy snapshots. */
208
+ task_id?: string;
209
+ workspace?: import('./rooms-tasks/workspace.js').OwnedWorkspace;
181
210
  room_id: string;
182
211
  room_identity_cid: string;
183
212
  identity_name: string;
@@ -298,6 +327,8 @@ export declare function validateBrainValue(value: BarePreset, file: string, poin
298
327
  export declare function validateEffectiveAgentTemplate(definition: AgentTemplateDefinition, id?: string): AgentTemplateDefinition;
299
328
  export declare function assertBareKeys(value: unknown, allowed: string[], label: string): BarePreset;
300
329
  export declare function splitRootFor(base: string): string;
330
+ /** Read only room connection/owner settings for an existing layout. */
331
+ export declare function loadRoomsConfig(configPath?: string): ReturnType<typeof validateRoomsConfig>;
301
332
  /** Load a v2 manifest and bare Agent/Role/Brain documents from its stem directory. */
302
333
  export declare function loadConfig(configPath?: string, options?: {
303
334
  yamlMode?: YamlMode;
@@ -307,6 +338,8 @@ export declare function loadConfig(configPath?: string, options?: {
307
338
  temporary?: boolean;
308
339
  };
309
340
  skipWatchdogs?: boolean;
341
+ /** The one Owner invitation file that tunnel setup writes itself and that may therefore still be absent. */
342
+ deferredOwnerInviteFile?: string;
310
343
  }): FleetConfig;
311
344
  /** Full read-only Agent resolution used by launch dry-runs and room plan validation. */
312
345
  export declare function resolveAgentDefinitionDryRun(configPath: string, id: string, definition: AgentDefinition): ResolvedRole;
@@ -331,10 +364,22 @@ export declare function resolvePermissions(defaults: unknown, role: Partial<Comm
331
364
  * malformed block so a typo fails loudly rather than silently disarming a monitor.
332
365
  * Exported so temp-spawn (which builds a ResolvedRole by hand) resolves identically.
333
366
  */
367
+ /**
368
+ * A monitor without an explicit `interrupt` steers wakes at the next tool
369
+ * boundary. Hermes cannot, so its default stays non-interrupting; sessions
370
+ * without tool-boundary steering fall back to non-cancelling delivery.
371
+ */
372
+ export declare function defaultMonitorInterrupt(harness: string | undefined): MonitorInterrupt;
373
+ /**
374
+ * Resolve a persisted temporary-role monitor. A snapshot written before
375
+ * monitor.interrupt existed keeps the non-interrupting delivery it ran with.
376
+ */
377
+ export declare function resolveSnapshotMonitor(monitor: unknown): MonitorConfig;
334
378
  export declare function resolveMonitorConfig(defMonitor: unknown, roleMonitor?: Partial<MonitorConfig>, labels?: {
335
379
  base?: string;
336
380
  file?: string;
337
381
  name?: string;
382
+ harness?: string;
338
383
  }): MonitorConfig;
339
384
  export declare function findRole(cfg: FleetConfig, name: string): ResolvedRole;
340
385
  export {};
package/dist/config.js CHANGED
@@ -24,6 +24,25 @@ export const NOTIFY_EVENT_TYPES = [
24
24
  'message_received', 'file_received', 'sibling_contact_added', 'local_contact_request',
25
25
  'pending_message', 'contact_restored', 'inbound_error', 'state_import_failed',
26
26
  ];
27
+ /**
28
+ * Workflows Fleet prepares native harness execution policy for. Declared per
29
+ * Agent; never inferred from a role's name or persona, and never inherited.
30
+ */
31
+ export const MANAGED_CLI_WORKFLOW_IDS = ['task-workflow'];
32
+ /**
33
+ * Current-chat file delivery is on for every Agent and takes the path the Agent
34
+ * provides. A legacy block is shape-checked only: `enabled: false` does not turn
35
+ * delivery off and `directory` does not restrict or create anything.
36
+ */
37
+ export function validateFileDelivery(value) {
38
+ if (value === undefined)
39
+ return undefined;
40
+ if (!isPlainObject(value) || Object.keys(value).some(k => !['enabled', 'directory'].includes(k))
41
+ || (value.enabled !== undefined && typeof value.enabled !== 'boolean')
42
+ || (value.directory !== undefined && typeof value.directory !== 'string'))
43
+ throw new ConfigError('file_delivery is retired and ignored; it accepts only the legacy enabled:boolean and directory:string keys');
44
+ return value;
45
+ }
27
46
  /** Default wake sources when a role does not list its own. */
28
47
  export const DEFAULT_WAKE_SOURCES = ['message_received', 'file_received', 'local_contact_request', 'pending_message'];
29
48
  const MONITOR_KEYS = [
@@ -139,7 +158,7 @@ export const ROLE_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;
139
158
  const ROLE_KEYS = [
140
159
  'harness', 'session', 'session_options', 'permissions', 'identity', 'cwd', 'coordinator', 'mission', 'persona', 'bio',
141
160
  'briefing_file', 'model', 'effort', 'model_chain', 'max_tokens', 'autocompact_pct', 'env', 'oversee', 'harness_options',
142
- 'isolation', 'monitor', 'owner_channel', 'worklog', 'auth_proxy',
161
+ 'isolation', 'monitor', 'owner_channel', 'worklog', 'auth_proxy', 'managed_cli', 'file_delivery',
143
162
  ];
144
163
  export const ROLE_PRESET_KEYS = ['mission', 'persona', 'bio', 'briefing_file'];
145
164
  export const BRAIN_PRESET_KEYS = [
@@ -148,7 +167,7 @@ export const BRAIN_PRESET_KEYS = [
148
167
  ];
149
168
  export const AGENT_KEYS = [
150
169
  'role', 'brain', 'permissions', 'identity', 'cwd', 'coordinator', 'env', 'oversee',
151
- 'isolation', 'monitor', 'owner_channel', 'worklog', 'auth_proxy', 'loops',
170
+ 'isolation', 'monitor', 'owner_channel', 'worklog', 'auth_proxy', 'loops', 'managed_cli', 'file_delivery',
152
171
  ];
153
172
  const AGENT_INSTANCE_KEYS = ['template', 'overrides'];
154
173
  const TEMPLATE_FORBIDDEN_KEYS = ['identity'];
@@ -194,6 +213,7 @@ export function validateBrainValue(value, file, pointer) {
194
213
  }
195
214
  /** Pure launch-boundary validation for a fully resolved temporary Agent definition. */
196
215
  export function validateEffectiveAgentTemplate(definition, id = 'room-member') {
216
+ validateFileDelivery(definition.file_delivery);
197
217
  const value = structuredClone(definition);
198
218
  const bad = Object.keys(value).filter(key => !AGENT_KEYS.includes(key));
199
219
  if (bad.length)
@@ -236,6 +256,12 @@ function validateAgentScalars(value, file, id) {
236
256
  if (current !== undefined && (typeof current !== 'string' || !current.trim()))
237
257
  schemaError(file, `/agents/${id}/${key}`, 'must be a non-blank string');
238
258
  }
259
+ if (value.managed_cli !== undefined) {
260
+ const ids = value.managed_cli;
261
+ if (!Array.isArray(ids) || ids.some(entry => !MANAGED_CLI_WORKFLOW_IDS.includes(entry))
262
+ || new Set(ids).size !== ids.length)
263
+ schemaError(file, `/agents/${id}/managed_cli`, `must be a list of distinct workflow IDs; supported: ${MANAGED_CLI_WORKFLOW_IDS.join(', ')}`);
264
+ }
239
265
  if (value.coordinator !== undefined
240
266
  && (typeof value.coordinator !== 'string' || !ROLE_NAME_RE.test(value.coordinator)))
241
267
  schemaError(file, `/agents/${id}/coordinator`, 'must be a valid Agent ID');
@@ -575,6 +601,13 @@ function deepSub(v, vars) {
575
601
  return Object.fromEntries(Object.entries(v).map(([k, x]) => [k, deepSub(x, vars)]));
576
602
  return v;
577
603
  }
604
+ /** Read only room connection/owner settings for an existing layout. */
605
+ export function loadRoomsConfig(configPath = defaultConfigPath()) {
606
+ assertTrustedPath(configPath, 'file');
607
+ const doc = parseFleetDocument(configPath, readFileSync(configPath, 'utf8')).value;
608
+ const vars = (doc.vars ?? {});
609
+ return validateRoomsConfig(deepSub(doc.rooms, vars), vars, configPath);
610
+ }
578
611
  /** Load a v2 manifest and bare Agent/Role/Brain documents from its stem directory. */
579
612
  export function loadConfig(configPath, options = {}) {
580
613
  const base = configPath ?? defaultConfigPath();
@@ -628,6 +661,7 @@ export function loadConfig(configPath, options = {}) {
628
661
  const bad = Object.keys(r).filter(k => !ROLE_KEYS.includes(k));
629
662
  if (bad.length)
630
663
  throw new ConfigError(`${file}: role '${name}' has unknown key(s) ${bad.join(', ')}; allowed: ${ROLE_KEYS.join(', ')}`);
664
+ validateFileDelivery(r.file_delivery);
631
665
  const isolation = r.isolation ?? defaults.isolation;
632
666
  const session = resolveSession(r.session ?? defaults.session, file, name);
633
667
  const sessionOptions = resolveSessionOptions(defaults.session_options, r.session_options, session, file, name);
@@ -649,11 +683,11 @@ export function loadConfig(configPath, options = {}) {
649
683
  if (problems.length)
650
684
  throw new ConfigError(`${file}: role '${name}' ${problems.join('; ')}`);
651
685
  }
652
- const monitor = resolveMonitorConfig(defaults.monitor, r.monitor, { base, file, name });
686
+ const harness = r.harness ?? defaults.harness ?? 'claude-code';
687
+ const monitor = resolveMonitorConfig(defaults.monitor, r.monitor, { base, file, name, harness });
653
688
  const ownerChannel = resolveOwnerChannelConfig(defaults.owner_channel, r.owner_channel, session, file, name);
654
689
  const worklog = resolveWorklogPolicy(defaults.worklog, r.worklog, file, name);
655
690
  const authProxy = resolveAuthProxy(defaults.auth_proxy, r.auth_proxy, file, name);
656
- const harness = r.harness ?? defaults.harness ?? 'claude-code';
657
691
  if (session === 'codex-app-server' && harness !== 'codex')
658
692
  throw new ConfigError(`${file}: role '${name}' session: codex-app-server requires harness: codex`);
659
693
  const defaultHarness = defaults.harness ?? 'claude-code';
@@ -757,7 +791,7 @@ export function loadConfig(configPath, options = {}) {
757
791
  if (doc.rooms !== undefined) {
758
792
  if (rooms)
759
793
  throw new ConfigError(`rooms: defined in multiple files; last: ${file}`);
760
- const validated = validateRoomsConfig(deepSub(doc.rooms, vars), vars, file);
794
+ const validated = validateRoomsConfig(deepSub(doc.rooms, vars), vars, file, options.deferredOwnerInviteFile);
761
795
  ownerInviteFingerprint = validated._invite?.fingerprint;
762
796
  ownerInvite = validated._invite?.value;
763
797
  const { _invite: _, ...clean } = validated;
@@ -1135,6 +1169,23 @@ function resolveStartStaggerMs(raw, base) {
1135
1169
  * malformed block so a typo fails loudly rather than silently disarming a monitor.
1136
1170
  * Exported so temp-spawn (which builds a ResolvedRole by hand) resolves identically.
1137
1171
  */
1172
+ /**
1173
+ * A monitor without an explicit `interrupt` steers wakes at the next tool
1174
+ * boundary. Hermes cannot, so its default stays non-interrupting; sessions
1175
+ * without tool-boundary steering fall back to non-cancelling delivery.
1176
+ */
1177
+ export function defaultMonitorInterrupt(harness) {
1178
+ return harness === 'hermes' ? false : 'after_tool';
1179
+ }
1180
+ /**
1181
+ * Resolve a persisted temporary-role monitor. A snapshot written before
1182
+ * monitor.interrupt existed keeps the non-interrupting delivery it ran with.
1183
+ */
1184
+ export function resolveSnapshotMonitor(monitor) {
1185
+ if (!isPlainObject(monitor))
1186
+ return resolveMonitorConfig(undefined, monitor);
1187
+ return resolveMonitorConfig(undefined, { interrupt: false, ...monitor });
1188
+ }
1138
1189
  export function resolveMonitorConfig(defMonitor, roleMonitor, labels = {}) {
1139
1190
  const where = labels.file && labels.name ? `${labels.file}: role '${labels.name}' ` : '';
1140
1191
  if (defMonitor !== undefined && !isPlainObject(defMonitor))
@@ -1169,7 +1220,7 @@ export function resolveMonitorConfig(defMonitor, roleMonitor, labels = {}) {
1169
1220
  wake_sources: merged.wake_sources ?? [...DEFAULT_WAKE_SOURCES],
1170
1221
  batch_ms: merged.batch_ms ?? MONITOR_DEFAULT_BATCH_MS,
1171
1222
  inject: merged.inject ?? 'notification',
1172
- interrupt: merged.interrupt ?? false,
1223
+ interrupt: merged.interrupt ?? defaultMonitorInterrupt(labels.harness),
1173
1224
  ...(merged.stall_recovery !== undefined ? { stall_recovery: merged.stall_recovery } : {}),
1174
1225
  ...(merged.stall_timeout_ms !== undefined ? { stall_timeout_ms: merged.stall_timeout_ms } : {}),
1175
1226
  turn_fail_threshold: merged.turn_fail_threshold ?? MONITOR_DEFAULT_TURN_FAIL_THRESHOLD,
@@ -153,7 +153,7 @@ export interface DaemonIdentityProvisionerOptions {
153
153
  export declare function daemonIdentityProvisioner(env?: NodeJS.ProcessEnv, attachClient?: (options: AttachOursClientOptions) => Promise<IdentityInventoryClient>, options?: DaemonIdentityProvisionerOptions): IdentityProvisioner;
154
154
  /** Inventory-only variant for session-owned temporary identity lifecycles. */
155
155
  export declare function daemonIdentityInventoryProvisioner(env?: NodeJS.ProcessEnv, attachClient?: (options: AttachOursClientOptions) => Promise<IdentityInventoryClient>): IdentityProvisioner;
156
- /** Atomically write a bare Agent file, journalling it for rollback. */
156
+ /** Atomically write an owner-private Agent file, journalling it for rollback. */
157
157
  export declare function writeRoleFile(tx: CreationTransaction, file: string, contents: string): void;
158
158
  /** Where a setting's effective value came from. */
159
159
  export type ProvenanceSource = 'cli' | 'agent-template' | 'fleet-default' | 'caller-role' | 'built-in';
package/dist/creation.js CHANGED
@@ -213,10 +213,10 @@ export async function ensureIdentity(name, profile, provisioner, log = () => { }
213
213
  export function daemonIdentityProvisioner(env = process.env, attachClient = attachOursClient, options = {}) {
214
214
  const connect = (leaseToken) => {
215
215
  const profile = readClientProfile(env);
216
- return attachClient(profile ? {
216
+ return attachClient({
217
217
  endpoint: profile.endpoint, expectedInstanceId: profile.expectedInstanceId,
218
218
  credentialPath: profile.credentialPath, sessionMode: 'external', leaseToken, env: {},
219
- } : { env, leaseToken, clientPid: process.pid });
219
+ });
220
220
  };
221
221
  const provisioner = {
222
222
  async exists(name) {
@@ -294,10 +294,10 @@ export function daemonIdentityInventoryProvisioner(env = process.env, attachClie
294
294
  acceptTemporaryExisting: true,
295
295
  });
296
296
  }
297
- /** Atomically write a bare Agent file, journalling it for rollback. */
297
+ /** Atomically write an owner-private Agent file, journalling it for rollback. */
298
298
  export function writeRoleFile(tx, file, contents) {
299
299
  const existed = existsSync(file);
300
- replaceFileAtomically(file, contents, 0o644);
300
+ replaceFileAtomically(file, contents, 0o600);
301
301
  tx.record({
302
302
  stage: `Agent file ${file}`,
303
303
  // Only remove what THIS transaction created; never delete a file the
@@ -34,14 +34,7 @@ interface GenerationProbeDeps {
34
34
  canonicalize?(path: string): string;
35
35
  attachClient?(options: AttachOursClientOptions): Pick<OursClient, 'version' | 'identities' | 'close'> | Promise<Pick<OursClient, 'version' | 'identities' | 'close'>>;
36
36
  }
37
- /**
38
- * Corroborate the loopback daemon's unauthenticated `/info`, its credentialed
39
- * identity-index readiness route, and its local boot-generation record. The
40
- * index enforces auth when the daemon visibility requires it; open visibility
41
- * deliberately does not. No source is sufficient
42
- * alone: `/info` has no boot id, the identity index has no generation, and a
43
- * stale `ready` file can outlive the process that wrote it.
44
- */
37
+ /** Read generation and readiness through the selected gateway. Server paths are opaque. */
45
38
  export declare function probeDaemonGeneration(fetch: FetchLike, env: NodeJS.ProcessEnv, deps?: GenerationProbeDeps): Promise<DaemonGenerationProbe>;
46
39
  export declare class DaemonGenerationObserver {
47
40
  private current?;
@@ -1,8 +1,7 @@
1
- import { readFileSync, realpathSync } from 'node:fs';
2
- import { join, resolve } from 'node:path';
1
+ import { readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
3
  import { createHash, randomUUID } from 'node:crypto';
4
4
  import { attachOursClient, } from '@ours.network/sdk/client';
5
- import { readDaemonConfig, resolveEndpoint } from './monitor.js';
6
5
  import { readClientProfile } from './client-profile.js';
7
6
  import { replaceFileAtomically } from './atomic-file.js';
8
7
  export const DAEMON_RECOVERY_MAX_ATTEMPTS = 6;
@@ -39,129 +38,25 @@ function startupProgress(value) {
39
38
  return undefined;
40
39
  return row;
41
40
  }
42
- function canonical(path, deps) {
43
- const absolute = resolve(path);
44
- return deps.canonicalize?.(absolute) ?? realpathSync.native(absolute);
45
- }
46
- /**
47
- * Corroborate the loopback daemon's unauthenticated `/info`, its credentialed
48
- * identity-index readiness route, and its local boot-generation record. The
49
- * index enforces auth when the daemon visibility requires it; open visibility
50
- * deliberately does not. No source is sufficient
51
- * alone: `/info` has no boot id, the identity index has no generation, and a
52
- * stale `ready` file can outlive the process that wrote it.
53
- */
41
+ /** Read generation and readiness through the selected gateway. Server paths are opaque. */
54
42
  export async function probeDaemonGeneration(fetch, env, deps = {}) {
55
- const profile = readClientProfile(env);
56
- if (profile || env.OURS_DAEMON_ID)
57
- return probeSelectedDaemon(env, deps, profile);
58
- const endpoint = resolveEndpoint(env);
59
- let response;
60
- try {
61
- response = await fetch(`${endpoint.origin}/info`, { headers: endpoint.headers });
62
- }
63
- catch {
64
- return { state: 'unavailable', reason: 'DAEMON_INFO_UNREACHABLE' };
65
- }
66
- if (!response.ok)
67
- return {
68
- state: 'unavailable',
69
- reason: response.status === 401 ? 'DAEMON_INFO_UNAUTHORIZED' : 'DAEMON_INFO_HTTP_ERROR',
70
- };
71
- let info;
72
- try {
73
- const value = await response.json();
74
- if (!value || typeof value !== 'object' || Array.isArray(value))
75
- throw new Error('shape');
76
- info = value;
77
- }
78
- catch {
79
- return { state: 'unavailable', reason: 'DAEMON_INFO_INVALID' };
80
- }
81
- if (info.name !== 'ours' || !positiveInteger(info.pid)
82
- || typeof info.stateDir !== 'string' || info.stateDir.length === 0)
83
- return { state: 'unavailable', reason: 'DAEMON_INFO_INVALID' };
84
- let reportedStateDir;
85
- let expectedStateDir;
86
- try {
87
- reportedStateDir = canonical(info.stateDir, deps);
88
- expectedStateDir = canonical(endpoint.stateDir, deps);
89
- }
90
- catch {
91
- return { state: 'unavailable', reason: 'DAEMON_STATE_DIR_UNAVAILABLE' };
92
- }
93
- if (reportedStateDir !== expectedStateDir)
94
- return { state: 'unavailable', reason: 'DAEMON_STATE_DIR_MISMATCH' };
95
- // `/identities` is the daemon's credential-capable readiness route. A
96
- // valid-but-empty index is a documented intermediate startup state, never
97
- // proof of readiness.
98
- let identitiesResponse;
99
- try {
100
- identitiesResponse = await fetch(`${endpoint.origin}/identities`, { headers: endpoint.headers });
101
- }
102
- catch {
103
- return { state: 'unavailable', reason: 'DAEMON_IDENTITIES_UNREACHABLE' };
104
- }
105
- if (!identitiesResponse.ok)
106
- return {
107
- state: 'unavailable',
108
- reason: identitiesResponse.status === 401
109
- ? 'DAEMON_IDENTITIES_UNAUTHORIZED' : 'DAEMON_IDENTITIES_HTTP_ERROR',
110
- };
111
- try {
112
- const body = await identitiesResponse.json();
113
- if (!body || typeof body !== 'object' || Array.isArray(body)
114
- || !Array.isArray(body.identities))
115
- return { state: 'unavailable', reason: 'DAEMON_IDENTITIES_INVALID' };
116
- if (body.identities.length === 0)
117
- return { state: 'unavailable', reason: 'DAEMON_IDENTITIES_NOT_READY' };
118
- }
119
- catch {
120
- return { state: 'unavailable', reason: 'DAEMON_IDENTITIES_INVALID' };
121
- }
122
- let progress;
123
43
  try {
124
- const text = deps.readText?.(join(reportedStateDir, 'startup-progress.json'))
125
- ?? readFileSync(join(reportedStateDir, 'startup-progress.json'), 'utf8');
126
- progress = startupProgress(JSON.parse(text));
44
+ return await probeSelectedDaemon(deps, readClientProfile(env));
127
45
  }
128
46
  catch {
129
- return { state: 'unavailable', reason: 'DAEMON_PROGRESS_UNAVAILABLE' };
47
+ return { state: 'unavailable', reason: 'CLIENT_GATEWAY_PROFILE_INVALID' };
130
48
  }
131
- if (!progress)
132
- return { state: 'unavailable', reason: 'DAEMON_PROGRESS_INVALID' };
133
- if (progress.phase !== 'ready')
134
- return { state: 'unavailable', reason: 'DAEMON_PROGRESS_NOT_READY' };
135
- if (progress.pid !== info.pid)
136
- return { state: 'unavailable', reason: 'DAEMON_GENERATION_MISMATCH' };
137
- return {
138
- state: 'ready',
139
- generation: {
140
- // Keep bootId opaque. Its current writer uses `${pid}-${startedAt}`, but
141
- // equality—not its formatting—is the generation contract Fleet needs.
142
- bootId: progress.bootId,
143
- pid: progress.pid,
144
- startedAt: progress.startedAt,
145
- stateDir: reportedStateDir,
146
- },
147
- };
148
49
  }
149
50
  /** Container selection uses public SDK reads; daemon paths/PIDs remain opaque metadata. */
150
- async function probeSelectedDaemon(env, deps, profile) {
51
+ async function probeSelectedDaemon(deps, profile) {
151
52
  // Defer credential-file access to SDK selection, which checks the configured
152
53
  // daemon identity/capability before it reads or sends the credential.
153
- const endpoint = profile ? undefined : resolveEndpoint(env, false);
154
- const token = profile ? undefined : env.OURS_API_TOKEN?.trim() || readDaemonConfig(env).apiToken;
155
54
  let client;
156
55
  try {
157
- const options = profile ? {
56
+ const options = {
158
57
  endpoint: profile.endpoint, expectedInstanceId: profile.expectedInstanceId,
159
58
  credentialPath: profile.credentialPath,
160
59
  sessionMode: 'external', leaseToken: randomUUID(), env: {},
161
- } : {
162
- endpoint: endpoint.origin, expectedInstanceId: env.OURS_DAEMON_ID,
163
- sessionMode: 'external', leaseToken: randomUUID(),
164
- ...(token ? { token } : { credentialPath: join(endpoint.stateDir, 'daemon-token') }),
165
60
  };
166
61
  client = await (deps.attachClient?.(options) ?? attachOursClient(options));
167
62
  const info = await client.version({ startup: true });
@@ -189,7 +84,7 @@ async function probeSelectedDaemon(env, deps, profile) {
189
84
  return { state: 'unavailable', reason: 'DAEMON_SELECTED_PROBE_UNAVAILABLE' };
190
85
  }
191
86
  finally {
192
- await client?.close();
87
+ await client?.close().catch(() => undefined);
193
88
  }
194
89
  }
195
90
  export class DaemonGenerationObserver {