@phnx-labs/agents-cli 1.22.46 → 1.22.49

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 (348) hide show
  1. package/CHANGELOG.md +663 -0
  2. package/LICENSE +102 -182
  3. package/README.md +96 -49
  4. package/dist/bootstrap.js +4 -2
  5. package/dist/cli/command-registry.d.ts +2 -1
  6. package/dist/cli/command-registry.js +6 -2
  7. package/dist/commands/accounts.d.ts +58 -0
  8. package/dist/commands/accounts.js +243 -25
  9. package/dist/commands/artifacts.js +7 -6
  10. package/dist/commands/attach.js +1 -1
  11. package/dist/commands/auth.js +7 -5
  12. package/dist/commands/browser-sessions-picker.js +9 -7
  13. package/dist/commands/browser.js +711 -62
  14. package/dist/commands/config.d.ts +0 -1
  15. package/dist/commands/config.js +26 -24
  16. package/dist/commands/cost.d.ts +1 -1
  17. package/dist/commands/daemon.d.ts +21 -0
  18. package/dist/commands/daemon.js +147 -12
  19. package/dist/commands/detach.d.ts +13 -0
  20. package/dist/commands/detach.js +11 -8
  21. package/dist/commands/exec.js +107 -53
  22. package/dist/commands/feed-watch.d.ts +2 -0
  23. package/dist/commands/feed-watch.js +28 -0
  24. package/dist/commands/feed.js +27 -0
  25. package/dist/commands/feedback.js +3 -19
  26. package/dist/commands/focus.d.ts +14 -0
  27. package/dist/commands/focus.js +48 -5
  28. package/dist/commands/go.d.ts +3 -0
  29. package/dist/commands/go.js +16 -3
  30. package/dist/commands/insights.d.ts +1 -1
  31. package/dist/commands/insights.js +2 -2
  32. package/dist/commands/inspect.js +2 -2
  33. package/dist/commands/lease.d.ts +1 -1
  34. package/dist/commands/lease.js +7 -6
  35. package/dist/commands/mailboxes.js +4 -3
  36. package/dist/commands/menubar.js +11 -4
  37. package/dist/commands/projects.d.ts +16 -1
  38. package/dist/commands/projects.js +58 -64
  39. package/dist/commands/resume.js +1 -1
  40. package/dist/commands/route.js +4 -4
  41. package/dist/commands/routines.js +4 -3
  42. package/dist/commands/run-broadcast.d.ts +1 -1
  43. package/dist/commands/run-broadcast.js +1 -1
  44. package/dist/commands/sessions-picker-factory.d.ts +2 -1
  45. package/dist/commands/sessions-picker-factory.js +1 -1
  46. package/dist/commands/sessions-picker.d.ts +22 -0
  47. package/dist/commands/sessions-picker.js +48 -9
  48. package/dist/commands/sessions-stop.d.ts +24 -0
  49. package/dist/commands/sessions-stop.js +66 -0
  50. package/dist/commands/sessions-trace.d.ts +82 -0
  51. package/dist/commands/sessions-trace.js +387 -0
  52. package/dist/commands/sessions.js +5 -0
  53. package/dist/commands/setup-secrets.js +23 -0
  54. package/dist/commands/share.d.ts +20 -5
  55. package/dist/commands/share.js +152 -52
  56. package/dist/commands/ssh.d.ts +15 -0
  57. package/dist/commands/ssh.js +243 -18
  58. package/dist/commands/teams.js +34 -2
  59. package/dist/commands/traces.d.ts +2 -0
  60. package/dist/commands/traces.js +184 -0
  61. package/dist/commands/view.d.ts +2 -0
  62. package/dist/commands/view.js +32 -62
  63. package/dist/commands/watchdog.js +9 -14
  64. package/dist/index.d.ts +1 -0
  65. package/dist/index.js +5 -0
  66. package/dist/lib/account-capabilities.d.ts +4 -0
  67. package/dist/lib/account-capabilities.js +13 -9
  68. package/dist/lib/account-registry.d.ts +2 -0
  69. package/dist/lib/account-registry.js +30 -2
  70. package/dist/lib/accounting/rotate.d.ts +9 -0
  71. package/dist/lib/accounting/rotate.js +12 -2
  72. package/dist/lib/accounting/usage.d.ts +84 -6
  73. package/dist/lib/accounting/usage.js +293 -75
  74. package/dist/lib/agent-modes.js +29 -1
  75. package/dist/lib/agent-spec/agents.d.ts +4 -3
  76. package/dist/lib/agent-spec/agents.js +25 -15
  77. package/dist/lib/analytics/mix-commands.d.ts +1 -1
  78. package/dist/lib/analytics/mix-commands.js +2 -2
  79. package/dist/lib/auth-health.d.ts +13 -3
  80. package/dist/lib/auth-health.js +50 -8
  81. package/dist/lib/browser/devices.d.ts +19 -0
  82. package/dist/lib/browser/devices.js +23 -0
  83. package/dist/lib/browser/drivers/ssh.d.ts +16 -2
  84. package/dist/lib/browser/drivers/ssh.js +36 -9
  85. package/dist/lib/browser/ipc.d.ts +1 -1
  86. package/dist/lib/browser/ipc.js +40 -9
  87. package/dist/lib/browser/profiles.d.ts +104 -65
  88. package/dist/lib/browser/profiles.js +277 -165
  89. package/dist/lib/browser/registry.d.ts +39 -0
  90. package/dist/lib/browser/registry.js +149 -0
  91. package/dist/lib/browser/remote-control.d.ts +28 -2
  92. package/dist/lib/browser/remote-control.js +35 -3
  93. package/dist/lib/browser/resolve-target.d.ts +68 -0
  94. package/dist/lib/browser/resolve-target.js +250 -0
  95. package/dist/lib/browser/runtime-state.d.ts +44 -11
  96. package/dist/lib/browser/runtime-state.js +98 -15
  97. package/dist/lib/browser/service.d.ts +65 -9
  98. package/dist/lib/browser/service.js +196 -61
  99. package/dist/lib/browser/sessions-list.d.ts +1 -3
  100. package/dist/lib/browser/sessions-list.js +3 -16
  101. package/dist/lib/browser/task-index.d.ts +70 -0
  102. package/dist/lib/browser/task-index.js +180 -0
  103. package/dist/lib/browser/types.d.ts +12 -1
  104. package/dist/lib/byok-usage.js +2 -2
  105. package/dist/lib/claude-statusline.d.ts +29 -0
  106. package/dist/lib/claude-statusline.js +139 -0
  107. package/dist/lib/cloud/host.d.ts +1 -1
  108. package/dist/lib/cloud/host.js +1 -1
  109. package/dist/lib/cloud/rush.js +1 -1
  110. package/dist/lib/codex-policy.d.ts +11 -1
  111. package/dist/lib/codex-policy.js +20 -5
  112. package/dist/lib/computer/computer-rpc.js +2 -2
  113. package/dist/lib/computer/download.d.ts +15 -15
  114. package/dist/lib/computer/download.js +35 -98
  115. package/dist/lib/computer/ssh-tunnel.d.ts +0 -3
  116. package/dist/lib/computer/ssh-tunnel.js +12 -22
  117. package/dist/lib/config-keys.d.ts +6 -11
  118. package/dist/lib/config-keys.js +18 -19
  119. package/dist/lib/crabbox/cli.d.ts +1 -1
  120. package/dist/lib/crabbox/cli.js +2 -2
  121. package/dist/lib/crabbox/lease.d.ts +9 -0
  122. package/dist/lib/crabbox/lease.js +70 -15
  123. package/dist/lib/crabbox/runtimes.js +1 -1
  124. package/dist/lib/daemon/account-state-daemon-service.d.ts +16 -0
  125. package/dist/lib/daemon/account-state-daemon-service.js +26 -0
  126. package/dist/lib/daemon/browser-ipc-service.d.ts +20 -0
  127. package/dist/lib/daemon/browser-ipc-service.js +46 -0
  128. package/dist/lib/daemon/daemon.d.ts +3 -0
  129. package/dist/lib/daemon/daemon.js +212 -444
  130. package/dist/lib/daemon/device-probe-service.d.ts +26 -0
  131. package/dist/lib/daemon/device-probe-service.js +47 -0
  132. package/dist/lib/daemon/keychain-reap-service.d.ts +17 -0
  133. package/dist/lib/daemon/keychain-reap-service.js +32 -0
  134. package/dist/lib/daemon/monitor-engine-service.d.ts +22 -0
  135. package/dist/lib/daemon/monitor-engine-service.js +29 -0
  136. package/dist/lib/daemon/runner.js +15 -2
  137. package/dist/lib/daemon/secrets-broker-service.d.ts +20 -0
  138. package/dist/lib/daemon/secrets-broker-service.js +66 -0
  139. package/dist/lib/daemon/self-heal-service.d.ts +27 -0
  140. package/dist/lib/daemon/self-heal-service.js +48 -0
  141. package/dist/lib/daemon/service.d.ts +102 -0
  142. package/dist/lib/daemon/service.js +98 -0
  143. package/dist/lib/daemon/session-index-service.d.ts +22 -0
  144. package/dist/lib/daemon/session-index-service.js +40 -0
  145. package/dist/lib/daemon/state-dir-check-service.d.ts +43 -0
  146. package/dist/lib/daemon/state-dir-check-service.js +63 -0
  147. package/dist/lib/daemon/supervisor.d.ts +87 -0
  148. package/dist/lib/daemon/supervisor.js +298 -0
  149. package/dist/lib/daemon/watchdog-service.d.ts +19 -0
  150. package/dist/lib/daemon/watchdog-service.js +40 -0
  151. package/dist/lib/daemon-health.d.ts +15 -0
  152. package/dist/lib/daemon-health.js +29 -5
  153. package/dist/lib/daemon-services.d.ts +8 -1
  154. package/dist/lib/daemon-services.js +55 -0
  155. package/dist/lib/daemon-ticks.d.ts +13 -2
  156. package/dist/lib/daemon-ticks.js +22 -20
  157. package/dist/lib/device-config.d.ts +25 -10
  158. package/dist/lib/device-config.js +90 -39
  159. package/dist/lib/devices/config-migration.d.ts +7 -0
  160. package/dist/lib/devices/config-migration.js +67 -3
  161. package/dist/lib/devices/health.d.ts +27 -2
  162. package/dist/lib/devices/health.js +39 -9
  163. package/dist/lib/devices/interactive-host.d.ts +15 -0
  164. package/dist/lib/devices/interactive-host.js +53 -0
  165. package/dist/lib/devices/registry.d.ts +61 -4
  166. package/dist/lib/devices/registry.js +94 -38
  167. package/dist/lib/devices/stats-cache.d.ts +26 -0
  168. package/dist/lib/devices/stats-cache.js +59 -7
  169. package/dist/lib/devices/worker-pick.d.ts +48 -0
  170. package/dist/lib/devices/worker-pick.js +113 -0
  171. package/dist/lib/exec.d.ts +70 -14
  172. package/dist/lib/exec.js +110 -38
  173. package/dist/lib/feed/answer.d.ts +29 -0
  174. package/dist/lib/feed/answer.js +145 -0
  175. package/dist/lib/feed/attention.d.ts +83 -0
  176. package/dist/lib/feed/attention.js +0 -0
  177. package/dist/lib/feed/feed.d.ts +109 -0
  178. package/dist/lib/feed/feed.js +154 -3
  179. package/dist/lib/feed/pr-status.d.ts +14 -0
  180. package/dist/lib/feed/pr-status.js +47 -0
  181. package/dist/lib/feed/watch.d.ts +59 -0
  182. package/dist/lib/feed/watch.js +180 -0
  183. package/dist/lib/fleet/capture.js +6 -0
  184. package/dist/lib/fleet/remote-login.js +8 -3
  185. package/dist/lib/fleet/types.d.ts +17 -0
  186. package/dist/lib/harness/adapter.d.ts +11 -0
  187. package/dist/lib/harness/adapters/claude.js +38 -24
  188. package/dist/lib/harness/adapters/codex.js +2 -4
  189. package/dist/lib/harness/adapters/cursor.js +8 -11
  190. package/dist/lib/helper-download.d.ts +108 -0
  191. package/dist/lib/helper-download.js +194 -0
  192. package/dist/lib/helper-versions.d.ts +52 -0
  193. package/dist/lib/helper-versions.js +58 -0
  194. package/dist/lib/hooks/cache.js +19 -0
  195. package/dist/lib/hooks/install.js +2 -2
  196. package/dist/lib/hooks/match.d.ts +3 -0
  197. package/dist/lib/hooks/match.js +25 -0
  198. package/dist/lib/hosts/credentials.d.ts +1 -1
  199. package/dist/lib/hosts/credentials.js +1 -1
  200. package/dist/lib/hosts/dispatch.d.ts +7 -1
  201. package/dist/lib/hosts/dispatch.js +24 -5
  202. package/dist/lib/hosts/passthrough.d.ts +8 -15
  203. package/dist/lib/hosts/passthrough.js +35 -16
  204. package/dist/lib/hosts/providers/devices.d.ts +1 -1
  205. package/dist/lib/hosts/providers/devices.js +1 -1
  206. package/dist/lib/hosts/reconnect.d.ts +179 -21
  207. package/dist/lib/hosts/reconnect.js +266 -45
  208. package/dist/lib/hosts/registry.js +7 -0
  209. package/dist/lib/installations/migrate.d.ts +4 -5
  210. package/dist/lib/installations/migrate.js +6 -7
  211. package/dist/lib/installations/shims.d.ts +1 -1
  212. package/dist/lib/installations/shims.js +23 -13
  213. package/dist/lib/installations/versions.js +25 -2
  214. package/dist/lib/linear-autoclose.d.ts +1 -1
  215. package/dist/lib/linear-autoclose.js +1 -1
  216. package/dist/lib/loop.d.ts +2 -2
  217. package/dist/lib/loop.js +1 -1
  218. package/dist/lib/menubar/download-menubar.d.ts +47 -0
  219. package/dist/lib/menubar/download-menubar.js +60 -0
  220. package/dist/lib/menubar/install-menubar.d.ts +44 -7
  221. package/dist/lib/menubar/install-menubar.js +105 -23
  222. package/dist/lib/menubar/notify-desktop.d.ts +3 -3
  223. package/dist/lib/menubar/notify-desktop.js +6 -6
  224. package/dist/lib/model-tiers.d.ts +1 -1
  225. package/dist/lib/open-url.d.ts +60 -2
  226. package/dist/lib/open-url.js +167 -12
  227. package/dist/lib/project-probe.d.ts +1 -1
  228. package/dist/lib/project-probe.js +1 -1
  229. package/dist/lib/project-pull.d.ts +1 -1
  230. package/dist/lib/project-pull.js +2 -2
  231. package/dist/lib/projects.d.ts +1 -1
  232. package/dist/lib/projects.js +1 -1
  233. package/dist/lib/refresh-coordinator.d.ts +1 -1
  234. package/dist/lib/refresh-coordinator.js +1 -1
  235. package/dist/lib/sandbox.js +6 -7
  236. package/dist/lib/secrets/download-keychain.d.ts +47 -0
  237. package/dist/lib/secrets/download-keychain.js +70 -0
  238. package/dist/lib/secrets/install-helper.d.ts +20 -1
  239. package/dist/lib/secrets/install-helper.js +44 -3
  240. package/dist/lib/session/active.d.ts +67 -0
  241. package/dist/lib/session/active.js +86 -2
  242. package/dist/lib/session/db.d.ts +11 -1
  243. package/dist/lib/session/db.js +142 -8
  244. package/dist/lib/session/discover.d.ts +23 -1
  245. package/dist/lib/session/discover.js +44 -10
  246. package/dist/lib/session/highlights.d.ts +49 -1
  247. package/dist/lib/session/highlights.js +95 -0
  248. package/dist/lib/session/host-link.d.ts +16 -2
  249. package/dist/lib/session/host-link.js +7 -1
  250. package/dist/lib/session/parse.js +33 -1
  251. package/dist/lib/session/prompt.d.ts +35 -0
  252. package/dist/lib/session/prompt.js +56 -0
  253. package/dist/lib/session/remote/remote-list.d.ts +9 -0
  254. package/dist/lib/session/remote/remote-list.js +19 -2
  255. package/dist/lib/session/remote/watch.d.ts +1 -1
  256. package/dist/lib/session/remote/watch.js +17 -3
  257. package/dist/lib/session/render.js +7 -3
  258. package/dist/lib/session/session-cache.d.ts +53 -0
  259. package/dist/lib/session/session-cache.js +93 -1
  260. package/dist/lib/session/state.js +1 -1
  261. package/dist/lib/session/tool-calls.d.ts +2 -0
  262. package/dist/lib/session/tool-calls.js +1 -1
  263. package/dist/lib/session/trajectory-compare.d.ts +47 -0
  264. package/dist/lib/session/trajectory-compare.js +116 -0
  265. package/dist/lib/session/trajectory-html.d.ts +19 -0
  266. package/dist/lib/session/trajectory-html.js +770 -0
  267. package/dist/lib/session/trajectory-lineage.d.ts +92 -0
  268. package/dist/lib/session/trajectory-lineage.js +195 -0
  269. package/dist/lib/session/trajectory-text.d.ts +37 -0
  270. package/dist/lib/session/trajectory-text.js +284 -0
  271. package/dist/lib/session/trajectory.d.ts +102 -0
  272. package/dist/lib/session/trajectory.js +384 -0
  273. package/dist/lib/session/types.d.ts +15 -0
  274. package/dist/lib/sha256-asset.d.ts +26 -0
  275. package/dist/lib/sha256-asset.js +41 -0
  276. package/dist/lib/share/backend.d.ts +95 -0
  277. package/dist/lib/share/backend.js +139 -0
  278. package/dist/lib/share/delete.d.ts +6 -2
  279. package/dist/lib/share/delete.js +8 -9
  280. package/dist/lib/share/html.d.ts +22 -0
  281. package/dist/lib/share/html.js +88 -0
  282. package/dist/lib/share/provision.d.ts +18 -4
  283. package/dist/lib/share/provision.js +38 -4
  284. package/dist/lib/share/publish.d.ts +39 -15
  285. package/dist/lib/share/publish.js +55 -26
  286. package/dist/lib/share/worker-template.js +171 -11
  287. package/dist/lib/sqlite.js +16 -3
  288. package/dist/lib/ssh-exec.d.ts +65 -0
  289. package/dist/lib/ssh-exec.js +120 -4
  290. package/dist/lib/startup/command-registry.d.ts +3 -1
  291. package/dist/lib/startup/command-registry.js +6 -3
  292. package/dist/lib/startup/dev-build.js +3 -3
  293. package/dist/lib/state.d.ts +2 -2
  294. package/dist/lib/state.js +11 -5
  295. package/dist/lib/subagents-registry.js +1 -1
  296. package/dist/lib/teams/agents.js +9 -0
  297. package/dist/lib/terminal/index.d.ts +1 -1
  298. package/dist/lib/terminal/inject.d.ts +19 -0
  299. package/dist/lib/terminal/inject.js +19 -9
  300. package/dist/lib/terminal/types.d.ts +1 -1
  301. package/dist/lib/terminal/types.js +1 -1
  302. package/dist/lib/tmux/orphan-reap.js +1 -1
  303. package/dist/lib/tmux/session.d.ts +46 -13
  304. package/dist/lib/tmux/session.js +204 -27
  305. package/dist/lib/traces/backend.d.ts +29 -0
  306. package/dist/lib/traces/backend.js +46 -0
  307. package/dist/lib/traces/classify.d.ts +52 -0
  308. package/dist/lib/traces/classify.js +72 -0
  309. package/dist/lib/traces/config.d.ts +10 -0
  310. package/dist/lib/traces/config.js +2 -0
  311. package/dist/lib/traces/provision.d.ts +19 -0
  312. package/dist/lib/traces/provision.js +30 -0
  313. package/dist/lib/traces/sync.d.ts +150 -0
  314. package/dist/lib/traces/sync.js +447 -0
  315. package/dist/lib/traces/worker-template.d.ts +4 -0
  316. package/dist/lib/traces/worker-template.js +159 -0
  317. package/dist/lib/types.d.ts +34 -19
  318. package/dist/lib/types.js +14 -0
  319. package/dist/lib/usage-backoff.d.ts +2 -1
  320. package/dist/lib/usage-backoff.js +60 -19
  321. package/dist/lib/usage-refresh.d.ts +18 -4
  322. package/dist/lib/usage-refresh.js +68 -19
  323. package/dist/lib/watchdog/log.d.ts +1 -1
  324. package/dist/lib/watchdog/log.js +1 -1
  325. package/dist/lib/watchdog/runner.d.ts +36 -45
  326. package/dist/lib/watchdog/runner.js +150 -119
  327. package/dist/lib/watchdog/service.d.ts +0 -1
  328. package/dist/lib/watchdog/service.js +0 -1
  329. package/dist/lib/watchdog/watchdog-agent.d.ts +38 -0
  330. package/dist/lib/watchdog/watchdog-agent.js +59 -0
  331. package/dist/lib/watchdog/watchdog.d.ts +11 -2
  332. package/dist/lib/watchdog/watchdog.js +37 -104
  333. package/dist/lib/workflows.d.ts +1 -1
  334. package/package.json +5 -7
  335. package/dist/commands/usage.d.ts +0 -27
  336. package/dist/commands/usage.js +0 -96
  337. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  338. package/dist/lib/menubar/MenubarHelper.app/Contents/Info.plist +0 -24
  339. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  340. package/dist/lib/menubar/MenubarHelper.app/Contents/Resources/AppIcon.icns +0 -0
  341. package/dist/lib/menubar/MenubarHelper.app/Contents/_CodeSignature/CodeResources +0 -128
  342. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  343. package/dist/lib/secrets/Agents CLI.app/Contents/Info.plist +0 -24
  344. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  345. package/dist/lib/secrets/Agents CLI.app/Contents/_CodeSignature/CodeResources +0 -123
  346. package/dist/lib/secrets/Agents CLI.app/Contents/embedded.provisionprofile +0 -0
  347. package/dist/lib/usage-fleet.d.ts +0 -32
  348. package/dist/lib/usage-fleet.js +0 -125
@@ -0,0 +1,139 @@
1
+ /**
2
+ * ShareBackend — the token-source seam for `agents artifacts share`.
3
+ *
4
+ * Two legitimate principals, picked once at publish time:
5
+ * - **managed**: the caller is signed in to Phoenix (`readSession()`), no
6
+ * explicit BYO override. Token is the Phoenix access_token; endpoint is
7
+ * the already-live `share.agents-cli.sh`. Zero Cloudflare setup.
8
+ * - **byo**: the existing static WRITE_TOKEN path (`readShareConfig()` +
9
+ * `readWriteToken()`). Unchanged for power users / custom domains / fleet
10
+ * injection of `SHARE_WRITE_TOKEN`.
11
+ *
12
+ * Dispatch is not a fallback: signed-in AND no BYO override → managed;
13
+ * otherwise BYO. Fail loud when neither principal can authenticate.
14
+ *
15
+ * Explicit BYO override (any one is enough):
16
+ * - `opts.byo === true`
17
+ * - `opts.writeToken` (a caller-supplied static token, including tests)
18
+ * - `AGENTS_SHARE_BACKEND=byo`
19
+ */
20
+ import { PHOENIX_ID_BASE, readSession } from '../identity/client.js';
21
+ import { DEFAULT_SHARE_DOMAIN, readShareConfig, readWriteToken, readWriteTokenEnv, } from './config.js';
22
+ /** Env var that forces the BYO path. Value must be exactly `byo`. */
23
+ export const SHARE_BACKEND_ENV = 'AGENTS_SHARE_BACKEND';
24
+ /** URL-safe namespace: lowercase `[a-z0-9-]+`. Matches the Worker's sanitize.
25
+ *
26
+ * This is URL-safety, not collision-resistance: two values that differ only
27
+ * in case or punctuation share a prefix. */
28
+ export function sanitizeShareNamespace(s) {
29
+ return s.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
30
+ }
31
+ /**
32
+ * Public managed-share handle from a verified email.
33
+ *
34
+ * `muqsitnawaz@gmail.com` → `muqsitnawaz`. Plus-tags are dropped
35
+ * (`muqsitnawaz+dev@gmail.com` → `muqsitnawaz`) so the URL stays the
36
+ * account's default name. Empty / missing email → `''` (caller falls
37
+ * back to userId). Must match the Worker `handleFromEmail`.
38
+ */
39
+ export function handleFromEmail(email) {
40
+ if (!email)
41
+ return '';
42
+ const local = email.split('@')[0] ?? '';
43
+ const beforePlus = local.split('+')[0] ?? local;
44
+ return sanitizeShareNamespace(beforePlus);
45
+ }
46
+ /** Managed URL namespace: email handle, else sanitized userId (never empty if either is set). */
47
+ export function managedShareHandle(session) {
48
+ return handleFromEmail(session.email) || sanitizeShareNamespace(session.userId ?? '');
49
+ }
50
+ export function managedShareBaseUrl() {
51
+ return `https://${DEFAULT_SHARE_DOMAIN}`;
52
+ }
53
+ function shareEndpointHost(value) {
54
+ return value.replace(/^https?:\/\//i, '').replace(/\/+$/, '').toLowerCase();
55
+ }
56
+ /**
57
+ * True when this config is the platform managed endpoint (`share.agents-cli.sh`).
58
+ * The deploy path uses this — not "the caller is signed in" — to decide whether
59
+ * to bind `PHOENIX_ID_BASE` on the Worker.
60
+ */
61
+ export function isManagedShareEndpoint(cfg) {
62
+ const managedHost = DEFAULT_SHARE_DOMAIN.toLowerCase();
63
+ if (cfg.domain && shareEndpointHost(cfg.domain) === managedHost)
64
+ return true;
65
+ if (cfg.baseUrl && shareEndpointHost(cfg.baseUrl) === managedHost)
66
+ return true;
67
+ return false;
68
+ }
69
+ /**
70
+ * Phoenix ID URL to bind on a managed Worker deploy. `undefined` for a
71
+ * pure-BYO Worker (WRITE_TOKEN only). Fail loud if this is a managed deploy
72
+ * but the base is empty — never skip-set a blank secret.
73
+ */
74
+ export function phoenixIdBaseForDeploy(opts = {}, cfg) {
75
+ const managed = opts.managed === true || (cfg != null && isManagedShareEndpoint(cfg));
76
+ if (!managed)
77
+ return undefined;
78
+ const base = PHOENIX_ID_BASE.replace(/\/+$/, '').trim();
79
+ if (!base) {
80
+ throw new Error('Managed share deploy requires PHOENIX_ID_BASE so the Worker can verify Phoenix bearers. Set the PHOENIX_ID_BASE env var.');
81
+ }
82
+ return base;
83
+ }
84
+ /**
85
+ * Pick the principal. Signed-in (`readSession() != null`) AND no explicit BYO
86
+ * override → managed; otherwise BYO.
87
+ */
88
+ export function shouldUseManaged(opts = {}) {
89
+ if (opts.byo === true)
90
+ return false;
91
+ if (opts.writeToken)
92
+ return false;
93
+ if ((process.env[SHARE_BACKEND_ENV] ?? '').trim().toLowerCase() === 'byo')
94
+ return false;
95
+ const session = opts.session === undefined ? readSession() : opts.session;
96
+ return session != null;
97
+ }
98
+ export function resolveShareBackend(opts = {}) {
99
+ if (shouldUseManaged(opts)) {
100
+ const session = opts.session === undefined ? readSession() : opts.session;
101
+ if (!session) {
102
+ throw new Error("Not signed in. Run 'agents auth login'.");
103
+ }
104
+ return resolveManagedBackend(session);
105
+ }
106
+ return resolveByoBackend(opts);
107
+ }
108
+ function resolveManagedBackend(session) {
109
+ if (!session.access_token) {
110
+ throw new Error("Not signed in. Run 'agents auth login'.");
111
+ }
112
+ const namespace = managedShareHandle(session);
113
+ if (!namespace) {
114
+ throw new Error("Signed in but the session has no email or user id. Run 'agents auth login' again.");
115
+ }
116
+ return {
117
+ kind: 'managed',
118
+ baseUrl: managedShareBaseUrl(),
119
+ token: session.access_token,
120
+ namespace,
121
+ };
122
+ }
123
+ function resolveByoBackend(opts) {
124
+ const cfg = opts.config ?? readShareConfig();
125
+ if (!cfg) {
126
+ throw new Error("Not set up yet. Run 'agents auth login' to publish on the managed endpoint (zero Cloudflare setup), or 'agents artifacts setup' / 'agents artifacts share join' for your own Cloudflare.");
127
+ }
128
+ const token = opts.writeToken ??
129
+ (opts.requireToken === false ? (readWriteTokenEnv() ?? '') : readWriteToken());
130
+ // Namespace is the GitHub username. An explicit --github-user is sanitized
131
+ // here; otherwise publish fills it via resolveShareUsername (gh/git config).
132
+ const namespace = opts.githubUser ? sanitizeShareNamespace(opts.githubUser) : '';
133
+ return {
134
+ kind: 'byo',
135
+ baseUrl: cfg.baseUrl.replace(/\/+$/, ''),
136
+ token,
137
+ namespace,
138
+ };
139
+ }
@@ -68,7 +68,7 @@ export interface DeleteShareOptions {
68
68
  /** Skip deleting the target's retained revisions (`<key>/rev-*`, RUSH-2683
69
69
  * revision retention) — default: delete them too. A republished-then-deleted
70
70
  * share would otherwise leave its prior world-readable versions live for up
71
- * to the bucket's lifecycle max-age (see docs/share.md §Revisions). */
71
+ * to the bucket's lifecycle max-age (see docs/distribution.md). */
72
72
  keepRevisions?: boolean;
73
73
  /** Treat an already-missing target as a no-op success instead of an error
74
74
  * (mirrors SQL's `DROP ... IF EXISTS`). Default: missing target is an error. */
@@ -77,8 +77,12 @@ export interface DeleteShareOptions {
77
77
  githubUser?: string;
78
78
  /** DI seam for tests — override the persisted share endpoint config. */
79
79
  config?: ShareConfig;
80
- /** DI seam for tests — override the keychain-backed write token. */
80
+ /** DI seam for tests — override the keychain-backed write token. Selects BYO. */
81
81
  writeToken?: string;
82
+ /** DI seam for tests — override `readSession()`. `null` means signed out. */
83
+ session?: import('../identity/client.js').PhoenixSession | null;
84
+ /** Force the BYO Cloudflare path even when signed in. */
85
+ byo?: boolean;
82
86
  /** DI seam for tests — override the real HTTP DELETE. */
83
87
  deleter?: DeleteFn;
84
88
  /** DI seam for tests — override the real HTTP existence check. */
@@ -7,7 +7,7 @@
7
7
  // returns `{"ok":true}` — so `{"ok":true}` alone is never proof of a takedown.
8
8
  // Every delete here is followed by a status check that must observe 404 before
9
9
  // the operation is reported as successful.
10
- import { readShareConfig, readWriteToken } from './config.js';
10
+ import { resolveShareBackend } from './backend.js';
11
11
  import { buildShareKey, resolveShareUsername } from './publish.js';
12
12
  /**
13
13
  * Normalize any of the three accepted target forms to the R2 key that publish
@@ -103,7 +103,7 @@ export async function deleteObject(endpoint, key, opts = {}) {
103
103
  const existedBefore = before.status !== 404;
104
104
  const r = await del(url, { authorization: `Bearer ${endpoint.token}` });
105
105
  if (!r.ok) {
106
- throw new Error(`Delete failed (${r.status}) for ${url}. Check the write token, or that 'agents artifacts setup' completed.`);
106
+ throw new Error(`Delete failed (${r.status}) for ${url}. Check the bearer (Phoenix session or WRITE_TOKEN), or that 'agents artifacts setup' completed.`);
107
107
  }
108
108
  const after = await check(url);
109
109
  const verified404 = after.status === 404;
@@ -113,13 +113,12 @@ export async function deleteObject(endpoint, key, opts = {}) {
113
113
  * are gone. Throws on an unverified takedown — never reports success for an
114
114
  * object that still resolves. */
115
115
  export async function deleteShare(target, opts = {}) {
116
- const cfg = opts.config ?? readShareConfig();
117
- if (!cfg) {
118
- throw new Error("Not set up yet. Run 'agents artifacts setup' (provision your own endpoint) or 'agents artifacts share join' (use an existing one).");
119
- }
120
- const token = opts.writeToken ?? readWriteToken();
121
- const resolved = await resolveDeleteTarget(target, { githubUser: opts.githubUser });
122
- const endpoint = { baseUrl: cfg.baseUrl, token };
116
+ const backend = resolveShareBackend(opts);
117
+ const githubUser = backend.kind === 'managed'
118
+ ? backend.namespace
119
+ : opts.githubUser || backend.namespace || undefined;
120
+ const resolved = await resolveDeleteTarget(target, { githubUser });
121
+ const endpoint = { baseUrl: backend.baseUrl, token: backend.token };
123
122
  const page = await deleteObject(endpoint, resolved.key, { deleter: opts.deleter, checker: opts.checker });
124
123
  if (!page.existedBefore) {
125
124
  if (opts.ifExists) {
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Make an HTML page self-contained enough to view on share.agents-cli.sh.
3
+ *
4
+ * Chrome "Save as" (and some renderers) leave `file:///…html#section` TOC
5
+ * links and sibling image paths. Those work on disk and 404 on the share
6
+ * Worker, which only stores the one PUT body. Rewrite same-document file
7
+ * anchors to `#section`, and inline local image files as data URIs.
8
+ *
9
+ * https citations, data: URIs already in the page, and missing files are
10
+ * left alone. This is not a bundler — it only fixes what would otherwise
11
+ * render as a broken page after a single-file publish.
12
+ */
13
+ /** Skip inlining a sibling that would bloat the page past a reasonable PUT. */
14
+ export declare const MAX_INLINE_BYTES: number;
15
+ /**
16
+ * `href="file:///tmp/page.html#purpose"` → `href="#purpose"`.
17
+ * Bare `file:///tmp/page.html` (no hash) becomes `href="#"`.
18
+ */
19
+ export declare function rewriteFileAnchors(html: string): string;
20
+ /** Replace local image src/href with a data URI when the file exists next to the page. */
21
+ export declare function inlineLocalAssets(html: string, htmlPath: string): string;
22
+ export declare function prepareShareHtml(html: string, htmlPath: string): string;
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Make an HTML page self-contained enough to view on share.agents-cli.sh.
3
+ *
4
+ * Chrome "Save as" (and some renderers) leave `file:///…html#section` TOC
5
+ * links and sibling image paths. Those work on disk and 404 on the share
6
+ * Worker, which only stores the one PUT body. Rewrite same-document file
7
+ * anchors to `#section`, and inline local image files as data URIs.
8
+ *
9
+ * https citations, data: URIs already in the page, and missing files are
10
+ * left alone. This is not a bundler — it only fixes what would otherwise
11
+ * render as a broken page after a single-file publish.
12
+ */
13
+ import { existsSync, readFileSync } from 'node:fs';
14
+ import { dirname, extname, resolve } from 'node:path';
15
+ import { fileURLToPath } from 'node:url';
16
+ /** Skip inlining a sibling that would bloat the page past a reasonable PUT. */
17
+ export const MAX_INLINE_BYTES = 4 * 1024 * 1024;
18
+ const IMAGE_MIME = {
19
+ '.png': 'image/png',
20
+ '.jpg': 'image/jpeg',
21
+ '.jpeg': 'image/jpeg',
22
+ '.gif': 'image/gif',
23
+ '.webp': 'image/webp',
24
+ '.svg': 'image/svg+xml',
25
+ '.ico': 'image/x-icon',
26
+ '.avif': 'image/avif',
27
+ };
28
+ /**
29
+ * `href="file:///tmp/page.html#purpose"` → `href="#purpose"`.
30
+ * Bare `file:///tmp/page.html` (no hash) becomes `href="#"`.
31
+ */
32
+ export function rewriteFileAnchors(html) {
33
+ return html.replace(/\b(href\s*=\s*["'])file:\/\/[^"'#]*(#[^"']*)?(["'])/gi, (_m, attr, hash, quote) => `${attr}${hash ?? '#'}${quote}`);
34
+ }
35
+ function isRemoteOrSpecial(url) {
36
+ return (url.startsWith('data:') ||
37
+ url.startsWith('http://') ||
38
+ url.startsWith('https://') ||
39
+ url.startsWith('//') ||
40
+ url.startsWith('#') ||
41
+ url.startsWith('mailto:') ||
42
+ url.startsWith('javascript:') ||
43
+ url.startsWith('agents:'));
44
+ }
45
+ function localImagePath(url, htmlDir) {
46
+ if (!url || isRemoteOrSpecial(url))
47
+ return null;
48
+ const withoutHash = url.split('#')[0] ?? url;
49
+ let fsPath;
50
+ if (withoutHash.startsWith('file:')) {
51
+ try {
52
+ fsPath = fileURLToPath(withoutHash);
53
+ }
54
+ catch {
55
+ return null;
56
+ }
57
+ }
58
+ else {
59
+ fsPath = resolve(htmlDir, withoutHash);
60
+ }
61
+ if (!existsSync(fsPath))
62
+ return null;
63
+ const mime = IMAGE_MIME[extname(fsPath).toLowerCase()];
64
+ if (!mime)
65
+ return null;
66
+ return { path: fsPath, mime };
67
+ }
68
+ /** Replace local image src/href with a data URI when the file exists next to the page. */
69
+ export function inlineLocalAssets(html, htmlPath) {
70
+ const dir = dirname(htmlPath);
71
+ return html.replace(/\b((?:src|href)\s*=\s*["'])([^"']+)(["'])/gi, (full, pre, url, post) => {
72
+ const local = localImagePath(url, dir);
73
+ if (!local)
74
+ return full;
75
+ try {
76
+ const buf = readFileSync(local.path);
77
+ if (buf.length > MAX_INLINE_BYTES)
78
+ return full;
79
+ return `${pre}data:${local.mime};base64,${buf.toString('base64')}${post}`;
80
+ }
81
+ catch {
82
+ return full;
83
+ }
84
+ });
85
+ }
86
+ export function prepareShareHtml(html, htmlPath) {
87
+ return inlineLocalAssets(rewriteFileAnchors(html), htmlPath);
88
+ }
@@ -61,6 +61,18 @@ export interface UpdateWorkerResult {
61
61
  /** True when the upload was skipped because `previousHash` already matched. */
62
62
  skipped: boolean;
63
63
  }
64
+ /** Cloudflare `secret_text` name the Worker reads as `env.PHOENIX_ID_BASE`. */
65
+ export declare const WORKER_PHOENIX_ID_BASE_SECRET = "PHOENIX_ID_BASE";
66
+ export type UpdateWorkerOpts = ProvisionOptions & {
67
+ force?: boolean;
68
+ /**
69
+ * Phoenix ID base URL to bind as `PHOENIX_ID_BASE` after the script upload.
70
+ * Pass this for a managed deployment; omit it for a pure-BYO Worker (which
71
+ * authenticates only via WRITE_TOKEN). An empty string is a caller bug and
72
+ * fails loud — do not pass a blank to "skip".
73
+ */
74
+ phoenixIdBase?: string;
75
+ };
64
76
  /**
65
77
  * Re-deploy the Worker script against an ALREADY-provisioned endpoint (same
66
78
  * account/worker/bucket `deployWorker` was first called with) and idempotently
@@ -78,7 +90,9 @@ export interface UpdateWorkerResult {
78
90
  * API right after the upload — the same two-call sequence first-time
79
91
  * provisioning already uses (`deployWorker` then `setWorkerSecret`), except
80
92
  * `writeToken` here is the caller's EXISTING token, never a freshly generated
81
- * one. Cloudflare's own docs describe exactly this "secrets survive a
93
+ * one. A managed deploy also re-applies `PHOENIX_ID_BASE` the same way (the
94
+ * Worker reads it to verify Phoenix bearers); a pure-BYO deploy omits it.
95
+ * Cloudflare's own docs describe exactly this "secrets survive a
82
96
  * subsequent write" contract for the sibling `wrangler versions upload
83
97
  * --secrets-file` flow ("Secrets not included in the file are preserved from
84
98
  * the previous version" —
@@ -86,9 +100,9 @@ export interface UpdateWorkerResult {
86
100
  * re-setting the secret to its own value after every deploy gets the same
87
101
  * outcome without depending on an unverified upload-time flag.
88
102
  */
89
- export declare function updateWorker(apiToken: string, accountId: string, workerName: string, bucketName: string, script: string, writeToken: string, previousHash: string | undefined, opts?: ProvisionOptions & {
90
- force?: boolean;
91
- }): Promise<UpdateWorkerResult>;
103
+ export declare function updateWorker(apiToken: string, accountId: string, workerName: string, bucketName: string, script: string, writeToken: string, previousHash: string | undefined, opts?: UpdateWorkerOpts): Promise<UpdateWorkerResult>;
104
+ /** Add/update a secret_text binding using Cloudflare's Workers Secrets API. */
105
+ export declare function putWorkerSecret(apiToken: string, accountId: string, workerName: string, name: string, text: string, opts?: ProvisionOptions): Promise<void>;
92
106
  /** Add/update the WRITE_TOKEN binding using Cloudflare's Workers Secrets API. */
93
107
  export declare function setWorkerSecret(apiToken: string, accountId: string, workerName: string, writeToken: string, opts?: ProvisionOptions): Promise<void>;
94
108
  /** Enable the free `*.workers.dev` route for the script, and return the account subdomain. */
@@ -101,6 +101,8 @@ export async function deployWorker(apiToken, accountId, workerName, script, buck
101
101
  export function hashWorkerScript(script) {
102
102
  return createHash('sha256').update(script, 'utf8').digest('hex');
103
103
  }
104
+ /** Cloudflare `secret_text` name the Worker reads as `env.PHOENIX_ID_BASE`. */
105
+ export const WORKER_PHOENIX_ID_BASE_SECRET = 'PHOENIX_ID_BASE';
104
106
  /**
105
107
  * Re-deploy the Worker script against an ALREADY-provisioned endpoint (same
106
108
  * account/worker/bucket `deployWorker` was first called with) and idempotently
@@ -118,7 +120,9 @@ export function hashWorkerScript(script) {
118
120
  * API right after the upload — the same two-call sequence first-time
119
121
  * provisioning already uses (`deployWorker` then `setWorkerSecret`), except
120
122
  * `writeToken` here is the caller's EXISTING token, never a freshly generated
121
- * one. Cloudflare's own docs describe exactly this "secrets survive a
123
+ * one. A managed deploy also re-applies `PHOENIX_ID_BASE` the same way (the
124
+ * Worker reads it to verify Phoenix bearers); a pure-BYO deploy omits it.
125
+ * Cloudflare's own docs describe exactly this "secrets survive a
122
126
  * subsequent write" contract for the sibling `wrangler versions upload
123
127
  * --secrets-file` flow ("Secrets not included in the file are preserved from
124
128
  * the previous version" —
@@ -129,6 +133,13 @@ export function hashWorkerScript(script) {
129
133
  export async function updateWorker(apiToken, accountId, workerName, bucketName, script, writeToken, previousHash, opts = {}) {
130
134
  const templateHash = hashWorkerScript(script);
131
135
  if (!opts.force && previousHash === templateHash) {
136
+ // Script is current so we skip the upload (which would wipe secrets). A
137
+ // managed Worker still needs PHOENIX_ID_BASE present — a prior upload from
138
+ // a CLI that never set it left the secret missing, and this is the heal
139
+ // that does not require --force or a dummy template bump.
140
+ if (opts.phoenixIdBase !== undefined) {
141
+ await applyPhoenixIdBaseSecret(apiToken, accountId, workerName, opts.phoenixIdBase, opts);
142
+ }
132
143
  return { templateHash, skipped: true };
133
144
  }
134
145
  await deployWorker(apiToken, accountId, workerName, script, bucketName, opts);
@@ -143,18 +154,41 @@ export async function updateWorker(apiToken, accountId, workerName, bucketName,
143
154
  const detail = e instanceof Error ? e.message : String(e);
144
155
  throw new Error(`Worker deployed but the write token failed to re-apply — re-run \`agents artifacts share update\` to fix this before publishing/deleting anything. (${detail})`);
145
156
  }
157
+ if (opts.phoenixIdBase !== undefined) {
158
+ try {
159
+ await applyPhoenixIdBaseSecret(apiToken, accountId, workerName, opts.phoenixIdBase, opts);
160
+ }
161
+ catch (e) {
162
+ const detail = e instanceof Error ? e.message : String(e);
163
+ throw new Error(`Worker deployed but PHOENIX_ID_BASE failed to re-apply — Phoenix-bearer publishes will 401 until you re-run \`agents artifacts share update\`. (${detail})`);
164
+ }
165
+ }
146
166
  return { templateHash, skipped: false };
147
167
  }
148
- /** Add/update the WRITE_TOKEN binding using Cloudflare's Workers Secrets API. */
149
- export async function setWorkerSecret(apiToken, accountId, workerName, writeToken, opts = {}) {
168
+ /** Add/update a secret_text binding using Cloudflare's Workers Secrets API. */
169
+ export async function putWorkerSecret(apiToken, accountId, workerName, name, text, opts = {}) {
150
170
  const request = opts.request ?? defaultCloudflareRequester;
151
171
  await request({
152
172
  apiToken,
153
173
  method: 'PUT',
154
174
  pathname: `/accounts/${accountId}/workers/scripts/${workerName}/secrets`,
155
- body: { name: 'WRITE_TOKEN', text: writeToken, type: 'secret_text' },
175
+ body: { name, text, type: 'secret_text' },
156
176
  });
157
177
  }
178
+ /** Add/update the WRITE_TOKEN binding using Cloudflare's Workers Secrets API. */
179
+ export async function setWorkerSecret(apiToken, accountId, workerName, writeToken, opts = {}) {
180
+ await putWorkerSecret(apiToken, accountId, workerName, 'WRITE_TOKEN', writeToken, opts);
181
+ }
182
+ function normalizePhoenixIdBase(phoenixIdBase) {
183
+ const base = phoenixIdBase.replace(/\/+$/, '').trim();
184
+ if (!base) {
185
+ throw new Error('Managed share deploy requires a non-empty PHOENIX_ID_BASE so the Worker can verify Phoenix bearers. Set the PHOENIX_ID_BASE env var.');
186
+ }
187
+ return base;
188
+ }
189
+ async function applyPhoenixIdBaseSecret(apiToken, accountId, workerName, phoenixIdBase, opts = {}) {
190
+ await putWorkerSecret(apiToken, accountId, workerName, WORKER_PHOENIX_ID_BASE_SECRET, normalizePhoenixIdBase(phoenixIdBase), opts);
191
+ }
158
192
  /** Enable the free `*.workers.dev` route for the script, and return the account subdomain. */
159
193
  export async function enableWorkersDev(apiToken, accountId, workerName, opts = {}) {
160
194
  const request = opts.request ?? defaultCloudflareRequester;
@@ -18,10 +18,18 @@ export interface PublishOptions {
18
18
  */
19
19
  expire?: string;
20
20
  contentType?: string;
21
+ /**
22
+ * Server-enforced visibility (RUSH-3135). `public` (default) is listed in
23
+ * the gallery; `unlisted` is a capability URL (GET still 200, X-Robots-Tag:
24
+ * noindex, hidden from gallery/list). `org` is Phase 2 — the Worker 400s it.
25
+ */
26
+ visibility?: ShareVisibility;
21
27
  /**
22
28
  * Hide this page from the public `/<user>` gallery and `agents artifacts share list`
23
29
  * (metadata `visibility=unlisted`). The direct URL is still world-readable —
24
- * unlisted, not secret (RUSH-2443). Alias of `--private` on the CLI.
30
+ * unlisted, not secret (RUSH-2443). Alias of `--visibility unlisted` /
31
+ * `--private` on the CLI. Kept so `sessions share` and existing callers do
32
+ * not break.
25
33
  */
26
34
  unlisted?: boolean;
27
35
  /**
@@ -39,8 +47,12 @@ export interface PublishOptions {
39
47
  githubUser?: string;
40
48
  /** DI seam for tests — override the persisted share endpoint config. */
41
49
  config?: ShareConfig;
42
- /** DI seam for tests — override the keychain-backed write token. */
50
+ /** DI seam for tests — override the keychain-backed write token. Selects BYO. */
43
51
  writeToken?: string;
52
+ /** DI seam for tests — override `readSession()`. `null` means signed out. */
53
+ session?: import('../identity/client.js').PhoenixSession | null;
54
+ /** Force the BYO Cloudflare path even when signed in. */
55
+ byo?: boolean;
44
56
  /** DI seam for tests — override the real HTTP PUT. */
45
57
  uploader?: PutFn;
46
58
  /** DI seam for tests — override cover capture (returns a PNG buffer or null). */
@@ -55,22 +67,26 @@ export interface PublishOptions {
55
67
  /**
56
68
  * Structured metadata (`--meta key=value`, repeatable). Keys are validated by
57
69
  * {@link parseMetaEntries} — lowercase `[a-z0-9-]`, and may not collide with
58
- * {@link RESERVED_META_KEYS}, which the CLI sets automatically.
70
+ * {@link RESERVED_META_KEYS} (Worker-stamped owner/visibility/expires-at,
71
+ * plus provenance the CLI sets automatically).
59
72
  */
60
73
  meta?: Record<string, string>;
61
74
  /**
62
75
  * Skip revision retention on this publish — overwrite an existing slug's
63
76
  * object in place with no `<slug>/rev-<ts>` backup of the version it replaces
64
- * (default: keep it; see docs/share.md §Revisions).
77
+ * (default: keep it; see docs/distribution.md).
65
78
  */
66
79
  noRevision?: boolean;
67
80
  /** DI seam for tests — override provenance auto-capture (agent/session/host/repo/date). */
68
81
  provenance?: ShareProvenance;
69
82
  }
83
+ export type ShareVisibility = 'public' | 'unlisted';
70
84
  export interface PublishResult {
71
85
  url: string;
72
86
  expiresAt?: string;
73
87
  coverUrl?: string;
88
+ /** Server-enforced visibility stamped on the object. */
89
+ visibility?: ShareVisibility;
74
90
  /** True when the page was published with `visibility=unlisted`. */
75
91
  unlisted?: boolean;
76
92
  /** The label stored with this share — explicit (`--label`) or derived. */
@@ -78,6 +94,11 @@ export interface PublishResult {
78
94
  /** Whether `label` came from `--label` or was auto-derived. */
79
95
  labelSource?: 'explicit' | 'derived';
80
96
  }
97
+ /** `--unlisted` / `{ unlisted: true }` map to `unlisted`; otherwise `visibility` (default public). */
98
+ export declare function resolveShareVisibility(opts?: {
99
+ visibility?: ShareVisibility;
100
+ unlisted?: boolean;
101
+ }): ShareVisibility;
81
102
  export interface ShareProvenance {
82
103
  /** Harness/agent name (`AGENTS_AGENT_NAME`), when publishing from an agent run. */
83
104
  agent?: string;
@@ -91,11 +112,12 @@ export interface ShareProvenance {
91
112
  date?: string;
92
113
  }
93
114
  /**
94
- * Reserved `customMetadata` keys the CLI sets automatically from the exec env,
95
- * git, and the local clock (plus `label`/`label-source`) a `--meta key=value`
96
- * may not target any of these (see {@link parseMetaEntries}).
115
+ * Reserved `customMetadata` keys a `--meta key=value` may not target (see
116
+ * {@link parseMetaEntries}). Matches the Worker's `RESERVED_METADATA_KEYS`:
117
+ * provenance the CLI sets automatically, plus `expires-at` / `visibility` /
118
+ * `owner` which the Worker stamps itself.
97
119
  */
98
- export declare const RESERVED_META_KEYS: readonly ["agent", "session", "host", "repo", "date", "label", "label-source"];
120
+ export declare const RESERVED_META_KEYS: readonly ["expires-at", "visibility", "owner", "agent", "session", "host", "repo", "date", "label", "label-source"];
99
121
  /**
100
122
  * Auto-capture publish provenance from the exec env, git, and the local clock.
101
123
  * Every field is present only when the environment genuinely carries it — a
@@ -113,8 +135,9 @@ export declare function resolveShareProvenance(opts?: {
113
135
  /**
114
136
  * Parse repeated `--meta key=value` CLI args into a validated metadata record.
115
137
  * Keys are lowercase `[a-z0-9-]`, up to 64 characters, and may not collide with
116
- * {@link RESERVED_META_KEYS} (the provenance the CLI sets automatically, plus
117
- * label/label-source) — throws naming the offending pair on any violation.
138
+ * {@link RESERVED_META_KEYS} (Worker-stamped owner/visibility/expires-at, plus
139
+ * the provenance the CLI sets automatically, plus label/label-source) — throws
140
+ * naming the offending pair on any violation.
118
141
  */
119
142
  export declare function parseMetaEntries(pairs: string[]): Record<string, string>;
120
143
  /** Throws when the combined `customMetadata` payload would exceed {@link MAX_METADATA_BYTES}. */
@@ -201,16 +224,17 @@ export declare function slugify(name: string): string;
201
224
  /** The project the file belongs to — git repo name, else the cwd's basename. */
202
225
  export declare function detectProject(dir?: string): string;
203
226
  /**
204
- * Notion-style default slug: `<project>-<feature>-<16hex>`. Project scopes the link
205
- * to the repo the agent is in; the random tail keeps it unguessable + collision-free.
206
- * A leading `plan-` on the filename is dropped (it's redundant under the project).
227
+ * Readable slug + view id: `<feature>-<16hex>`. A leading `plan-` on the
228
+ * filename is dropped. The project no longer prefixes the slug the URL
229
+ * namespace is already the publisher's handle (`/<you>/<slug>`).
207
230
  *
208
231
  * The tail is 8 random bytes (64-bit, 16 hex chars). Reads are public — the URL is
209
232
  * the only capability — so the nonce must be genuinely infeasible to brute-force,
210
- * not merely unlisted; 64 bits puts a blind guess out of reach. (See docs/share.md
233
+ * not merely unlisted; 64 bits puts a blind guess out of reach. (See docs/distribution.md
211
234
  * §Security for the threat model and `--expire` for sensitive content.)
235
+ * `--slug` still publishes that exact slug, no view-id appended.
212
236
  */
213
- export declare function defaultSlug(filePath: string, dir?: string): string;
237
+ export declare function defaultSlug(filePath: string, _dir?: string): string;
214
238
  /**
215
239
  * Best-effort OG cover: capture a screenshot, upload it as `<slug>.png`, and return
216
240
  * the page body with og:image meta injected (+ the cover URL). All IO is injected