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

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 (414) hide show
  1. package/README.md +279 -68
  2. package/dist/account-origin.d.ts +2 -0
  3. package/dist/account-origin.js +6 -0
  4. package/dist/agent-ours/bridge.js +26 -9
  5. package/dist/agent-ours/correspondence.d.ts +10 -0
  6. package/dist/agent-ours/correspondence.js +1 -0
  7. package/dist/agent-ours/file-rpc.d.ts +12 -0
  8. package/dist/agent-ours/file-rpc.js +18 -4
  9. package/dist/agent-ours/harness.js +9 -1
  10. package/dist/agent-ours/mcp-endpoint.d.ts +19 -0
  11. package/dist/agent-ours/mcp-endpoint.js +98 -25
  12. package/dist/agent-ours/runtime.d.ts +9 -1
  13. package/dist/agent-ours/runtime.js +50 -2
  14. package/dist/agent-ours/service.d.ts +24 -1
  15. package/dist/agent-ours/service.js +97 -13
  16. package/dist/application/codex-models.d.ts +15 -0
  17. package/dist/application/codex-models.js +56 -0
  18. package/dist/application/conversation-history.d.ts +27 -0
  19. package/dist/application/conversation-history.js +215 -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 +2 -2
  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 +17 -3
  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 +61 -17
  35. package/dist/application/session-control.js +207 -23
  36. package/dist/application/supervisor-ours-tools.js +5 -11
  37. package/dist/application/task-layouts.d.ts +91 -0
  38. package/dist/application/task-layouts.js +259 -0
  39. package/dist/application/task-room-service.d.ts +99 -3
  40. package/dist/application/task-room-service.js +285 -32
  41. package/dist/application/types.d.ts +2 -0
  42. package/dist/atomic-file.d.ts +34 -1
  43. package/dist/atomic-file.js +161 -18
  44. package/dist/briefing.d.ts +3 -1
  45. package/dist/briefing.js +97 -31
  46. package/dist/build-info.json +9 -4
  47. package/dist/capabilities.d.ts +9 -1
  48. package/dist/capabilities.js +13 -0
  49. package/dist/cli.js +400 -37
  50. package/dist/client-profile.d.ts +5 -17
  51. package/dist/client-profile.js +4 -127
  52. package/dist/config.d.ts +45 -0
  53. package/dist/config.js +57 -6
  54. package/dist/creation.d.ts +1 -1
  55. package/dist/creation.js +4 -4
  56. package/dist/daemon-recovery.d.ts +1 -8
  57. package/dist/daemon-recovery.js +8 -113
  58. package/dist/docs.d.ts +1 -1
  59. package/dist/docs.js +207 -19
  60. package/dist/doctor.d.ts +4 -1
  61. package/dist/doctor.js +75 -60
  62. package/dist/erased-resources.d.ts +9 -0
  63. package/dist/erased-resources.js +87 -0
  64. package/dist/file-delivery/reader.d.ts +15 -0
  65. package/dist/file-delivery/reader.js +63 -0
  66. package/dist/file-delivery/store.d.ts +15 -0
  67. package/dist/file-delivery/store.js +124 -0
  68. package/dist/file-delivery/types.d.ts +19 -0
  69. package/dist/file-delivery/types.js +1 -0
  70. package/dist/fleet-command-audit.d.ts +7 -0
  71. package/dist/fleet-command-audit.js +24 -8
  72. package/dist/harness/agent-session.d.ts +4 -0
  73. package/dist/harness/claude-code-session.js +1 -1
  74. package/dist/harness/claude-code.js +21 -11
  75. package/dist/harness/claude-runtime.d.ts +12 -0
  76. package/dist/harness/claude-runtime.js +43 -0
  77. package/dist/harness/codex-app-server-proxy.d.ts +4 -1
  78. package/dist/harness/codex-app-server-proxy.js +41 -5
  79. package/dist/harness/codex-reasoning.d.ts +5 -0
  80. package/dist/harness/codex-reasoning.js +12 -0
  81. package/dist/harness/codex-runtime.d.ts +11 -1
  82. package/dist/harness/codex-runtime.js +31 -4
  83. package/dist/harness/codex-session.js +2 -2
  84. package/dist/harness/codex.js +24 -12
  85. package/dist/init-wizard.d.ts +2 -0
  86. package/dist/init-wizard.js +38 -19
  87. package/dist/isolation/policy.js +6 -1
  88. package/dist/isolation/types.d.ts +5 -0
  89. package/dist/managed-cli.d.ts +253 -0
  90. package/dist/managed-cli.js +923 -0
  91. package/dist/managed-recovery.d.ts +13 -0
  92. package/dist/managed-recovery.js +31 -0
  93. package/dist/minimal-setup.d.ts +2 -0
  94. package/dist/minimal-setup.js +44 -0
  95. package/dist/monitor.d.ts +8 -34
  96. package/dist/monitor.js +89 -152
  97. package/dist/notifications/fleet-producer.d.ts +19 -0
  98. package/dist/notifications/fleet-producer.js +208 -0
  99. package/dist/notifications/outbox.d.ts +46 -0
  100. package/dist/notifications/outbox.js +158 -0
  101. package/dist/notifications/target-cleanup.d.ts +10 -0
  102. package/dist/notifications/target-cleanup.js +63 -0
  103. package/dist/notifications/task-producer.d.ts +18 -0
  104. package/dist/notifications/task-producer.js +67 -0
  105. package/dist/ops.d.ts +2 -0
  106. package/dist/ops.js +20 -3
  107. package/dist/owner-channel/channel.js +17 -6
  108. package/dist/owner-channel/commands.d.ts +4 -0
  109. package/dist/owner-channel/commands.js +8 -0
  110. package/dist/owner-channel/lifecycle-outbox.js +4 -3
  111. package/dist/owner-channel/ours-client.js +2 -17
  112. package/dist/paths.d.ts +2 -0
  113. package/dist/paths.js +2 -0
  114. package/dist/preset-migration.js +43 -0
  115. package/dist/process-incarnation.d.ts +23 -0
  116. package/dist/process-incarnation.js +42 -0
  117. package/dist/reminders/manager.d.ts +75 -0
  118. package/dist/reminders/manager.js +278 -0
  119. package/dist/reminders/runtime.d.ts +27 -0
  120. package/dist/reminders/runtime.js +32 -0
  121. package/dist/reminders/schedule.d.ts +37 -0
  122. package/dist/reminders/schedule.js +104 -0
  123. package/dist/reminders/store.d.ts +341 -0
  124. package/dist/reminders/store.js +762 -0
  125. package/dist/reminders/tools.d.ts +20 -0
  126. package/dist/reminders/tools.js +114 -0
  127. package/dist/resolved-plan.js +1 -0
  128. package/dist/rooms-tasks/add-member.d.ts +48 -0
  129. package/dist/rooms-tasks/add-member.js +83 -0
  130. package/dist/rooms-tasks/archived-absence.d.ts +8 -0
  131. package/dist/rooms-tasks/archived-absence.js +48 -0
  132. package/dist/rooms-tasks/cli.js +65 -5
  133. package/dist/rooms-tasks/close.d.ts +6 -2
  134. package/dist/rooms-tasks/close.js +246 -37
  135. package/dist/rooms-tasks/config.d.ts +1 -1
  136. package/dist/rooms-tasks/config.js +11 -4
  137. package/dist/rooms-tasks/cowork-adapter.d.ts +12 -5
  138. package/dist/rooms-tasks/cowork-adapter.js +15 -121
  139. package/dist/rooms-tasks/cowork-http.js +56 -6
  140. package/dist/rooms-tasks/deletion.d.ts +1 -1
  141. package/dist/rooms-tasks/deletion.js +84 -5
  142. package/dist/rooms-tasks/erasure.d.ts +6 -0
  143. package/dist/rooms-tasks/erasure.js +173 -0
  144. package/dist/rooms-tasks/external-worker.d.ts +1 -1
  145. package/dist/rooms-tasks/external-worker.js +3 -4
  146. package/dist/rooms-tasks/layout-binding-client.d.ts +11 -0
  147. package/dist/rooms-tasks/layout-binding-client.js +56 -0
  148. package/dist/rooms-tasks/layout-binding-grants.d.ts +21 -0
  149. package/dist/rooms-tasks/layout-binding-grants.js +128 -0
  150. package/dist/rooms-tasks/layout-cli.d.ts +4 -0
  151. package/dist/rooms-tasks/layout-cli.js +107 -0
  152. package/dist/rooms-tasks/layout-config.d.ts +11 -0
  153. package/dist/rooms-tasks/layout-config.js +89 -0
  154. package/dist/rooms-tasks/layout-control.d.ts +21 -0
  155. package/dist/rooms-tasks/layout-control.js +52 -0
  156. package/dist/rooms-tasks/layout-member-retirement.d.ts +10 -0
  157. package/dist/rooms-tasks/layout-member-retirement.js +90 -0
  158. package/dist/rooms-tasks/layout-service.d.ts +43 -0
  159. package/dist/rooms-tasks/layout-service.js +203 -0
  160. package/dist/rooms-tasks/layout.d.ts +121 -0
  161. package/dist/rooms-tasks/layout.js +285 -0
  162. package/dist/rooms-tasks/legacy-task-member.d.ts +19 -0
  163. package/dist/rooms-tasks/legacy-task-member.js +116 -0
  164. package/dist/rooms-tasks/live-readiness.d.ts +18 -0
  165. package/dist/rooms-tasks/live-readiness.js +85 -0
  166. package/dist/rooms-tasks/member-ownership.d.ts +5 -0
  167. package/dist/rooms-tasks/member-ownership.js +40 -0
  168. package/dist/rooms-tasks/member-startup.d.ts +1 -0
  169. package/dist/rooms-tasks/member-startup.js +2 -0
  170. package/dist/rooms-tasks/provision.d.ts +3 -0
  171. package/dist/rooms-tasks/provision.js +101 -49
  172. package/dist/rooms-tasks/recovery.d.ts +19 -0
  173. package/dist/rooms-tasks/recovery.js +110 -0
  174. package/dist/rooms-tasks/room-state.d.ts +4 -2
  175. package/dist/rooms-tasks/room-state.js +47 -8
  176. package/dist/rooms-tasks/task-service-retirement.d.ts +11 -0
  177. package/dist/rooms-tasks/task-service-retirement.js +21 -0
  178. package/dist/rooms-tasks/task-state.d.ts +51 -8
  179. package/dist/rooms-tasks/task-state.js +245 -25
  180. package/dist/rooms-tasks/types.d.ts +40 -0
  181. package/dist/rooms-tasks/workspace-artifacts.d.ts +6 -0
  182. package/dist/rooms-tasks/workspace-artifacts.js +93 -0
  183. package/dist/rooms-tasks/workspace.d.ts +35 -0
  184. package/dist/rooms-tasks/workspace.js +325 -0
  185. package/dist/runner.d.ts +33 -4
  186. package/dist/runner.js +389 -56
  187. package/dist/session/acp.d.ts +75 -2
  188. package/dist/session/acp.js +345 -82
  189. package/dist/session/arbiter.d.ts +98 -0
  190. package/dist/session/arbiter.js +272 -3
  191. package/dist/session/codex-app-server.d.ts +45 -1
  192. package/dist/session/codex-app-server.js +225 -32
  193. package/dist/session/control.d.ts +17 -3
  194. package/dist/session/control.js +213 -23
  195. package/dist/session/conversation-normalizer.d.ts +2 -1
  196. package/dist/session/conversation-normalizer.js +1 -1
  197. package/dist/session/conversation-observation.d.ts +25 -0
  198. package/dist/session/conversation-observation.js +100 -0
  199. package/dist/session/conversation-replay.d.ts +50 -0
  200. package/dist/session/conversation-replay.js +203 -0
  201. package/dist/session/conversation-store.d.ts +15 -1
  202. package/dist/session/conversation-store.js +206 -26
  203. package/dist/session/conversation-types.d.ts +57 -4
  204. package/dist/session/prompt-batch.d.ts +79 -0
  205. package/dist/session/prompt-batch.js +120 -0
  206. package/dist/session/task-notice.d.ts +14 -0
  207. package/dist/session/task-notice.js +13 -0
  208. package/dist/session/types.d.ts +42 -1
  209. package/dist/setup-tunnel-preflight.d.ts +34 -0
  210. package/dist/setup-tunnel-preflight.js +62 -0
  211. package/dist/socket-path.d.ts +2 -0
  212. package/dist/socket-path.js +22 -0
  213. package/dist/spawn.d.ts +5 -1
  214. package/dist/spawn.js +40 -4
  215. package/dist/startup-prompt.d.ts +15 -0
  216. package/dist/startup-prompt.js +71 -0
  217. package/dist/startup-readiness.d.ts +32 -0
  218. package/dist/startup-readiness.js +101 -0
  219. package/dist/startup-telemetry.d.ts +16 -0
  220. package/dist/startup-telemetry.js +46 -0
  221. package/dist/subscriptions/cli.d.ts +91 -0
  222. package/dist/subscriptions/cli.js +223 -0
  223. package/dist/subscriptions/launch.d.ts +37 -0
  224. package/dist/subscriptions/launch.js +93 -0
  225. package/dist/subscriptions/login.d.ts +76 -0
  226. package/dist/subscriptions/login.js +207 -0
  227. package/dist/subscriptions/observed.d.ts +7 -0
  228. package/dist/subscriptions/observed.js +44 -0
  229. package/dist/subscriptions/probe.d.ts +10 -0
  230. package/dist/subscriptions/probe.js +73 -0
  231. package/dist/subscriptions/service.d.ts +102 -0
  232. package/dist/subscriptions/service.js +364 -0
  233. package/dist/subscriptions/store.d.ts +71 -0
  234. package/dist/subscriptions/store.js +140 -0
  235. package/dist/supervisor/adoption.d.ts +8 -0
  236. package/dist/supervisor/adoption.js +78 -0
  237. package/dist/supervisor/catalog.d.ts +62 -0
  238. package/dist/supervisor/catalog.js +254 -0
  239. package/dist/supervisor/fleet.d.ts +8 -0
  240. package/dist/supervisor/fleet.js +89 -0
  241. package/dist/supervisor/index.js +3 -6
  242. package/dist/supervisor/launchd.d.ts +1 -1
  243. package/dist/supervisor/launchd.js +26 -13
  244. package/dist/supervisor/legacy.d.ts +35 -0
  245. package/dist/supervisor/legacy.js +524 -0
  246. package/dist/supervisor/manager.d.ts +15 -0
  247. package/dist/supervisor/manager.js +270 -0
  248. package/dist/supervisor/registration-refresh.d.ts +45 -0
  249. package/dist/supervisor/registration-refresh.js +266 -0
  250. package/dist/supervisor/scope.d.ts +4 -0
  251. package/dist/supervisor/scope.js +10 -0
  252. package/dist/supervisor/systemd.d.ts +2 -2
  253. package/dist/supervisor/systemd.js +19 -33
  254. package/dist/task-supervision.d.ts +9 -0
  255. package/dist/task-supervision.js +145 -0
  256. package/dist/temp-idle.d.ts +17 -0
  257. package/dist/temp-idle.js +42 -0
  258. package/dist/temp-lifecycle.d.ts +23 -8
  259. package/dist/temp-lifecycle.js +123 -66
  260. package/dist/temp-supervisor-recovery.d.ts +1 -1
  261. package/dist/temp-supervisor-recovery.js +2 -2
  262. package/dist/tunnel-setup-completion.d.ts +7 -0
  263. package/dist/tunnel-setup-completion.js +13 -0
  264. package/dist/tunnel-setup-input.d.ts +19 -0
  265. package/dist/tunnel-setup-input.js +124 -0
  266. package/dist/web/agent-attachments.d.ts +29 -0
  267. package/dist/web/agent-attachments.js +162 -0
  268. package/dist/web/auth.d.ts +65 -2
  269. package/dist/web/auth.js +201 -11
  270. package/dist/web/available-port.d.ts +2 -0
  271. package/dist/web/available-port.js +23 -0
  272. package/dist/web/control.d.ts +3 -3
  273. package/dist/web/control.js +10 -8
  274. package/dist/web/conversation-stream-codec.d.ts +23 -0
  275. package/dist/web/conversation-stream-codec.js +110 -0
  276. package/dist/web/conversation-stream.d.ts +25 -0
  277. package/dist/web/conversation-stream.js +231 -0
  278. package/dist/web/fleet-config-service.d.ts +4 -1
  279. package/dist/web/fleet-config-service.js +46 -15
  280. package/dist/web/prefix-gateway.d.ts +32 -0
  281. package/dist/web/prefix-gateway.js +238 -0
  282. package/dist/web/runtime.d.ts +3 -1
  283. package/dist/web/runtime.js +128 -33
  284. package/dist/web/server.d.ts +16 -0
  285. package/dist/web/server.js +639 -55
  286. package/dist/web/service.d.ts +11 -2
  287. package/dist/web/service.js +30 -4
  288. package/dist/web/workspace-devices.d.ts +107 -0
  289. package/dist/web/workspace-devices.js +277 -0
  290. package/dist/web/workspace-tunnel.d.ts +1 -0
  291. package/dist/web/workspace-tunnel.js +34 -0
  292. package/dist/workspace-enrollment.d.ts +83 -0
  293. package/dist/workspace-enrollment.js +580 -0
  294. package/dist/workspace-replacement.d.ts +66 -0
  295. package/dist/workspace-replacement.js +220 -0
  296. package/docs/acp-files.md +146 -0
  297. package/docs/conversation-stream.md +190 -0
  298. package/docs/fleet-migration.md +54 -0
  299. package/docs/live-voice.md +13 -0
  300. package/docs/room-layouts.md +227 -0
  301. package/docs/self-reminders.md +374 -0
  302. package/docs/task-workspaces.md +225 -0
  303. package/docs/validation/managed-cli-permissions.md +421 -0
  304. package/examples/room-layouts/fresh.yaml +27 -0
  305. package/examples/room-layouts/scoped.yaml +21 -0
  306. package/examples/room-layouts/shared.yaml +19 -0
  307. package/package.json +24 -20
  308. package/presets/README.md +78 -0
  309. package/presets/brain-catalog.json +8 -2
  310. package/presets/fleet/agent_templates/Critic.yaml +1 -1
  311. package/presets/fleet/agent_templates/Developer.yaml +1 -1
  312. package/presets/fleet/agent_templates/Engineer.yaml +5 -0
  313. package/presets/fleet/agent_templates/LocalCoordinator.yaml +4 -2
  314. package/presets/fleet/agents/FleetCoordinator.yaml +1 -1
  315. package/presets/fleet/brains/claude-fable-5-1-high.yaml +5 -0
  316. package/presets/fleet/brains/claude-fable-5-1-low.yaml +5 -0
  317. package/presets/fleet/brains/claude-fable-5-1-max.yaml +5 -0
  318. package/presets/fleet/brains/claude-fable-5-1-medium.yaml +5 -0
  319. package/presets/fleet/brains/claude-fable-5-1-xhigh.yaml +5 -0
  320. package/presets/fleet/brains/claude-fable-5-high.yaml +1 -1
  321. package/presets/fleet/brains/claude-fable-5-low.yaml +1 -1
  322. package/presets/fleet/brains/claude-fable-5-max.yaml +1 -1
  323. package/presets/fleet/brains/claude-fable-5-medium.yaml +1 -1
  324. package/presets/fleet/brains/claude-fable-5-xhigh.yaml +1 -1
  325. package/presets/fleet/brains/claude-haiku-4-5-20251001-default.yaml +4 -0
  326. package/presets/fleet/brains/claude-opus-5-5-high.yaml +5 -0
  327. package/presets/fleet/brains/claude-opus-5-5-low.yaml +5 -0
  328. package/presets/fleet/brains/claude-opus-5-5-max.yaml +5 -0
  329. package/presets/fleet/brains/claude-opus-5-5-medium.yaml +5 -0
  330. package/presets/fleet/brains/claude-opus-5-5-xhigh.yaml +5 -0
  331. package/presets/fleet/brains/claude-opus-5-high.yaml +1 -1
  332. package/presets/fleet/brains/claude-opus-5-low.yaml +1 -1
  333. package/presets/fleet/brains/claude-opus-5-max.yaml +1 -1
  334. package/presets/fleet/brains/claude-opus-5-medium.yaml +1 -1
  335. package/presets/fleet/brains/claude-opus-5-xhigh.yaml +1 -1
  336. package/presets/fleet/brains/claude-sonnet-5-high.yaml +1 -1
  337. package/presets/fleet/brains/claude-sonnet-5-low.yaml +1 -1
  338. package/presets/fleet/brains/claude-sonnet-5-max.yaml +1 -1
  339. package/presets/fleet/brains/claude-sonnet-5-medium.yaml +1 -1
  340. package/presets/fleet/brains/claude-sonnet-5-xhigh.yaml +1 -1
  341. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-high.yaml +1 -1
  342. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-low.yaml +1 -1
  343. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-medium.yaml +1 -1
  344. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-xhigh.yaml +1 -1
  345. package/presets/fleet/brains/codex-gpt-5-4-high.yaml +1 -1
  346. package/presets/fleet/brains/codex-gpt-5-4-low.yaml +1 -1
  347. package/presets/fleet/brains/codex-gpt-5-4-medium.yaml +1 -1
  348. package/presets/fleet/brains/codex-gpt-5-4-mini-high.yaml +1 -1
  349. package/presets/fleet/brains/codex-gpt-5-4-mini-low.yaml +1 -1
  350. package/presets/fleet/brains/codex-gpt-5-4-mini-medium.yaml +1 -1
  351. package/presets/fleet/brains/codex-gpt-5-4-mini-xhigh.yaml +1 -1
  352. package/presets/fleet/brains/codex-gpt-5-4-xhigh.yaml +1 -1
  353. package/presets/fleet/brains/codex-gpt-5-5-high.yaml +1 -1
  354. package/presets/fleet/brains/codex-gpt-5-5-low.yaml +1 -1
  355. package/presets/fleet/brains/codex-gpt-5-5-medium.yaml +1 -1
  356. package/presets/fleet/brains/codex-gpt-5-5-xhigh.yaml +1 -1
  357. package/presets/fleet/brains/codex-gpt-5-6-luna-high.yaml +1 -1
  358. package/presets/fleet/brains/codex-gpt-5-6-luna-low.yaml +1 -1
  359. package/presets/fleet/brains/codex-gpt-5-6-luna-max.yaml +1 -1
  360. package/presets/fleet/brains/codex-gpt-5-6-luna-medium.yaml +1 -1
  361. package/presets/fleet/brains/codex-gpt-5-6-luna-xhigh.yaml +1 -1
  362. package/presets/fleet/brains/codex-gpt-5-6-sol-high.yaml +1 -1
  363. package/presets/fleet/brains/codex-gpt-5-6-sol-low.yaml +1 -1
  364. package/presets/fleet/brains/codex-gpt-5-6-sol-max.yaml +1 -1
  365. package/presets/fleet/brains/codex-gpt-5-6-sol-medium.yaml +1 -1
  366. package/presets/fleet/brains/codex-gpt-5-6-sol-ultra.yaml +1 -1
  367. package/presets/fleet/brains/codex-gpt-5-6-sol-xhigh.yaml +1 -1
  368. package/presets/fleet/brains/codex-gpt-5-6-terra-high.yaml +1 -1
  369. package/presets/fleet/brains/codex-gpt-5-6-terra-low.yaml +1 -1
  370. package/presets/fleet/brains/codex-gpt-5-6-terra-max.yaml +1 -1
  371. package/presets/fleet/brains/codex-gpt-5-6-terra-medium.yaml +1 -1
  372. package/presets/fleet/brains/codex-gpt-5-6-terra-ultra.yaml +1 -1
  373. package/presets/fleet/brains/codex-gpt-5-6-terra-xhigh.yaml +1 -1
  374. package/presets/fleet/brains/codex-gpt-6-1-sol-high.yaml +5 -0
  375. package/presets/fleet/brains/codex-gpt-6-1-sol-low.yaml +5 -0
  376. package/presets/fleet/brains/codex-gpt-6-1-sol-max.yaml +5 -0
  377. package/presets/fleet/brains/codex-gpt-6-1-sol-medium.yaml +5 -0
  378. package/presets/fleet/brains/codex-gpt-6-1-sol-ultra.yaml +5 -0
  379. package/presets/fleet/brains/codex-gpt-6-1-sol-xhigh.yaml +5 -0
  380. package/presets/fleet/brains/codex-gpt-6-astra-high.yaml +1 -1
  381. package/presets/fleet/brains/codex-gpt-6-astra-low.yaml +1 -1
  382. package/presets/fleet/brains/codex-gpt-6-astra-max.yaml +1 -1
  383. package/presets/fleet/brains/codex-gpt-6-astra-medium.yaml +1 -1
  384. package/presets/fleet/brains/codex-gpt-6-astra-ultra.yaml +1 -1
  385. package/presets/fleet/brains/codex-gpt-6-astra-xhigh.yaml +1 -1
  386. package/presets/fleet/brains/codex-gpt-6-luna-high.yaml +5 -0
  387. package/presets/fleet/brains/codex-gpt-6-luna-low.yaml +5 -0
  388. package/presets/fleet/brains/codex-gpt-6-luna-max.yaml +5 -0
  389. package/presets/fleet/brains/codex-gpt-6-luna-medium.yaml +5 -0
  390. package/presets/fleet/brains/codex-gpt-6-luna-xhigh.yaml +5 -0
  391. package/presets/fleet/brains/codex-gpt-6-sol-high.yaml +5 -0
  392. package/presets/fleet/brains/codex-gpt-6-sol-low.yaml +5 -0
  393. package/presets/fleet/brains/codex-gpt-6-sol-max.yaml +5 -0
  394. package/presets/fleet/brains/codex-gpt-6-sol-medium.yaml +5 -0
  395. package/presets/fleet/brains/codex-gpt-6-sol-ultra.yaml +5 -0
  396. package/presets/fleet/brains/codex-gpt-6-sol-xhigh.yaml +5 -0
  397. package/presets/fleet/roles/Coordinator.yaml +12 -11
  398. package/presets/fleet/roles/Critic.yaml +13 -0
  399. package/presets/fleet/roles/Developer.yaml +13 -0
  400. package/presets/fleet/roles/Engineer.yaml +53 -0
  401. package/presets/fleet/room_layouts/engineering.yaml +25 -0
  402. package/presets/fleet/room_layouts/pair.yaml +24 -0
  403. package/presets/fleet/room_layouts/single.yaml +17 -0
  404. package/presets/fleet/room_layouts/team.yaml +30 -0
  405. package/presets/fleet/room_templates/engineering.yaml +19 -0
  406. package/presets/manifest.json +2 -2
  407. package/dist/web-app/assets/index-59GF-gsZ.css +0 -1
  408. package/dist/web-app/assets/index-C0h3ALvs.js +0 -10
  409. package/dist/web-app/icons/ours-fleet-maskable.svg +0 -4
  410. package/dist/web-app/icons/ours-fleet.svg +0 -4
  411. package/dist/web-app/index.html +0 -17
  412. package/dist/web-app/manifest.webmanifest +0 -15
  413. package/dist/web-app/offline.html +0 -18
  414. package/dist/web-app/sw.js +0 -51
@@ -0,0 +1,56 @@
1
+ import { statSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { resolveBundledAcpAgent } from '../harness/acp-agent.js';
4
+ import { probeCodexRuntime } from '../harness/codex-runtime.js';
5
+ import { codexOfferedModels, profileEnv } from '../subscriptions/cli.js';
6
+ import { profileHome, readSubscriptionState } from '../subscriptions/store.js';
7
+ const KNOWN_FOR_MS = 5 * 60_000;
8
+ const UNKNOWN_FOR_MS = 10_000;
9
+ /** When the profile's sign-in last changed; a new sign-in must not reuse another account's answer. */
10
+ function signInStamp(home) {
11
+ try {
12
+ return statSync(join(home, 'auth.json')).mtimeMs;
13
+ }
14
+ catch {
15
+ return 0;
16
+ }
17
+ }
18
+ /**
19
+ * The models offered to the active Codex account by the runtime that sessions will actually use.
20
+ * An answer is reused only for the same executable, version, profile and sign-in.
21
+ */
22
+ export function createCodexModelDiscovery(overrides = {}) {
23
+ const deps = {
24
+ runtime: () => probeCodexRuntime(resolveBundledAcpAgent('@agentclientprotocol/codex-acp', 'codex-acp', 'codex-acp'), process.env),
25
+ ask: codexOfferedModels,
26
+ now: Date.now,
27
+ ...overrides,
28
+ };
29
+ let cached;
30
+ let pending;
31
+ return async () => {
32
+ let key, executable, env;
33
+ try {
34
+ const profileId = readSubscriptionState().providers.codex.activeProfileId;
35
+ const profile = profileHome('codex', profileId);
36
+ const runtime = await deps.runtime();
37
+ executable = runtime.executable;
38
+ env = profileEnv('CODEX_HOME', profileId, profile);
39
+ key = [runtime.executable, runtime.version, profileId, signInStamp(profile)].join('\n');
40
+ }
41
+ catch (error) {
42
+ return { state: 'unknown', reason: error instanceof Error ? error.message : String(error) };
43
+ }
44
+ if (cached && cached.key === key && cached.until > deps.now())
45
+ return cached.value;
46
+ if (pending?.key === key)
47
+ return pending.answer;
48
+ const answer = deps.ask(executable, env).then(value => {
49
+ cached = { key, until: deps.now() + (value.state === 'known' ? KNOWN_FOR_MS : UNKNOWN_FOR_MS), value };
50
+ return value;
51
+ }).finally(() => { if (pending?.key === key)
52
+ pending = undefined; });
53
+ pending = { key, answer };
54
+ return answer;
55
+ };
56
+ }
@@ -0,0 +1,27 @@
1
+ import type { ConversationEventV1 } from '../session/conversation-types.js';
2
+ import type { ConversationPageView } from './session-control.js';
3
+ /** Whether a ledger event belongs in the conversation: the live generation, or history of the resumed ACP session. */
4
+ export declare function conversationEventVisible(event: ConversationEventV1, sessionGeneration: string, resumedSessionId?: string): boolean;
5
+ export interface ConversationTailPage extends ConversationPageView {
6
+ /** Pass as `before` to read the next older page. */
7
+ olderCursor?: string;
8
+ hasOlder: boolean;
9
+ /** Latest page only: older events the view still needs, the current session's latest capabilities and still-pending permission requests. */
10
+ context: ConversationEventV1[];
11
+ }
12
+ /**
13
+ * The newest `limit` visible events before `before` (or the newest overall),
14
+ * read backwards from the ledger so opening a long session costs one page.
15
+ * `nextCursor` is the newest ledger position seen, for forward `after` paging.
16
+ */
17
+ export declare function conversationTailPage(stateDir: string, request: {
18
+ before?: string;
19
+ limit?: number;
20
+ }, snapshot: ConversationPageView['snapshot'], resumedSessionId?: string): Promise<ConversationTailPage>;
21
+ /** Read the existing ACP session ledger without opening its writer/recovery store. */
22
+ export declare function resumedConversationPage(stateDir: string, request: {
23
+ after?: string;
24
+ limit?: number;
25
+ }, live: ConversationPageView, expectedSessionId: string): Promise<ConversationPageView>;
26
+ /** Download authorization requires an actual published attachment, never an orphan copy. */
27
+ export declare function conversationHasAttachment(stateDir: string, attachment: import('../file-delivery/types.js').DeliveredFile): Promise<boolean>;
@@ -0,0 +1,215 @@
1
+ import { createReadStream } from 'node:fs';
2
+ import { open, readFile, readdir } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { createInterface } from 'node:readline';
5
+ const HISTORICAL_KINDS = ['file.attached', 'fleet.task_created', 'prompt.admitted', 'message.chunk', 'message.replace', 'tool.upsert', 'tool.content_chunk', 'turn.completed'];
6
+ /** Whether a ledger event belongs in the conversation: the live generation, or history of the resumed ACP session. */
7
+ export function conversationEventVisible(event, sessionGeneration, resumedSessionId) {
8
+ return event.source !== 'agent_replay' && (event.sessionGeneration === sessionGeneration || (!!resumedSessionId && HISTORICAL_KINDS.includes(event.kind) && event.acpSessionId === resumedSessionId));
9
+ }
10
+ /** Newest-first lines of a file, read in chunks from its end; `visit` returns false to stop. */
11
+ async function readLinesBackward(path, visit) {
12
+ const file = await open(path, 'r');
13
+ try {
14
+ let position = (await file.stat()).size;
15
+ let carry = Buffer.alloc(0);
16
+ while (position > 0) {
17
+ const size = Math.min(256 * 1024, position);
18
+ position -= size;
19
+ const chunk = Buffer.alloc(size);
20
+ await file.read(chunk, 0, size, position);
21
+ let buffer = Buffer.concat([chunk, carry]);
22
+ let end = buffer.length;
23
+ for (let i = buffer.length - 1; i >= 0; i--) {
24
+ if (buffer[i] !== 10)
25
+ continue;
26
+ if (end > i + 1 && !visit(buffer.toString('utf8', i + 1, end)))
27
+ return false;
28
+ end = i;
29
+ }
30
+ carry = buffer.subarray(0, end);
31
+ }
32
+ if (carry.length && !visit(carry.toString('utf8')))
33
+ return false;
34
+ return true;
35
+ }
36
+ finally {
37
+ await file.close();
38
+ }
39
+ }
40
+ /** The last event cursor in a segment, read from its tail; undefined when none is readable. */
41
+ async function lastSeq(path) {
42
+ let seq;
43
+ await readLinesBackward(path, line => { try {
44
+ const value = Number(JSON.parse(line).seq);
45
+ if (Number.isSafeInteger(value)) {
46
+ seq = value;
47
+ return false;
48
+ }
49
+ }
50
+ catch { } return true; });
51
+ return seq;
52
+ }
53
+ /**
54
+ * The newest `limit` visible events before `before` (or the newest overall),
55
+ * read backwards from the ledger so opening a long session costs one page.
56
+ * `nextCursor` is the newest ledger position seen, for forward `after` paging.
57
+ */
58
+ export async function conversationTailPage(stateDir, request, snapshot, resumedSessionId) {
59
+ const before = request.before === undefined ? Infinity : Number(request.before);
60
+ if (before !== Infinity && (!Number.isSafeInteger(before) || before < 0))
61
+ throw new Error('before must be a ledger cursor');
62
+ const limit = Math.min(1000, Math.max(1, Number.isFinite(request.limit) ? Math.floor(request.limit) : 200));
63
+ let files = [];
64
+ try {
65
+ files = (await readdir(join(stateDir, '.conversation'))).filter(n => /^events-\d{6}\.jsonl$/.test(n)).sort().reverse();
66
+ }
67
+ catch { }
68
+ const events = [];
69
+ let newest;
70
+ let hasOlder = false;
71
+ const barrier = snapshot.ledgerBarrier;
72
+ const pending = new Set(snapshot.pendingPermissionIds);
73
+ let capabilities;
74
+ const context = [];
75
+ // Context only accompanies the newest page; older pages stop as soon as they are full.
76
+ const wantsContext = () => before === Infinity && (!capabilities || pending.size > 0);
77
+ const generation = `"sessionGeneration":${JSON.stringify(snapshot.sessionGeneration)}`;
78
+ for (const file of files) {
79
+ const more = await readLinesBackward(join(stateDir, '.conversation', file), line => {
80
+ if (hasOlder) {
81
+ // The page is full; only the current generation's context kinds matter. Generations are
82
+ // appended in order, so the first line of an older one ends the search.
83
+ if (!line.includes(generation))
84
+ return !line.includes('"sessionGeneration":') && wantsContext();
85
+ if (!line.includes('"capabilities.updated"') && !line.includes('"permission.requested"'))
86
+ return wantsContext();
87
+ }
88
+ let event;
89
+ try {
90
+ event = JSON.parse(line);
91
+ }
92
+ catch {
93
+ return true;
94
+ }
95
+ const seq = Number(event.seq);
96
+ if (!Number.isSafeInteger(seq))
97
+ return true;
98
+ if (barrier !== undefined && seq > barrier)
99
+ return true;
100
+ newest ??= seq;
101
+ if (seq < before && conversationEventVisible(event, snapshot.sessionGeneration, resumedSessionId)) {
102
+ const inPage = !hasOlder && events.length < limit;
103
+ if (event.sessionGeneration === snapshot.sessionGeneration) {
104
+ if (event.kind === 'capabilities.updated' && !capabilities) {
105
+ capabilities = event;
106
+ if (!inPage)
107
+ context.push(event);
108
+ }
109
+ if (event.kind === 'permission.requested' && event.permissionId && pending.delete(event.permissionId) && !inPage)
110
+ context.push(event);
111
+ }
112
+ if (inPage)
113
+ events.push(event);
114
+ else
115
+ hasOlder = true;
116
+ }
117
+ return !hasOlder || wantsContext();
118
+ });
119
+ if (!more)
120
+ break;
121
+ }
122
+ events.reverse();
123
+ context.reverse();
124
+ return { events, snapshot, hasOlder, context, hasMore: false,
125
+ ...(events.length ? { olderCursor: String(events[0].seq) } : {}),
126
+ ...(before === Infinity && (barrier !== undefined || newest !== undefined) ? { nextCursor: String(barrier ?? newest) } : {}) };
127
+ }
128
+ /** Read the existing ACP session ledger without opening its writer/recovery store. */
129
+ export async function resumedConversationPage(stateDir, request, live, expectedSessionId) {
130
+ let sessionId;
131
+ let files;
132
+ try {
133
+ sessionId = (await readFile(join(stateDir, '.acp-session-id'), 'utf8')).trim();
134
+ files = (await readdir(join(stateDir, '.conversation'))).filter(n => /^events-\d{6}\.jsonl$/.test(n)).sort();
135
+ }
136
+ catch {
137
+ return live;
138
+ }
139
+ if (!sessionId || sessionId !== expectedSessionId || !files.length)
140
+ return live;
141
+ const after = Number(request.after ?? 0);
142
+ if (!Number.isSafeInteger(after) || after < 0)
143
+ return live;
144
+ const limit = Math.min(1000, Math.max(1, Number.isFinite(request.limit) ? Math.floor(request.limit) : 200));
145
+ const events = [];
146
+ let next = String(after);
147
+ let first;
148
+ let hasMore = false;
149
+ scan: for (const file of files) {
150
+ // Forward polling asks for the newest few events: skip whole segments that end at or before the cursor.
151
+ const end = await lastSeq(join(stateDir, '.conversation', file));
152
+ if (end !== undefined && end <= after)
153
+ continue;
154
+ const input = createReadStream(join(stateDir, '.conversation', file), { encoding: 'utf8' });
155
+ const lines = createInterface({ input, crlfDelay: Infinity });
156
+ try {
157
+ for await (const line of lines) {
158
+ let event;
159
+ try {
160
+ event = JSON.parse(line);
161
+ }
162
+ catch {
163
+ continue;
164
+ }
165
+ const cursor = Number(event.seq);
166
+ if (!Number.isSafeInteger(cursor) || cursor <= after)
167
+ continue;
168
+ const historical = ['file.attached', 'fleet.task_created', 'prompt.admitted', 'message.chunk', 'message.replace', 'tool.upsert', 'tool.content_chunk', 'turn.completed'].includes(event.kind);
169
+ const visible = event.source !== 'agent_replay' && (event.sessionGeneration === live.snapshot.sessionGeneration || (historical && event.acpSessionId === sessionId));
170
+ if (!visible) {
171
+ next = String(cursor);
172
+ continue;
173
+ }
174
+ if (events.length === limit) {
175
+ hasMore = true;
176
+ break scan;
177
+ }
178
+ first ??= String(cursor);
179
+ events.push(event);
180
+ next = String(cursor);
181
+ }
182
+ }
183
+ finally {
184
+ lines.close();
185
+ input.destroy();
186
+ }
187
+ }
188
+ // If a fresh/resumed session changed during the read, use the live page only.
189
+ if ((await readFile(join(stateDir, '.acp-session-id'), 'utf8')).trim() !== sessionId)
190
+ return live;
191
+ return { ...live, events, firstAvailableCursor: first, nextCursor: next, hasMore };
192
+ }
193
+ /** Download authorization requires an actual published attachment, never an orphan copy. */
194
+ export async function conversationHasAttachment(stateDir, attachment) {
195
+ const dir = join(stateDir, '.conversation');
196
+ const names = (await readdir(dir)).filter(n => /^events-\d+\.jsonl$/.test(n)).sort().reverse();
197
+ let found = false;
198
+ for (const name of names) {
199
+ await readLinesBackward(join(dir, name), line => {
200
+ try {
201
+ const e = JSON.parse(line);
202
+ const a = e.payload.attachment;
203
+ if (e.kind === 'file.attached' && e.source === 'agent' && a?.id === attachment.id
204
+ && e.sessionGeneration === attachment.sessionGeneration && e.acpSessionId === attachment.acpSessionId
205
+ && e.turnId === attachment.turnId && JSON.stringify(a) === JSON.stringify(attachment))
206
+ found = true;
207
+ }
208
+ catch { /* unreadable lines cannot authorize a download */ }
209
+ return !found;
210
+ });
211
+ if (found)
212
+ break;
213
+ }
214
+ return found;
215
+ }
@@ -0,0 +1,62 @@
1
+ import { type FSWatcher } from 'node:fs';
2
+ import { type SessionBackendId } from '../config.js';
3
+ export interface ConversationRoleState {
4
+ roleId: string;
5
+ /** Connection-owned ordering; never a session stateRevision. */
6
+ roleRevision: number;
7
+ roleLifetime: string;
8
+ availability: 'available' | 'unavailable' | 'missing';
9
+ fallbackHarness?: string;
10
+ backend?: SessionBackendId;
11
+ stateDir?: string;
12
+ health: 'healthy' | 'unsupported' | 'failed';
13
+ failure?: 'watch-unsupported' | 'watch-error' | 'watch-closed' | 'role-read-failed' | 'observer-disposed';
14
+ }
15
+ export interface ConversationRoleObservation {
16
+ snapshot(): ConversationRoleState;
17
+ subscribe(listener: (state: ConversationRoleState) => void): {
18
+ snapshot: ConversationRoleState;
19
+ unsubscribe(): void;
20
+ };
21
+ dispose(): void;
22
+ }
23
+ export type ObserveConversationRole = (listener: (state: ConversationRoleState) => void) => ConversationRoleObservation;
24
+ export interface ConversationRoleObserverOptions {
25
+ roleId: string;
26
+ configPath?: string;
27
+ permanentRoot?: string;
28
+ temporaryRoot?: string;
29
+ watch?: (path: string, listener: (event: string, filename: string | null) => void) => Pick<FSWatcher, 'on' | 'close'>;
30
+ subscribeMutations?: (listener: () => void) => () => void;
31
+ }
32
+ /** Native directory notifications are assumed reliable on qualified host/mount setups.
33
+ * No periodic reads or claim of detecting every silently dropped filesystem event.
34
+ */
35
+ export declare class ConversationRoleObserver implements ConversationRoleObservation {
36
+ private readonly options;
37
+ private readonly listener;
38
+ private state;
39
+ private watchers;
40
+ private detach?;
41
+ private disposed;
42
+ private readonly listeners;
43
+ private queued;
44
+ private fingerprint?;
45
+ private readonly configPath;
46
+ private readonly permanent;
47
+ private readonly temporary;
48
+ constructor(options: ConversationRoleObserverOptions, listener: (state: ConversationRoleState) => void);
49
+ snapshot(): ConversationRoleState;
50
+ subscribe(listener: (state: ConversationRoleState) => void): {
51
+ snapshot: ConversationRoleState;
52
+ unsubscribe: () => void;
53
+ };
54
+ private publish;
55
+ dispose(): void;
56
+ private release;
57
+ private fail;
58
+ private schedule;
59
+ private refresh;
60
+ private install;
61
+ private watchFailure;
62
+ }
@@ -0,0 +1,206 @@
1
+ import { createHash, randomUUID } from 'node:crypto';
2
+ import { lstatSync, readFileSync, realpathSync, watch } from 'node:fs';
3
+ import { basename, dirname, join, resolve } from 'node:path';
4
+ import { parse } from 'yaml';
5
+ import { loadConfig, ROLE_NAME_RE, splitRootFor } from '../config.js';
6
+ import { agentsRoot, defaultConfigPath, tmpRoot } from '../paths.js';
7
+ import { controlSocketPath } from '../session/control.js';
8
+ function identity(path) {
9
+ try {
10
+ const s = lstatSync(path);
11
+ return `${s.dev}:${s.ino}:${s.birthtimeMs}`;
12
+ }
13
+ catch (error) {
14
+ if (error.code === 'ENOENT')
15
+ return;
16
+ throw error;
17
+ }
18
+ }
19
+ /** Native directory notifications are assumed reliable on qualified host/mount setups.
20
+ * No periodic reads or claim of detecting every silently dropped filesystem event.
21
+ */
22
+ export class ConversationRoleObserver {
23
+ options;
24
+ listener;
25
+ state;
26
+ watchers = new Map();
27
+ detach;
28
+ disposed = false;
29
+ listeners = new Set();
30
+ queued = false;
31
+ fingerprint;
32
+ configPath;
33
+ permanent;
34
+ temporary;
35
+ constructor(options, listener) {
36
+ this.options = options;
37
+ this.listener = listener;
38
+ if (!ROLE_NAME_RE.test(options.roleId))
39
+ throw new Error('invalid role id');
40
+ this.configPath = resolve(options.configPath ?? defaultConfigPath());
41
+ this.permanent = resolve(options.permanentRoot ?? agentsRoot(), options.roleId);
42
+ this.temporary = resolve(options.temporaryRoot ?? tmpRoot(), options.roleId);
43
+ this.state = { roleId: options.roleId, roleRevision: 0, roleLifetime: randomUUID(), availability: 'missing', health: 'healthy' };
44
+ this.refresh();
45
+ if (this.state.health === 'healthy')
46
+ this.detach = options.subscribeMutations?.(() => this.schedule());
47
+ }
48
+ snapshot() {
49
+ return this.disposed ? { ...this.state, health: 'failed', failure: 'observer-disposed' } : { ...this.state };
50
+ }
51
+ subscribe(listener) {
52
+ if (!this.disposed)
53
+ this.listeners.add(listener);
54
+ return { snapshot: this.snapshot(), unsubscribe: () => { this.listeners.delete(listener); } };
55
+ }
56
+ publish() {
57
+ this.listener(this.snapshot());
58
+ for (const listener of this.listeners)
59
+ listener(this.snapshot());
60
+ }
61
+ dispose() {
62
+ if (this.disposed)
63
+ return;
64
+ this.disposed = true;
65
+ this.release();
66
+ this.listeners.clear();
67
+ }
68
+ release() {
69
+ const retired = [...this.watchers.values()];
70
+ // Retire before close: native close events may arrive synchronously or later.
71
+ this.watchers.clear();
72
+ for (const watcher of retired)
73
+ watcher.handle.close();
74
+ this.detach?.();
75
+ this.detach = undefined;
76
+ }
77
+ fail(failure) {
78
+ if (this.disposed || this.state.health !== 'healthy')
79
+ return;
80
+ this.state = { ...this.state, roleRevision: this.state.roleRevision + 1, health: failure === 'watch-unsupported' ? 'unsupported' : 'failed', failure };
81
+ this.release();
82
+ this.publish();
83
+ }
84
+ schedule() {
85
+ if (this.queued || this.disposed || this.state.health !== 'healthy')
86
+ return;
87
+ this.queued = true;
88
+ queueMicrotask(() => { this.queued = false; if (!this.disposed && this.state.health === 'healthy')
89
+ this.refresh(); });
90
+ }
91
+ refresh() {
92
+ try {
93
+ // Install parents before reading, including absent children, so atomic rename
94
+ // and recreation cannot strand us watching an unlinked inode.
95
+ this.install();
96
+ if (this.state.health !== 'healthy')
97
+ return;
98
+ let configured;
99
+ const split = splitRootFor(this.configPath);
100
+ if (identity(this.configPath) && identity(split) && identity(join(split, 'agents')))
101
+ configured = loadConfig(this.configPath).roles.find(role => role.name === this.options.roleId);
102
+ const permanentId = identity(this.permanent), temporaryId = identity(this.temporary);
103
+ const stateDir = temporaryId ? realpathSync(this.temporary) : permanentId ? realpathSync(this.permanent) : undefined;
104
+ let temporary;
105
+ if (!configured && temporaryId && identity(join(this.temporary, 'role.yaml'))) {
106
+ const raw = parse(readFileSync(join(this.temporary, 'role.yaml'), 'utf8'));
107
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)
108
+ || (raw.session !== undefined && raw.session !== 'acp' && raw.session !== 'codex-app-server'))
109
+ throw new Error('invalid temporary role snapshot');
110
+ temporary = { session: raw.session ?? 'acp', harness: typeof raw.harness === 'string' ? raw.harness : 'claude-code' };
111
+ }
112
+ const backend = configured?.session ?? temporary?.session;
113
+ const fallbackHarness = configured?.harness ?? temporary?.harness;
114
+ const socket = stateDir ? identity(controlSocketPath(stateDir)) : undefined;
115
+ const tokenPath = stateDir && join(stateDir, '.control-token');
116
+ const token = tokenPath && identity(tokenPath) ? createHash('sha256').update(readFileSync(tokenPath)).digest('hex') : undefined;
117
+ const exists = Boolean(configured || permanentId || temporaryId);
118
+ const availability = !exists ? 'missing' : stateDir && socket && token && backend ? 'available' : 'unavailable';
119
+ const fingerprint = JSON.stringify([Boolean(configured), permanentId, temporaryId, backend, socket, token]);
120
+ const lifetime = this.fingerprint === fingerprint ? this.state.roleLifetime : randomUUID();
121
+ this.fingerprint = fingerprint;
122
+ const next = { roleId: this.options.roleId, roleRevision: this.state.roleRevision, roleLifetime: lifetime,
123
+ availability, fallbackHarness, backend, stateDir, health: 'healthy' };
124
+ if (JSON.stringify(next) !== JSON.stringify(this.state)) {
125
+ this.state = { ...next, roleRevision: this.state.roleRevision + 1 };
126
+ this.publish();
127
+ }
128
+ }
129
+ catch {
130
+ this.fail('role-read-failed');
131
+ }
132
+ }
133
+ install() {
134
+ const wanted = new Map();
135
+ const add = (dir, child) => {
136
+ if (child === undefined)
137
+ wanted.set(dir, null);
138
+ else if (wanted.get(dir) !== null) {
139
+ const names = wanted.get(dir) ?? new Set();
140
+ names.add(child);
141
+ wanted.set(dir, names);
142
+ }
143
+ };
144
+ const parents = (path, boundary) => {
145
+ while (path !== boundary && dirname(path) !== path) {
146
+ add(dirname(path), basename(path));
147
+ path = dirname(path);
148
+ }
149
+ };
150
+ const configRoot = splitRootFor(this.configPath);
151
+ const configBoundary = dirname(dirname(this.configPath));
152
+ parents(this.configPath, configBoundary);
153
+ for (const dir of [configRoot, ...['agents', 'brains', 'roles', 'agent_templates'].map(kind => join(configRoot, kind))]) {
154
+ parents(dir, configBoundary);
155
+ add(dir);
156
+ }
157
+ for (const dir of [this.permanent, this.temporary]) {
158
+ parents(dir, dirname(dirname(dirname(dir))));
159
+ for (const name of ['role.yaml', '.control-token', '.control.sock'])
160
+ add(dir, name);
161
+ const socket = controlSocketPath(dir);
162
+ parents(socket, dirname(dirname(socket)));
163
+ }
164
+ for (const [dir, current] of this.watchers) {
165
+ if (!wanted.has(dir) || identity(dir) !== current.identity) {
166
+ this.watchers.delete(dir);
167
+ current.handle.close();
168
+ }
169
+ }
170
+ for (const [dir, names] of wanted) {
171
+ const id = identity(dir);
172
+ if (!id)
173
+ continue;
174
+ const existing = this.watchers.get(dir);
175
+ if (existing) {
176
+ existing.names = names;
177
+ continue;
178
+ }
179
+ try {
180
+ const handle = (this.options.watch ?? ((path, listener) => watch(path, { persistent: false }, listener)))(dir, (_event, filename) => {
181
+ const entry = this.watchers.get(dir);
182
+ if (filename === null || !entry?.names || entry.names.has(String(filename)) || String(filename) === basename(dir))
183
+ this.schedule();
184
+ });
185
+ this.watchers.set(dir, { identity: id, names, handle });
186
+ handle.on('error', (error) => {
187
+ if (this.watchers.get(dir)?.handle === handle)
188
+ this.watchFailure(error);
189
+ });
190
+ handle.on('close', () => {
191
+ if (this.watchers.get(dir)?.handle !== handle)
192
+ return;
193
+ this.watchers.delete(dir);
194
+ this.fail('watch-closed');
195
+ });
196
+ }
197
+ catch (error) {
198
+ this.watchFailure(error);
199
+ return;
200
+ }
201
+ }
202
+ }
203
+ watchFailure(error) {
204
+ this.fail(['ENOSYS', 'ENOTSUP', 'ERR_FEATURE_UNAVAILABLE_ON_PLATFORM'].includes(error.code ?? '') ? 'watch-unsupported' : 'watch-error');
205
+ }
206
+ }
@@ -24,7 +24,7 @@ export declare class FleetQueryService {
24
24
  private readonly options;
25
25
  private readonly control;
26
26
  constructor(options: FleetQueryOptions);
27
- list(): Promise<Array<{
27
+ list(includeTemporary?: boolean): Promise<Array<{
28
28
  role: RoleRecord;
29
29
  status: RoleStatus;
30
30
  capabilities: RoleCapabilities;
@@ -75,9 +75,9 @@ export class FleetQueryService {
75
75
  this.options = options;
76
76
  this.control = options.control ?? controlRequest;
77
77
  }
78
- async list() {
78
+ async list(includeTemporary = false) {
79
79
  const roles = (await this.options.repository.list())
80
- .filter(role => role.configured && role.lifetime === 'permanent');
80
+ .filter(role => (role.configured && role.lifetime === 'permanent') || (includeTemporary && role.lifetime === 'temporary'));
81
81
  return Promise.all(roles.map(async (role) => {
82
82
  const status = await this.status(role);
83
83
  return { role, status, capabilities: roleCapabilities(role, status, this.options.capabilityContext) };
@@ -3,7 +3,6 @@ import { createHmac, randomBytes } from 'node:crypto';
3
3
  import { join } from 'node:path';
4
4
  import { realExec } from '../exec.js';
5
5
  import { logsRoot } from '../paths.js';
6
- import { unitFor } from '../supervisor/systemd.js';
7
6
  import { ROLE_NAME_RE } from '../config.js';
8
7
  import { FleetError } from './errors.js';
9
8
  const STANDARD_REDACTIONS = [
@@ -78,12 +77,13 @@ export class StructuredLogService {
78
77
  }
79
78
  async tail(roleId, requested, cursor) {
80
79
  const limit = Math.min(Math.max(requested, 1), 1_000);
81
- const args = this.backend.id === 'systemd'
82
- ? {
83
- cmd: 'journalctl',
84
- args: ['--user', '-u', unitFor(roleId), '-o', 'json', '--no-pager', '-n', String(limit)],
85
- }
86
- : this.backend.logsArgs(roleId, false);
80
+ const source = this.backend.logsArgs(roleId, false);
81
+ const args = { cmd: source.cmd, args: [...source.args] };
82
+ const count = args.args.indexOf('-n');
83
+ if (count >= 0)
84
+ args.args[count + 1] = String(limit);
85
+ if (args.cmd === 'journalctl')
86
+ args.args.push('-o', 'json', '--no-pager', '-n', String(limit));
87
87
  if (!['journalctl', 'tail', 'tmux'].includes(args.cmd))
88
88
  throw new FleetError('capability_unavailable', 'log backend is unsupported');
89
89
  const result = await this.exec(args.cmd, args.args);
@@ -93,7 +93,7 @@ export class StructuredLogService {
93
93
  const parsed = lines.map((line, index) => {
94
94
  let text = line;
95
95
  let at;
96
- if (this.backend.id === 'systemd') {
96
+ if (args.cmd === 'journalctl') {
97
97
  try {
98
98
  const json = JSON.parse(line);
99
99
  text = typeof json.MESSAGE === 'string' ? json.MESSAGE : line;
@@ -14,7 +14,7 @@ export interface HarnessModelCatalog {
14
14
  export declare function codexModelCatalog(path?: string): HarnessModelCatalog;
15
15
  /**
16
16
  * Claude Code 2.1 has no typed model-list endpoint. These exact IDs are the
17
- * versioned adapter contract shipped by the installed 2.1 CLI, not aliases and
17
+ * versioned adapter contract verified with CLI 2.1.281, not aliases and
18
18
  * not a claim about account entitlement (which Claude validates at launch).
19
19
  */
20
20
  export declare function claudeModelCatalog(): HarnessModelCatalog;
@@ -41,17 +41,20 @@ export function codexModelCatalog(path = join(homedir(), '.codex', 'models_cache
41
41
  }
42
42
  /**
43
43
  * Claude Code 2.1 has no typed model-list endpoint. These exact IDs are the
44
- * versioned adapter contract shipped by the installed 2.1 CLI, not aliases and
44
+ * versioned adapter contract verified with CLI 2.1.281, not aliases and
45
45
  * not a claim about account entitlement (which Claude validates at launch).
46
46
  */
47
47
  export function claudeModelCatalog() {
48
48
  const reasoningEfforts = ['low', 'medium', 'high', 'xhigh', 'max'];
49
49
  return {
50
50
  models: [
51
+ { id: 'claude-fable-5-1', label: 'Claude Fable 5.1', reasoningEfforts, source: 'claude-adapter-2.1' },
52
+ { id: 'claude-opus-5-5', label: 'Claude Opus 5.5', reasoningEfforts, source: 'claude-adapter-2.1' },
53
+ { id: 'claude-haiku-4-5-20251001', label: 'Claude Haiku 4.5', reasoningEfforts: [], source: 'claude-adapter-2.1' },
51
54
  { id: 'claude-fable-5', label: 'Claude Fable 5', reasoningEfforts, source: 'claude-adapter-2.1' },
52
55
  { id: 'claude-opus-5', label: 'Claude Opus 5', reasoningEfforts, source: 'claude-adapter-2.1' },
53
56
  { id: 'claude-sonnet-5', label: 'Claude Sonnet 5', reasoningEfforts, source: 'claude-adapter-2.1' },
54
57
  ],
55
- warnings: ['Claude Code exposes no typed model-list endpoint; choices are exact 2.1 adapter IDs and entitlement is validated at launch.'],
58
+ warnings: ['Claude Code exposes no typed model-list endpoint; choices require a current Claude runtime (verified with 2.1.281); older bundled SDKs need CLAUDE_CODE_EXECUTABLE. Entitlement is validated at launch.'],
56
59
  };
57
60
  }