@phnx-labs/agents-cli 1.22.47 → 1.22.50
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.
- package/CHANGELOG.md +503 -17
- package/README.md +76 -32
- package/dist/bootstrap.js +4 -2
- package/dist/cli/command-registry.d.ts +1 -0
- package/dist/cli/command-registry.js +2 -0
- package/dist/commands/accounts.d.ts +58 -0
- package/dist/commands/accounts.js +201 -39
- package/dist/commands/artifacts.js +7 -6
- package/dist/commands/attach.js +1 -1
- package/dist/commands/browser.js +501 -103
- package/dist/commands/config.d.ts +0 -1
- package/dist/commands/config.js +0 -20
- package/dist/commands/daemon-test-harness.d.ts +42 -0
- package/dist/commands/daemon-test-harness.js +90 -0
- package/dist/commands/daemon.d.ts +21 -0
- package/dist/commands/daemon.js +147 -12
- package/dist/commands/device-config-test-harness.d.ts +11 -0
- package/dist/commands/device-config-test-harness.js +59 -0
- package/dist/commands/exec.js +76 -16
- package/dist/commands/focus.d.ts +14 -0
- package/dist/commands/focus.js +48 -5
- package/dist/commands/go.d.ts +3 -0
- package/dist/commands/go.js +16 -3
- package/dist/commands/inspect.js +2 -2
- package/dist/commands/lease.d.ts +1 -1
- package/dist/commands/lease.js +4 -3
- package/dist/commands/mailboxes.js +4 -3
- package/dist/commands/menubar.js +11 -4
- package/dist/commands/projects.d.ts +16 -1
- package/dist/commands/projects.js +58 -64
- package/dist/commands/resume.js +1 -1
- package/dist/commands/route.js +4 -4
- package/dist/commands/routines.js +3 -2
- package/dist/commands/run-broadcast.d.ts +1 -1
- package/dist/commands/run-broadcast.js +1 -1
- package/dist/commands/sessions-picker.d.ts +22 -0
- package/dist/commands/sessions-picker.js +48 -9
- package/dist/commands/sessions-trace.js +1 -1
- package/dist/commands/sessions.js +1 -0
- package/dist/commands/setup-secrets.js +23 -0
- package/dist/commands/share.d.ts +20 -5
- package/dist/commands/share.js +158 -53
- package/dist/commands/ssh.js +54 -7
- package/dist/commands/teams.d.ts +12 -0
- package/dist/commands/teams.js +44 -67
- package/dist/commands/traces.d.ts +2 -0
- package/dist/commands/traces.js +188 -0
- package/dist/commands/view.d.ts +1 -1
- package/dist/commands/view.js +17 -34
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -0
- package/dist/lib/account-provider-registry.d.ts +9 -0
- package/dist/lib/account-provider-registry.js +20 -0
- package/dist/lib/accounting/account-pool-collect.d.ts +34 -0
- package/dist/lib/accounting/account-pool-collect.js +71 -0
- package/dist/lib/accounting/account-pool.d.ts +46 -0
- package/dist/lib/accounting/account-pool.js +33 -0
- package/dist/lib/accounting/capacity.d.ts +24 -0
- package/dist/lib/accounting/capacity.js +30 -0
- package/dist/lib/accounting/rotate.d.ts +11 -18
- package/dist/lib/accounting/rotate.js +6 -24
- package/dist/lib/accounting/usage.d.ts +14 -3
- package/dist/lib/accounting/usage.js +64 -18
- package/dist/lib/agent-spec/agents.js +11 -9
- package/dist/lib/browser/drivers/ssh.d.ts +16 -2
- package/dist/lib/browser/drivers/ssh.js +36 -9
- package/dist/lib/browser/ipc.js +8 -3
- package/dist/lib/browser/profiles.d.ts +35 -101
- package/dist/lib/browser/profiles.js +130 -301
- package/dist/lib/browser/registry.d.ts +39 -0
- package/dist/lib/browser/registry.js +149 -0
- package/dist/lib/browser/remote-control.d.ts +8 -6
- package/dist/lib/browser/remote-control.js +8 -6
- package/dist/lib/browser/resolve-target.d.ts +68 -0
- package/dist/lib/browser/resolve-target.js +250 -0
- package/dist/lib/browser/runtime-state.d.ts +40 -16
- package/dist/lib/browser/runtime-state.js +92 -25
- package/dist/lib/browser/service.d.ts +28 -9
- package/dist/lib/browser/service.js +139 -62
- package/dist/lib/browser/task-index.d.ts +70 -0
- package/dist/lib/browser/task-index.js +180 -0
- package/dist/lib/byok-usage.js +2 -2
- package/dist/lib/claude-statusline.d.ts +29 -0
- package/dist/lib/claude-statusline.js +139 -0
- package/dist/lib/cloud/host.d.ts +1 -1
- package/dist/lib/cloud/host.js +1 -1
- package/dist/lib/cloud/rush.js +1 -1
- package/dist/lib/computer/computer-rpc.js +2 -2
- package/dist/lib/computer/download.d.ts +15 -15
- package/dist/lib/computer/download.js +35 -98
- package/dist/lib/computer/ssh-tunnel.d.ts +0 -3
- package/dist/lib/computer/ssh-tunnel.js +12 -22
- package/dist/lib/config-keys.d.ts +2 -8
- package/dist/lib/config-keys.js +2 -13
- package/dist/lib/crabbox/cli.d.ts +1 -1
- package/dist/lib/crabbox/cli.js +2 -2
- package/dist/lib/crabbox/lease.d.ts +9 -0
- package/dist/lib/crabbox/lease.js +70 -15
- package/dist/lib/crabbox/runtimes.js +1 -1
- package/dist/lib/daemon/account-state-daemon-service.d.ts +16 -0
- package/dist/lib/daemon/account-state-daemon-service.js +26 -0
- package/dist/lib/daemon/browser-ipc-service.d.ts +20 -0
- package/dist/lib/daemon/browser-ipc-service.js +46 -0
- package/dist/lib/daemon/daemon.d.ts +3 -0
- package/dist/lib/daemon/daemon.js +212 -444
- package/dist/lib/daemon/device-probe-service.d.ts +26 -0
- package/dist/lib/daemon/device-probe-service.js +47 -0
- package/dist/lib/daemon/keychain-reap-service.d.ts +17 -0
- package/dist/lib/daemon/keychain-reap-service.js +32 -0
- package/dist/lib/daemon/monitor-engine-service.d.ts +22 -0
- package/dist/lib/daemon/monitor-engine-service.js +29 -0
- package/dist/lib/daemon/secrets-broker-service.d.ts +20 -0
- package/dist/lib/daemon/secrets-broker-service.js +66 -0
- package/dist/lib/daemon/self-heal-service.d.ts +27 -0
- package/dist/lib/daemon/self-heal-service.js +48 -0
- package/dist/lib/daemon/service.d.ts +102 -0
- package/dist/lib/daemon/service.js +98 -0
- package/dist/lib/daemon/session-index-service.d.ts +22 -0
- package/dist/lib/daemon/session-index-service.js +40 -0
- package/dist/lib/daemon/state-dir-check-service.d.ts +43 -0
- package/dist/lib/daemon/state-dir-check-service.js +63 -0
- package/dist/lib/daemon/supervisor.d.ts +87 -0
- package/dist/lib/daemon/supervisor.js +298 -0
- package/dist/lib/daemon/watchdog-service.d.ts +19 -0
- package/dist/lib/daemon/watchdog-service.js +40 -0
- package/dist/lib/daemon-health.d.ts +15 -0
- package/dist/lib/daemon-health.js +29 -5
- package/dist/lib/daemon-services.d.ts +8 -1
- package/dist/lib/daemon-services.js +55 -0
- package/dist/lib/daemon-ticks.d.ts +13 -2
- package/dist/lib/daemon-ticks.js +20 -18
- package/dist/lib/device-config.d.ts +0 -2
- package/dist/lib/device-config.js +1 -23
- package/dist/lib/devices/registry.d.ts +1 -1
- package/dist/lib/devices/registry.js +1 -1
- package/dist/lib/devices/stats-cache.d.ts +20 -0
- package/dist/lib/devices/stats-cache.js +49 -5
- package/dist/lib/devices/worker-pick.d.ts +48 -0
- package/dist/lib/devices/worker-pick.js +113 -0
- package/dist/lib/exec.d.ts +67 -13
- package/dist/lib/exec.js +85 -29
- package/dist/lib/harness/adapters/cursor.js +8 -11
- package/dist/lib/helper-download.d.ts +108 -0
- package/dist/lib/helper-download.js +194 -0
- package/dist/lib/helper-versions.d.ts +52 -0
- package/dist/lib/helper-versions.js +58 -0
- package/dist/lib/hooks/cache.js +11 -0
- package/dist/lib/hooks/install.js +2 -2
- package/dist/lib/hosts/credentials.d.ts +1 -1
- package/dist/lib/hosts/credentials.js +1 -1
- package/dist/lib/hosts/dispatch.d.ts +7 -1
- package/dist/lib/hosts/dispatch.js +24 -5
- package/dist/lib/hosts/passthrough.d.ts +8 -15
- package/dist/lib/hosts/passthrough.js +19 -16
- package/dist/lib/hosts/providers/devices.d.ts +1 -1
- package/dist/lib/hosts/providers/devices.js +1 -1
- package/dist/lib/hosts/reconnect.d.ts +179 -21
- package/dist/lib/hosts/reconnect.js +266 -45
- package/dist/lib/installations/migrate.d.ts +4 -5
- package/dist/lib/installations/migrate.js +6 -7
- package/dist/lib/installations/shims.d.ts +1 -1
- package/dist/lib/installations/shims.js +23 -13
- package/dist/lib/installations/store.js +6 -3
- package/dist/lib/installations/versions.js +73 -48
- package/dist/lib/linear-autoclose.d.ts +1 -1
- package/dist/lib/linear-autoclose.js +1 -1
- package/dist/lib/loop.d.ts +2 -2
- package/dist/lib/loop.js +1 -1
- package/dist/lib/menubar/download-menubar.d.ts +47 -0
- package/dist/lib/menubar/download-menubar.js +60 -0
- package/dist/lib/menubar/install-menubar.d.ts +31 -7
- package/dist/lib/menubar/install-menubar.js +79 -21
- package/dist/lib/menubar/notify-desktop.d.ts +3 -3
- package/dist/lib/menubar/notify-desktop.js +6 -6
- package/dist/lib/model-tiers.d.ts +1 -1
- package/dist/lib/project-probe.d.ts +1 -1
- package/dist/lib/project-probe.js +1 -1
- package/dist/lib/project-pull.d.ts +1 -1
- package/dist/lib/project-pull.js +2 -2
- package/dist/lib/projects.d.ts +1 -1
- package/dist/lib/projects.js +1 -1
- package/dist/lib/sandbox.js +6 -7
- package/dist/lib/secrets/download-keychain.d.ts +47 -0
- package/dist/lib/secrets/download-keychain.js +70 -0
- package/dist/lib/secrets/install-helper.d.ts +20 -1
- package/dist/lib/secrets/install-helper.js +44 -3
- package/dist/lib/session/active.js +17 -1
- package/dist/lib/session/db.d.ts +11 -1
- package/dist/lib/session/db.js +138 -6
- package/dist/lib/session/discover.d.ts +21 -1
- package/dist/lib/session/discover.js +33 -5
- package/dist/lib/session/highlights.d.ts +49 -1
- package/dist/lib/session/highlights.js +95 -0
- package/dist/lib/session/host-link.d.ts +16 -2
- package/dist/lib/session/host-link.js +7 -1
- package/dist/lib/session/parse.js +33 -1
- package/dist/lib/session/remote/remote-list.d.ts +9 -0
- package/dist/lib/session/remote/remote-list.js +19 -2
- package/dist/lib/session/remote/watch.js +11 -2
- package/dist/lib/session/session-cache.d.ts +53 -0
- package/dist/lib/session/session-cache.js +88 -0
- package/dist/lib/session/state.js +1 -1
- package/dist/lib/session/tool-calls.d.ts +2 -0
- package/dist/lib/session/tool-calls.js +1 -1
- package/dist/lib/session/trajectory-html.d.ts +5 -1
- package/dist/lib/session/trajectory-html.js +42 -22
- package/dist/lib/session/trajectory-text.js +9 -2
- package/dist/lib/session/trajectory.js +53 -4
- package/dist/lib/session/types.d.ts +15 -0
- package/dist/lib/sha256-asset.d.ts +26 -0
- package/dist/lib/sha256-asset.js +41 -0
- package/dist/lib/share/backend.d.ts +95 -0
- package/dist/lib/share/backend.js +139 -0
- package/dist/lib/share/delete.d.ts +6 -2
- package/dist/lib/share/delete.js +8 -9
- package/dist/lib/share/html.d.ts +22 -0
- package/dist/lib/share/html.js +88 -0
- package/dist/lib/share/provision.d.ts +18 -4
- package/dist/lib/share/provision.js +38 -4
- package/dist/lib/share/publish.d.ts +44 -15
- package/dist/lib/share/publish.js +58 -26
- package/dist/lib/share/worker-template.js +402 -25
- package/dist/lib/sqlite.js +16 -3
- package/dist/lib/ssh-exec.d.ts +65 -0
- package/dist/lib/ssh-exec.js +120 -4
- package/dist/lib/startup/command-registry.js +1 -1
- package/dist/lib/startup/dev-build.js +3 -3
- package/dist/lib/state.d.ts +1 -1
- package/dist/lib/state.js +7 -3
- package/dist/lib/subagents-registry.js +1 -1
- package/dist/lib/teams/agents.d.ts +14 -12
- package/dist/lib/teams/agents.js +188 -73
- package/dist/lib/teams/api.d.ts +6 -1
- package/dist/lib/teams/api.js +2 -0
- package/dist/lib/teams/scheduler.d.ts +7 -0
- package/dist/lib/teams/scheduler.js +26 -8
- package/dist/lib/terminal/index.d.ts +1 -1
- package/dist/lib/terminal/types.d.ts +1 -1
- package/dist/lib/terminal/types.js +1 -1
- package/dist/lib/tmux/orphan-reap.js +1 -1
- package/dist/lib/tmux/session.js +31 -0
- package/dist/lib/traces/backend.d.ts +29 -0
- package/dist/lib/traces/backend.js +46 -0
- package/dist/lib/traces/classify.d.ts +52 -0
- package/dist/lib/traces/classify.js +72 -0
- package/dist/lib/traces/config.d.ts +10 -0
- package/dist/lib/traces/config.js +2 -0
- package/dist/lib/traces/provision.d.ts +19 -0
- package/dist/lib/traces/provision.js +30 -0
- package/dist/lib/traces/sync.d.ts +150 -0
- package/dist/lib/traces/sync.js +459 -0
- package/dist/lib/traces/worker-template.d.ts +4 -0
- package/dist/lib/traces/worker-template.js +159 -0
- package/dist/lib/types.d.ts +18 -19
- package/dist/lib/types.js +14 -0
- package/dist/lib/usage-refresh.d.ts +1 -1
- package/dist/lib/usage-refresh.js +11 -8
- package/dist/lib/workflows.d.ts +1 -1
- package/package.json +4 -6
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/Info.plist +0 -24
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/Resources/AppIcon.icns +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/_CodeSignature/CodeResources +0 -128
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/Info.plist +0 -26
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/Resources/AppIcon.icns +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/_CodeSignature/CodeResources +0 -135
- package/dist/lib/secrets/Agents CLI.app/Contents/embedded.provisionprofile +0 -0
- package/dist/lib/usage-fleet.d.ts +0 -32
- package/dist/lib/usage-fleet.js +0 -125
|
@@ -18,10 +18,20 @@ 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). `me` requires a Phoenix session and is
|
|
25
|
+
* visible only to the signed-in owner; `org` requires the same and is visible
|
|
26
|
+
* to members of the same Phoenix organization.
|
|
27
|
+
*/
|
|
28
|
+
visibility?: ShareVisibility;
|
|
21
29
|
/**
|
|
22
30
|
* Hide this page from the public `/<user>` gallery and `agents artifacts share list`
|
|
23
31
|
* (metadata `visibility=unlisted`). The direct URL is still world-readable —
|
|
24
|
-
* unlisted, not secret (RUSH-2443). Alias of `--
|
|
32
|
+
* unlisted, not secret (RUSH-2443). Alias of `--visibility unlisted` /
|
|
33
|
+
* `--private` on the CLI. Kept so `sessions share` and existing callers do
|
|
34
|
+
* not break.
|
|
25
35
|
*/
|
|
26
36
|
unlisted?: boolean;
|
|
27
37
|
/**
|
|
@@ -39,8 +49,12 @@ export interface PublishOptions {
|
|
|
39
49
|
githubUser?: string;
|
|
40
50
|
/** DI seam for tests — override the persisted share endpoint config. */
|
|
41
51
|
config?: ShareConfig;
|
|
42
|
-
/** DI seam for tests — override the keychain-backed write token. */
|
|
52
|
+
/** DI seam for tests — override the keychain-backed write token. Selects BYO. */
|
|
43
53
|
writeToken?: string;
|
|
54
|
+
/** DI seam for tests — override `readSession()`. `null` means signed out. */
|
|
55
|
+
session?: import('../identity/client.js').PhoenixSession | null;
|
|
56
|
+
/** Force the BYO Cloudflare path even when signed in. */
|
|
57
|
+
byo?: boolean;
|
|
44
58
|
/** DI seam for tests — override the real HTTP PUT. */
|
|
45
59
|
uploader?: PutFn;
|
|
46
60
|
/** DI seam for tests — override cover capture (returns a PNG buffer or null). */
|
|
@@ -55,22 +69,26 @@ export interface PublishOptions {
|
|
|
55
69
|
/**
|
|
56
70
|
* Structured metadata (`--meta key=value`, repeatable). Keys are validated by
|
|
57
71
|
* {@link parseMetaEntries} — lowercase `[a-z0-9-]`, and may not collide with
|
|
58
|
-
* {@link RESERVED_META_KEYS}
|
|
72
|
+
* {@link RESERVED_META_KEYS} (Worker-stamped owner/visibility/expires-at,
|
|
73
|
+
* plus provenance the CLI sets automatically).
|
|
59
74
|
*/
|
|
60
75
|
meta?: Record<string, string>;
|
|
61
76
|
/**
|
|
62
77
|
* Skip revision retention on this publish — overwrite an existing slug's
|
|
63
78
|
* object in place with no `<slug>/rev-<ts>` backup of the version it replaces
|
|
64
|
-
* (default: keep it; see docs/
|
|
79
|
+
* (default: keep it; see docs/distribution.md).
|
|
65
80
|
*/
|
|
66
81
|
noRevision?: boolean;
|
|
67
82
|
/** DI seam for tests — override provenance auto-capture (agent/session/host/repo/date). */
|
|
68
83
|
provenance?: ShareProvenance;
|
|
69
84
|
}
|
|
85
|
+
export type ShareVisibility = 'public' | 'unlisted' | 'me' | 'org';
|
|
70
86
|
export interface PublishResult {
|
|
71
87
|
url: string;
|
|
72
88
|
expiresAt?: string;
|
|
73
89
|
coverUrl?: string;
|
|
90
|
+
/** Server-enforced visibility stamped on the object. */
|
|
91
|
+
visibility?: ShareVisibility;
|
|
74
92
|
/** True when the page was published with `visibility=unlisted`. */
|
|
75
93
|
unlisted?: boolean;
|
|
76
94
|
/** The label stored with this share — explicit (`--label`) or derived. */
|
|
@@ -78,6 +96,14 @@ export interface PublishResult {
|
|
|
78
96
|
/** Whether `label` came from `--label` or was auto-derived. */
|
|
79
97
|
labelSource?: 'explicit' | 'derived';
|
|
80
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* `--unlisted` / `{ unlisted: true }` map to `unlisted`; `--visibility me|org`
|
|
101
|
+
* passes through; otherwise `visibility` (default public).
|
|
102
|
+
*/
|
|
103
|
+
export declare function resolveShareVisibility(opts?: {
|
|
104
|
+
visibility?: ShareVisibility;
|
|
105
|
+
unlisted?: boolean;
|
|
106
|
+
}): ShareVisibility;
|
|
81
107
|
export interface ShareProvenance {
|
|
82
108
|
/** Harness/agent name (`AGENTS_AGENT_NAME`), when publishing from an agent run. */
|
|
83
109
|
agent?: string;
|
|
@@ -91,11 +117,12 @@ export interface ShareProvenance {
|
|
|
91
117
|
date?: string;
|
|
92
118
|
}
|
|
93
119
|
/**
|
|
94
|
-
* Reserved `customMetadata` keys
|
|
95
|
-
*
|
|
96
|
-
*
|
|
120
|
+
* Reserved `customMetadata` keys a `--meta key=value` may not target (see
|
|
121
|
+
* {@link parseMetaEntries}). Matches the Worker's `RESERVED_METADATA_KEYS`:
|
|
122
|
+
* provenance the CLI sets automatically, plus `expires-at` / `visibility` /
|
|
123
|
+
* `owner` which the Worker stamps itself.
|
|
97
124
|
*/
|
|
98
|
-
export declare const RESERVED_META_KEYS: readonly ["agent", "session", "host", "repo", "date", "label", "label-source"];
|
|
125
|
+
export declare const RESERVED_META_KEYS: readonly ["expires-at", "visibility", "owner", "agent", "session", "host", "repo", "date", "label", "label-source"];
|
|
99
126
|
/**
|
|
100
127
|
* Auto-capture publish provenance from the exec env, git, and the local clock.
|
|
101
128
|
* Every field is present only when the environment genuinely carries it — a
|
|
@@ -113,8 +140,9 @@ export declare function resolveShareProvenance(opts?: {
|
|
|
113
140
|
/**
|
|
114
141
|
* Parse repeated `--meta key=value` CLI args into a validated metadata record.
|
|
115
142
|
* Keys are lowercase `[a-z0-9-]`, up to 64 characters, and may not collide with
|
|
116
|
-
* {@link RESERVED_META_KEYS} (
|
|
117
|
-
* label/label-source) — throws
|
|
143
|
+
* {@link RESERVED_META_KEYS} (Worker-stamped owner/visibility/expires-at, plus
|
|
144
|
+
* the provenance the CLI sets automatically, plus label/label-source) — throws
|
|
145
|
+
* naming the offending pair on any violation.
|
|
118
146
|
*/
|
|
119
147
|
export declare function parseMetaEntries(pairs: string[]): Record<string, string>;
|
|
120
148
|
/** Throws when the combined `customMetadata` payload would exceed {@link MAX_METADATA_BYTES}. */
|
|
@@ -201,16 +229,17 @@ export declare function slugify(name: string): string;
|
|
|
201
229
|
/** The project the file belongs to — git repo name, else the cwd's basename. */
|
|
202
230
|
export declare function detectProject(dir?: string): string;
|
|
203
231
|
/**
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
232
|
+
* Readable slug + view id: `<feature>-<16hex>`. A leading `plan-` on the
|
|
233
|
+
* filename is dropped. The project no longer prefixes the slug — the URL
|
|
234
|
+
* namespace is already the publisher's handle (`/<you>/<slug>`).
|
|
207
235
|
*
|
|
208
236
|
* The tail is 8 random bytes (64-bit, 16 hex chars). Reads are public — the URL is
|
|
209
237
|
* 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/
|
|
238
|
+
* not merely unlisted; 64 bits puts a blind guess out of reach. (See docs/distribution.md
|
|
211
239
|
* §Security for the threat model and `--expire` for sensitive content.)
|
|
240
|
+
* `--slug` still publishes that exact slug, no view-id appended.
|
|
212
241
|
*/
|
|
213
|
-
export declare function defaultSlug(filePath: string,
|
|
242
|
+
export declare function defaultSlug(filePath: string, _dir?: string): string;
|
|
214
243
|
/**
|
|
215
244
|
* Best-effort OG cover: capture a screenshot, upload it as `<slug>.png`, and return
|
|
216
245
|
* the page body with og:image meta injected (+ the cover URL). All IO is injected
|
|
@@ -10,17 +10,42 @@ import { basename } from 'node:path';
|
|
|
10
10
|
import { execFileSync } from 'node:child_process';
|
|
11
11
|
import { randomBytes } from 'node:crypto';
|
|
12
12
|
import { hostname as osHostname } from 'node:os';
|
|
13
|
-
import { readShareConfig
|
|
13
|
+
import { readShareConfig } from './config.js';
|
|
14
14
|
import { resolveGitHubUsername } from '../git.js';
|
|
15
|
+
import { resolveShareBackend, sanitizeShareNamespace } from './backend.js';
|
|
15
16
|
import { captureCover, OG_WIDTH, OG_HEIGHT, OG_SCALE } from './capture.js';
|
|
16
17
|
import { deriveMeta, injectOgMeta } from './og.js';
|
|
17
18
|
import { injectAnalyticsBeacon } from './analytics.js';
|
|
19
|
+
import { prepareShareHtml } from './html.js';
|
|
18
20
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* may not target any of these (see {@link parseMetaEntries}).
|
|
21
|
+
* `--unlisted` / `{ unlisted: true }` map to `unlisted`; `--visibility me|org`
|
|
22
|
+
* passes through; otherwise `visibility` (default public).
|
|
22
23
|
*/
|
|
23
|
-
export
|
|
24
|
+
export function resolveShareVisibility(opts = {}) {
|
|
25
|
+
if (opts.unlisted === true)
|
|
26
|
+
return 'unlisted';
|
|
27
|
+
if (opts.visibility === 'unlisted' || opts.visibility === 'me' || opts.visibility === 'org')
|
|
28
|
+
return opts.visibility;
|
|
29
|
+
return 'public';
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Reserved `customMetadata` keys a `--meta key=value` may not target (see
|
|
33
|
+
* {@link parseMetaEntries}). Matches the Worker's `RESERVED_METADATA_KEYS`:
|
|
34
|
+
* provenance the CLI sets automatically, plus `expires-at` / `visibility` /
|
|
35
|
+
* `owner` which the Worker stamps itself.
|
|
36
|
+
*/
|
|
37
|
+
export const RESERVED_META_KEYS = [
|
|
38
|
+
'expires-at',
|
|
39
|
+
'visibility',
|
|
40
|
+
'owner',
|
|
41
|
+
'agent',
|
|
42
|
+
'session',
|
|
43
|
+
'host',
|
|
44
|
+
'repo',
|
|
45
|
+
'date',
|
|
46
|
+
'label',
|
|
47
|
+
'label-source',
|
|
48
|
+
];
|
|
24
49
|
const META_KEY_RE = /^[a-z0-9-]{1,64}$/;
|
|
25
50
|
/**
|
|
26
51
|
* Auto-capture publish provenance from the exec env, git, and the local clock.
|
|
@@ -43,8 +68,9 @@ export function resolveShareProvenance(opts = {}) {
|
|
|
43
68
|
/**
|
|
44
69
|
* Parse repeated `--meta key=value` CLI args into a validated metadata record.
|
|
45
70
|
* Keys are lowercase `[a-z0-9-]`, up to 64 characters, and may not collide with
|
|
46
|
-
* {@link RESERVED_META_KEYS} (
|
|
47
|
-
* label/label-source) — throws
|
|
71
|
+
* {@link RESERVED_META_KEYS} (Worker-stamped owner/visibility/expires-at, plus
|
|
72
|
+
* the provenance the CLI sets automatically, plus label/label-source) — throws
|
|
73
|
+
* naming the offending pair on any violation.
|
|
48
74
|
*/
|
|
49
75
|
export function parseMetaEntries(pairs) {
|
|
50
76
|
const meta = {};
|
|
@@ -59,7 +85,7 @@ export function parseMetaEntries(pairs) {
|
|
|
59
85
|
throw new Error(`Bad --meta key '${key}'. Keys are lowercase letters, digits, and hyphens, up to 64 characters.`);
|
|
60
86
|
}
|
|
61
87
|
if (RESERVED_META_KEYS.includes(key)) {
|
|
62
|
-
throw new Error(`--meta ${key}=… is reserved (set automatically from your session/git) — pass a different key.`);
|
|
88
|
+
throw new Error(`--meta ${key}=… is reserved (Worker-stamped, or set automatically from your session/git) — pass a different key.`);
|
|
63
89
|
}
|
|
64
90
|
meta[key] = value;
|
|
65
91
|
}
|
|
@@ -293,7 +319,7 @@ export function slugify(name) {
|
|
|
293
319
|
.slice(0, 60) || 'page');
|
|
294
320
|
}
|
|
295
321
|
function sanitizeSlugPart(s) {
|
|
296
|
-
return s
|
|
322
|
+
return sanitizeShareNamespace(s);
|
|
297
323
|
}
|
|
298
324
|
/** The current repo's name, or undefined outside a git checkout — never a
|
|
299
325
|
* fallback guess, since callers that want one (detectProject) supply it themselves. */
|
|
@@ -317,18 +343,19 @@ export function detectProject(dir = process.cwd()) {
|
|
|
317
343
|
return gitRepoName(dir) ?? (sanitizeSlugPart(basename(dir)) || 'share');
|
|
318
344
|
}
|
|
319
345
|
/**
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
346
|
+
* Readable slug + view id: `<feature>-<16hex>`. A leading `plan-` on the
|
|
347
|
+
* filename is dropped. The project no longer prefixes the slug — the URL
|
|
348
|
+
* namespace is already the publisher's handle (`/<you>/<slug>`).
|
|
323
349
|
*
|
|
324
350
|
* The tail is 8 random bytes (64-bit, 16 hex chars). Reads are public — the URL is
|
|
325
351
|
* the only capability — so the nonce must be genuinely infeasible to brute-force,
|
|
326
|
-
* not merely unlisted; 64 bits puts a blind guess out of reach. (See docs/
|
|
352
|
+
* not merely unlisted; 64 bits puts a blind guess out of reach. (See docs/distribution.md
|
|
327
353
|
* §Security for the threat model and `--expire` for sensitive content.)
|
|
354
|
+
* `--slug` still publishes that exact slug, no view-id appended.
|
|
328
355
|
*/
|
|
329
|
-
export function defaultSlug(filePath,
|
|
356
|
+
export function defaultSlug(filePath, _dir) {
|
|
330
357
|
const feature = slugify(filePath).replace(/^plan-/, '') || 'page';
|
|
331
|
-
return `${
|
|
358
|
+
return `${feature}-${randomBytes(8).toString('hex')}`;
|
|
332
359
|
}
|
|
333
360
|
function guessContentType(filePath) {
|
|
334
361
|
if (/\.html?$/i.test(filePath))
|
|
@@ -419,14 +446,12 @@ export function buildShareKey(username, slugPart) {
|
|
|
419
446
|
return `${user}/${part}`;
|
|
420
447
|
}
|
|
421
448
|
export async function publishFile(filePath, opts = {}) {
|
|
422
|
-
const
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
const
|
|
427
|
-
|
|
428
|
-
const analyticsToken = opts.analyticsToken ?? cfg.analyticsToken;
|
|
429
|
-
return publishToEndpoint(filePath, { baseUrl: cfg.baseUrl, token }, {
|
|
449
|
+
const backend = resolveShareBackend(opts);
|
|
450
|
+
const username = backend.kind === 'managed'
|
|
451
|
+
? backend.namespace
|
|
452
|
+
: await resolveShareUsername({ githubUser: opts.githubUser || backend.namespace || undefined });
|
|
453
|
+
const analyticsToken = opts.analyticsToken ?? (backend.kind === 'byo' ? (opts.config ?? readShareConfig())?.analyticsToken : undefined);
|
|
454
|
+
return publishToEndpoint(filePath, { baseUrl: backend.baseUrl, token: backend.token }, {
|
|
430
455
|
...opts,
|
|
431
456
|
githubUser: username,
|
|
432
457
|
analyticsToken,
|
|
@@ -437,7 +462,8 @@ export async function publishToEndpoint(filePath, endpoint, opts = {}) {
|
|
|
437
462
|
const slugPart = (opts.slug ?? defaultSlug(filePath)).replace(/^\/+/, '');
|
|
438
463
|
const key = buildShareKey(username, slugPart);
|
|
439
464
|
const expiresAt = resolveExpire(opts.expire);
|
|
440
|
-
const
|
|
465
|
+
const visibility = resolveShareVisibility(opts);
|
|
466
|
+
const unlisted = visibility === 'unlisted';
|
|
441
467
|
const pageUrl = `${endpoint.baseUrl.replace(/\/+$/, '')}/${key}`;
|
|
442
468
|
const provenance = opts.provenance ?? resolveShareProvenance();
|
|
443
469
|
const meta = opts.meta ?? {};
|
|
@@ -449,6 +475,9 @@ export async function publishToEndpoint(filePath, endpoint, opts = {}) {
|
|
|
449
475
|
let body = readFileSync(filePath);
|
|
450
476
|
let coverUrl;
|
|
451
477
|
const isHtml = /\.html?$/i.test(filePath);
|
|
478
|
+
if (isHtml) {
|
|
479
|
+
body = Buffer.from(prepareShareHtml(body.toString('utf8'), filePath), 'utf8');
|
|
480
|
+
}
|
|
452
481
|
const explicitLabel = opts.label?.trim();
|
|
453
482
|
// sanitizeLabel here (not just inside deriveLabel) covers an explicit
|
|
454
483
|
// --label/--title the caller typed with an embedded newline — deriveLabel
|
|
@@ -492,8 +521,7 @@ export async function publishToEndpoint(filePath, endpoint, opts = {}) {
|
|
|
492
521
|
const h = { authorization: `Bearer ${endpoint.token}`, 'content-type': contentType };
|
|
493
522
|
if (expiresAt)
|
|
494
523
|
h['x-share-expires-at'] = expiresAt;
|
|
495
|
-
|
|
496
|
-
h['x-share-visibility'] = 'unlisted';
|
|
524
|
+
h['x-share-visibility'] = visibility;
|
|
497
525
|
// Every free-text header goes through toHeaderValue: a non-latin1 code point
|
|
498
526
|
// anywhere in a label, a repo name, or a --meta value throws inside fetch and
|
|
499
527
|
// crashes the publish outright.
|
|
@@ -541,6 +569,9 @@ export async function publishToEndpoint(filePath, endpoint, opts = {}) {
|
|
|
541
569
|
}
|
|
542
570
|
const r = await put(pageUrl, body, authHeaders(opts.contentType ?? guessContentType(filePath)));
|
|
543
571
|
if (!r.ok) {
|
|
572
|
+
if (r.status === 409) {
|
|
573
|
+
throw new Error(`Handle '${username}' is already claimed by another account. The public URL namespace is the email local-part; two Phoenix users cannot share it.`);
|
|
574
|
+
}
|
|
544
575
|
throw new Error(`Publish failed (${r.status}) for ${pageUrl}. Check the write token, or that 'agents artifacts setup' completed.`);
|
|
545
576
|
}
|
|
546
577
|
return {
|
|
@@ -549,6 +580,7 @@ export async function publishToEndpoint(filePath, endpoint, opts = {}) {
|
|
|
549
580
|
coverUrl,
|
|
550
581
|
label,
|
|
551
582
|
labelSource,
|
|
583
|
+
visibility,
|
|
552
584
|
...(unlisted ? { unlisted: true } : {}),
|
|
553
585
|
};
|
|
554
586
|
}
|