@phnx-labs/agents-cli 1.22.114 → 1.22.115
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 +110 -0
- package/README.md +22 -102
- package/dist/browser.js +0 -0
- package/dist/cli/command-registry.js +0 -7
- package/dist/commands/accounts.d.ts +3 -77
- package/dist/commands/accounts.js +13 -366
- package/dist/commands/audit.js +1 -1
- package/dist/commands/auth.js +0 -2
- package/dist/commands/browser.d.ts +53 -0
- package/dist/commands/browser.js +199 -9
- package/dist/commands/doctor.d.ts +2 -3
- package/dist/commands/doctor.js +0 -11
- package/dist/commands/events.d.ts +1 -3
- package/dist/commands/events.js +4 -7
- package/dist/commands/exec.d.ts +0 -1
- package/dist/commands/exec.js +2 -7
- package/dist/commands/feed-watch.js +52 -8
- package/dist/commands/focus.js +1 -1
- package/dist/commands/go.d.ts +0 -17
- package/dist/commands/go.js +2 -19
- package/dist/commands/logs.js +1 -1
- package/dist/commands/mcp.js +8 -83
- package/dist/commands/memory.js +4 -47
- package/dist/commands/message.js +4 -4
- package/dist/commands/plugins.js +1 -93
- package/dist/commands/repo.js +0 -44
- package/dist/commands/resume.js +4 -1
- package/dist/commands/secrets-passthrough.js +2 -2
- package/dist/commands/send.d.ts +4 -4
- package/dist/commands/send.js +6 -51
- package/dist/commands/sessions-backup-setup.js +1 -1
- package/dist/commands/sessions-resume.js +0 -1
- package/dist/commands/sessions-share.d.ts +5 -7
- package/dist/commands/sessions-share.js +98 -49
- package/dist/commands/sessions.js +1 -8
- package/dist/commands/setup-browser.js +18 -2
- package/dist/commands/setup-computer.js +20 -6
- package/dist/commands/setup-secrets.js +24 -4
- package/dist/commands/setup-terminal.d.ts +3 -0
- package/dist/commands/setup-terminal.js +22 -0
- package/dist/commands/setup.d.ts +1 -1
- package/dist/commands/setup.js +20 -10
- package/dist/commands/skills.js +0 -8
- package/dist/commands/ssh.d.ts +6 -0
- package/dist/commands/ssh.js +92 -233
- package/dist/commands/sync.js +14 -5
- package/dist/commands/teams.js +1 -1
- package/dist/commands/traces.js +1 -1
- package/dist/lib/accounts/add.d.ts +0 -5
- package/dist/lib/accounts/add.js +1 -7
- package/dist/lib/artifacts-client.d.ts +20 -0
- package/dist/lib/artifacts-client.js +46 -0
- package/dist/lib/auth-mint.js +2 -2
- package/dist/lib/browser/runtime-state.d.ts +55 -0
- package/dist/lib/browser/runtime-state.js +99 -18
- package/dist/lib/browser/service.js +21 -1
- package/dist/lib/cli-resources.js +3 -1
- package/dist/lib/cloud/dispatch.js +1 -1
- package/dist/lib/cloudflare/creds.d.ts +10 -0
- package/dist/lib/cloudflare/creds.js +46 -0
- package/dist/lib/cloudflare/provision.d.ts +35 -0
- package/dist/lib/cloudflare/provision.js +144 -0
- package/dist/lib/computer/sessions-list.d.ts +55 -0
- package/dist/lib/computer/sessions-list.js +168 -1
- package/dist/lib/daemon/daemon.js +8 -1
- package/dist/lib/daemon/feed-stream-service.d.ts +23 -0
- package/dist/lib/daemon/feed-stream-service.js +40 -0
- package/dist/lib/daemon-services.d.ts +1 -1
- package/dist/lib/daemon-services.js +5 -0
- package/dist/lib/devices/connect.d.ts +49 -5
- package/dist/lib/devices/connect.js +169 -21
- package/dist/lib/feed/envelope.d.ts +79 -0
- package/dist/lib/feed/envelope.js +23 -0
- package/dist/lib/feed/events.d.ts +6 -0
- package/dist/lib/feed/events.js +8 -0
- package/dist/lib/feed/hub-server.d.ts +86 -0
- package/dist/lib/feed/hub-server.js +334 -0
- package/dist/lib/feed/hub.d.ts +95 -0
- package/dist/lib/feed/hub.js +255 -0
- package/dist/lib/feed/tool-activity.d.ts +108 -0
- package/dist/lib/feed/tool-activity.js +313 -0
- package/dist/lib/feed/tools.d.ts +198 -0
- package/dist/lib/feed/tools.js +265 -0
- package/dist/lib/feed/watch.d.ts +50 -50
- package/dist/lib/feed/watch.js +147 -16
- package/dist/lib/format.d.ts +1 -1
- package/dist/lib/format.js +1 -1
- package/dist/lib/git.d.ts +0 -16
- package/dist/lib/git.js +0 -58
- package/dist/lib/helper-versions.js +1 -1
- package/dist/lib/hosts/remote-cmd.d.ts +51 -1
- package/dist/lib/hosts/remote-cmd.js +125 -8
- package/dist/lib/hosts/remote-cmd.test-fixture.d.ts +2 -0
- package/dist/lib/hosts/remote-cmd.test-fixture.js +22 -0
- package/dist/lib/mcp.js +17 -11
- package/dist/lib/probe.d.ts +4 -1
- package/dist/lib/probe.js +5 -2
- package/dist/lib/pwsh.d.ts +33 -0
- package/dist/lib/pwsh.js +56 -0
- package/dist/lib/redact.d.ts +8 -0
- package/dist/lib/redact.js +11 -0
- package/dist/lib/refresh.d.ts +6 -2
- package/dist/lib/refresh.js +92 -72
- package/dist/lib/secrets-cli.d.ts +11 -0
- package/dist/lib/secrets-cli.js +30 -0
- package/dist/lib/secrets-client.js +3 -2
- package/dist/lib/session/detached.d.ts +7 -0
- package/dist/lib/session/detached.js +29 -0
- package/dist/lib/session/remote/peer-stream.d.ts +24 -2
- package/dist/lib/session/remote/peer-stream.js +33 -6
- package/dist/lib/session/sync/backend.d.ts +3 -3
- package/dist/lib/session/sync/backend.js +3 -3
- package/dist/lib/session/sync/provision.d.ts +1 -1
- package/dist/lib/session/sync/provision.js +2 -2
- package/dist/lib/sessions-client.js +0 -3
- package/dist/lib/setup-tool-install.d.ts +3 -0
- package/dist/lib/setup-tool-install.js +26 -0
- package/dist/lib/setup-tool-status.d.ts +22 -0
- package/dist/lib/setup-tool-status.js +215 -0
- package/dist/lib/share-runtime.d.ts +11 -0
- package/dist/lib/share-runtime.js +63 -0
- package/dist/lib/smart-launch.d.ts +1 -5
- package/dist/lib/smart-launch.js +3 -11
- package/dist/lib/ssh-exec.d.ts +44 -0
- package/dist/lib/ssh-exec.js +119 -0
- package/dist/lib/startup/command-registry.d.ts +6 -4
- package/dist/lib/startup/command-registry.js +10 -7
- package/dist/lib/state.js +2 -2
- package/dist/lib/storage/selection.d.ts +2 -2
- package/dist/lib/storage/selection.js +2 -2
- package/dist/lib/sync-umbrella.d.ts +5 -0
- package/dist/lib/sync-umbrella.js +18 -10
- package/dist/lib/traces/backend.d.ts +1 -2
- package/dist/lib/traces/backend.js +1 -2
- package/dist/lib/traces/provision.d.ts +1 -1
- package/dist/lib/traces/provision.js +2 -2
- package/dist/lib/types.d.ts +8 -6
- package/package.json +2 -3
- package/dist/commands/artifacts-setup.d.ts +0 -53
- package/dist/commands/artifacts-setup.js +0 -161
- package/dist/commands/artifacts.d.ts +0 -18
- package/dist/commands/artifacts.js +0 -58
- package/dist/commands/attach.d.ts +0 -12
- package/dist/commands/attach.js +0 -86
- package/dist/commands/auth-mint.d.ts +0 -12
- package/dist/commands/auth-mint.js +0 -108
- package/dist/commands/reconnect.d.ts +0 -46
- package/dist/commands/reconnect.js +0 -115
- package/dist/commands/share.d.ts +0 -293
- package/dist/commands/share.js +0 -1424
- package/dist/lib/share/analytics.d.ts +0 -13
- package/dist/lib/share/analytics.js +0 -45
- package/dist/lib/share/backend.d.ts +0 -120
- package/dist/lib/share/backend.js +0 -176
- package/dist/lib/share/capture.d.ts +0 -31
- package/dist/lib/share/capture.js +0 -174
- package/dist/lib/share/config.d.ts +0 -72
- package/dist/lib/share/config.js +0 -211
- package/dist/lib/share/delete.d.ts +0 -123
- package/dist/lib/share/delete.js +0 -173
- package/dist/lib/share/html.d.ts +0 -20
- package/dist/lib/share/html.js +0 -88
- package/dist/lib/share/http-error.d.ts +0 -53
- package/dist/lib/share/http-error.js +0 -65
- package/dist/lib/share/og.d.ts +0 -26
- package/dist/lib/share/og.js +0 -84
- package/dist/lib/share/provision.d.ts +0 -127
- package/dist/lib/share/provision.js +0 -285
- package/dist/lib/share/publish.d.ts +0 -379
- package/dist/lib/share/publish.js +0 -818
- package/dist/lib/share/worker-template.d.ts +0 -27
- package/dist/lib/share/worker-template.js +0 -2424
- package/dist/lib/storage/index.d.ts +0 -14
- package/dist/lib/storage/index.js +0 -14
- package/dist/lib/storage/visibility.d.ts +0 -82
- package/dist/lib/storage/visibility.js +0 -99
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/** Cloudflare Web Analytics snippet for a given zone token. */
|
|
2
|
-
export declare function renderBeacon(token: string): string;
|
|
3
|
-
/**
|
|
4
|
-
* Inject the CF Web Analytics beacon into an HTML page. Idempotent: any existing
|
|
5
|
-
* agents-share analytics block is removed first. The snippet is appended before
|
|
6
|
-
* `</body>` when present, otherwise before `</head>`, otherwise prepended to the
|
|
7
|
-
* document so it still loads.
|
|
8
|
-
*/
|
|
9
|
-
export declare function injectAnalyticsBeacon(html: string, token: string): string;
|
|
10
|
-
/** True if the share config has a non-empty analytics token. */
|
|
11
|
-
export declare function analyticsEnabled(cfg: {
|
|
12
|
-
analyticsToken?: string;
|
|
13
|
-
} | undefined | null): boolean;
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
// Cloudflare Web Analytics injection for `agents artifacts share`.
|
|
2
|
-
//
|
|
3
|
-
// The beacon is cookieless and privacy-first, which matters because a lot of shared
|
|
4
|
-
// content (games, kid-facing pages) should avoid GA4-style tracking. The token is
|
|
5
|
-
// stored in the synced share config and injected into every published HTML page at
|
|
6
|
-
// publish time, so analytics work with zero user effort once setup is complete.
|
|
7
|
-
const BEACON_OPEN = '<!-- agents-share:analytics -->';
|
|
8
|
-
const BEACON_CLOSE = '<!-- /agents-share:analytics -->';
|
|
9
|
-
/** Cloudflare Web Analytics snippet for a given zone token. */
|
|
10
|
-
export function renderBeacon(token) {
|
|
11
|
-
const payload = JSON.stringify({ token });
|
|
12
|
-
return (`${BEACON_OPEN}\n` +
|
|
13
|
-
'<script defer ' +
|
|
14
|
-
'src="https://static.cloudflareinsights.com/beacon.min.js" ' +
|
|
15
|
-
`data-cf-beacon='${payload}'></script>\n` +
|
|
16
|
-
`${BEACON_CLOSE}\n`);
|
|
17
|
-
}
|
|
18
|
-
/** Strip a previously-injected analytics block so re-publishing doesn't duplicate it. */
|
|
19
|
-
function stripPrevious(html) {
|
|
20
|
-
const re = new RegExp(`${BEACON_OPEN}[\\s\\S]*?${BEACON_CLOSE}\\n?`, 'g');
|
|
21
|
-
return html.replace(re, '');
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Inject the CF Web Analytics beacon into an HTML page. Idempotent: any existing
|
|
25
|
-
* agents-share analytics block is removed first. The snippet is appended before
|
|
26
|
-
* `</body>` when present, otherwise before `</head>`, otherwise prepended to the
|
|
27
|
-
* document so it still loads.
|
|
28
|
-
*/
|
|
29
|
-
export function injectAnalyticsBeacon(html, token) {
|
|
30
|
-
if (!token)
|
|
31
|
-
return html;
|
|
32
|
-
const cleaned = stripPrevious(html);
|
|
33
|
-
const block = renderBeacon(token);
|
|
34
|
-
const bodyClose = cleaned.search(/<\/body>/i);
|
|
35
|
-
if (bodyClose !== -1)
|
|
36
|
-
return cleaned.slice(0, bodyClose) + block + cleaned.slice(bodyClose);
|
|
37
|
-
const headClose = cleaned.search(/<\/head>/i);
|
|
38
|
-
if (headClose !== -1)
|
|
39
|
-
return cleaned.slice(0, headClose) + block + cleaned.slice(headClose);
|
|
40
|
-
return block + cleaned;
|
|
41
|
-
}
|
|
42
|
-
/** True if the share config has a non-empty analytics token. */
|
|
43
|
-
export function analyticsEnabled(cfg) {
|
|
44
|
-
return Boolean(cfg?.analyticsToken && cfg.analyticsToken.trim().length > 0);
|
|
45
|
-
}
|
|
@@ -1,120 +0,0 @@
|
|
|
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.getrush.ai`. 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 { type PhoenixSession } from '../identity/client.js';
|
|
21
|
-
import { type ShareConfig } from './config.js';
|
|
22
|
-
export type ShareBackendKind = 'managed' | 'byo';
|
|
23
|
-
export interface ShareBackend {
|
|
24
|
-
kind: ShareBackendKind;
|
|
25
|
-
/** Public base URL of the share Worker, no trailing slash. */
|
|
26
|
-
baseUrl: string;
|
|
27
|
-
/** Bearer sent as `Authorization`. Phoenix access_token or WRITE_TOKEN. */
|
|
28
|
-
token: string;
|
|
29
|
-
/** URL namespace prefix (`<namespace>/<slug>`). Phoenix handle (email local-part) or GitHub username. */
|
|
30
|
-
namespace: string;
|
|
31
|
-
}
|
|
32
|
-
export interface ResolveShareBackendOpts {
|
|
33
|
-
/** Force the BYO Cloudflare path even when signed in. */
|
|
34
|
-
byo?: boolean;
|
|
35
|
-
/** Override the namespace (BYO: GitHub username; ignored on managed — the
|
|
36
|
-
* worker 403s a Phoenix PUT whose first segment is not the verified handle). */
|
|
37
|
-
githubUser?: string;
|
|
38
|
-
/** DI seam — a static write token selects BYO. */
|
|
39
|
-
writeToken?: string;
|
|
40
|
-
/** DI seam — persisted BYO endpoint config. */
|
|
41
|
-
config?: ShareConfig;
|
|
42
|
-
/** DI seam — override `readSession()`. `null` means signed out. */
|
|
43
|
-
session?: PhoenixSession | null;
|
|
44
|
-
/**
|
|
45
|
-
* When false, BYO may resolve without a WRITE_TOKEN. Public GET routes
|
|
46
|
-
* (list / revisions / status) don't need one; publish and delete do.
|
|
47
|
-
* Default true.
|
|
48
|
-
*/
|
|
49
|
-
requireToken?: boolean;
|
|
50
|
-
}
|
|
51
|
-
/** Env var that forces the BYO path. Value must be exactly `byo`. */
|
|
52
|
-
export declare const SHARE_BACKEND_ENV = "AGENTS_SHARE_BACKEND";
|
|
53
|
-
/** URL-safe namespace: lowercase `[a-z0-9-]+`. Matches the Worker's sanitize.
|
|
54
|
-
*
|
|
55
|
-
* This is URL-safety, not collision-resistance: two values that differ only
|
|
56
|
-
* in case or punctuation share a prefix. */
|
|
57
|
-
export declare function sanitizeShareNamespace(s: string): string;
|
|
58
|
-
/**
|
|
59
|
-
* Public managed-share handle from a verified email.
|
|
60
|
-
*
|
|
61
|
-
* `muqsitnawaz@gmail.com` → `muqsitnawaz`. Plus-tags are dropped
|
|
62
|
-
* (`muqsitnawaz+dev@gmail.com` → `muqsitnawaz`) so the URL stays the
|
|
63
|
-
* account's default name. Empty / missing email → `''` (caller falls
|
|
64
|
-
* back to userId). Must match the Worker `handleFromEmail`.
|
|
65
|
-
*/
|
|
66
|
-
export declare function handleFromEmail(email: string | undefined): string;
|
|
67
|
-
/** Managed URL namespace: email handle, else sanitized userId (never empty if either is set). */
|
|
68
|
-
export declare function managedShareHandle(session: Pick<PhoenixSession, 'email' | 'userId'>): string;
|
|
69
|
-
export declare function managedShareBaseUrl(): string;
|
|
70
|
-
/**
|
|
71
|
-
* True when this config is the platform managed endpoint (`share.getrush.ai`, or a
|
|
72
|
-
* legacy alias — `share.agents-cli.sh` / `artifacts.prix.dev` — still bound to the
|
|
73
|
-
* same Worker). The
|
|
74
|
-
* deploy path uses this — not "the caller is signed in" — to decide whether to
|
|
75
|
-
* bind `PHOENIX_ID_BASE` on the Worker.
|
|
76
|
-
*/
|
|
77
|
-
export declare function isManagedShareEndpoint(cfg: {
|
|
78
|
-
baseUrl?: string;
|
|
79
|
-
domain?: string;
|
|
80
|
-
}): boolean;
|
|
81
|
-
/**
|
|
82
|
-
* Phoenix ID URL to bind on a managed Worker deploy. `undefined` for a
|
|
83
|
-
* pure-BYO Worker (WRITE_TOKEN only). Fail loud if this is a managed deploy
|
|
84
|
-
* but the base is empty — never skip-set a blank secret.
|
|
85
|
-
*/
|
|
86
|
-
export declare function phoenixIdBaseForDeploy(opts?: {
|
|
87
|
-
managed?: boolean;
|
|
88
|
-
}, cfg?: {
|
|
89
|
-
baseUrl?: string;
|
|
90
|
-
domain?: string;
|
|
91
|
-
}): string | undefined;
|
|
92
|
-
/**
|
|
93
|
-
* Managed collaboration backend config to bind on a managed Worker deploy
|
|
94
|
-
* (PHNX-3835): `PRIX_ARTIFACT_COLLAB_BASE` (the Prix artifact-collaboration API
|
|
95
|
-
* base) and `ARTIFACT_COLLAB_SERVICE_TOKEN` (the service credential the Worker
|
|
96
|
-
* sends as `Authorization: Bearer`, NEVER surfaced to the browser). Both are read
|
|
97
|
-
* from the deploy environment.
|
|
98
|
-
*
|
|
99
|
-
* Deliberately dormant-by-default: the two secrets are applied ONLY when BOTH are
|
|
100
|
-
* present. Until the Prix API counterpart is live an operator leaves them unset,
|
|
101
|
-
* and the Worker fails `/__collab` closed (404) with the artifact page GET
|
|
102
|
-
* unaffected. A pure-BYO endpoint never gets them (it has no Phoenix identity).
|
|
103
|
-
* Unlike `phoenixIdBaseForDeploy` this never throws on absence — collaboration is
|
|
104
|
-
* additive, not required for a working managed deploy.
|
|
105
|
-
*/
|
|
106
|
-
export declare function collabConfigForDeploy(opts?: {
|
|
107
|
-
managed?: boolean;
|
|
108
|
-
}, cfg?: {
|
|
109
|
-
baseUrl?: string;
|
|
110
|
-
domain?: string;
|
|
111
|
-
}): {
|
|
112
|
-
collabBase?: string;
|
|
113
|
-
collabServiceToken?: string;
|
|
114
|
-
};
|
|
115
|
-
/**
|
|
116
|
-
* Pick the principal via the shared selection policy. Signed-in AND no explicit
|
|
117
|
-
* BYO override → managed; otherwise BYO.
|
|
118
|
-
*/
|
|
119
|
-
export declare function shouldUseManaged(opts?: ResolveShareBackendOpts): boolean;
|
|
120
|
-
export declare function resolveShareBackend(opts?: ResolveShareBackendOpts): ShareBackend;
|
|
@@ -1,176 +0,0 @@
|
|
|
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.getrush.ai`. 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 { selectStorageBackendKind } from '../storage/selection.js';
|
|
22
|
-
import { DEFAULT_SHARE_DOMAIN, LEGACY_MANAGED_SHARE_DOMAINS, readShareConfig, readWriteToken, readWriteTokenEnv, } from './config.js';
|
|
23
|
-
/** Env var that forces the BYO path. Value must be exactly `byo`. */
|
|
24
|
-
export const SHARE_BACKEND_ENV = 'AGENTS_SHARE_BACKEND';
|
|
25
|
-
/** URL-safe namespace: lowercase `[a-z0-9-]+`. Matches the Worker's sanitize.
|
|
26
|
-
*
|
|
27
|
-
* This is URL-safety, not collision-resistance: two values that differ only
|
|
28
|
-
* in case or punctuation share a prefix. */
|
|
29
|
-
export function sanitizeShareNamespace(s) {
|
|
30
|
-
return s.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Public managed-share handle from a verified email.
|
|
34
|
-
*
|
|
35
|
-
* `muqsitnawaz@gmail.com` → `muqsitnawaz`. Plus-tags are dropped
|
|
36
|
-
* (`muqsitnawaz+dev@gmail.com` → `muqsitnawaz`) so the URL stays the
|
|
37
|
-
* account's default name. Empty / missing email → `''` (caller falls
|
|
38
|
-
* back to userId). Must match the Worker `handleFromEmail`.
|
|
39
|
-
*/
|
|
40
|
-
export function handleFromEmail(email) {
|
|
41
|
-
if (!email)
|
|
42
|
-
return '';
|
|
43
|
-
const local = email.split('@')[0] ?? '';
|
|
44
|
-
const beforePlus = local.split('+')[0] ?? local;
|
|
45
|
-
return sanitizeShareNamespace(beforePlus);
|
|
46
|
-
}
|
|
47
|
-
/** Managed URL namespace: email handle, else sanitized userId (never empty if either is set). */
|
|
48
|
-
export function managedShareHandle(session) {
|
|
49
|
-
return handleFromEmail(session.email) || sanitizeShareNamespace(session.userId ?? '');
|
|
50
|
-
}
|
|
51
|
-
export function managedShareBaseUrl() {
|
|
52
|
-
return `https://${DEFAULT_SHARE_DOMAIN}`;
|
|
53
|
-
}
|
|
54
|
-
function shareEndpointHost(value) {
|
|
55
|
-
return value.replace(/^https?:\/\//i, '').replace(/\/+$/, '').toLowerCase();
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* True when this config is the platform managed endpoint (`share.getrush.ai`, or a
|
|
59
|
-
* legacy alias — `share.agents-cli.sh` / `artifacts.prix.dev` — still bound to the
|
|
60
|
-
* same Worker). The
|
|
61
|
-
* deploy path uses this — not "the caller is signed in" — to decide whether to
|
|
62
|
-
* bind `PHOENIX_ID_BASE` on the Worker.
|
|
63
|
-
*/
|
|
64
|
-
export function isManagedShareEndpoint(cfg) {
|
|
65
|
-
const managedHosts = new Set([DEFAULT_SHARE_DOMAIN, ...LEGACY_MANAGED_SHARE_DOMAINS].map((h) => h.toLowerCase()));
|
|
66
|
-
if (cfg.domain && managedHosts.has(shareEndpointHost(cfg.domain)))
|
|
67
|
-
return true;
|
|
68
|
-
if (cfg.baseUrl && managedHosts.has(shareEndpointHost(cfg.baseUrl)))
|
|
69
|
-
return true;
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Phoenix ID URL to bind on a managed Worker deploy. `undefined` for a
|
|
74
|
-
* pure-BYO Worker (WRITE_TOKEN only). Fail loud if this is a managed deploy
|
|
75
|
-
* but the base is empty — never skip-set a blank secret.
|
|
76
|
-
*/
|
|
77
|
-
export function phoenixIdBaseForDeploy(opts = {}, cfg) {
|
|
78
|
-
const managed = opts.managed === true || (cfg != null && isManagedShareEndpoint(cfg));
|
|
79
|
-
if (!managed)
|
|
80
|
-
return undefined;
|
|
81
|
-
const base = PHOENIX_ID_BASE.replace(/\/+$/, '').trim();
|
|
82
|
-
if (!base) {
|
|
83
|
-
throw new Error('Managed share deploy requires PHOENIX_ID_BASE so the Worker can verify Phoenix bearers. Set the PHOENIX_ID_BASE env var.');
|
|
84
|
-
}
|
|
85
|
-
return base;
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Managed collaboration backend config to bind on a managed Worker deploy
|
|
89
|
-
* (PHNX-3835): `PRIX_ARTIFACT_COLLAB_BASE` (the Prix artifact-collaboration API
|
|
90
|
-
* base) and `ARTIFACT_COLLAB_SERVICE_TOKEN` (the service credential the Worker
|
|
91
|
-
* sends as `Authorization: Bearer`, NEVER surfaced to the browser). Both are read
|
|
92
|
-
* from the deploy environment.
|
|
93
|
-
*
|
|
94
|
-
* Deliberately dormant-by-default: the two secrets are applied ONLY when BOTH are
|
|
95
|
-
* present. Until the Prix API counterpart is live an operator leaves them unset,
|
|
96
|
-
* and the Worker fails `/__collab` closed (404) with the artifact page GET
|
|
97
|
-
* unaffected. A pure-BYO endpoint never gets them (it has no Phoenix identity).
|
|
98
|
-
* Unlike `phoenixIdBaseForDeploy` this never throws on absence — collaboration is
|
|
99
|
-
* additive, not required for a working managed deploy.
|
|
100
|
-
*/
|
|
101
|
-
export function collabConfigForDeploy(opts = {}, cfg) {
|
|
102
|
-
const managed = opts.managed === true || (cfg != null && isManagedShareEndpoint(cfg));
|
|
103
|
-
if (!managed)
|
|
104
|
-
return {};
|
|
105
|
-
const base = (process.env.PRIX_ARTIFACT_COLLAB_BASE || '').replace(/\/+$/, '').trim();
|
|
106
|
-
const token = (process.env.ARTIFACT_COLLAB_SERVICE_TOKEN || '').trim();
|
|
107
|
-
if (!base || !token)
|
|
108
|
-
return {};
|
|
109
|
-
return { collabBase: base, collabServiceToken: token };
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* The share surface's BYO-override signals: an explicit `--byo`, a
|
|
113
|
-
* caller-supplied static write token, or `AGENTS_SHARE_BACKEND=byo`. Detecting
|
|
114
|
-
* WHICH signals count is surface-specific; the managed-vs-BYO decision itself is
|
|
115
|
-
* the shared policy (`selectStorageBackendKind`). A persisted BYO endpoint config
|
|
116
|
-
* is deliberately NOT an override here — a signed-in user with a stale BYO config
|
|
117
|
-
* still publishes to managed unless they opt out explicitly (the product's
|
|
118
|
-
* managed-first contract).
|
|
119
|
-
*/
|
|
120
|
-
function shareByoOverride(opts) {
|
|
121
|
-
if (opts.byo === true)
|
|
122
|
-
return true;
|
|
123
|
-
if (opts.writeToken)
|
|
124
|
-
return true;
|
|
125
|
-
return (process.env[SHARE_BACKEND_ENV] ?? '').trim().toLowerCase() === 'byo';
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Pick the principal via the shared selection policy. Signed-in AND no explicit
|
|
129
|
-
* BYO override → managed; otherwise BYO.
|
|
130
|
-
*/
|
|
131
|
-
export function shouldUseManaged(opts = {}) {
|
|
132
|
-
return (selectStorageBackendKind({ byoOverride: shareByoOverride(opts), session: opts.session }) ===
|
|
133
|
-
'managed');
|
|
134
|
-
}
|
|
135
|
-
export function resolveShareBackend(opts = {}) {
|
|
136
|
-
if (shouldUseManaged(opts)) {
|
|
137
|
-
const session = opts.session === undefined ? readSession() : opts.session;
|
|
138
|
-
if (!session) {
|
|
139
|
-
throw new Error("Not signed in. Run 'agents auth login'.");
|
|
140
|
-
}
|
|
141
|
-
return resolveManagedBackend(session);
|
|
142
|
-
}
|
|
143
|
-
return resolveByoBackend(opts);
|
|
144
|
-
}
|
|
145
|
-
function resolveManagedBackend(session) {
|
|
146
|
-
if (!session.access_token) {
|
|
147
|
-
throw new Error("Not signed in. Run 'agents auth login'.");
|
|
148
|
-
}
|
|
149
|
-
const namespace = managedShareHandle(session);
|
|
150
|
-
if (!namespace) {
|
|
151
|
-
throw new Error("Signed in but the session has no email or user id. Run 'agents auth login' again.");
|
|
152
|
-
}
|
|
153
|
-
return {
|
|
154
|
-
kind: 'managed',
|
|
155
|
-
baseUrl: managedShareBaseUrl(),
|
|
156
|
-
token: session.access_token,
|
|
157
|
-
namespace,
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
function resolveByoBackend(opts) {
|
|
161
|
-
const cfg = opts.config ?? readShareConfig();
|
|
162
|
-
if (!cfg) {
|
|
163
|
-
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.");
|
|
164
|
-
}
|
|
165
|
-
const token = opts.writeToken ??
|
|
166
|
-
(opts.requireToken === false ? (readWriteTokenEnv() ?? '') : readWriteToken());
|
|
167
|
-
// Namespace is the GitHub username. An explicit --github-user is sanitized
|
|
168
|
-
// here; otherwise publish fills it via resolveShareUsername (gh/git config).
|
|
169
|
-
const namespace = opts.githubUser ? sanitizeShareNamespace(opts.githubUser) : '';
|
|
170
|
-
return {
|
|
171
|
-
kind: 'byo',
|
|
172
|
-
baseUrl: cfg.baseUrl.replace(/\/+$/, ''),
|
|
173
|
-
token,
|
|
174
|
-
namespace,
|
|
175
|
-
};
|
|
176
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Render an HTML file to a 1200×630 PNG — the Open Graph cover for a shared plan.
|
|
3
|
-
*
|
|
4
|
-
* When `agents artifacts share plan.html` runs, we screenshot the plan's own hero and use it
|
|
5
|
-
* as the `og:image`, so the link unfurls into a card in Slack / iMessage / Twitter /
|
|
6
|
-
* Discord. No AI, no central render service: it's a headless screenshot on the
|
|
7
|
-
* publisher's machine, so it works identically for us and for any user, and costs
|
|
8
|
-
* nothing.
|
|
9
|
-
*
|
|
10
|
-
* Browser resolution reuses the repo's own detector (`findFirstInstalledBrowser`,
|
|
11
|
-
* the same auto-pick behind `agents browser`), then falls back to a managed
|
|
12
|
-
* Chromium in the Playwright/Puppeteer caches (present on machines that have done
|
|
13
|
-
* browser automation), then `PUPPETEER_EXECUTABLE_PATH`. If nothing headless-capable
|
|
14
|
-
* is found, `captureCover` returns null and publishing proceeds without a cover —
|
|
15
|
-
* the link still works, it just won't have a preview image.
|
|
16
|
-
*/
|
|
17
|
-
/** OG standard card size; captured at OG_SCALE× for retina crispness. */
|
|
18
|
-
export declare const OG_WIDTH = 1200;
|
|
19
|
-
export declare const OG_HEIGHT = 630;
|
|
20
|
-
/** Device scale factor for the capture — the served PNG is OG_WIDTH*OG_SCALE × OG_HEIGHT*OG_SCALE. */
|
|
21
|
-
export declare const OG_SCALE = 2;
|
|
22
|
-
/** Ordered list of candidate Chromium-family binaries to try for headless capture. */
|
|
23
|
-
export declare function candidateBrowsers(): string[];
|
|
24
|
-
/** Newest-first Chromium binaries under the Playwright / Puppeteer download caches. */
|
|
25
|
-
export declare function scanCaches(home?: string, platform?: NodeJS.Platform): string[];
|
|
26
|
-
/**
|
|
27
|
-
* Screenshot `htmlPath`'s top 1200×630 (its hero) to a PNG buffer, or null if no
|
|
28
|
-
* headless-capable browser is available or every candidate fails. Never throws —
|
|
29
|
-
* a cover is a nice-to-have, never a reason to fail a publish.
|
|
30
|
-
*/
|
|
31
|
-
export declare function captureCover(htmlPath: string, timeoutMs?: number): Promise<Buffer | null>;
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Render an HTML file to a 1200×630 PNG — the Open Graph cover for a shared plan.
|
|
3
|
-
*
|
|
4
|
-
* When `agents artifacts share plan.html` runs, we screenshot the plan's own hero and use it
|
|
5
|
-
* as the `og:image`, so the link unfurls into a card in Slack / iMessage / Twitter /
|
|
6
|
-
* Discord. No AI, no central render service: it's a headless screenshot on the
|
|
7
|
-
* publisher's machine, so it works identically for us and for any user, and costs
|
|
8
|
-
* nothing.
|
|
9
|
-
*
|
|
10
|
-
* Browser resolution reuses the repo's own detector (`findFirstInstalledBrowser`,
|
|
11
|
-
* the same auto-pick behind `agents browser`), then falls back to a managed
|
|
12
|
-
* Chromium in the Playwright/Puppeteer caches (present on machines that have done
|
|
13
|
-
* browser automation), then `PUPPETEER_EXECUTABLE_PATH`. If nothing headless-capable
|
|
14
|
-
* is found, `captureCover` returns null and publishing proceeds without a cover —
|
|
15
|
-
* the link still works, it just won't have a preview image.
|
|
16
|
-
*/
|
|
17
|
-
import { execFile } from 'node:child_process';
|
|
18
|
-
import fs from 'node:fs';
|
|
19
|
-
import os from 'node:os';
|
|
20
|
-
import path from 'node:path';
|
|
21
|
-
import { findFirstInstalledBrowser } from '../browser/chrome.js';
|
|
22
|
-
/** OG standard card size; captured at OG_SCALE× for retina crispness. */
|
|
23
|
-
export const OG_WIDTH = 1200;
|
|
24
|
-
export const OG_HEIGHT = 630;
|
|
25
|
-
/** Device scale factor for the capture — the served PNG is OG_WIDTH*OG_SCALE × OG_HEIGHT*OG_SCALE. */
|
|
26
|
-
export const OG_SCALE = 2;
|
|
27
|
-
// Installed browsers that are poor `--headless` hosts (they hang instead of
|
|
28
|
-
// capturing). We still let a managed Chromium or an explicit override handle those
|
|
29
|
-
// machines; we just don't burn a timeout probing these. (Only members of the
|
|
30
|
-
// browser detector's `BrowserType` are meaningful here; Comet is the real case.)
|
|
31
|
-
const BAD_HEADLESS_TYPES = new Set(['comet']);
|
|
32
|
-
/** Ordered list of candidate Chromium-family binaries to try for headless capture. */
|
|
33
|
-
export function candidateBrowsers() {
|
|
34
|
-
const out = [];
|
|
35
|
-
const push = (p) => {
|
|
36
|
-
if (p && fs.existsSync(p) && !out.includes(p))
|
|
37
|
-
out.push(p);
|
|
38
|
-
};
|
|
39
|
-
// 1) Explicit overrides are contracts, not hints. A typo must fail at the
|
|
40
|
-
// boundary instead of silently falling through to an unrelated browser.
|
|
41
|
-
for (const name of ['PUPPETEER_EXECUTABLE_PATH', 'AGENTS_SHARE_BROWSER']) {
|
|
42
|
-
const value = process.env[name]?.trim();
|
|
43
|
-
if (!value)
|
|
44
|
-
continue;
|
|
45
|
-
if (!fs.existsSync(value)) {
|
|
46
|
-
throw new Error(`${name} points to a browser that does not exist: ${value}`);
|
|
47
|
-
}
|
|
48
|
-
push(value);
|
|
49
|
-
}
|
|
50
|
-
// 2) Managed Chromium in the Playwright / Puppeteer caches — purpose-built for
|
|
51
|
-
// headless, so it's the most reliable capture host when present.
|
|
52
|
-
for (const bin of scanCaches())
|
|
53
|
-
push(bin);
|
|
54
|
-
// 3) The repo's own auto-pick (Chrome → Brave → Edge → Chromium by platform),
|
|
55
|
-
// skipping browsers known to be poor headless hosts so we don't eat a timeout.
|
|
56
|
-
try {
|
|
57
|
-
const pick = findFirstInstalledBrowser();
|
|
58
|
-
if (pick && !BAD_HEADLESS_TYPES.has(pick.browserType))
|
|
59
|
-
push(pick.binary);
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
// detector is best-effort
|
|
63
|
-
}
|
|
64
|
-
return out;
|
|
65
|
-
}
|
|
66
|
-
/** Newest-first Chromium binaries under the Playwright / Puppeteer download caches. */
|
|
67
|
-
export function scanCaches(home = os.homedir(), platform = os.platform()) {
|
|
68
|
-
const roots = platform === 'darwin'
|
|
69
|
-
? [
|
|
70
|
-
path.join(home, 'Library/Caches/ms-playwright'),
|
|
71
|
-
path.join(home, '.cache/ms-playwright'),
|
|
72
|
-
path.join(home, '.cache/puppeteer/chrome'),
|
|
73
|
-
]
|
|
74
|
-
: [path.join(home, '.cache/ms-playwright'), path.join(home, '.cache/puppeteer/chrome')];
|
|
75
|
-
const rel = platform === 'darwin'
|
|
76
|
-
? [
|
|
77
|
-
'chrome-mac/Chromium.app/Contents/MacOS/Chromium',
|
|
78
|
-
'chrome-mac-arm64/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing',
|
|
79
|
-
'chrome-mac-x64/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing',
|
|
80
|
-
// Playwright's newer headless-shell packages (chromium_headless_shell-*) —
|
|
81
|
-
// a raw binary, not an .app bundle.
|
|
82
|
-
'chrome-headless-shell-mac-arm64/chrome-headless-shell',
|
|
83
|
-
'chrome-headless-shell-mac-x64/chrome-headless-shell',
|
|
84
|
-
]
|
|
85
|
-
: [
|
|
86
|
-
'chrome-linux/chrome',
|
|
87
|
-
'chrome-linux64/chrome',
|
|
88
|
-
'chrome-headless-shell-linux64/chrome-headless-shell',
|
|
89
|
-
];
|
|
90
|
-
const found = [];
|
|
91
|
-
for (const root of roots) {
|
|
92
|
-
let entries;
|
|
93
|
-
try {
|
|
94
|
-
entries = fs.readdirSync(root).sort().reverse(); // newest version dir first
|
|
95
|
-
}
|
|
96
|
-
catch {
|
|
97
|
-
continue;
|
|
98
|
-
}
|
|
99
|
-
for (const e of entries) {
|
|
100
|
-
for (const r of rel) {
|
|
101
|
-
const p = path.join(root, e, r);
|
|
102
|
-
if (fs.existsSync(p))
|
|
103
|
-
found.push(p);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
return found;
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Screenshot `htmlPath`'s top 1200×630 (its hero) to a PNG buffer, or null if no
|
|
111
|
-
* headless-capable browser is available or every candidate fails. Never throws —
|
|
112
|
-
* a cover is a nice-to-have, never a reason to fail a publish.
|
|
113
|
-
*/
|
|
114
|
-
export async function captureCover(htmlPath, timeoutMs = 15_000) {
|
|
115
|
-
const abs = path.resolve(htmlPath);
|
|
116
|
-
if (!fs.existsSync(abs))
|
|
117
|
-
return null;
|
|
118
|
-
const fileUrl = `file://${abs.split('/').map(encodeURIComponent).join('/')}`;
|
|
119
|
-
const candidates = candidateBrowsers();
|
|
120
|
-
if (candidates.length === 0) {
|
|
121
|
-
// A silently-dropped cover reads as "the CLI decided this page needs none",
|
|
122
|
-
// when in fact no headless browser was found. Say so and point at the escape
|
|
123
|
-
// hatch instead of leaving the publish coverless with no explanation.
|
|
124
|
-
process.stderr.write('[agents artifacts share] no headless browser found for the OG cover — install Chrome/Chromium ' +
|
|
125
|
-
'or set AGENTS_SHARE_BROWSER=/path/to/chrome. Publishing without a preview image.\n');
|
|
126
|
-
return null;
|
|
127
|
-
}
|
|
128
|
-
let lastFailure = '';
|
|
129
|
-
for (const bin of candidates) {
|
|
130
|
-
const outPng = path.join(os.tmpdir(), `agents-share-cover-${process.pid}-${Date.now()}.png`);
|
|
131
|
-
const userDir = fs.mkdtempSync(path.join(os.tmpdir(), 'agents-share-chrome-'));
|
|
132
|
-
try {
|
|
133
|
-
await new Promise((resolve, reject) => {
|
|
134
|
-
execFile(bin, [
|
|
135
|
-
'--headless=new',
|
|
136
|
-
'--disable-gpu',
|
|
137
|
-
'--hide-scrollbars',
|
|
138
|
-
'--no-first-run',
|
|
139
|
-
'--no-default-browser-check',
|
|
140
|
-
`--force-device-scale-factor=${OG_SCALE}`,
|
|
141
|
-
// Bound page JS (count-up animations etc.) so the shot fires promptly
|
|
142
|
-
// instead of waiting on long-running timers.
|
|
143
|
-
'--virtual-time-budget=8000',
|
|
144
|
-
`--window-size=${OG_WIDTH},${OG_HEIGHT}`,
|
|
145
|
-
`--user-data-dir=${userDir}`,
|
|
146
|
-
`--screenshot=${outPng}`,
|
|
147
|
-
fileUrl,
|
|
148
|
-
], { timeout: timeoutMs }, (err) => (err ? reject(err) : resolve()));
|
|
149
|
-
});
|
|
150
|
-
if (fs.existsSync(outPng)) {
|
|
151
|
-
const buf = fs.readFileSync(outPng);
|
|
152
|
-
// A valid PNG starts with the 8-byte signature; guard against 0-byte writes.
|
|
153
|
-
if (buf.length > 8 && buf[0] === 0x89 && buf[1] === 0x50)
|
|
154
|
-
return buf;
|
|
155
|
-
lastFailure = `${path.basename(bin)}: produced no valid PNG`;
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
lastFailure = `${path.basename(bin)}: no screenshot written`;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
catch (err) {
|
|
162
|
-
lastFailure = `${path.basename(bin)}: ${err.message}`;
|
|
163
|
-
}
|
|
164
|
-
finally {
|
|
165
|
-
fs.rmSync(outPng, { force: true });
|
|
166
|
-
fs.rmSync(userDir, { recursive: true, force: true });
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
// Every candidate ran but none yielded a cover — surface the last reason so a
|
|
170
|
-
// missing preview card is diagnosable (timeout, crash, bad binary) rather than silent.
|
|
171
|
-
process.stderr.write(`[agents artifacts share] OG cover capture failed (${lastFailure || 'unknown error'}) — ` +
|
|
172
|
-
'publishing without a preview image. Set AGENTS_SHARE_BROWSER to override.\n');
|
|
173
|
-
return null;
|
|
174
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
export interface ShareConfig {
|
|
2
|
-
/** Public base, e.g. `https://share.getrush.ai` or `https://agent-share.<acct>.workers.dev`. */
|
|
3
|
-
baseUrl: string;
|
|
4
|
-
accountId: string;
|
|
5
|
-
workerName: string;
|
|
6
|
-
bucketName: string;
|
|
7
|
-
/** Custom domain when mapped (e.g. `share.getrush.ai`). */
|
|
8
|
-
domain?: string;
|
|
9
|
-
/** Cloudflare Web Analytics token injected into published HTML pages. */
|
|
10
|
-
analyticsToken?: string;
|
|
11
|
-
/** sha256 of the Worker script deployed at the last provision/update. Absent
|
|
12
|
-
* on any config written before this field existed — treat that as "unknown",
|
|
13
|
-
* never as "outdated" (there is nothing to compare against). */
|
|
14
|
-
templateHash?: string;
|
|
15
|
-
}
|
|
16
|
-
export declare const SHARE_BUNDLE = "share";
|
|
17
|
-
export declare const SHARE_TOKEN_KEY = "WRITE_TOKEN";
|
|
18
|
-
export declare const SHARE_TOKEN_ENV_KEY = "SHARE_WRITE_TOKEN";
|
|
19
|
-
export declare const DEFAULT_CF_BUNDLE = "cloudflare";
|
|
20
|
-
export declare const DEFAULT_WORKER_NAME = "agents-share";
|
|
21
|
-
export declare const DEFAULT_BUCKET_NAME = "agents-share";
|
|
22
|
-
export declare const DEFAULT_SHARE_DOMAIN = "share.getrush.ai";
|
|
23
|
-
export declare const LEGACY_MANAGED_SHARE_DOMAINS: readonly ["share.agents-cli.sh", "artifacts.prix.dev"];
|
|
24
|
-
/** The write token may be injected ephemerally into fleet/cloud agents. */
|
|
25
|
-
export declare function readWriteTokenEnv(env?: NodeJS.ProcessEnv): string | null;
|
|
26
|
-
/**
|
|
27
|
-
* Read the persisted endpoint config, or null if there is no `share.baseUrl`.
|
|
28
|
-
*
|
|
29
|
-
* Publish talks only to `baseUrl` with `WRITE_TOKEN`. `accountId` / worker /
|
|
30
|
-
* bucket are provisioning metadata for `setup`/`update`. Requiring all four
|
|
31
|
-
* (and treating `accountId: ""` as missing) made `status` and publish both
|
|
32
|
-
* report "not set up" on an endpoint that still worked — RUSH-2837.
|
|
33
|
-
*/
|
|
34
|
-
export declare function readShareConfig(): ShareConfig | null;
|
|
35
|
-
/** Persist the endpoint config to `agents.yaml` (syncs across the fleet).
|
|
36
|
-
* Empty strings never overwrite a previously stored value and are not written
|
|
37
|
-
* back as `accountId: ""` (that form made {@link readShareConfig} return null
|
|
38
|
-
* under the old all-fields-required check, and it is still useless). */
|
|
39
|
-
export declare function writeShareConfig(cfg: ShareConfig): void;
|
|
40
|
-
/** A fresh 32-byte hex write token. */
|
|
41
|
-
export declare function generateWriteToken(): string;
|
|
42
|
-
/** Persist the raw write token into the `share` secrets bundle (keychain-backed,
|
|
43
|
-
* fleet-injectable). Mirrors the add-key sequence in `commands/secrets.ts`. */
|
|
44
|
-
export declare function storeWriteToken(token: string): void;
|
|
45
|
-
/** Read the raw write token from the `share` secrets bundle. */
|
|
46
|
-
export declare function readWriteTokenFromBundle(): string;
|
|
47
|
-
/** Read the raw write token from injected env first, then the local bundle.
|
|
48
|
-
* Throws with an actionable message if absent (run setup/join first). */
|
|
49
|
-
export declare function readWriteToken(): string;
|
|
50
|
-
/** Best-effort runtime env for spawned agents. Never throws AND never prompts.
|
|
51
|
-
*
|
|
52
|
-
* Auto-injecting the share write token on every `agents run` is a background
|
|
53
|
-
* convenience, NOT a user-initiated secret access — so it MUST NOT raise a Touch
|
|
54
|
-
* ID sheet (SEC-13: an agent launch never pops biometry on its own). This was the
|
|
55
|
-
* per-run prompt storm: `share` is a keychain bundle that is rarely broker-held,
|
|
56
|
-
* so an interactive read here spawned the helper and popped Touch ID on EVERY
|
|
57
|
-
* launch. The read is now always `agentOnly` — it resolves the token only from the
|
|
58
|
-
* injected env or an already-held / no-ACL bundle, and silently returns undefined
|
|
59
|
-
* otherwise (the caller runs without auto-share; the agent can still publish via
|
|
60
|
-
* its own `agents artifacts share`). To get zero-friction auto-share with no prompt: unlock
|
|
61
|
-
* once (`agents secrets unlock share`) or make it no-ACL (`agents secrets policy
|
|
62
|
-
* share never`). */
|
|
63
|
-
export declare function shareRuntimeEnv(): Record<string, string> | undefined;
|
|
64
|
-
/** Cloudflare API credentials for provisioning, read from `cloudflare` (or a
|
|
65
|
-
* user-named bundle). Fuzzy-matches key names so it works across bundle layouts. */
|
|
66
|
-
export declare function readCloudflareCreds(bundle?: string, override?: {
|
|
67
|
-
apiToken?: string;
|
|
68
|
-
accountId?: string;
|
|
69
|
-
}): {
|
|
70
|
-
apiToken: string;
|
|
71
|
-
accountId: string;
|
|
72
|
-
};
|