@ours.network/fleet 1.2.0-nightly.34 → 1.2.0-nightly.36

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 (187) hide show
  1. package/README.md +28 -49
  2. package/dist/application/codex-models.d.ts +15 -0
  3. package/dist/application/codex-models.js +56 -0
  4. package/dist/build-info.json +4 -4
  5. package/dist/cli.js +11 -41
  6. package/dist/config.d.ts +2 -0
  7. package/dist/config.js +1 -1
  8. package/dist/docs.d.ts +1 -1
  9. package/dist/docs.js +10 -15
  10. package/dist/harness/codex-runtime.d.ts +11 -1
  11. package/dist/harness/codex-runtime.js +31 -4
  12. package/dist/harness/codex.js +4 -2
  13. package/dist/init-wizard.js +2 -1
  14. package/dist/minimal-setup.js +2 -1
  15. package/dist/paths.d.ts +2 -0
  16. package/dist/paths.js +2 -0
  17. package/dist/rooms-tasks/config.d.ts +1 -1
  18. package/dist/rooms-tasks/config.js +8 -3
  19. package/dist/subscriptions/cli.d.ts +15 -2
  20. package/dist/subscriptions/cli.js +41 -4
  21. package/dist/web/auth.d.ts +1 -1
  22. package/dist/web/auth.js +2 -5
  23. package/dist/web/control.d.ts +1 -2
  24. package/dist/web/control.js +0 -2
  25. package/dist/web/prefix-gateway.js +2 -7
  26. package/dist/web/runtime.d.ts +0 -2
  27. package/dist/web/runtime.js +3 -18
  28. package/dist/web/server.d.ts +3 -1
  29. package/dist/web/server.js +14 -35
  30. package/dist/workspace-enrollment.d.ts +17 -0
  31. package/dist/workspace-enrollment.js +117 -9
  32. package/package.json +2 -3
  33. package/presets/fleet/agent_templates/Critic.yaml +1 -1
  34. package/presets/fleet/agent_templates/Developer.yaml +1 -1
  35. package/presets/fleet/agent_templates/Engineer.yaml +1 -1
  36. package/presets/fleet/agent_templates/LocalCoordinator.yaml +1 -1
  37. package/presets/fleet/agents/FleetCoordinator.yaml +1 -1
  38. package/presets/fleet/roles/Coordinator.yaml +6 -0
  39. package/presets/manifest.json +1 -1
  40. package/dist/web-app/assets/FleetApp-D58F4xje.css +0 -1
  41. package/dist/web-app/assets/FleetApp-Gjz3h8uS.js +0 -302
  42. package/dist/web-app/assets/FleetApp-Gjz3h8uS.js.map +0 -1
  43. package/dist/web-app/assets/abnfDiagram-VCTEODGH-t4h5V8Cs.js +0 -2
  44. package/dist/web-app/assets/abnfDiagram-VCTEODGH-t4h5V8Cs.js.map +0 -1
  45. package/dist/web-app/assets/arc-DbufDTF6.js +0 -2
  46. package/dist/web-app/assets/arc-DbufDTF6.js.map +0 -1
  47. package/dist/web-app/assets/architectureDiagram-5GKGNRK7-D6K8jMN5.js +0 -37
  48. package/dist/web-app/assets/architectureDiagram-5GKGNRK7-D6K8jMN5.js.map +0 -1
  49. package/dist/web-app/assets/blockDiagram-I7D4REHJ-CWvkET2x.js +0 -130
  50. package/dist/web-app/assets/blockDiagram-I7D4REHJ-CWvkET2x.js.map +0 -1
  51. package/dist/web-app/assets/browser-B7y08DsC.js +0 -9
  52. package/dist/web-app/assets/browser-B7y08DsC.js.map +0 -1
  53. package/dist/web-app/assets/c4Diagram-7LVT6UL2-RNWA7VnD.js +0 -39
  54. package/dist/web-app/assets/c4Diagram-7LVT6UL2-RNWA7VnD.js.map +0 -1
  55. package/dist/web-app/assets/channel-BF3U9sI8.js +0 -2
  56. package/dist/web-app/assets/channel-BF3U9sI8.js.map +0 -1
  57. package/dist/web-app/assets/chunk-2Q5K7J3B-pdEuY4vj.js +0 -2
  58. package/dist/web-app/assets/chunk-2Q5K7J3B-pdEuY4vj.js.map +0 -1
  59. package/dist/web-app/assets/chunk-5VM5RSS4-DuAUtdUC.js +0 -16
  60. package/dist/web-app/assets/chunk-5VM5RSS4-DuAUtdUC.js.map +0 -1
  61. package/dist/web-app/assets/chunk-F27PBJKO-6kpb80Xt.js +0 -2
  62. package/dist/web-app/assets/chunk-F27PBJKO-6kpb80Xt.js.map +0 -1
  63. package/dist/web-app/assets/chunk-IMKFNOWR-DWC84P6A.js +0 -232
  64. package/dist/web-app/assets/chunk-IMKFNOWR-DWC84P6A.js.map +0 -1
  65. package/dist/web-app/assets/chunk-JWPE2WC7-FHO-M3vi.js +0 -2
  66. package/dist/web-app/assets/chunk-JWPE2WC7-FHO-M3vi.js.map +0 -1
  67. package/dist/web-app/assets/chunk-POPQ4Y6H-CjnlKvmR.js +0 -2
  68. package/dist/web-app/assets/chunk-POPQ4Y6H-CjnlKvmR.js.map +0 -1
  69. package/dist/web-app/assets/chunk-SVP7TREG-WHYWJ6xq.js +0 -89
  70. package/dist/web-app/assets/chunk-SVP7TREG-WHYWJ6xq.js.map +0 -1
  71. package/dist/web-app/assets/chunk-TICWLB2K-POupMpyL.js +0 -207
  72. package/dist/web-app/assets/chunk-TICWLB2K-POupMpyL.js.map +0 -1
  73. package/dist/web-app/assets/chunk-XXDRQBXY-Cw5HHqH-.js +0 -2
  74. package/dist/web-app/assets/chunk-XXDRQBXY-Cw5HHqH-.js.map +0 -1
  75. package/dist/web-app/assets/classDiagram-ZZMXUADV-1hdMzIme.js +0 -2
  76. package/dist/web-app/assets/classDiagram-ZZMXUADV-1hdMzIme.js.map +0 -1
  77. package/dist/web-app/assets/classDiagram-v2-VYDZK3BY-1hdMzIme.js +0 -2
  78. package/dist/web-app/assets/classDiagram-v2-VYDZK3BY-1hdMzIme.js.map +0 -1
  79. package/dist/web-app/assets/cose-bilkent-JH36ORCC-Cp6Hjine.js +0 -2
  80. package/dist/web-app/assets/cose-bilkent-JH36ORCC-Cp6Hjine.js.map +0 -1
  81. package/dist/web-app/assets/cynefin-OW5HDTMX-DI-DeNUk.js +0 -179
  82. package/dist/web-app/assets/cynefin-OW5HDTMX-DI-DeNUk.js.map +0 -1
  83. package/dist/web-app/assets/cynefinDiagram-5FMLGOSQ-todBCANI.js +0 -63
  84. package/dist/web-app/assets/cynefinDiagram-5FMLGOSQ-todBCANI.js.map +0 -1
  85. package/dist/web-app/assets/cytoscape.esm-CtNdOvlO.js +0 -332
  86. package/dist/web-app/assets/cytoscape.esm-CtNdOvlO.js.map +0 -1
  87. package/dist/web-app/assets/dagre-GXQ25YYZ-BvIVo7eh.js +0 -5
  88. package/dist/web-app/assets/dagre-GXQ25YYZ-BvIVo7eh.js.map +0 -1
  89. package/dist/web-app/assets/defaultLocale-DX6XiGOO.js +0 -2
  90. package/dist/web-app/assets/defaultLocale-DX6XiGOO.js.map +0 -1
  91. package/dist/web-app/assets/diagram-S7CK7UJ4-k9vDGlB5.js +0 -31
  92. package/dist/web-app/assets/diagram-S7CK7UJ4-k9vDGlB5.js.map +0 -1
  93. package/dist/web-app/assets/diagram-UQ7AKVKN-Bv7BT1dE.js +0 -42
  94. package/dist/web-app/assets/diagram-UQ7AKVKN-Bv7BT1dE.js.map +0 -1
  95. package/dist/web-app/assets/diagram-VSXAHHWV-m9I9AumX.js +0 -4
  96. package/dist/web-app/assets/diagram-VSXAHHWV-m9I9AumX.js.map +0 -1
  97. package/dist/web-app/assets/diagram-VX7I27RA-4VJ2qozS.js +0 -25
  98. package/dist/web-app/assets/diagram-VX7I27RA-4VJ2qozS.js.map +0 -1
  99. package/dist/web-app/assets/diagram-Z3DM3KII-CvH8JIEd.js +0 -25
  100. package/dist/web-app/assets/diagram-Z3DM3KII-CvH8JIEd.js.map +0 -1
  101. package/dist/web-app/assets/ebnfDiagram-PWID7BFC-DAGs23hd.js +0 -2
  102. package/dist/web-app/assets/ebnfDiagram-PWID7BFC-DAGs23hd.js.map +0 -1
  103. package/dist/web-app/assets/erDiagram-RLTQ6QDP-CEMyWKIa.js +0 -100
  104. package/dist/web-app/assets/erDiagram-RLTQ6QDP-CEMyWKIa.js.map +0 -1
  105. package/dist/web-app/assets/flowDiagram-HODETNUW-BnraxJTV.js +0 -169
  106. package/dist/web-app/assets/flowDiagram-HODETNUW-BnraxJTV.js.map +0 -1
  107. package/dist/web-app/assets/ganttDiagram-EL5Y4UJY-V6d4ICW0.js +0 -293
  108. package/dist/web-app/assets/ganttDiagram-EL5Y4UJY-V6d4ICW0.js.map +0 -1
  109. package/dist/web-app/assets/gitGraphDiagram-WWUBYQGX-Bj_gqcba.js +0 -107
  110. package/dist/web-app/assets/gitGraphDiagram-WWUBYQGX-Bj_gqcba.js.map +0 -1
  111. package/dist/web-app/assets/index-C4BdeFB9.css +0 -1
  112. package/dist/web-app/assets/index-i9rKiqYX.js +0 -430
  113. package/dist/web-app/assets/index-i9rKiqYX.js.map +0 -1
  114. package/dist/web-app/assets/infoDiagram-27XIBGKW-Dfm89NLl.js +0 -3
  115. package/dist/web-app/assets/infoDiagram-27XIBGKW-Dfm89NLl.js.map +0 -1
  116. package/dist/web-app/assets/init-Gi6I4Gst.js +0 -2
  117. package/dist/web-app/assets/init-Gi6I4Gst.js.map +0 -1
  118. package/dist/web-app/assets/ishikawaDiagram-5VMMS53U-D-ISiJTS.js +0 -71
  119. package/dist/web-app/assets/ishikawaDiagram-5VMMS53U-D-ISiJTS.js.map +0 -1
  120. package/dist/web-app/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  121. package/dist/web-app/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  122. package/dist/web-app/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  123. package/dist/web-app/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  124. package/dist/web-app/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  125. package/dist/web-app/assets/journeyDiagram-3NMN7TZE-TTySrzws.js +0 -140
  126. package/dist/web-app/assets/journeyDiagram-3NMN7TZE-TTySrzws.js.map +0 -1
  127. package/dist/web-app/assets/kanban-definition-UXKFOSKX-BxntsBft.js +0 -90
  128. package/dist/web-app/assets/kanban-definition-UXKFOSKX-BxntsBft.js.map +0 -1
  129. package/dist/web-app/assets/katex-HP8lGamR.js +0 -258
  130. package/dist/web-app/assets/katex-HP8lGamR.js.map +0 -1
  131. package/dist/web-app/assets/layout-0sZak8Ho.js +0 -2
  132. package/dist/web-app/assets/layout-0sZak8Ho.js.map +0 -1
  133. package/dist/web-app/assets/linear-D4xk4kUi.js +0 -2
  134. package/dist/web-app/assets/linear-D4xk4kUi.js.map +0 -1
  135. package/dist/web-app/assets/mermaid.core-CNKolAgz.js +0 -313
  136. package/dist/web-app/assets/mermaid.core-CNKolAgz.js.map +0 -1
  137. package/dist/web-app/assets/mindmap-definition-YA3MSWOX-DLJijY_l.js +0 -97
  138. package/dist/web-app/assets/mindmap-definition-YA3MSWOX-DLJijY_l.js.map +0 -1
  139. package/dist/web-app/assets/ordinal-Cboi1Yqb.js +0 -2
  140. package/dist/web-app/assets/ordinal-Cboi1Yqb.js.map +0 -1
  141. package/dist/web-app/assets/pegDiagram-XKGWAZYB-xjrh9rBd.js +0 -2
  142. package/dist/web-app/assets/pegDiagram-XKGWAZYB-xjrh9rBd.js.map +0 -1
  143. package/dist/web-app/assets/pieDiagram-E7YTZNPT-CHE8ZMXN.js +0 -40
  144. package/dist/web-app/assets/pieDiagram-E7YTZNPT-CHE8ZMXN.js.map +0 -1
  145. package/dist/web-app/assets/quadrantDiagram-AXDQQJYC-CDlEe9sg.js +0 -8
  146. package/dist/web-app/assets/quadrantDiagram-AXDQQJYC-CDlEe9sg.js.map +0 -1
  147. package/dist/web-app/assets/railroadDiagram-O6MQD6OU-Dv7lFZ_v.js +0 -2
  148. package/dist/web-app/assets/railroadDiagram-O6MQD6OU-Dv7lFZ_v.js.map +0 -1
  149. package/dist/web-app/assets/requirementDiagram-BXWQKSXE-BetEel-k.js +0 -85
  150. package/dist/web-app/assets/requirementDiagram-BXWQKSXE-BetEel-k.js.map +0 -1
  151. package/dist/web-app/assets/sankeyDiagram-P5KCCOFB-DCQgLfvK.js +0 -41
  152. package/dist/web-app/assets/sankeyDiagram-P5KCCOFB-DCQgLfvK.js.map +0 -1
  153. package/dist/web-app/assets/sequenceDiagram-WJ2MYXX4-CsGOoqu_.js +0 -163
  154. package/dist/web-app/assets/sequenceDiagram-WJ2MYXX4-CsGOoqu_.js.map +0 -1
  155. package/dist/web-app/assets/sizeCapture-INFHLROL-CLQRMiEc.js +0 -2
  156. package/dist/web-app/assets/sizeCapture-INFHLROL-CLQRMiEc.js.map +0 -1
  157. package/dist/web-app/assets/stateDiagram-D77RDMKH-D2MRdC5Q.js +0 -2
  158. package/dist/web-app/assets/stateDiagram-D77RDMKH-D2MRdC5Q.js.map +0 -1
  159. package/dist/web-app/assets/stateDiagram-v2-MP3YSRHH-CToAT5fD.js +0 -2
  160. package/dist/web-app/assets/stateDiagram-v2-MP3YSRHH-CToAT5fD.js.map +0 -1
  161. package/dist/web-app/assets/swimlanes-42K2YHIH-BGjHfR8x.js +0 -2
  162. package/dist/web-app/assets/swimlanes-42K2YHIH-BGjHfR8x.js.map +0 -1
  163. package/dist/web-app/assets/swimlanesDiagram-VR7AAH4N-bLHg88Vk.js +0 -9
  164. package/dist/web-app/assets/swimlanesDiagram-VR7AAH4N-bLHg88Vk.js.map +0 -1
  165. package/dist/web-app/assets/timeline-definition-24CTP7MA-DhGtHQ0p.js +0 -121
  166. package/dist/web-app/assets/timeline-definition-24CTP7MA-DhGtHQ0p.js.map +0 -1
  167. package/dist/web-app/assets/vennDiagram-4TSXK5OY-Dv5irf00.js +0 -35
  168. package/dist/web-app/assets/vennDiagram-4TSXK5OY-Dv5irf00.js.map +0 -1
  169. package/dist/web-app/assets/wardleyDiagram-VM6X3IG4-JGiUTj5x.js +0 -79
  170. package/dist/web-app/assets/wardleyDiagram-VM6X3IG4-JGiUTj5x.js.map +0 -1
  171. package/dist/web-app/assets/xychartDiagram-S5SC5T6Z-Dw5ev7_Q.js +0 -8
  172. package/dist/web-app/assets/xychartDiagram-S5SC5T6Z-Dw5ev7_Q.js.map +0 -1
  173. package/dist/web-app/fleet-index.html +0 -19
  174. package/dist/web-app/fleet.webmanifest +0 -37
  175. package/dist/web-app/icons/apple-touch-icon.png +0 -0
  176. package/dist/web-app/icons/favicon-16.png +0 -0
  177. package/dist/web-app/icons/favicon-32.png +0 -0
  178. package/dist/web-app/icons/icon-192-maskable.png +0 -0
  179. package/dist/web-app/icons/icon-192.png +0 -0
  180. package/dist/web-app/icons/icon-512-maskable.png +0 -0
  181. package/dist/web-app/icons/icon-512.png +0 -0
  182. package/dist/web-app/index.html +0 -19
  183. package/dist/web-app/manifest.webmanifest +0 -17
  184. package/dist/web-app/sw.js +0 -221
  185. package/dist/web-app/version.json +0 -1
  186. package/dist/web-app/workspace-install.sh +0 -148
  187. package/dist/web-app/workspace-tunnel.sh +0 -40
package/README.md CHANGED
@@ -139,76 +139,55 @@ the caller's owner channel with the caller and spawned-role details. This is an
139
139
  honest-actor convenience and attribution path, not a security boundary; host
140
140
  shells and deliberately bypassed absolute binaries retain direct behavior.
141
141
 
142
- ## Local web API
142
+ ## Local HTTP service
143
143
 
144
- Frontend source and builds are maintained in the standalone `ours-web` repository. Fleet builds only its backend API. Configure a separately built frontend static root when serving the unified application through the gateway. The former console source is preserved there under `legacy-fleet/`.
145
-
146
- ### Console API usage
147
-
148
- The interactive console is packaged with `@ours.network/fleet` and binds to
149
- IPv4 loopback by default. Remote or proxy exposure is always explicit:
144
+ Fleet is an HTTP backend. It serves no pages, bundles no frontend and opens no
145
+ browser: every screen belongs to the App, which calls this API with a device
146
+ credential. Any address outside `/api/` answers JSON `404`.
150
147
 
151
148
  ```sh
152
- npm run build
153
- ours-fleet web
149
+ ours-fleet setup-tunnel # connect this host to your App workspace
150
+ ours-fleet link-device # connect another browser or device
154
151
  # choose a free port for an isolated test:
155
- ours-fleet web serve --port 0 --no-open
156
- # nginx/TLS terminates at the declared browser origin; fleet remains loopback-bound
152
+ ours-fleet web serve --port 0
153
+ # nginx/TLS terminates at the declared origin; fleet remains loopback-bound
157
154
  ours-fleet web install --public-origin https://fleet.example.com --password-file /secure/fleet-password
158
- # Intentional no-password mode, for example when nginx already authenticates:
159
- ours-fleet web install --public-origin https://fleet.example.com --no-password
160
155
  ```
161
156
 
162
- The normal `ours-fleet web` command installs or updates an owner-level native
163
- service, starts it on stable `127.0.0.1:49271`, and opens/re-pairs the browser.
164
- Linux uses a systemd user unit and macOS uses a LaunchAgent; both restart after
165
- process failures and send logs to the native supervisor. Service management is
166
- explicit through `ours-fleet web install|start|stop|restart|status|uninstall`.
167
- Use `ours-fleet web serve` for a foreground development process. Linux login
168
- persistence requires linger; the installer reports when it is missing but
157
+ `ours-fleet web` installs or updates an owner-level native service and starts
158
+ it on stable `127.0.0.1:49271`. Linux uses a systemd user unit and macOS uses a
159
+ LaunchAgent; both restart after process failures and send logs to the native
160
+ supervisor. Service management is explicit through
161
+ `ours-fleet web install|start|stop|restart|status|uninstall`. Use
162
+ `ours-fleet web serve` for a foreground development process. `--no-open` is
163
+ still accepted because installed service units pass it; it has no effect. Linux
164
+ login persistence requires linger; the installer reports when it is missing but
169
165
  never enables it or requests root privileges.
170
166
 
171
- The normal command opens a one-time five-minute fragment directly in the local
172
- browser; it does not print a reusable secret. If the browser needs pairing
173
- again while the server is running, use `ours-fleet web open`. The fragment is
174
- exchanged once and removed from history. A paired browser receives a rotating,
175
- 30-day `HttpOnly; SameSite=Strict` device credential and can return after a
176
- session idle timeout or server restart. Use **Sign out** to revoke the current
177
- browser, or `ours-fleet web revoke-all` to revoke every trusted browser and
178
- active web session.
179
-
180
- Only a domain-separated SHA-256 device-secret hash and bounded timestamps are
181
- stored in the owner-private fleet state directory (`0700` directory, `0600`
182
- atomic file). The re-pair and revoke controls use an owner-private Unix socket;
183
- local processes running as the same OS user are therefore inside the trust
184
- boundary.
167
+ Use `ours-fleet web revoke-all` to revoke every linked device and active
168
+ session. Only a domain-separated SHA-256 device-secret hash and bounded
169
+ timestamps are stored in the owner-private fleet state directory (`0700`
170
+ directory, `0600` atomic file). The link and revoke controls use an
171
+ owner-private Unix socket; local processes running as the same OS user are
172
+ therefore inside the trust boundary.
185
173
 
186
174
  On first setup, the CLI requires an explicit access choice: `--password-file`
187
175
  or `--pairing` for protected access, or `--no-password` for intentional
188
176
  unprotected access. `--password-file` stores only a salted scrypt verifier in
189
- the owner-private web state; the source file remains operator-managed. New
190
- browsers sign in and then receive the same rotating HttpOnly trusted-device
191
- credential. `--no-password` is deliberately named and prints a warning: anyone
192
- who can reach that origin can control the fleet.
177
+ the owner-private web state; the source file remains operator-managed.
178
+ `--no-password` is deliberately named and prints a warning: anyone who can
179
+ reach that origin can control the fleet.
193
180
 
194
181
  For nginx on a VPS, keep the default loopback bind and set the exact external
195
182
  `--public-origin` (scheme, hostname, optional port). nginx should proxy HTTP and
196
183
  WebSocket upgrades to `127.0.0.1:49271` and provide TLS; rewriting the upstream
197
- Host is not required because the declared browser Origin remains authoritative. To listen beyond
184
+ Host is not required because the declared Origin remains authoritative. To listen beyond
198
185
  loopback, add an explicit `--bind`; fleet refuses a non-loopback bind without a
199
186
  public origin. Host and Origin validation use that declaration rather than
200
187
  trusting forwarded headers. `localhost` and `127.0.0.1` both work in normal
201
- local mode; an unconfigured hostname gets a self-describing HTML page instead
202
- of raw internal Host-header JSON.
203
-
204
- The console is installable as a standalone PWA. Its service worker caches only
205
- the data-free offline page and successful content-hashed JavaScript/CSS assets.
206
- HTML stays network-first and no API, authentication, bootstrap, device,
207
- WebSocket, terminal, event, audit, log, session, query-bearing, or error response
208
- is cached. When the local daemon is unavailable, the PWA shows an explicit
209
- offline shell and no stale fleet state.
188
+ local mode; an unconfigured hostname is refused with a JSON error.
210
189
 
211
- The console provides evidence-separated inventory and status, ACP activity and
190
+ The API provides evidence-separated inventory and status, ACP activity and
212
191
  permission controls, redacted logs, typed text send, confirmed lifecycle
213
192
  actions, and transactional permanent/temporary creation. Identity is fixed to
214
193
  the role name. Creation uses the authenticated
@@ -0,0 +1,15 @@
1
+ import { type OfferedModels } from '../subscriptions/cli.js';
2
+ export interface CodexModelDiscoveryDeps {
3
+ /** The Codex executable ACP sessions will run, and its version. */
4
+ runtime(): Promise<{
5
+ executable: string;
6
+ version: string;
7
+ }>;
8
+ ask(executable: string, env: NodeJS.ProcessEnv): Promise<OfferedModels>;
9
+ now(): number;
10
+ }
11
+ /**
12
+ * The models offered to the active Codex account by the runtime that sessions will actually use.
13
+ * An answer is reused only for the same executable, version, profile and sign-in.
14
+ */
15
+ export declare function createCodexModelDiscovery(overrides?: Partial<CodexModelDiscoveryDeps>): () => Promise<OfferedModels>;
@@ -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
+ }
@@ -1,9 +1,9 @@
1
1
  {
2
- "version": "1.2.0-nightly.34",
3
- "buildId": "1d0ffc344d7e",
4
- "commit": "b17e975b8f21b865f6690fc7299851447b53fdad",
2
+ "version": "1.2.0-nightly.36",
3
+ "buildId": "63df63bcda45",
4
+ "commit": "b4575c95acd1ae2fee42f8f8871bfe9d816a1b1a",
5
5
  "dirty": true,
6
- "builtAt": "2026-10-02T12:17:07.327Z",
6
+ "builtAt": "2026-10-02T18:04:01.351Z",
7
7
  "capabilities": [
8
8
  "workspace.enroll.preserve-profile-v1",
9
9
  "cowork.http-management-v1",
package/dist/cli.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import { ensureMinimalSetup } from './minimal-setup.js';
3
- import { configureWorkspacePort } from './workspace-enrollment.js';
3
+ import { confirmWorkspaceTarget } from './workspace-enrollment.js';
4
4
  import { clearPendingTunnelSetup, readPendingTunnelSetup, requiredPortAfterExpiry, savePendingTunnelSetup, setupTunnelPreflight } from './setup-tunnel-preflight.js';
5
5
  import { availableWebPort } from './web/available-port.js';
6
6
  import QRCode from 'qrcode';
7
- import { readWorkspacePayload, enrollWorkspace } from './workspace-enrollment.js';
7
+ import { readWorkspacePayload, enrollWorkspace, checkWorkspaceConfiguration } from './workspace-enrollment.js';
8
8
  import { waitForRoleDaemon } from './startup-readiness.js';
9
9
  import { SupervisorOursTools } from './application/supervisor-ours-tools.js';
10
10
  import { runTempSupervisor, TEMP_RECYCLE_EXIT } from './temp-supervisor-recovery.js';
@@ -1394,7 +1394,7 @@ cOpt(program.command('migrate-role-defaults')
1394
1394
  die(error);
1395
1395
  }
1396
1396
  });
1397
- const webCommand = cOpt(program.command('web').description('start or open the secure localhost fleet web console'))
1397
+ const webCommand = cOpt(program.command('web').description('start the Fleet HTTP service used by the App'))
1398
1398
  .enablePositionalOptions()
1399
1399
  .option('--port <port>', 'loopback service port (default: 49271)', value => {
1400
1400
  const port = Number(value);
@@ -1402,7 +1402,7 @@ const webCommand = cOpt(program.command('web').description('start or open the se
1402
1402
  throw new Error('invalid port');
1403
1403
  return port;
1404
1404
  })
1405
- .option('--no-open', 'do not open a browser automatically')
1405
+ .option('--no-open', 'accepted for existing service units; Fleet opens no browser')
1406
1406
  .option('--bind <address>', 'explicit listen address (default: 127.0.0.1)')
1407
1407
  .option('--public-origin <url>', 'browser origin served by an explicit reverse proxy')
1408
1408
  .option('--password-file <path>', 'configure password protection from an owner-readable file')
@@ -1419,12 +1419,7 @@ const webCommand = cOpt(program.command('web').description('start or open the se
1419
1419
  if (accessNotice)
1420
1420
  process.stdout.write(accessNotice + '\n');
1421
1421
  await manager.start();
1422
- if (opts.open !== false) {
1423
- await requestWebControlWhenReady('open');
1424
- process.stdout.write('Control-panel authentication opened in the browser.\n');
1425
- }
1426
- else
1427
- process.stdout.write('Web service started; run `ours-fleet web open` to pair a browser.\n');
1422
+ process.stdout.write('Fleet service started.\n');
1428
1423
  }
1429
1424
  catch (e) {
1430
1425
  die(e);
@@ -1437,7 +1432,7 @@ const webPort = (command) => cOpt(command)
1437
1432
  throw new Error('invalid port');
1438
1433
  return port;
1439
1434
  });
1440
- const webServe = cOpt(webCommand.command('serve').description('run the web console in the foreground'))
1435
+ const webServe = cOpt(webCommand.command('serve').description('run the Fleet HTTP service in the foreground'))
1441
1436
  .option('--port <port>', 'loopback port (default: 49271; 0 chooses a free port)', value => {
1442
1437
  const port = Number(value);
1443
1438
  if (!Number.isInteger(port) || port < 0 || port > 65_535)
@@ -1445,7 +1440,7 @@ const webServe = cOpt(webCommand.command('serve').description('run the web conso
1445
1440
  return port;
1446
1441
  });
1447
1442
  webServe
1448
- .option('--no-open', 'do not open a browser automatically')
1443
+ .option('--no-open', 'accepted for existing service units; Fleet opens no browser')
1449
1444
  .option('--bind <address>', 'explicit listen address (default: 127.0.0.1)')
1450
1445
  .option('--public-origin <url>', 'browser origin served by an explicit reverse proxy')
1451
1446
  .option('--password-file <path>', 'configure password protection from an owner-readable file')
@@ -1456,15 +1451,12 @@ webServe
1456
1451
  const accessNotice = configureWebAccess(opts);
1457
1452
  const consoleServer = await startWebConsole({
1458
1453
  configPath: opts.configuration, port: opts.port,
1459
- open: opts.open !== false, binPath, bind: opts.bind, publicOrigin: opts.publicOrigin,
1454
+ binPath, bind: opts.bind, publicOrigin: opts.publicOrigin,
1460
1455
  log: line => process.stderr.write(line + '\n'),
1461
1456
  });
1462
1457
  if (accessNotice)
1463
1458
  process.stdout.write(accessNotice + '\n');
1464
1459
  process.stdout.write(`ours-fleet web listening on ${consoleServer.address}\n`);
1465
- process.stdout.write(opts.open !== false
1466
- ? 'Control-panel authentication opened in the browser.\n'
1467
- : 'Run `ours-fleet web open` to authenticate a browser.\n');
1468
1460
  const shutdown = async () => { await consoleServer.close(); process.exit(0); };
1469
1461
  process.once('SIGINT', () => { void shutdown(); });
1470
1462
  process.once('SIGTERM', () => { void shutdown(); });
@@ -1523,16 +1515,6 @@ webCommand.command('uninstall').description('stop and uninstall the owner web se
1523
1515
  die(e);
1524
1516
  }
1525
1517
  });
1526
- webCommand.command('open').description('securely open or re-pair a browser with the running console')
1527
- .action(async () => {
1528
- try {
1529
- await requestWebControl('open');
1530
- process.stdout.write('Control-panel authentication opened in the browser.\n');
1531
- }
1532
- catch (e) {
1533
- die(e);
1534
- }
1535
- });
1536
1518
  async function workspaceEnrollmentCommand(opts, setupTunnel = false) {
1537
1519
  try {
1538
1520
  if (setupTunnel && opts.check && opts.resume)
@@ -1541,6 +1523,7 @@ async function workspaceEnrollmentCommand(opts, setupTunnel = false) {
1541
1523
  throw Error('--check and --resume take no payload file or migration flag');
1542
1524
  if (setupTunnel && opts.check) {
1543
1525
  await setupTunnelPreflight();
1526
+ await checkWorkspaceConfiguration(opts.configuration ?? defaultConfigPath());
1544
1527
  process.stdout.write('Tunnel setup prerequisites are available.\n');
1545
1528
  return;
1546
1529
  }
@@ -1557,6 +1540,7 @@ async function workspaceEnrollmentCommand(opts, setupTunnel = false) {
1557
1540
  const payload = readWorkspacePayload(opts.file);
1558
1541
  if (setupTunnel) {
1559
1542
  await setupTunnelPreflight();
1543
+ await checkWorkspaceConfiguration(opts.configuration ?? defaultConfigPath());
1560
1544
  await ensureMinimalSetup(opts.configuration ?? defaultConfigPath());
1561
1545
  }
1562
1546
  const result = await enrollWorkspace(payload, opts.configuration, { migrateAppOrigin: opts.migrateAppOrigin, preserveProfile: setupTunnel || opts.preserveProfile });
@@ -1629,7 +1613,7 @@ async function finishWorkspaceService(pending, configuration, record) {
1629
1613
  pending = { ...pending, requestedPorts: [...(pending.requestedPorts ?? []), bound.port] };
1630
1614
  savePendingTunnelSetup(pending);
1631
1615
  }
1632
- await configureWorkspacePort(pending, pending.hostWorkspaceId, pending.rootCid, bound.port);
1616
+ await confirmWorkspaceTarget(pending, pending.hostWorkspaceId, pending.rootCid, bound.port, error => { process.stderr.write(`The enrollment contact could not be removed from Messenger (${error instanceof Error ? error.message : String(error)}); it can be removed there by hand.\n`); });
1633
1617
  }
1634
1618
  else if (bound.port !== requiredPort)
1635
1619
  throw Error(`The setup window has expired and the tunnel points at port ${requiredPort}, but this host could only bind port ${bound.port}. Free port ${requiredPort} on this host`);
@@ -1669,20 +1653,6 @@ webCommand.command('revoke-all').description('revoke all trusted browsers and ac
1669
1653
  die(e);
1670
1654
  }
1671
1655
  });
1672
- async function requestWebControlWhenReady(command) {
1673
- let last;
1674
- for (let attempt = 0; attempt < 40; attempt++) {
1675
- try {
1676
- await requestWebControl(command, undefined, 500);
1677
- return;
1678
- }
1679
- catch (error) {
1680
- last = error;
1681
- await new Promise(resolve => setTimeout(resolve, 125));
1682
- }
1683
- }
1684
- throw last;
1685
- }
1686
1656
  function configureWebAccess(opts) {
1687
1657
  if (opts.publicOrigin)
1688
1658
  validatePublicOrigin(opts.publicOrigin);
package/dist/config.d.ts CHANGED
@@ -311,6 +311,8 @@ export declare function loadConfig(configPath?: string, options?: {
311
311
  temporary?: boolean;
312
312
  };
313
313
  skipWatchdogs?: boolean;
314
+ /** The one Owner invitation file that tunnel setup writes itself and that may therefore still be absent. */
315
+ deferredOwnerInviteFile?: string;
314
316
  }): FleetConfig;
315
317
  /** Full read-only Agent resolution used by launch dry-runs and room plan validation. */
316
318
  export declare function resolveAgentDefinitionDryRun(configPath: string, id: string, definition: AgentDefinition): ResolvedRole;
package/dist/config.js CHANGED
@@ -764,7 +764,7 @@ export function loadConfig(configPath, options = {}) {
764
764
  if (doc.rooms !== undefined) {
765
765
  if (rooms)
766
766
  throw new ConfigError(`rooms: defined in multiple files; last: ${file}`);
767
- const validated = validateRoomsConfig(deepSub(doc.rooms, vars), vars, file);
767
+ const validated = validateRoomsConfig(deepSub(doc.rooms, vars), vars, file, options.deferredOwnerInviteFile);
768
768
  ownerInviteFingerprint = validated._invite?.fingerprint;
769
769
  ownerInvite = validated._invite?.value;
770
770
  const { _invite: _, ...clean } = validated;