@phnx-labs/agents-cli 1.22.75 → 1.22.76
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 +117 -0
- package/README.md +20 -8
- package/dist/bootstrap.js +7 -7
- package/dist/cli/command-registry.js +5 -0
- package/dist/commands/artifacts-setup.js +1 -1
- package/dist/commands/artifacts.js +1 -1
- package/dist/commands/auth.js +7 -1
- package/dist/commands/browser.js +104 -10
- package/dist/commands/commands.js +7 -6
- package/dist/commands/config.js +27 -4
- package/dist/commands/cost.js +6 -4
- package/dist/commands/doctor.d.ts +6 -5
- package/dist/commands/doctor.js +32 -274
- package/dist/commands/exec.d.ts +2 -0
- package/dist/commands/exec.js +9 -2
- package/dist/commands/harness.d.ts +1 -0
- package/dist/commands/harness.js +11 -3
- package/dist/commands/hooks.js +7 -6
- package/dist/commands/mcp.js +7 -6
- package/dist/commands/memory.js +7 -7
- package/dist/commands/monitors.js +3 -2
- package/dist/commands/open.d.ts +25 -12
- package/dist/commands/open.js +24 -10
- package/dist/commands/permissions.js +7 -6
- package/dist/commands/plugins.js +21 -17
- package/dist/commands/route.js +33 -16
- package/dist/commands/rules.js +7 -12
- package/dist/commands/sessions-share.js +1 -1
- package/dist/commands/setup-watchdog.js +2 -2
- package/dist/commands/setup.js +22 -1
- package/dist/commands/share.js +26 -10
- package/dist/commands/skills.js +7 -6
- package/dist/commands/subagents.js +7 -6
- package/dist/commands/sync.js +81 -10
- package/dist/commands/view.js +4 -1
- package/dist/commands/watchdog.d.ts +1 -1
- package/dist/commands/watchdog.js +10 -10
- package/dist/commands/webhook.d.ts +4 -0
- package/dist/commands/webhook.js +22 -4
- package/dist/commands/workflows.js +7 -6
- package/dist/lib/accounting/rotate.d.ts +3 -1
- package/dist/lib/accounting/rotate.js +8 -4
- package/dist/lib/auth-health.d.ts +2 -0
- package/dist/lib/auth-health.js +2 -0
- package/dist/lib/browser/chrome.d.ts +21 -0
- package/dist/lib/browser/chrome.js +60 -3
- package/dist/lib/browser/drivers/local.d.ts +21 -0
- package/dist/lib/browser/drivers/local.js +102 -9
- package/dist/lib/browser/profiles.d.ts +29 -1
- package/dist/lib/browser/profiles.js +50 -1
- package/dist/lib/browser/types.d.ts +18 -0
- package/dist/lib/config-keys.d.ts +7 -2
- package/dist/lib/config-keys.js +17 -2
- package/dist/lib/daemon/daemon.js +8 -0
- package/dist/lib/daemon/session-summarizer-service.d.ts +24 -0
- package/dist/lib/daemon/session-summarizer-service.js +39 -0
- package/dist/lib/daemon-services.d.ts +1 -1
- package/dist/lib/daemon-services.js +5 -0
- package/dist/lib/daemon-ticks.d.ts +2 -2
- package/dist/lib/daemon-ticks.js +2 -1
- package/dist/lib/deeplink/register.js +10 -9
- package/dist/lib/deeplink/url.d.ts +4 -4
- package/dist/lib/deeplink/url.js +4 -4
- package/dist/lib/device-config.js +25 -0
- package/dist/lib/devices/doctor-findings.d.ts +4 -4
- package/dist/lib/devices/doctor-findings.js +14 -8
- package/dist/lib/devices/registry.js +2 -0
- package/dist/lib/devices/stats-cache.d.ts +4 -0
- package/dist/lib/devices/stats-cache.js +19 -0
- package/dist/lib/drift-sync.d.ts +3 -1
- package/dist/lib/drift-sync.js +16 -5
- package/dist/lib/exec.d.ts +2 -0
- package/dist/lib/exec.js +16 -1
- package/dist/lib/fleet-shared-state.d.ts +8 -0
- package/dist/lib/heal.d.ts +4 -3
- package/dist/lib/heal.js +5 -4
- package/dist/lib/hosts/ready.d.ts +1 -1
- package/dist/lib/hosts/ready.js +16 -4
- package/dist/lib/hosts/reconnect.js +4 -2
- package/dist/lib/identity/client.d.ts +6 -0
- package/dist/lib/identity/index.d.ts +16 -0
- package/dist/lib/identity/index.js +25 -1
- package/dist/lib/profiles.d.ts +2 -0
- package/dist/lib/profiles.js +28 -9
- package/dist/lib/reconcile-and-repair.d.ts +109 -0
- package/dist/lib/reconcile-and-repair.js +267 -0
- package/dist/lib/routers.d.ts +12 -1
- package/dist/lib/routers.js +30 -1
- package/dist/lib/scheduling/routines.js +8 -2
- package/dist/lib/session/active.d.ts +13 -0
- package/dist/lib/session/db.d.ts +47 -7
- package/dist/lib/session/db.js +114 -12
- package/dist/lib/session/mirror.js +58 -0
- package/dist/lib/session/remote/watch.js +22 -2
- package/dist/lib/session/session-cache.d.ts +19 -0
- package/dist/lib/session/session-cache.js +46 -0
- package/dist/lib/session/types.d.ts +34 -0
- package/dist/lib/share/backend.d.ts +6 -4
- package/dist/lib/share/backend.js +10 -8
- package/dist/lib/share/config.d.ts +4 -3
- package/dist/lib/share/config.js +10 -1
- package/dist/lib/share/delete.d.ts +1 -1
- package/dist/lib/share/delete.js +1 -1
- package/dist/lib/share/html.d.ts +1 -1
- package/dist/lib/share/html.js +1 -1
- package/dist/lib/share/provision.d.ts +1 -1
- package/dist/lib/share/provision.js +2 -2
- package/dist/lib/share/publish.d.ts +23 -7
- package/dist/lib/share/publish.js +58 -12
- package/dist/lib/share/worker-template.js +221 -60
- package/dist/lib/startup/command-registry.js +2 -2
- package/dist/lib/state.d.ts +15 -0
- package/dist/lib/state.js +29 -7
- package/dist/lib/summarizer/config.d.ts +46 -0
- package/dist/lib/summarizer/config.js +83 -0
- package/dist/lib/summarizer/pass.d.ts +45 -0
- package/dist/lib/summarizer/pass.js +112 -0
- package/dist/lib/summarizer/summarize.d.ts +68 -0
- package/dist/lib/summarizer/summarize.js +120 -0
- package/dist/lib/teams/agents.d.ts +4 -3
- package/dist/lib/teams/agents.js +12 -4
- package/dist/lib/teams/scheduler.d.ts +4 -2
- package/dist/lib/teams/scheduler.js +6 -6
- package/dist/lib/tmux/session.d.ts +2 -0
- package/dist/lib/tmux/session.js +7 -1
- package/dist/lib/types.d.ts +20 -0
- package/dist/lib/verbs.d.ts +23 -0
- package/dist/lib/verbs.js +24 -0
- package/dist/lib/view-types.d.ts +4 -0
- package/dist/lib/watchdog/rotate.d.ts +1 -1
- package/dist/lib/watchdog/rotate.js +1 -1
- package/package.json +1 -1
package/dist/lib/share/config.js
CHANGED
|
@@ -17,7 +17,16 @@ export const SHARE_TOKEN_ENV_KEY = 'SHARE_WRITE_TOKEN';
|
|
|
17
17
|
export const DEFAULT_CF_BUNDLE = 'cloudflare';
|
|
18
18
|
export const DEFAULT_WORKER_NAME = 'agents-share';
|
|
19
19
|
export const DEFAULT_BUCKET_NAME = 'agents-share';
|
|
20
|
-
|
|
20
|
+
// The Rush product share endpoint (PHNX-3960): share.getrush.ai on the product
|
|
21
|
+
// domain. Publishing prints this host; bound to the `agents-share` Worker in the
|
|
22
|
+
// Phoenix CF account. share.agents-cli.sh + artifacts.prix.dev stay bound as legacy aliases.
|
|
23
|
+
export const DEFAULT_SHARE_DOMAIN = 'share.getrush.ai';
|
|
24
|
+
// Managed hosts still recognized as "the platform endpoint" for backward
|
|
25
|
+
// compatibility. `share.agents-cli.sh` is the pre-PHNX-3960 default: it stays
|
|
26
|
+
// attached to the same Worker, so every link already shared on it keeps
|
|
27
|
+
// resolving, and a persisted config pointing at it is still treated as managed
|
|
28
|
+
// (e.g. for deploy-time PHOENIX_ID_BASE binding). Compared lowercased.
|
|
29
|
+
export const LEGACY_MANAGED_SHARE_DOMAINS = ['share.agents-cli.sh', 'artifacts.prix.dev'];
|
|
21
30
|
/** The write token may be injected ephemerally into fleet/cloud agents. */
|
|
22
31
|
export function readWriteTokenEnv(env = process.env) {
|
|
23
32
|
const token = env[SHARE_TOKEN_ENV_KEY]?.trim();
|
|
@@ -31,7 +31,7 @@ export interface ResolvedShareTarget {
|
|
|
31
31
|
/**
|
|
32
32
|
* Normalize any of the three accepted target forms to the R2 key that publish
|
|
33
33
|
* would have written:
|
|
34
|
-
* - a full share URL: `https://share.
|
|
34
|
+
* - a full share URL: `https://share.getrush.ai/<user>/<slug>`
|
|
35
35
|
* - `<user>/<slug>`
|
|
36
36
|
* - a bare `<slug>` — resolved against the caller's own namespace exactly as
|
|
37
37
|
* `publishToEndpoint` resolves it at publish time (resolveShareUsername +
|
package/dist/lib/share/delete.js
CHANGED
|
@@ -13,7 +13,7 @@ import { extractShareHttpError, formatShareHttpErrorDetail } from './http-error.
|
|
|
13
13
|
/**
|
|
14
14
|
* Normalize any of the three accepted target forms to the R2 key that publish
|
|
15
15
|
* would have written:
|
|
16
|
-
* - a full share URL: `https://share.
|
|
16
|
+
* - a full share URL: `https://share.getrush.ai/<user>/<slug>`
|
|
17
17
|
* - `<user>/<slug>`
|
|
18
18
|
* - a bare `<slug>` — resolved against the caller's own namespace exactly as
|
|
19
19
|
* `publishToEndpoint` resolves it at publish time (resolveShareUsername +
|
package/dist/lib/share/html.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Make an HTML page self-contained enough to view on share.
|
|
2
|
+
* Make an HTML page self-contained enough to view on share.getrush.ai.
|
|
3
3
|
*
|
|
4
4
|
* Chrome "Save as" (and some renderers) leave `file:///…html#section` TOC
|
|
5
5
|
* links and sibling image paths. Those work on disk and 404 on the share
|
package/dist/lib/share/html.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Make an HTML page self-contained enough to view on share.
|
|
2
|
+
* Make an HTML page self-contained enough to view on share.getrush.ai.
|
|
3
3
|
*
|
|
4
4
|
* Chrome "Save as" (and some renderers) leave `file:///…html#section` TOC
|
|
5
5
|
* links and sibling image paths. Those work on disk and 404 on the share
|
|
@@ -110,6 +110,6 @@ export declare function setWorkerSecret(apiToken: string, accountId: string, wor
|
|
|
110
110
|
export declare function enableWorkersDev(apiToken: string, accountId: string, workerName: string, opts?: ProvisionOptions): Promise<string>;
|
|
111
111
|
/** Resolve a zone id for a domain the token can see, or null if not owned/visible. */
|
|
112
112
|
export declare function findZoneId(apiToken: string, domain: string, opts?: ProvisionOptions): Promise<string | null>;
|
|
113
|
-
/** Map a custom hostname (e.g. `share.
|
|
113
|
+
/** Map a custom hostname (e.g. `share.getrush.ai`) to the Worker via Workers Custom Domains. */
|
|
114
114
|
export declare function addCustomDomain(apiToken: string, accountId: string, workerName: string, zoneId: string, hostname: string, opts?: ProvisionOptions): Promise<void>;
|
|
115
115
|
export {};
|
|
@@ -219,7 +219,7 @@ export async function enableWorkersDev(apiToken, accountId, workerName, opts = {
|
|
|
219
219
|
/** Resolve a zone id for a domain the token can see, or null if not owned/visible. */
|
|
220
220
|
export async function findZoneId(apiToken, domain, opts = {}) {
|
|
221
221
|
const request = opts.request ?? defaultCloudflareRequester;
|
|
222
|
-
// Try the exact name, then the registrable parent (share.
|
|
222
|
+
// Try the exact name, then the registrable parent (share.getrush.ai -> getrush.ai).
|
|
223
223
|
const candidates = [domain, domain.split('.').slice(-2).join('.')];
|
|
224
224
|
for (const name of candidates) {
|
|
225
225
|
const zones = await request({
|
|
@@ -232,7 +232,7 @@ export async function findZoneId(apiToken, domain, opts = {}) {
|
|
|
232
232
|
}
|
|
233
233
|
return null;
|
|
234
234
|
}
|
|
235
|
-
/** Map a custom hostname (e.g. `share.
|
|
235
|
+
/** Map a custom hostname (e.g. `share.getrush.ai`) to the Worker via Workers Custom Domains. */
|
|
236
236
|
export async function addCustomDomain(apiToken, accountId, workerName, zoneId, hostname, opts = {}) {
|
|
237
237
|
const request = opts.request ?? defaultCloudflareRequester;
|
|
238
238
|
try {
|
|
@@ -69,8 +69,17 @@ export interface PublishOptions {
|
|
|
69
69
|
analytics?: boolean;
|
|
70
70
|
/** Override the analytics token from share config. */
|
|
71
71
|
analyticsToken?: string;
|
|
72
|
-
/** Override the GitHub username used for the URL namespace. */
|
|
72
|
+
/** Override the GitHub username used for the URL namespace (BYO path). */
|
|
73
73
|
githubUser?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Override the managed public handle (PHNX-3547). Managed publishes normally
|
|
76
|
+
* namespace under the email local-part; when that handle is taken — or a
|
|
77
|
+
* vanity namespace is wanted — pass an alternate. Sanitized to
|
|
78
|
+
* `[a-z0-9-]` (max 63 chars, matching the Worker); the Worker binds it with
|
|
79
|
+
* the same first-writer claim as a derived handle. Ignored on BYO (use
|
|
80
|
+
* `githubUser` there).
|
|
81
|
+
*/
|
|
82
|
+
handle?: string;
|
|
74
83
|
/** DI seam for tests — override the persisted share endpoint config. */
|
|
75
84
|
config?: ShareConfig;
|
|
76
85
|
/** DI seam for tests — override the keychain-backed write token. Selects BYO. */
|
|
@@ -209,12 +218,15 @@ export declare function resolveShareProvenance(opts?: {
|
|
|
209
218
|
}): ShareProvenance;
|
|
210
219
|
/**
|
|
211
220
|
* The sharer's avatar URL, stamped so the share bar can show a real profile
|
|
212
|
-
* picture instead of only the initials circle.
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
221
|
+
* picture instead of only the initials circle. A hosted OAuth profile image
|
|
222
|
+
* already known to identity (PhoenixSession.avatarUrl — captured at login and
|
|
223
|
+
* refreshed from `/api/v1/auth/me`) wins outright; only when none exists do we
|
|
224
|
+
* fall back to a Gravatar keyed on the SHA-256 of the signed-in user's
|
|
225
|
+
* lowercased email (Gravatar resolves either MD5 or SHA-256), with `d=404` so
|
|
226
|
+
* Gravatar returns 404 for a user who has none — the bar's `<img>` onerror
|
|
227
|
+
* then falls back to the initials circle. Only the hash lands in public
|
|
228
|
+
* metadata, never the raw email. Returns '' when signed out (BYO without a
|
|
229
|
+
* Phoenix session), leaving the bar on the initials circle.
|
|
218
230
|
*
|
|
219
231
|
* `opts.session === null` means "explicitly signed out" (a test seam / BYO) and
|
|
220
232
|
* yields ''; `undefined` reads the real persisted session.
|
|
@@ -369,4 +381,8 @@ export declare function resolveShareUsername(opts?: {
|
|
|
369
381
|
/** Build the R2 object key from a namespace username and a slug part. */
|
|
370
382
|
export declare function buildShareKey(username: string, slugPart: string): string;
|
|
371
383
|
export declare function publishFile(filePath: string, opts?: PublishOptions): Promise<PublishResult>;
|
|
384
|
+
/** Sanitize a caller-chosen managed handle to the Worker's namespace shape.
|
|
385
|
+
* Returns '' when the result is empty or over the Worker's 63-char cap (the
|
|
386
|
+
* caller then falls back to the derived handle / errors). */
|
|
387
|
+
export declare function resolveManagedHandle(handle: string | undefined): string;
|
|
372
388
|
export declare function publishToEndpoint(filePath: string, endpoint: PublishEndpoint, opts?: PublishOptions): Promise<PublishResult>;
|
|
@@ -129,18 +129,24 @@ export function resolveShareProvenance(opts = {}) {
|
|
|
129
129
|
}
|
|
130
130
|
/**
|
|
131
131
|
* The sharer's avatar URL, stamped so the share bar can show a real profile
|
|
132
|
-
* picture instead of only the initials circle.
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
132
|
+
* picture instead of only the initials circle. A hosted OAuth profile image
|
|
133
|
+
* already known to identity (PhoenixSession.avatarUrl — captured at login and
|
|
134
|
+
* refreshed from `/api/v1/auth/me`) wins outright; only when none exists do we
|
|
135
|
+
* fall back to a Gravatar keyed on the SHA-256 of the signed-in user's
|
|
136
|
+
* lowercased email (Gravatar resolves either MD5 or SHA-256), with `d=404` so
|
|
137
|
+
* Gravatar returns 404 for a user who has none — the bar's `<img>` onerror
|
|
138
|
+
* then falls back to the initials circle. Only the hash lands in public
|
|
139
|
+
* metadata, never the raw email. Returns '' when signed out (BYO without a
|
|
140
|
+
* Phoenix session), leaving the bar on the initials circle.
|
|
138
141
|
*
|
|
139
142
|
* `opts.session === null` means "explicitly signed out" (a test seam / BYO) and
|
|
140
143
|
* yields ''; `undefined` reads the real persisted session.
|
|
141
144
|
*/
|
|
142
145
|
export function resolveShareAvatar(opts = {}) {
|
|
143
146
|
const session = opts.session !== undefined ? opts.session : readSession();
|
|
147
|
+
const hosted = session?.avatarUrl?.trim();
|
|
148
|
+
if (hosted && /^https:\/\//i.test(hosted))
|
|
149
|
+
return hosted;
|
|
144
150
|
const email = session?.email?.trim().toLowerCase();
|
|
145
151
|
if (!email)
|
|
146
152
|
return '';
|
|
@@ -553,8 +559,9 @@ export function buildShareKey(username, slugPart) {
|
|
|
553
559
|
}
|
|
554
560
|
export async function publishFile(filePath, opts = {}) {
|
|
555
561
|
const backend = resolveShareBackend(opts);
|
|
562
|
+
const managedHandle = backend.kind === 'managed' ? requireManagedHandle(opts.handle) : '';
|
|
556
563
|
const username = backend.kind === 'managed'
|
|
557
|
-
? backend.namespace
|
|
564
|
+
? managedHandle || backend.namespace
|
|
558
565
|
: await resolveShareUsername({ githubUser: opts.githubUser || backend.namespace || undefined });
|
|
559
566
|
const analyticsToken = opts.analyticsToken ?? (backend.kind === 'byo' ? (opts.config ?? readShareConfig())?.analyticsToken : undefined);
|
|
560
567
|
return publishToEndpoint(filePath, { baseUrl: backend.baseUrl, token: backend.token }, {
|
|
@@ -564,8 +571,28 @@ export async function publishFile(filePath, opts = {}) {
|
|
|
564
571
|
backendKind: backend.kind,
|
|
565
572
|
});
|
|
566
573
|
}
|
|
574
|
+
/** Sanitize a caller-chosen managed handle to the Worker's namespace shape.
|
|
575
|
+
* Returns '' when the result is empty or over the Worker's 63-char cap (the
|
|
576
|
+
* caller then falls back to the derived handle / errors). */
|
|
577
|
+
export function resolveManagedHandle(handle) {
|
|
578
|
+
if (!handle)
|
|
579
|
+
return '';
|
|
580
|
+
const sanitized = sanitizeShareNamespace(handle);
|
|
581
|
+
return sanitized && sanitized.length <= 63 ? sanitized : '';
|
|
582
|
+
}
|
|
583
|
+
function requireManagedHandle(handle) {
|
|
584
|
+
const resolved = resolveManagedHandle(handle);
|
|
585
|
+
if (handle && !resolved) {
|
|
586
|
+
throw new Error(`Invalid --handle '${handle}': must sanitize to 1-63 [a-z0-9-] characters`);
|
|
587
|
+
}
|
|
588
|
+
return resolved;
|
|
589
|
+
}
|
|
567
590
|
export async function publishToEndpoint(filePath, endpoint, opts = {}) {
|
|
568
|
-
|
|
591
|
+
// A managed publish may carry an explicit --handle: it namespaces the URL and
|
|
592
|
+
// rides the x-share-handle header so the Worker binds the claim to it (a
|
|
593
|
+
// derived handle is proven by the email; an alternate one must be declared).
|
|
594
|
+
const managedHandle = opts.backendKind === 'managed' ? requireManagedHandle(opts.handle) : '';
|
|
595
|
+
const username = managedHandle || (await resolveShareUsername(opts));
|
|
569
596
|
let body = readFileSync(filePath);
|
|
570
597
|
const expiresAt = resolveExpire(opts.expire);
|
|
571
598
|
const visibility = resolveShareVisibility(opts);
|
|
@@ -666,6 +693,8 @@ export async function publishToEndpoint(filePath, endpoint, opts = {}) {
|
|
|
666
693
|
assertMetadataSize(metadataPreview);
|
|
667
694
|
const authHeaders = (contentType) => {
|
|
668
695
|
const h = { authorization: `Bearer ${endpoint.token}`, 'content-type': contentType };
|
|
696
|
+
if (managedHandle)
|
|
697
|
+
h['x-share-handle'] = managedHandle;
|
|
669
698
|
if (expiresAt)
|
|
670
699
|
h['x-share-expires-at'] = expiresAt;
|
|
671
700
|
h['x-share-visibility'] = visibility;
|
|
@@ -748,11 +777,28 @@ export async function publishToEndpoint(filePath, endpoint, opts = {}) {
|
|
|
748
777
|
}
|
|
749
778
|
const r = await put(pageUrl, body, authHeaders(opts.contentType ?? guessContentType(filePath)));
|
|
750
779
|
if (!r.ok) {
|
|
751
|
-
|
|
752
|
-
|
|
780
|
+
// 409 has two distinct shapes on the managed Worker: 'handle taken' (the
|
|
781
|
+
// caller's namespace belongs to another account) and 'publish conflict'
|
|
782
|
+
// (a concurrent write won the republish race — retry, per PHNX-3547).
|
|
783
|
+
const httpError = extractShareHttpError({ status: r.status, body: r.body, retryAfter: r.retryAfter });
|
|
784
|
+
if (r.status === 409 && httpError.serverMessage === 'handle taken' && opts.backendKind === 'managed') {
|
|
785
|
+
throw new Error(`Handle '${username}' is already claimed by another account. ` +
|
|
786
|
+
'If you signed in again and got a new account id, republishing with the same email re-binds your handle automatically; ' +
|
|
787
|
+
'otherwise pick a different public namespace with --handle <name>.');
|
|
788
|
+
}
|
|
789
|
+
const detail = formatShareHttpErrorDetail(httpError);
|
|
790
|
+
// The write-token/setup advice is only meaningful for an auth failure — a
|
|
791
|
+
// 413 (quota/size) or 429 (rate) rejection has nothing to do with the
|
|
792
|
+
// token, and 'Check the write token' there is plain wrong (PHNX-3579).
|
|
793
|
+
// Managed endpoints carry a Phoenix bearer, so the recovery is re-login.
|
|
794
|
+
let advice = '';
|
|
795
|
+
if (r.status === 401 || r.status === 403) {
|
|
796
|
+
advice =
|
|
797
|
+
opts.backendKind === 'managed'
|
|
798
|
+
? ". Check that you're signed in — run 'agents auth login'."
|
|
799
|
+
: ". Check the write token, or that 'agents artifacts setup' completed.";
|
|
753
800
|
}
|
|
754
|
-
|
|
755
|
-
throw new Error(`Publish failed (${r.status}) for ${pageUrl}${detail}. Check the write token, or that 'agents artifacts setup' completed.`);
|
|
801
|
+
throw new Error(`Publish failed (${r.status}) for ${pageUrl}${detail}${advice}`);
|
|
756
802
|
}
|
|
757
803
|
// A token-gated page is only reachable WITH its key, so the URL we hand back
|
|
758
804
|
// (and store nowhere) carries it — https://<host>/<user>/<slug>?k=<token>.
|