@ours.network/fleet 1.2.0-nightly.4 → 1.2.0-nightly.40

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 (310) hide show
  1. package/README.md +165 -53
  2. package/dist/account-origin.d.ts +2 -0
  3. package/dist/account-origin.js +6 -0
  4. package/dist/agent-ours/bridge.js +9 -0
  5. package/dist/agent-ours/correspondence.d.ts +10 -0
  6. package/dist/agent-ours/correspondence.js +1 -0
  7. package/dist/agent-ours/harness.js +8 -0
  8. package/dist/agent-ours/runtime.d.ts +6 -0
  9. package/dist/agent-ours/runtime.js +36 -0
  10. package/dist/agent-ours/service.js +33 -13
  11. package/dist/application/codex-models.d.ts +15 -0
  12. package/dist/application/codex-models.js +56 -0
  13. package/dist/application/conversation-history.d.ts +25 -0
  14. package/dist/application/conversation-history.js +189 -0
  15. package/dist/application/fleet-query-service.d.ts +1 -1
  16. package/dist/application/fleet-query-service.js +2 -2
  17. package/dist/application/legacy-supervisor-identity.d.ts +7 -0
  18. package/dist/application/legacy-supervisor-identity.js +43 -0
  19. package/dist/application/model-catalog.d.ts +1 -1
  20. package/dist/application/model-catalog.js +5 -2
  21. package/dist/application/preset-provenance.d.ts +19 -0
  22. package/dist/application/preset-provenance.js +59 -0
  23. package/dist/application/role-creation-service.js +1 -1
  24. package/dist/application/room-layout-definitions.d.ts +45 -0
  25. package/dist/application/room-layout-definitions.js +130 -0
  26. package/dist/application/session-control.d.ts +18 -0
  27. package/dist/application/session-control.js +54 -3
  28. package/dist/application/supervisor-ours-tools.d.ts +159 -0
  29. package/dist/application/supervisor-ours-tools.js +113 -0
  30. package/dist/application/task-layouts.d.ts +91 -0
  31. package/dist/application/task-layouts.js +249 -0
  32. package/dist/application/task-room-service.d.ts +99 -3
  33. package/dist/application/task-room-service.js +296 -31
  34. package/dist/atomic-file.d.ts +5 -0
  35. package/dist/atomic-file.js +62 -1
  36. package/dist/build-info.json +6 -4
  37. package/dist/capabilities.d.ts +3 -1
  38. package/dist/capabilities.js +4 -0
  39. package/dist/cli.js +186 -34
  40. package/dist/client-profile.d.ts +5 -16
  41. package/dist/client-profile.js +4 -112
  42. package/dist/config.d.ts +13 -0
  43. package/dist/config.js +19 -4
  44. package/dist/creation.js +2 -2
  45. package/dist/daemon-recovery.d.ts +1 -8
  46. package/dist/daemon-recovery.js +8 -113
  47. package/dist/docs.d.ts +3 -3
  48. package/dist/docs.js +44 -22
  49. package/dist/doctor.d.ts +1 -1
  50. package/dist/doctor.js +46 -59
  51. package/dist/erased-resources.d.ts +9 -0
  52. package/dist/erased-resources.js +87 -0
  53. package/dist/fleet-command-audit.d.ts +1 -0
  54. package/dist/fleet-command-audit.js +11 -6
  55. package/dist/harness/claude-code.js +9 -1
  56. package/dist/harness/claude-runtime.d.ts +12 -0
  57. package/dist/harness/claude-runtime.js +43 -0
  58. package/dist/harness/codex-app-server-proxy.d.ts +4 -1
  59. package/dist/harness/codex-app-server-proxy.js +41 -5
  60. package/dist/harness/codex-runtime.d.ts +11 -1
  61. package/dist/harness/codex-runtime.js +31 -4
  62. package/dist/harness/codex.d.ts +3 -2
  63. package/dist/harness/codex.js +8 -5
  64. package/dist/init-wizard.d.ts +2 -0
  65. package/dist/init-wizard.js +38 -19
  66. package/dist/isolation/policy.js +2 -0
  67. package/dist/isolation/types.d.ts +5 -0
  68. package/dist/minimal-setup.d.ts +2 -0
  69. package/dist/minimal-setup.js +44 -0
  70. package/dist/monitor.d.ts +1 -34
  71. package/dist/monitor.js +24 -151
  72. package/dist/notifications/fleet-producer.d.ts +18 -0
  73. package/dist/notifications/fleet-producer.js +129 -0
  74. package/dist/notifications/outbox.d.ts +42 -0
  75. package/dist/notifications/outbox.js +149 -0
  76. package/dist/owner-channel/channel.d.ts +3 -0
  77. package/dist/owner-channel/channel.js +34 -6
  78. package/dist/owner-channel/commands.d.ts +4 -0
  79. package/dist/owner-channel/commands.js +8 -0
  80. package/dist/owner-channel/lifecycle-outbox.js +4 -3
  81. package/dist/owner-channel/ours-client.js +2 -17
  82. package/dist/paths.d.ts +2 -0
  83. package/dist/paths.js +2 -0
  84. package/dist/preset-migration.js +25 -0
  85. package/dist/rooms-tasks/add-member.d.ts +48 -0
  86. package/dist/rooms-tasks/add-member.js +83 -0
  87. package/dist/rooms-tasks/archived-absence.d.ts +8 -0
  88. package/dist/rooms-tasks/archived-absence.js +48 -0
  89. package/dist/rooms-tasks/cli.js +34 -5
  90. package/dist/rooms-tasks/close.d.ts +5 -2
  91. package/dist/rooms-tasks/close.js +208 -28
  92. package/dist/rooms-tasks/config.d.ts +1 -1
  93. package/dist/rooms-tasks/config.js +11 -4
  94. package/dist/rooms-tasks/cowork-adapter.d.ts +6 -4
  95. package/dist/rooms-tasks/cowork-adapter.js +11 -117
  96. package/dist/rooms-tasks/cowork-http.d.ts +3 -0
  97. package/dist/rooms-tasks/cowork-http.js +70 -0
  98. package/dist/rooms-tasks/deletion.d.ts +1 -1
  99. package/dist/rooms-tasks/deletion.js +74 -5
  100. package/dist/rooms-tasks/erasure.d.ts +6 -0
  101. package/dist/rooms-tasks/erasure.js +169 -0
  102. package/dist/rooms-tasks/external-worker.d.ts +1 -1
  103. package/dist/rooms-tasks/external-worker.js +3 -4
  104. package/dist/rooms-tasks/layout-binding-client.d.ts +11 -0
  105. package/dist/rooms-tasks/layout-binding-client.js +56 -0
  106. package/dist/rooms-tasks/layout-binding-grants.d.ts +21 -0
  107. package/dist/rooms-tasks/layout-binding-grants.js +128 -0
  108. package/dist/rooms-tasks/layout-cli.d.ts +4 -0
  109. package/dist/rooms-tasks/layout-cli.js +107 -0
  110. package/dist/rooms-tasks/layout-config.d.ts +11 -0
  111. package/dist/rooms-tasks/layout-config.js +89 -0
  112. package/dist/rooms-tasks/layout-control.d.ts +21 -0
  113. package/dist/rooms-tasks/layout-control.js +52 -0
  114. package/dist/rooms-tasks/layout-service.d.ts +42 -0
  115. package/dist/rooms-tasks/layout-service.js +185 -0
  116. package/dist/rooms-tasks/layout.d.ts +114 -0
  117. package/dist/rooms-tasks/layout.js +250 -0
  118. package/dist/rooms-tasks/live-readiness.d.ts +18 -0
  119. package/dist/rooms-tasks/live-readiness.js +85 -0
  120. package/dist/rooms-tasks/member-startup.d.ts +1 -0
  121. package/dist/rooms-tasks/member-startup.js +2 -0
  122. package/dist/rooms-tasks/provision.d.ts +14 -0
  123. package/dist/rooms-tasks/provision.js +173 -46
  124. package/dist/rooms-tasks/room-state.d.ts +4 -2
  125. package/dist/rooms-tasks/room-state.js +53 -8
  126. package/dist/rooms-tasks/task-state.d.ts +42 -7
  127. package/dist/rooms-tasks/task-state.js +153 -23
  128. package/dist/rooms-tasks/types.d.ts +28 -0
  129. package/dist/rooms-tasks/workspace-artifacts.d.ts +6 -0
  130. package/dist/rooms-tasks/workspace-artifacts.js +93 -0
  131. package/dist/rooms-tasks/workspace.d.ts +26 -0
  132. package/dist/rooms-tasks/workspace.js +195 -0
  133. package/dist/runner.d.ts +19 -3
  134. package/dist/runner.js +89 -29
  135. package/dist/session/acp.d.ts +7 -1
  136. package/dist/session/acp.js +21 -6
  137. package/dist/session/arbiter.d.ts +3 -0
  138. package/dist/session/arbiter.js +20 -2
  139. package/dist/session/codex-app-server.d.ts +3 -0
  140. package/dist/session/codex-app-server.js +26 -3
  141. package/dist/session/control.d.ts +10 -1
  142. package/dist/session/control.js +37 -2
  143. package/dist/session/conversation-normalizer.d.ts +2 -1
  144. package/dist/session/conversation-normalizer.js +1 -1
  145. package/dist/session/conversation-types.d.ts +5 -3
  146. package/dist/session/task-notice.d.ts +14 -0
  147. package/dist/session/task-notice.js +13 -0
  148. package/dist/session/types.d.ts +3 -0
  149. package/dist/setup-tunnel-preflight.d.ts +32 -0
  150. package/dist/setup-tunnel-preflight.js +58 -0
  151. package/dist/socket-path.d.ts +2 -0
  152. package/dist/socket-path.js +22 -0
  153. package/dist/spawn.js +7 -0
  154. package/dist/startup-readiness.d.ts +13 -0
  155. package/dist/startup-readiness.js +38 -0
  156. package/dist/subscriptions/cli.d.ts +91 -0
  157. package/dist/subscriptions/cli.js +223 -0
  158. package/dist/subscriptions/launch.d.ts +37 -0
  159. package/dist/subscriptions/launch.js +93 -0
  160. package/dist/subscriptions/login.d.ts +75 -0
  161. package/dist/subscriptions/login.js +182 -0
  162. package/dist/subscriptions/observed.d.ts +7 -0
  163. package/dist/subscriptions/observed.js +44 -0
  164. package/dist/subscriptions/probe.d.ts +10 -0
  165. package/dist/subscriptions/probe.js +73 -0
  166. package/dist/subscriptions/service.d.ts +102 -0
  167. package/dist/subscriptions/service.js +364 -0
  168. package/dist/subscriptions/store.d.ts +71 -0
  169. package/dist/subscriptions/store.js +140 -0
  170. package/dist/supervisor/launchd.js +2 -1
  171. package/dist/supervisor/systemd.js +9 -23
  172. package/dist/temp-idle.d.ts +17 -0
  173. package/dist/temp-idle.js +42 -0
  174. package/dist/temp-lifecycle.d.ts +6 -1
  175. package/dist/temp-lifecycle.js +29 -13
  176. package/dist/web/agent-attachments.d.ts +29 -0
  177. package/dist/web/agent-attachments.js +162 -0
  178. package/dist/web/auth.d.ts +29 -1
  179. package/dist/web/auth.js +81 -7
  180. package/dist/web/available-port.d.ts +2 -0
  181. package/dist/web/available-port.js +23 -0
  182. package/dist/web/control.d.ts +3 -3
  183. package/dist/web/control.js +10 -8
  184. package/dist/web/fleet-config-service.d.ts +4 -1
  185. package/dist/web/fleet-config-service.js +46 -15
  186. package/dist/web/prefix-gateway.d.ts +29 -0
  187. package/dist/web/prefix-gateway.js +206 -0
  188. package/dist/web/runtime.d.ts +3 -1
  189. package/dist/web/runtime.js +116 -31
  190. package/dist/web/server.d.ts +16 -0
  191. package/dist/web/server.js +501 -53
  192. package/dist/web/service.d.ts +11 -2
  193. package/dist/web/service.js +30 -4
  194. package/dist/web/workspace-devices.d.ts +29 -0
  195. package/dist/web/workspace-devices.js +84 -0
  196. package/dist/web/workspace-tunnel.d.ts +1 -0
  197. package/dist/web/workspace-tunnel.js +32 -0
  198. package/dist/workspace-enrollment.d.ts +53 -0
  199. package/dist/workspace-enrollment.js +370 -0
  200. package/docs/room-layouts.md +227 -0
  201. package/docs/task-workspaces.md +130 -0
  202. package/examples/room-layouts/fresh.yaml +27 -0
  203. package/examples/room-layouts/scoped.yaml +21 -0
  204. package/examples/room-layouts/shared.yaml +19 -0
  205. package/package.json +13 -18
  206. package/presets/README.md +78 -0
  207. package/presets/brain-catalog.json +8 -2
  208. package/presets/fleet/agent_templates/Critic.yaml +1 -1
  209. package/presets/fleet/agent_templates/Developer.yaml +1 -1
  210. package/presets/fleet/agent_templates/Engineer.yaml +5 -0
  211. package/presets/fleet/agent_templates/LocalCoordinator.yaml +1 -1
  212. package/presets/fleet/agents/FleetCoordinator.yaml +1 -1
  213. package/presets/fleet/brains/claude-fable-5-1-high.yaml +5 -0
  214. package/presets/fleet/brains/claude-fable-5-1-low.yaml +5 -0
  215. package/presets/fleet/brains/claude-fable-5-1-max.yaml +5 -0
  216. package/presets/fleet/brains/claude-fable-5-1-medium.yaml +5 -0
  217. package/presets/fleet/brains/claude-fable-5-1-xhigh.yaml +5 -0
  218. package/presets/fleet/brains/claude-fable-5-high.yaml +1 -1
  219. package/presets/fleet/brains/claude-fable-5-low.yaml +1 -1
  220. package/presets/fleet/brains/claude-fable-5-max.yaml +1 -1
  221. package/presets/fleet/brains/claude-fable-5-medium.yaml +1 -1
  222. package/presets/fleet/brains/claude-fable-5-xhigh.yaml +1 -1
  223. package/presets/fleet/brains/claude-haiku-4-5-20251001-default.yaml +4 -0
  224. package/presets/fleet/brains/claude-opus-5-5-high.yaml +5 -0
  225. package/presets/fleet/brains/claude-opus-5-5-low.yaml +5 -0
  226. package/presets/fleet/brains/claude-opus-5-5-max.yaml +5 -0
  227. package/presets/fleet/brains/claude-opus-5-5-medium.yaml +5 -0
  228. package/presets/fleet/brains/claude-opus-5-5-xhigh.yaml +5 -0
  229. package/presets/fleet/brains/claude-opus-5-high.yaml +1 -1
  230. package/presets/fleet/brains/claude-opus-5-low.yaml +1 -1
  231. package/presets/fleet/brains/claude-opus-5-max.yaml +1 -1
  232. package/presets/fleet/brains/claude-opus-5-medium.yaml +1 -1
  233. package/presets/fleet/brains/claude-opus-5-xhigh.yaml +1 -1
  234. package/presets/fleet/brains/claude-sonnet-5-high.yaml +1 -1
  235. package/presets/fleet/brains/claude-sonnet-5-low.yaml +1 -1
  236. package/presets/fleet/brains/claude-sonnet-5-max.yaml +1 -1
  237. package/presets/fleet/brains/claude-sonnet-5-medium.yaml +1 -1
  238. package/presets/fleet/brains/claude-sonnet-5-xhigh.yaml +1 -1
  239. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-high.yaml +1 -1
  240. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-low.yaml +1 -1
  241. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-medium.yaml +1 -1
  242. package/presets/fleet/brains/codex-gpt-5-3-codex-spark-xhigh.yaml +1 -1
  243. package/presets/fleet/brains/codex-gpt-5-4-high.yaml +1 -1
  244. package/presets/fleet/brains/codex-gpt-5-4-low.yaml +1 -1
  245. package/presets/fleet/brains/codex-gpt-5-4-medium.yaml +1 -1
  246. package/presets/fleet/brains/codex-gpt-5-4-mini-high.yaml +1 -1
  247. package/presets/fleet/brains/codex-gpt-5-4-mini-low.yaml +1 -1
  248. package/presets/fleet/brains/codex-gpt-5-4-mini-medium.yaml +1 -1
  249. package/presets/fleet/brains/codex-gpt-5-4-mini-xhigh.yaml +1 -1
  250. package/presets/fleet/brains/codex-gpt-5-4-xhigh.yaml +1 -1
  251. package/presets/fleet/brains/codex-gpt-5-5-high.yaml +1 -1
  252. package/presets/fleet/brains/codex-gpt-5-5-low.yaml +1 -1
  253. package/presets/fleet/brains/codex-gpt-5-5-medium.yaml +1 -1
  254. package/presets/fleet/brains/codex-gpt-5-5-xhigh.yaml +1 -1
  255. package/presets/fleet/brains/codex-gpt-5-6-luna-high.yaml +1 -1
  256. package/presets/fleet/brains/codex-gpt-5-6-luna-low.yaml +1 -1
  257. package/presets/fleet/brains/codex-gpt-5-6-luna-max.yaml +1 -1
  258. package/presets/fleet/brains/codex-gpt-5-6-luna-medium.yaml +1 -1
  259. package/presets/fleet/brains/codex-gpt-5-6-luna-xhigh.yaml +1 -1
  260. package/presets/fleet/brains/codex-gpt-5-6-sol-high.yaml +1 -1
  261. package/presets/fleet/brains/codex-gpt-5-6-sol-low.yaml +1 -1
  262. package/presets/fleet/brains/codex-gpt-5-6-sol-max.yaml +1 -1
  263. package/presets/fleet/brains/codex-gpt-5-6-sol-medium.yaml +1 -1
  264. package/presets/fleet/brains/codex-gpt-5-6-sol-ultra.yaml +1 -1
  265. package/presets/fleet/brains/codex-gpt-5-6-sol-xhigh.yaml +1 -1
  266. package/presets/fleet/brains/codex-gpt-5-6-terra-high.yaml +1 -1
  267. package/presets/fleet/brains/codex-gpt-5-6-terra-low.yaml +1 -1
  268. package/presets/fleet/brains/codex-gpt-5-6-terra-max.yaml +1 -1
  269. package/presets/fleet/brains/codex-gpt-5-6-terra-medium.yaml +1 -1
  270. package/presets/fleet/brains/codex-gpt-5-6-terra-ultra.yaml +1 -1
  271. package/presets/fleet/brains/codex-gpt-5-6-terra-xhigh.yaml +1 -1
  272. package/presets/fleet/brains/codex-gpt-6-1-sol-high.yaml +5 -0
  273. package/presets/fleet/brains/codex-gpt-6-1-sol-low.yaml +5 -0
  274. package/presets/fleet/brains/codex-gpt-6-1-sol-max.yaml +5 -0
  275. package/presets/fleet/brains/codex-gpt-6-1-sol-medium.yaml +5 -0
  276. package/presets/fleet/brains/codex-gpt-6-1-sol-ultra.yaml +5 -0
  277. package/presets/fleet/brains/codex-gpt-6-1-sol-xhigh.yaml +5 -0
  278. package/presets/fleet/brains/codex-gpt-6-astra-high.yaml +1 -1
  279. package/presets/fleet/brains/codex-gpt-6-astra-low.yaml +1 -1
  280. package/presets/fleet/brains/codex-gpt-6-astra-max.yaml +1 -1
  281. package/presets/fleet/brains/codex-gpt-6-astra-medium.yaml +1 -1
  282. package/presets/fleet/brains/codex-gpt-6-astra-ultra.yaml +1 -1
  283. package/presets/fleet/brains/codex-gpt-6-astra-xhigh.yaml +1 -1
  284. package/presets/fleet/brains/codex-gpt-6-luna-high.yaml +5 -0
  285. package/presets/fleet/brains/codex-gpt-6-luna-low.yaml +5 -0
  286. package/presets/fleet/brains/codex-gpt-6-luna-max.yaml +5 -0
  287. package/presets/fleet/brains/codex-gpt-6-luna-medium.yaml +5 -0
  288. package/presets/fleet/brains/codex-gpt-6-luna-xhigh.yaml +5 -0
  289. package/presets/fleet/brains/codex-gpt-6-sol-high.yaml +5 -0
  290. package/presets/fleet/brains/codex-gpt-6-sol-low.yaml +5 -0
  291. package/presets/fleet/brains/codex-gpt-6-sol-max.yaml +5 -0
  292. package/presets/fleet/brains/codex-gpt-6-sol-medium.yaml +5 -0
  293. package/presets/fleet/brains/codex-gpt-6-sol-ultra.yaml +5 -0
  294. package/presets/fleet/brains/codex-gpt-6-sol-xhigh.yaml +5 -0
  295. package/presets/fleet/roles/Coordinator.yaml +34 -11
  296. package/presets/fleet/roles/Engineer.yaml +40 -0
  297. package/presets/fleet/room_layouts/engineering.yaml +25 -0
  298. package/presets/fleet/room_layouts/pair.yaml +24 -0
  299. package/presets/fleet/room_layouts/single.yaml +17 -0
  300. package/presets/fleet/room_layouts/team.yaml +30 -0
  301. package/presets/fleet/room_templates/engineering.yaml +19 -0
  302. package/presets/manifest.json +2 -2
  303. package/dist/web-app/assets/index-59GF-gsZ.css +0 -1
  304. package/dist/web-app/assets/index-C0h3ALvs.js +0 -10
  305. package/dist/web-app/icons/ours-fleet-maskable.svg +0 -4
  306. package/dist/web-app/icons/ours-fleet.svg +0 -4
  307. package/dist/web-app/index.html +0 -17
  308. package/dist/web-app/manifest.webmanifest +0 -15
  309. package/dist/web-app/offline.html +0 -18
  310. package/dist/web-app/sw.js +0 -51
@@ -1,3 +1,4 @@
1
+ import { socketPath as privateSocketPath } from '../socket-path.js';
1
2
  import { randomBytes, randomUUID, timingSafeEqual } from 'node:crypto';
2
3
  import { chmodSync, existsSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
3
4
  import { createConnection, createServer } from 'node:net';
@@ -8,7 +9,7 @@ import { interruptSession, queueSessionPrompt, respondSessionPermission, respond
8
9
  const MAX_LINE_BYTES = 64 * 1024;
9
10
  /** Commands that require protocol version 3. */
10
11
  const V3_COMMANDS = new Set([
11
- 'conversation_page', 'conversation_follow', 'submit_prompt_v2', 'interrupt_v2',
12
+ 'conversation_page', 'conversation_follow', 'submit_prompt_v2', 'submit_voice_prompt', 'interrupt_v2',
12
13
  'respond_permission_v2',
13
14
  ]);
14
15
  /** The one retained-range projection shared by polling and live-follow admission. */
@@ -99,7 +100,7 @@ export function oversightTaxonomy(name = '<Name>') {
99
100
  export function oversightTaxonomyLines(name = '<Name>') {
100
101
  return oversightTaxonomy(name).map(r => `- **${r.result}** — ${r.meaning} → ${r.action}`);
101
102
  }
102
- export const controlSocketPath = (stateDir) => join(stateDir, '.control.sock');
103
+ export const controlSocketPath = (stateDir) => privateSocketPath(join(stateDir, '.control.sock'));
103
104
  export const controlTokenPath = (stateDir) => join(stateDir, '.control-token');
104
105
  function sameToken(actual, supplied) {
105
106
  const a = Buffer.from(actual);
@@ -116,9 +117,13 @@ export class RoleControlServer {
116
117
  sockets = new Set();
117
118
  /** Interrupt idempotency: same command id returns the first receipt. */
118
119
  interruptCommands = new Map();
120
+ correspondence;
121
+ setCorrespondence(value) { this.correspondence = value; }
119
122
  ownerChannel;
120
123
  loopManager;
121
124
  reloadConfig;
125
+ layoutControl;
126
+ setLayoutControl(handler) { this.layoutControl = handler; }
122
127
  fleetSpawner;
123
128
  fleetAuditor;
124
129
  constructor(stateDir, session, log) {
@@ -235,7 +240,9 @@ export class RoleControlServer {
235
240
  protocolVersion: this.session.conversationPage ? 3 : 2,
236
241
  features: [
237
242
  'events_since', 'observer_follow', 'retained_range',
243
+ ...(this.correspondence ? ['agent_correspondence'] : []),
238
244
  ...(this.session.conversationPage ? ['conversation_v3'] : []),
245
+ ...(this.session.submitPromptBrowser ? ['generation_bound_prompts'] : []),
239
246
  ...(this.session.capabilities?.steering ? ['steering'] : []),
240
247
  ...(this.session.capabilities?.permissions ? ['permissions'] : []),
241
248
  ...(this.session.capabilities?.messagePhases ? ['message_phases'] : []),
@@ -308,6 +315,13 @@ export class RoleControlServer {
308
315
  });
309
316
  return;
310
317
  }
318
+ case 'layout_control': {
319
+ if (request.version !== 2 || !request.layout || !this.layoutControl)
320
+ throw new SessionControlError('rejected', 'layout control unavailable');
321
+ const result = await this.layoutControl(request.layout);
322
+ this.write(socket, { version: 1, id: request.id, ok: true, result });
323
+ return;
324
+ }
311
325
  case 'fleet_spawn': {
312
326
  if (request.version !== 2 || !request.spawn || typeof request.spawn.name !== 'string')
313
327
  throw new SessionControlError('rejected', 'version 2 and typed spawn options are required');
@@ -362,6 +376,23 @@ export class RoleControlServer {
362
376
  this.write(socket, { version: 1, id: request.id, ok: true, result: { delivered: true } });
363
377
  return;
364
378
  }
379
+ case 'agent_contacts':
380
+ case 'agent_history': {
381
+ if (!this.correspondence)
382
+ throw new SessionControlError('rejected', 'Supervisor correspondence API is unavailable; this session needs an updated supervisor.');
383
+ const query = request.agentHistory;
384
+ if (request.command === 'agent_history' && (!query || !/^[a-f0-9]{64}$/i.test(query.peer_cid) || (query.limit !== undefined && (!Number.isInteger(query.limit) || query.limit < 1 || query.limit > 200)) || (query.before_seq !== undefined && (!Number.isSafeInteger(query.before_seq) || query.before_seq < 1))))
385
+ throw new SessionControlError('rejected', 'Valid peer_cid, limit (1–200) and before_seq are required.');
386
+ let result;
387
+ try {
388
+ result = request.command === 'agent_contacts' ? await this.correspondence.contacts() : await this.correspondence.history(query);
389
+ }
390
+ catch {
391
+ throw new SessionControlError('rejected', 'Supervisor correspondence read failed; identity or transport is unavailable.');
392
+ }
393
+ this.write(socket, { version: 1, id: request.id, ok: true, result });
394
+ return;
395
+ }
365
396
  case 'owner_channel_manage': {
366
397
  if (!request.ownerChannel || typeof request.ownerChannel.action !== 'string')
367
398
  throw new SessionControlError('rejected', 'owner-channel management action is required');
@@ -421,7 +452,10 @@ export class RoleControlServer {
421
452
  socket.write(JSON.stringify({ version: 1, conversationEvent: event }) + '\n');
422
453
  }) };
423
454
  }
455
+ case 'submit_voice_prompt':
424
456
  case 'submit_prompt_v2': {
457
+ if (request.command === 'submit_voice_prompt' && !request.expectedSessionGeneration?.trim())
458
+ throw new SessionControlError('rejected', 'expectedSessionGeneration is required');
425
459
  this.requireConversation(request);
426
460
  if (!request.commandId?.trim() || !request.text?.trim() || !request.actor?.trim()
427
461
  || request.source !== 'owner_admin_console')
@@ -432,6 +466,7 @@ export class RoleControlServer {
432
466
  const receipt = await this.session.submitPromptBrowser({
433
467
  commandId: request.commandId, text: request.text,
434
468
  source: 'owner_admin_console', actorBrowserSession: request.actor,
469
+ expectedSessionGeneration: request.expectedSessionGeneration,
435
470
  });
436
471
  this.write(socket, { version: 1, id: request.id, ok: true, result: receipt });
437
472
  }
@@ -1,5 +1,5 @@
1
1
  import type * as acp from '@agentclientprotocol/sdk';
2
- import type { AdapterMeta, ConversationEventKind, ConversationPayload } from './conversation-types.js';
2
+ import type { AdapterMeta, BoundedJson, ConversationEventKind, ConversationPayload } from './conversation-types.js';
3
3
  /**
4
4
  * Reduce one ACP v1 `session/update` into one conversation-domain event draft.
5
5
  *
@@ -43,4 +43,5 @@ export interface NormalizedUpdate {
43
43
  toolCallId?: string;
44
44
  adapterMeta?: AdapterMeta[];
45
45
  }
46
+ export declare function boundedJson(value: unknown): BoundedJson;
46
47
  export declare function normalizeSessionUpdate(update: acp.SessionUpdate, options?: NormalizeOptions): NormalizedUpdate;
@@ -246,7 +246,7 @@ function redactSensitiveJson(value) {
246
246
  };
247
247
  return { value: visit(value, 0), redacted };
248
248
  }
249
- function boundedJson(value) {
249
+ export function boundedJson(value) {
250
250
  let serialized;
251
251
  let safe;
252
252
  let redacted = false;
@@ -1,3 +1,4 @@
1
+ import type { TaskCreatedNotice } from './task-notice.js';
1
2
  import type { PromptOrigin, TurnCancellationSource, TurnOutcome } from './types.js';
2
3
  /**
3
4
  * Durable conversation domain schema for managed-session consoles.
@@ -7,11 +8,11 @@ import type { PromptOrigin, TurnCancellationSource, TurnOutcome } from './types.
7
8
  * file touches the wire: transport updates are reduced into these shapes by a
8
9
  * session adapter, and the store assigns `seq`/`eventId`/timestamps.
9
10
  */
10
- export type ConversationEventKind = 'prompt.admitted' | 'prompt.started' | 'prompt.interrupt_requested' | 'message.chunk' | 'message.replace' | 'thought.chunk' | 'thought.replace' | 'plan.replace' | 'tool.upsert' | 'tool.content_chunk' | 'permission.requested' | 'permission.resolved' | 'monitor.delivery' | 'usage.updated' | 'turn.state' | 'turn.completed' | 'session.state' | 'session.info' | 'capabilities.updated' | 'error'
11
+ export type ConversationEventKind = 'prompt.admitted' | 'prompt.started' | 'prompt.interrupt_requested' | 'message.chunk' | 'message.replace' | 'thought.chunk' | 'thought.replace' | 'plan.replace' | 'tool.upsert' | 'tool.content_chunk' | 'permission.requested' | 'permission.resolved' | 'fleet.task_created' | 'monitor.delivery' | 'usage.updated' | 'turn.state' | 'turn.completed' | 'session.state' | 'session.info' | 'capabilities.updated' | 'error'
11
12
  /** A well-formed transport update this version cannot represent. Bounded, never a crash. */
12
13
  | 'unsupported';
13
14
  /** Where a conversation record came from. Typed provenance, never prompt text. */
14
- export type ConversationSource = 'owner_admin_console' | 'owner_channel' | 'fleet_monitor' | 'scheduled_loop' | 'startup' | 'local_console' | 'agent' | 'agent_replay';
15
+ export type ConversationSource = 'owner_admin_console' | 'owner_channel' | 'fleet_monitor' | 'scheduled_loop' | 'startup' | 'local_console' | 'agent' | 'agent_replay' | 'fleet_lifecycle';
15
16
  export interface NormalizedText {
16
17
  type: 'text';
17
18
  text: string;
@@ -227,7 +228,7 @@ export interface BoundedJson {
227
228
  digest?: string;
228
229
  redacted?: true;
229
230
  }
230
- export type ConversationPayload = MessageChunkPayload | ThoughtChunkPayload | PlanReplacePayload | ToolUpsertPayload | UsageUpdatedPayload | SessionStatePayload | SessionInfoPayload | CapabilitiesUpdatedPayload | UnsupportedPayload | PromptAdmittedPayload | PromptStartedPayload | PromptInterruptRequestedPayload | PermissionRequestedPayload | PermissionResolvedPayload | TurnStatePayload | TurnCompletedPayload | MonitorDeliveryPayload | SessionLifecyclePayload | ErrorPayload;
231
+ export type ConversationPayload = MessageChunkPayload | ThoughtChunkPayload | PlanReplacePayload | ToolUpsertPayload | UsageUpdatedPayload | SessionStatePayload | SessionInfoPayload | CapabilitiesUpdatedPayload | UnsupportedPayload | PromptAdmittedPayload | PromptStartedPayload | PromptInterruptRequestedPayload | PermissionRequestedPayload | PermissionResolvedPayload | TurnStatePayload | TurnCompletedPayload | MonitorDeliveryPayload | SessionLifecyclePayload | ErrorPayload | TaskCreatedNotice;
231
232
  export interface ConversationEventV1 {
232
233
  schemaVersion: 1;
233
234
  roleId: string;
@@ -262,6 +263,7 @@ export interface ConversationEventV1 {
262
263
  adapterMeta?: AdapterMeta[];
263
264
  }
264
265
  export interface SubmitPromptCommand {
266
+ expectedSessionGeneration?: string;
265
267
  /** Idempotency-Key / clientRequestId. Reuse with a different body is a conflict. */
266
268
  commandId: string;
267
269
  text: string;
@@ -0,0 +1,14 @@
1
+ import type { ConversationEventStore } from './conversation-store.js';
2
+ export interface TaskNoticeBinding {
3
+ sessionGeneration: string;
4
+ acpSessionId: string;
5
+ promptId: string;
6
+ }
7
+ export interface TaskCreatedNotice {
8
+ operationId: string;
9
+ taskId: string;
10
+ title: string;
11
+ state: string;
12
+ }
13
+ /** Only the trusted Fleet audit completion calls this, never model output. */
14
+ export declare function appendTaskCreated(store: ConversationEventStore, binding: TaskNoticeBinding, notice: TaskCreatedNotice): void;
@@ -0,0 +1,13 @@
1
+ /** Only the trusted Fleet audit completion calls this, never model output. */
2
+ export function appendTaskCreated(store, binding, notice) {
3
+ let after;
4
+ do {
5
+ const page = store.page({ after, limit: 1000 });
6
+ if (page.events.some(e => e.kind === 'fleet.task_created' && e.payload.operationId === notice.operationId))
7
+ return;
8
+ if (!page.hasMore)
9
+ break;
10
+ after = page.nextCursor;
11
+ } while (after);
12
+ store.append({ kind: 'fleet.task_created', source: 'fleet_lifecycle', ...binding, turnId: binding.promptId, payload: notice });
13
+ }
@@ -1,3 +1,4 @@
1
+ import type { TaskCreatedNotice, TaskNoticeBinding } from './task-notice.js';
1
2
  import type { SessionBackendId } from '../config.js';
2
3
  import type { ConversationEventV1, ConversationSnapshot, PromptReceipt, SubmitPromptCommand } from './conversation-types.js';
3
4
  /**
@@ -289,6 +290,8 @@ export interface AgentSession {
289
290
  readonly capabilities?: AgentSessionCapabilities;
290
291
  isAlive(): boolean;
291
292
  snapshot(): SessionSnapshot;
293
+ taskNoticeBinding?(): TaskNoticeBinding | undefined;
294
+ recordTaskCreated?(binding: TaskNoticeBinding, notice: TaskCreatedNotice): void;
292
295
  conversationPage?(request: {
293
296
  after?: string;
294
297
  limit?: number;
@@ -0,0 +1,32 @@
1
+ import { type Exec } from './exec.js';
2
+ import type { WorkspacePayload } from './workspace-enrollment.js';
3
+ /**
4
+ * Check what the steps after the one-time root proof depend on, before that
5
+ * proof is sent: a failure afterwards cannot be retried with a fresh command.
6
+ */
7
+ export declare function setupTunnelPreflight({ exec, platform, node }?: {
8
+ exec?: Exec;
9
+ platform?: NodeJS.Platform;
10
+ node?: string;
11
+ }): Promise<void>;
12
+ /** What the steps after the proof need, kept so they can be finished without a new command. */
13
+ export interface PendingTunnelSetup {
14
+ appOrigin: string;
15
+ origin: string;
16
+ hostWorkspaceId: string;
17
+ rootCid: string;
18
+ challenge: WorkspacePayload['challenge'];
19
+ /** Fleet configuration the setup started with; a resume must use the same one. */
20
+ configuration: string;
21
+ /** Every port sent to the account as the tunnel target. No answer was confirmed while this record exists, so the remote target is any of these or the default. */
22
+ requestedPorts?: number[];
23
+ }
24
+ export declare function savePendingTunnelSetup(pending: PendingTunnelSetup): void;
25
+ export declare function clearPendingTunnelSetup(): void;
26
+ export declare function readPendingTunnelSetup(): PendingTunnelSetup;
27
+ export declare const DEFAULT_TUNNEL_PORT = 49271;
28
+ /**
29
+ * The port the web service must bind when the account can no longer retarget
30
+ * the tunnel. Unknown when a different port was requested and never confirmed.
31
+ */
32
+ export declare function requiredPortAfterExpiry(pending: PendingTunnelSetup): number;
@@ -0,0 +1,58 @@
1
+ import { existsSync, lstatSync, readFileSync, rmSync } from 'node:fs';
2
+ import { userInfo } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { replaceFileAtomically } from './atomic-file.js';
5
+ import { realExec } from './exec.js';
6
+ import { stateRoot } from './paths.js';
7
+ const UNCHANGED = 'Nothing was changed and this host was not bound.';
8
+ /**
9
+ * Check what the steps after the one-time root proof depend on, before that
10
+ * proof is sent: a failure afterwards cannot be retried with a fresh command.
11
+ */
12
+ export async function setupTunnelPreflight({ exec = realExec, platform = process.platform, node = process.versions.node } = {}) {
13
+ const [major, minor] = node.split('.').map(Number);
14
+ if (major < 22 || (major === 22 && minor < 13))
15
+ throw Error(`Tunnel setup requires Node.js 22.13 or newer; this is ${node}. Update Node.js, then run a fresh tunnel setup command. ${UNCHANGED}`);
16
+ if (platform === 'linux') {
17
+ const manager = await exec('systemctl', ['--user', 'show-environment'], { timeout: 10_000 });
18
+ if (manager.code !== 0)
19
+ throw Error(`The user service manager is not reachable from this shell (${manager.stderr.trim().split('\n')[0] || `systemctl --user exited ${manager.code}`}). `
20
+ + `Log in directly as ${userInfo().username} (not through su or sudo), or run: sudo loginctl enable-linger ${userInfo().username} && export XDG_RUNTIME_DIR=/run/user/${process.getuid?.()} `
21
+ + `Then run a fresh tunnel setup command. ${UNCHANGED}`);
22
+ }
23
+ const help = await exec('cloudflared', ['tunnel', 'run', '--help'], { timeout: 10_000 });
24
+ if (help.code === 127)
25
+ throw Error(`cloudflared is not installed or not on PATH. Install it, then run a fresh tunnel setup command. ${UNCHANGED}`);
26
+ if (help.code !== 0 || !`${help.stdout}\n${help.stderr}`.includes('--token-file'))
27
+ throw Error(`This cloudflared is too old for tunnel setup (no --token-file support). Update cloudflared, then run a fresh tunnel setup command. ${UNCHANGED}`);
28
+ }
29
+ const pendingPath = () => join(stateRoot(), 'workspace', 'pending-setup.json');
30
+ export function savePendingTunnelSetup(pending) {
31
+ replaceFileAtomically(pendingPath(), JSON.stringify(pending) + '\n', 0o600);
32
+ }
33
+ export function clearPendingTunnelSetup() { rmSync(pendingPath(), { force: true }); }
34
+ export function readPendingTunnelSetup() {
35
+ const path = pendingPath();
36
+ if (!existsSync(path))
37
+ throw Error('No unfinished tunnel setup on this host. Run the tunnel setup command from the App.');
38
+ const stat = lstatSync(path);
39
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.uid !== process.getuid?.() || (stat.mode & 0o077) !== 0)
40
+ throw Error('Unfinished tunnel setup record must be an owned private file');
41
+ const pending = JSON.parse(readFileSync(path, 'utf8'));
42
+ if (typeof pending?.appOrigin !== 'string' || typeof pending.origin !== 'string' || typeof pending.hostWorkspaceId !== 'string'
43
+ || typeof pending.rootCid !== 'string' || !pending.challenge || !Number.isSafeInteger(pending.challenge.expiresAt) || typeof pending.configuration !== 'string'
44
+ || (pending.requestedPorts !== undefined && (!Array.isArray(pending.requestedPorts) || !pending.requestedPorts.every(Number.isInteger))))
45
+ throw Error('Unfinished tunnel setup record is invalid');
46
+ return pending;
47
+ }
48
+ export const DEFAULT_TUNNEL_PORT = 49_271;
49
+ /**
50
+ * The port the web service must bind when the account can no longer retarget
51
+ * the tunnel. Unknown when a different port was requested and never confirmed.
52
+ */
53
+ export function requiredPortAfterExpiry(pending) {
54
+ const other = [...new Set(pending.requestedPorts ?? [])].filter(port => port !== DEFAULT_TUNNEL_PORT);
55
+ if (!other.length)
56
+ return DEFAULT_TUNNEL_PORT;
57
+ throw Error(`The setup window has expired and it is unknown whether the tunnel points at port ${[...other, DEFAULT_TUNNEL_PORT].join(' or ')}: the account's answer to a port request was not received. This setup cannot be finished automatically`);
58
+ }
@@ -0,0 +1,2 @@
1
+ /** Optional private socket directory for deeply nested, isolated Fleet homes. */
2
+ export declare function socketPath(logicalPath: string): string;
@@ -0,0 +1,22 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { lstatSync, mkdirSync } from 'node:fs';
3
+ import { isAbsolute, join, resolve } from 'node:path';
4
+ /** Optional private socket directory for deeply nested, isolated Fleet homes. */
5
+ export function socketPath(logicalPath) {
6
+ const root = process.env.OURS_FLEET_SOCKET_ROOT;
7
+ if (!root) {
8
+ if (Buffer.byteLength(logicalPath) > 103)
9
+ throw new Error('Unix socket path is too long; configure a short private OURS_FLEET_SOCKET_ROOT');
10
+ return logicalPath;
11
+ }
12
+ if (!isAbsolute(root) || resolve(root) !== root)
13
+ throw new Error('OURS_FLEET_SOCKET_ROOT must be an absolute normalized path');
14
+ mkdirSync(root, { recursive: true, mode: 0o700 });
15
+ const stat = lstatSync(root);
16
+ if (!stat.isDirectory() || stat.isSymbolicLink() || stat.uid !== process.getuid?.() || (stat.mode & 0o777) !== 0o700)
17
+ throw new Error('OURS_FLEET_SOCKET_ROOT must be an owner-only 0700 directory');
18
+ const path = join(root, createHash('sha256').update(resolve(logicalPath)).digest('hex').slice(0, 24) + '.sock');
19
+ if (Buffer.byteLength(path) > 103)
20
+ throw new Error('OURS_FLEET_SOCKET_ROOT is too long');
21
+ return path;
22
+ }
package/dist/spawn.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { randomUUID } from 'node:crypto';
2
2
  import { storeRoomSecret, storeTemporaryLaunch, preparePermanentAssignment } from './agent-ours/service.js';
3
+ import { ensureWorkspace } from './rooms-tasks/workspace.js';
3
4
  import { spawn as spawnChild } from 'node:child_process';
4
5
  import { closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
5
6
  import { join } from 'node:path';
@@ -321,6 +322,12 @@ export async function spawnTemp(o, binPath, launch = independentSupervisor, crea
321
322
  if (o.isolationFile)
322
323
  readIsolationFile(o.isolationFile); // fail before reserving
323
324
  const prepared = resolvedSpawn(o); // canonical validation before mutation
325
+ if (o.roomMemberStartup?.workspace) {
326
+ const workspace = o.roomMemberStartup.workspace;
327
+ if (prepared.role.cwd !== workspace.path)
328
+ throw new Error('room member cwd must equal its recorded owned workspace');
329
+ ensureWorkspace(workspace);
330
+ }
324
331
  // Retire only supervisors whose recorded owner is definitively stopped. This
325
332
  // bounded pass keeps the active roster clean without deleting old evidence.
326
333
  await reclaimStaleTempState();
@@ -0,0 +1,13 @@
1
+ import { type DaemonGenerationProbe } from './daemon-recovery.js';
2
+ export declare const STARTUP_WAIT_MS = 240000;
3
+ export declare const STARTUP_RETRY_MS = 5000;
4
+ interface ReadinessDeps {
5
+ probe(env: NodeJS.ProcessEnv): Promise<DaemonGenerationProbe>;
6
+ now(): number;
7
+ sleep(ms: number): Promise<void>;
8
+ log(message: string): void;
9
+ env: NodeJS.ProcessEnv;
10
+ }
11
+ /** Read-only preflight: never binds identities, starts a harness or edits its ledger. */
12
+ export declare function waitForRoleDaemon(name: string, configPath?: string, partial?: Partial<ReadinessDeps>): Promise<void>;
13
+ export {};
@@ -0,0 +1,38 @@
1
+ import { agentDir } from './paths.js';
2
+ import { findRole, loadConfig } from './config.js';
3
+ import { resolveConfigPath } from './runner.js';
4
+ import { probeDaemonGeneration } from './daemon-recovery.js';
5
+ export const STARTUP_WAIT_MS = 240_000;
6
+ export const STARTUP_RETRY_MS = 5_000;
7
+ /** Read-only preflight: never binds identities, starts a harness or edits its ledger. */
8
+ export async function waitForRoleDaemon(name, configPath, partial = {}) {
9
+ const deps = {
10
+ probe: env => probeDaemonGeneration(((url, init) => globalThis.fetch(url, {
11
+ ...init, signal: AbortSignal.timeout(10_000),
12
+ })), env),
13
+ now: Date.now,
14
+ sleep: ms => new Promise(resolve => setTimeout(resolve, ms)),
15
+ log: message => process.stderr.write(message + '\n'),
16
+ env: process.env,
17
+ ...partial,
18
+ };
19
+ const path = resolveConfigPath(agentDir(name), configPath);
20
+ const role = findRole(loadConfig(path), name);
21
+ const env = { ...deps.env, ...role.env };
22
+ const deadline = deps.now() + STARTUP_WAIT_MS;
23
+ let lastReason = '';
24
+ while (deps.now() < deadline) {
25
+ const result = await deps.probe(env);
26
+ if (result.state === 'ready') {
27
+ deps.log(`[${name}] daemon ready; starting supervised agent`);
28
+ return;
29
+ }
30
+ // Only structured diagnostic codes, never endpoint responses or credentials.
31
+ const reason = /^[A-Z][A-Z0-9_]*$/.test(result.reason) ? result.reason : 'DAEMON_UNAVAILABLE';
32
+ if (reason !== lastReason)
33
+ deps.log(`[${name}] waiting for configured daemon: ${reason}`);
34
+ lastReason = reason;
35
+ await deps.sleep(Math.min(STARTUP_RETRY_MS, Math.max(0, deadline - deps.now())));
36
+ }
37
+ throw new Error(`Daemon not ready (${lastReason}); service manager will retry startup`);
38
+ }
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Thin adapters over the official CLIs. Nothing here reads or returns a token
3
+ * value: credentials stay in files the CLIs own, and secrets typed by the user
4
+ * (a Claude paste code) travel only over a child's stdin, never argv or logs.
5
+ */
6
+ export interface SubscriptionBinaries {
7
+ claude: string;
8
+ codex: string;
9
+ /** `script(1)`, used to give `claude auth login` the terminal it expects. */
10
+ script: string;
11
+ }
12
+ export declare const defaultBinaries: () => SubscriptionBinaries;
13
+ /**
14
+ * Child env for a profile helper: explicit home for added profiles, the CLI
15
+ * default otherwise. Every credential selector either CLI honours is removed,
16
+ * so a helper can only ever see the profile's own login.
17
+ */
18
+ export declare function profileEnv(homeVar: string, profileId: string, home: string, base?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
19
+ export interface ClaudeStatus {
20
+ loggedIn: boolean;
21
+ email?: string;
22
+ plan?: string;
23
+ org?: string;
24
+ authMethod?: string;
25
+ }
26
+ /** `claude auth status --json` (documented: exit 0 when logged in, 1 otherwise). */
27
+ export declare function claudeAuthStatus(bin: string, env: NodeJS.ProcessEnv, timeoutMs?: number): Promise<ClaudeStatus>;
28
+ /**
29
+ * Login expiry timestamps from the Claude credentials file. Field names are
30
+ * observed (Claude Code 2.1.x), not a documented contract, so absence is normal.
31
+ * Only the two numbers are kept; the parsed object is discarded immediately.
32
+ */
33
+ export declare function claudeLoginExpiry(home: string): {
34
+ accessExpiresAt?: number;
35
+ refreshExpiresAt?: number;
36
+ };
37
+ /** Minimal stdio JSON-RPC client for `codex app-server` (the supported transport). */
38
+ export declare class CodexAppServer {
39
+ private readonly child;
40
+ private id;
41
+ private buffer;
42
+ private readonly pending;
43
+ private readonly listeners;
44
+ private closed;
45
+ private constructor();
46
+ static start(bin: string, env: NodeJS.ProcessEnv, initializeTimeoutMs?: number): Promise<CodexAppServer>;
47
+ call<T = unknown>(method: string, params: unknown, timeoutMs?: number): Promise<T>;
48
+ onNotification(fn: (method: string, params: unknown) => void): () => void;
49
+ close(): void;
50
+ private onData;
51
+ }
52
+ /** One-shot use of an app-server for a profile. */
53
+ export declare function withCodex<T>(bin: string, env: NodeJS.ProcessEnv, fn: (s: CodexAppServer) => Promise<T>, initializeTimeoutMs?: number): Promise<T>;
54
+ /** What a Codex runtime offers the account it is signed in to. An empty list is an answer; unknown is not. */
55
+ export type OfferedModels = {
56
+ state: 'known';
57
+ models: string[];
58
+ } | {
59
+ state: 'unknown';
60
+ reason: string;
61
+ };
62
+ /**
63
+ * Ask this Codex executable, with this profile's environment, which models it offers (`model/list`,
64
+ * the call the ACP adapter itself uses). Nothing is inferred when it does not answer.
65
+ */
66
+ export declare function codexOfferedModels(bin: string, env: NodeJS.ProcessEnv, budgetMs?: number): Promise<OfferedModels>;
67
+ export interface UsageWindow {
68
+ id: string;
69
+ label: string;
70
+ usedPercent: number;
71
+ windowMins?: number;
72
+ resetsAt?: string;
73
+ }
74
+ interface CodexWindow {
75
+ usedPercent?: number;
76
+ windowDurationMins?: number | null;
77
+ resetsAt?: number | null;
78
+ }
79
+ interface CodexSnapshot {
80
+ limitId?: string | null;
81
+ limitName?: string | null;
82
+ primary?: CodexWindow | null;
83
+ secondary?: CodexWindow | null;
84
+ }
85
+ /** Flatten `account/rateLimits/read` into display windows. */
86
+ export declare function codexUsageWindows(result: {
87
+ rateLimits?: CodexSnapshot;
88
+ rateLimitsByLimitId?: Record<string, CodexSnapshot | undefined> | null;
89
+ }): UsageWindow[];
90
+ export declare function windowName(mins?: number): string;
91
+ export {};