@phnx-labs/agents-cli 1.22.68 → 1.22.70
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 +46 -0
- package/README.md +17 -14
- package/dist/bootstrap.js +3 -0
- package/dist/commands/accounts.js +23 -7
- package/dist/commands/exec.js +33 -23
- package/dist/commands/feed.js +20 -7
- package/dist/commands/import.js +2 -2
- package/dist/commands/models.js +2 -2
- package/dist/commands/monitors.js +3 -0
- package/dist/commands/permissions.js +2 -2
- package/dist/commands/projects.d.ts +26 -6
- package/dist/commands/projects.js +55 -22
- package/dist/commands/rules.js +1 -1
- package/dist/commands/send.js +35 -2
- package/dist/commands/sessions-inject.d.ts +58 -0
- package/dist/commands/sessions-inject.js +143 -7
- package/dist/commands/sessions-picker.js +1 -0
- package/dist/commands/share.js +43 -14
- package/dist/commands/ssh.js +205 -2
- package/dist/commands/traces.js +1 -1
- package/dist/lib/account-capabilities.js +0 -2
- package/dist/lib/account-registry.d.ts +3 -3
- package/dist/lib/account-registry.js +25 -7
- package/dist/lib/accounting/usage.d.ts +7 -2
- package/dist/lib/accounting/usage.js +142 -10
- package/dist/lib/acp/client.d.ts +1 -1
- package/dist/lib/acp/client.js +12 -1
- package/dist/lib/acp/harnesses.js +1 -1
- package/dist/lib/add-dir.js +0 -2
- package/dist/lib/agent-cli-commands.js +0 -2
- package/dist/lib/agent-spec/agents.d.ts +1 -1
- package/dist/lib/agent-spec/agents.js +2 -83
- package/dist/lib/boot-profile.d.ts +14 -0
- package/dist/lib/boot-profile.js +66 -0
- package/dist/lib/browser/ipc.js +9 -1
- package/dist/lib/browser/remote-control.d.ts +6 -3
- package/dist/lib/browser/remote-control.js +6 -3
- package/dist/lib/browser/service.d.ts +4 -1
- package/dist/lib/browser/service.js +7 -1
- package/dist/lib/channels/providers/desktop.d.ts +5 -4
- package/dist/lib/channels/providers/desktop.js +5 -4
- package/dist/lib/channels/registry.d.ts +6 -0
- package/dist/lib/channels/send.d.ts +11 -2
- package/dist/lib/channels/send.js +11 -2
- package/dist/lib/claude-account-token.js +108 -4
- package/dist/lib/cloud/rush.d.ts +10 -2
- package/dist/lib/cloud/rush.js +15 -9
- package/dist/lib/daemon/daemon.js +28 -8
- package/dist/lib/daemon/runner.js +6 -2
- package/dist/lib/devices/health.d.ts +38 -2
- package/dist/lib/devices/health.js +43 -5
- package/dist/lib/devices/worker-pick.d.ts +1 -1
- package/dist/lib/devices/worker-pick.js +4 -1
- package/dist/lib/exec.d.ts +2 -2
- package/dist/lib/exec.js +7 -34
- package/dist/lib/feed-broadcast.d.ts +47 -5
- package/dist/lib/feed-broadcast.js +127 -24
- package/dist/lib/hooks/install.js +0 -87
- package/dist/lib/installations/strategies.js +1 -1
- package/dist/lib/mcp-registry.js +0 -13
- package/dist/lib/mcp.js +2 -2
- package/dist/lib/model-tiers.js +1 -1
- package/dist/lib/models.js +0 -63
- package/dist/lib/monitors/engine.js +18 -0
- package/dist/lib/monitors/sources/command.js +13 -3
- package/dist/lib/monitors/sources/failure.d.ts +32 -0
- package/dist/lib/monitors/sources/failure.js +52 -0
- package/dist/lib/monitors/sources/types.d.ts +9 -0
- package/dist/lib/notify.d.ts +11 -0
- package/dist/lib/notify.js +17 -4
- package/dist/lib/owner-message.d.ts +55 -0
- package/dist/lib/owner-message.js +64 -0
- package/dist/lib/permissions-registry.d.ts +0 -2
- package/dist/lib/permissions-registry.js +3 -50
- package/dist/lib/permissions.d.ts +3 -17
- package/dist/lib/permissions.js +4 -73
- package/dist/lib/run-trace-sync.d.ts +15 -0
- package/dist/lib/run-trace-sync.js +43 -21
- package/dist/lib/rush-session.d.ts +19 -0
- package/dist/lib/rush-session.js +24 -0
- package/dist/lib/secrets/drivers/rush.js +2 -1
- package/dist/lib/secrets/filestore.d.ts +4 -0
- package/dist/lib/secrets/filestore.js +164 -3
- package/dist/lib/session/active.d.ts +10 -0
- package/dist/lib/session/active.js +3 -0
- package/dist/lib/session/cloud.js +2 -1
- package/dist/lib/session/db.d.ts +12 -1
- package/dist/lib/session/db.js +20 -1
- package/dist/lib/session/discover.js +81 -1
- package/dist/lib/session/linear.d.ts +13 -0
- package/dist/lib/session/linear.js +44 -0
- package/dist/lib/session/live-metadata.js +1 -0
- package/dist/lib/session/parse.js +2 -3
- package/dist/lib/session/prompt.d.ts +7 -1
- package/dist/lib/session/prompt.js +12 -2
- package/dist/lib/session/recovery.d.ts +21 -12
- package/dist/lib/session/recovery.js +29 -11
- package/dist/lib/session/remote/watch.js +5 -2
- package/dist/lib/session/state.js +11 -13
- package/dist/lib/share/backend.d.ts +2 -2
- package/dist/lib/share/backend.js +20 -9
- package/dist/lib/share/delete.d.ts +5 -1
- package/dist/lib/share/delete.js +7 -2
- package/dist/lib/share/http-error.d.ts +52 -0
- package/dist/lib/share/http-error.js +65 -0
- package/dist/lib/share/publish.d.ts +13 -3
- package/dist/lib/share/publish.js +19 -15
- package/dist/lib/share/worker-template.js +5 -1
- package/dist/lib/sink-format.d.ts +34 -0
- package/dist/lib/sink-format.js +17 -0
- package/dist/lib/smart-launch.js +27 -4
- package/dist/lib/staleness/detectors/permissions.js +0 -20
- package/dist/lib/staleness/writers/commands.js +1 -1
- package/dist/lib/staleness/writers/hooks.js +2 -2
- package/dist/lib/storage/index.d.ts +14 -0
- package/dist/lib/storage/index.js +14 -0
- package/dist/lib/storage/selection.d.ts +48 -0
- package/dist/lib/storage/selection.js +39 -0
- package/dist/lib/storage/visibility.d.ts +82 -0
- package/dist/lib/storage/visibility.js +99 -0
- package/dist/lib/subagents-registry.js +2 -12
- package/dist/lib/subagents.d.ts +0 -10
- package/dist/lib/subagents.js +0 -37
- package/dist/lib/teams/agents.js +3 -1
- package/dist/lib/teams/placement-probe.js +1 -0
- package/dist/lib/teams/scheduler.d.ts +8 -1
- package/dist/lib/teams/scheduler.js +4 -1
- package/dist/lib/traces/backend.js +13 -2
- package/dist/lib/types.d.ts +1 -1
- package/dist/lib/worktree/held.d.ts +166 -0
- package/dist/lib/worktree/held.js +368 -0
- package/package.json +2 -2
package/dist/lib/smart-launch.js
CHANGED
|
@@ -90,15 +90,29 @@ export function formatEmptyAutoPoolError() {
|
|
|
90
90
|
'mark one with `agents devices role <name> worker`, or widen the pool with `agents config set auto.pool all`.');
|
|
91
91
|
}
|
|
92
92
|
export function formatNoHealthyDeviceError(pool, signals, agent) {
|
|
93
|
+
let timedOutCount = 0;
|
|
93
94
|
const excluded = pool.map((key) => {
|
|
94
95
|
const signal = signals.get(key);
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
let reason;
|
|
97
|
+
if (signal?.reachable === true) {
|
|
98
|
+
reason = signal.headroom === 'loaded'
|
|
98
99
|
? 'overloaded'
|
|
99
100
|
: signal.installed !== true || signal.signedIn !== true
|
|
100
101
|
? 'no ready harness account'
|
|
101
102
|
: 'ineligible';
|
|
103
|
+
}
|
|
104
|
+
else if (signal?.timedOut) {
|
|
105
|
+
// A slow link is not an offline box. Saying "unreachable" here sent
|
|
106
|
+
// operators hunting a fleet outage that did not exist (PHNX-3682).
|
|
107
|
+
timedOutCount++;
|
|
108
|
+
reason = 'probe timed out';
|
|
109
|
+
}
|
|
110
|
+
else if (signal === undefined) {
|
|
111
|
+
reason = 'no probe signal';
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
reason = 'unreachable';
|
|
115
|
+
}
|
|
102
116
|
return `${key} (${reason})`;
|
|
103
117
|
}).join(', ');
|
|
104
118
|
const target = agent ? `can run ${agent}` : "for 'run auto'";
|
|
@@ -108,7 +122,16 @@ export function formatNoHealthyDeviceError(pool, signals, agent) {
|
|
|
108
122
|
// in this error's own candidate set, not just the ones with a doc.
|
|
109
123
|
const marked = describeAutoPool({ roster: pool });
|
|
110
124
|
const poolNote = marked ? ` [pool: ${marked}]` : '';
|
|
111
|
-
|
|
125
|
+
// Only talk about usage windows when a device was actually turned away for
|
|
126
|
+
// one. A pool that timed out needs a link/latency hint, not a reset time.
|
|
127
|
+
const scope = timedOutCount === pool.length
|
|
128
|
+
? `every probe (${pool.length}) exceeded`
|
|
129
|
+
: `${timedOutCount} of ${pool.length} probes exceeded`;
|
|
130
|
+
const hint = timedOutCount > 0
|
|
131
|
+
? `; ${scope} the probe budget — those devices are likely up but slow to answer`
|
|
132
|
+
+ ' (relayed Tailscale paths). Retry, or check `tailscale status` for a direct path.'
|
|
133
|
+
: '; earliest window resets unknown';
|
|
134
|
+
return `agents: no healthy device ${target}${poolNote} — excluded: ${excluded}${hint}`;
|
|
112
135
|
}
|
|
113
136
|
/**
|
|
114
137
|
* Pick the least-loaded healthy device that can run `agent` when the harness is
|
|
@@ -202,25 +202,6 @@ function buildDroidDetector() {
|
|
|
202
202
|
},
|
|
203
203
|
};
|
|
204
204
|
}
|
|
205
|
-
function buildKiroDetector() {
|
|
206
|
-
return {
|
|
207
|
-
kind: 'permissions',
|
|
208
|
-
agent: 'kiro',
|
|
209
|
-
list({ versionHome }) {
|
|
210
|
-
const permissionsPath = path.join(versionHome, '.kiro', 'settings', 'permissions.yaml');
|
|
211
|
-
if (!fs.existsSync(permissionsPath))
|
|
212
|
-
return [];
|
|
213
|
-
try {
|
|
214
|
-
const config = yaml.parse(fs.readFileSync(permissionsPath, 'utf-8'));
|
|
215
|
-
if (config && Array.isArray(config.rules) && config.rules.length > 0) {
|
|
216
|
-
return discoverPermissionGroups().map(g => g.name);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
catch { /* parse fail */ }
|
|
220
|
-
return [];
|
|
221
|
-
},
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
205
|
function buildOpenClawDetector() {
|
|
225
206
|
return {
|
|
226
207
|
kind: 'permissions',
|
|
@@ -296,7 +277,6 @@ const handlers = {
|
|
|
296
277
|
kimi: buildKimiDetector,
|
|
297
278
|
cursor: buildCursorDetector,
|
|
298
279
|
droid: buildDroidDetector,
|
|
299
|
-
kiro: buildKiroDetector,
|
|
300
280
|
openclaw: buildOpenClawDetector,
|
|
301
281
|
copilot: buildCopilotDetector,
|
|
302
282
|
hermes: buildHermesDetector,
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*
|
|
14
14
|
* - native command file — `{agentDir}/<commandsSubdir>/<name>.md` (or .toml
|
|
15
15
|
* when the agent's format is toml). Standard path for Claude, Codex
|
|
16
|
-
* < 0.117.0, Cursor, OpenCode, Copilot, Amp,
|
|
16
|
+
* < 0.117.0, Cursor, OpenCode, Copilot, Amp, Roo, Antigravity.
|
|
17
17
|
*
|
|
18
18
|
* Source resolution is `resolveCommandSource` (user → system → extras —
|
|
19
19
|
* project layer intentionally excluded).
|
|
@@ -90,9 +90,9 @@ function buildHooksWriter(agent) {
|
|
|
90
90
|
// so subrule-bundled guards (absolute paths outside the central hooks/
|
|
91
91
|
// copy set) get registered into ~/.grok/hooks/hooks.json via
|
|
92
92
|
// registerHooksForGrok — file copy alone only sees top-level available.hooks
|
|
93
|
-
// names (RUSH-1353). Copilot/
|
|
93
|
+
// names (RUSH-1353). Copilot/Goose load managed *.json under their
|
|
94
94
|
// hooks dirs the same way.
|
|
95
|
-
if (agent === 'claude' || agent === 'codex' || agent === 'antigravity' || agent === 'kimi' || agent === 'droid' || agent === 'copilot' || agent === '
|
|
95
|
+
if (agent === 'claude' || agent === 'codex' || agent === 'antigravity' || agent === 'kimi' || agent === 'droid' || agent === 'copilot' || agent === 'goose' || agent === 'cursor' || agent === 'grok' || agent === 'hermes' || agent === 'muse') {
|
|
96
96
|
registerHooksToSettings(agent, versionHome);
|
|
97
97
|
}
|
|
98
98
|
return { synced, paths };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `lib/storage` — the surface-agnostic core the managed-storage surfaces share:
|
|
3
|
+
*
|
|
4
|
+
* - {@link selection} the ONE managed-vs-BYO selection policy.
|
|
5
|
+
* - {@link visibility} the ONE visibility model + product default (`me`).
|
|
6
|
+
*
|
|
7
|
+
* Consume the SELECTION + VISIBILITY POLICY from here; keep each surface's typed,
|
|
8
|
+
* `kind`-tagged backend adapter (endpoint, namespace, covers) in that surface's
|
|
9
|
+
* own module. `agents artifacts share` (`lib/share/`) and `agents traces`
|
|
10
|
+
* (`lib/traces/`) are the two current adapters; the `sessions` sync adapter is
|
|
11
|
+
* the next consumer.
|
|
12
|
+
*/
|
|
13
|
+
export { type StorageBackendKind, type StorageSelectionOpts, selectStorageBackendKind, isManagedSelection, } from './selection.js';
|
|
14
|
+
export { type ShareVisibility, type VisibilityFlags, PUBLISH_VISIBILITY_LEVELS, EDITABLE_VISIBILITY_LEVELS, MANAGED_DEFAULT_VISIBILITY, BYO_DEFAULT_VISIBILITY, defaultVisibilityForBackend, explicitVisibility, resolveVisibility, publishVisibility, } from './visibility.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `lib/storage` — the surface-agnostic core the managed-storage surfaces share:
|
|
3
|
+
*
|
|
4
|
+
* - {@link selection} the ONE managed-vs-BYO selection policy.
|
|
5
|
+
* - {@link visibility} the ONE visibility model + product default (`me`).
|
|
6
|
+
*
|
|
7
|
+
* Consume the SELECTION + VISIBILITY POLICY from here; keep each surface's typed,
|
|
8
|
+
* `kind`-tagged backend adapter (endpoint, namespace, covers) in that surface's
|
|
9
|
+
* own module. `agents artifacts share` (`lib/share/`) and `agents traces`
|
|
10
|
+
* (`lib/traces/`) are the two current adapters; the `sessions` sync adapter is
|
|
11
|
+
* the next consumer.
|
|
12
|
+
*/
|
|
13
|
+
export { selectStorageBackendKind, isManagedSelection, } from './selection.js';
|
|
14
|
+
export { PUBLISH_VISIBILITY_LEVELS, EDITABLE_VISIBILITY_LEVELS, MANAGED_DEFAULT_VISIBILITY, BYO_DEFAULT_VISIBILITY, defaultVisibilityForBackend, explicitVisibility, resolveVisibility, publishVisibility, } from './visibility.js';
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE managed-vs-BYO storage-backend selection policy.
|
|
3
|
+
*
|
|
4
|
+
* Every surface that persists to Phoenix-managed storage (`agents artifacts
|
|
5
|
+
* share` today, `agents sessions` sync next) makes the SAME choice: run on OUR
|
|
6
|
+
* managed infrastructure when the caller is signed in to Phoenix, and only fall
|
|
7
|
+
* back to a bring-your-own bucket when the caller explicitly asked for it. This
|
|
8
|
+
* module owns that decision so it is not re-derived — and re-drifted — per
|
|
9
|
+
* surface.
|
|
10
|
+
*
|
|
11
|
+
* What lives here is ONLY the identity + selection policy. It deliberately does
|
|
12
|
+
* NOT know a surface's endpoint, namespace shape, public-read semantics, or OG
|
|
13
|
+
* covers — those differ (share uses an email-handle namespace with public reads
|
|
14
|
+
* and covers; a traces/sessions adapter uses the userId and differs again). Each
|
|
15
|
+
* surface keeps its own DISCRIMINATED, typed adapter that reads this decision and
|
|
16
|
+
* returns its own `kind`-tagged backend. See `lib/share/backend.ts` and
|
|
17
|
+
* `lib/traces/backend.ts` for the two adapters.
|
|
18
|
+
*/
|
|
19
|
+
import { type PhoenixSession } from '../identity/client.js';
|
|
20
|
+
/** The two legitimate principals any managed-capable surface can resolve to. */
|
|
21
|
+
export type StorageBackendKind = 'managed' | 'byo';
|
|
22
|
+
export interface StorageSelectionOpts {
|
|
23
|
+
/**
|
|
24
|
+
* True when the SURFACE detected an explicit bring-your-own override — a
|
|
25
|
+
* `--byo` flag, a caller-supplied static write token, a `…_BACKEND=byo` env,
|
|
26
|
+
* or a full BYO endpoint config. Detecting WHICH signals count is the
|
|
27
|
+
* surface's job (they differ per surface); this policy only honors the boolean.
|
|
28
|
+
*/
|
|
29
|
+
byoOverride?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* DI seam for the Phoenix session. `undefined` reads the real persisted
|
|
32
|
+
* session (`readSession()`); `null` means "explicitly signed out".
|
|
33
|
+
*/
|
|
34
|
+
session?: PhoenixSession | null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Pick the storage principal. Managed when signed in (`readSession() != null`)
|
|
38
|
+
* AND the surface reported no explicit BYO override; otherwise BYO.
|
|
39
|
+
*
|
|
40
|
+
* This is not a fallback chain — it is a single decision. A surface that cannot
|
|
41
|
+
* authenticate EITHER principal (signed out AND no BYO config) still reads `byo`
|
|
42
|
+
* here and fails loud in its own adapter, where the actionable "run auth login
|
|
43
|
+
* or set up your bucket" message belongs.
|
|
44
|
+
*/
|
|
45
|
+
export declare function selectStorageBackendKind(opts?: StorageSelectionOpts): StorageBackendKind;
|
|
46
|
+
/** True when the shared policy resolves to the managed principal. Thin sugar
|
|
47
|
+
* over {@link selectStorageBackendKind} for the common boolean check. */
|
|
48
|
+
export declare function isManagedSelection(opts?: StorageSelectionOpts): boolean;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE managed-vs-BYO storage-backend selection policy.
|
|
3
|
+
*
|
|
4
|
+
* Every surface that persists to Phoenix-managed storage (`agents artifacts
|
|
5
|
+
* share` today, `agents sessions` sync next) makes the SAME choice: run on OUR
|
|
6
|
+
* managed infrastructure when the caller is signed in to Phoenix, and only fall
|
|
7
|
+
* back to a bring-your-own bucket when the caller explicitly asked for it. This
|
|
8
|
+
* module owns that decision so it is not re-derived — and re-drifted — per
|
|
9
|
+
* surface.
|
|
10
|
+
*
|
|
11
|
+
* What lives here is ONLY the identity + selection policy. It deliberately does
|
|
12
|
+
* NOT know a surface's endpoint, namespace shape, public-read semantics, or OG
|
|
13
|
+
* covers — those differ (share uses an email-handle namespace with public reads
|
|
14
|
+
* and covers; a traces/sessions adapter uses the userId and differs again). Each
|
|
15
|
+
* surface keeps its own DISCRIMINATED, typed adapter that reads this decision and
|
|
16
|
+
* returns its own `kind`-tagged backend. See `lib/share/backend.ts` and
|
|
17
|
+
* `lib/traces/backend.ts` for the two adapters.
|
|
18
|
+
*/
|
|
19
|
+
import { readSession } from '../identity/client.js';
|
|
20
|
+
/**
|
|
21
|
+
* Pick the storage principal. Managed when signed in (`readSession() != null`)
|
|
22
|
+
* AND the surface reported no explicit BYO override; otherwise BYO.
|
|
23
|
+
*
|
|
24
|
+
* This is not a fallback chain — it is a single decision. A surface that cannot
|
|
25
|
+
* authenticate EITHER principal (signed out AND no BYO config) still reads `byo`
|
|
26
|
+
* here and fails loud in its own adapter, where the actionable "run auth login
|
|
27
|
+
* or set up your bucket" message belongs.
|
|
28
|
+
*/
|
|
29
|
+
export function selectStorageBackendKind(opts = {}) {
|
|
30
|
+
if (opts.byoOverride === true)
|
|
31
|
+
return 'byo';
|
|
32
|
+
const session = opts.session === undefined ? readSession() : opts.session;
|
|
33
|
+
return session != null ? 'managed' : 'byo';
|
|
34
|
+
}
|
|
35
|
+
/** True when the shared policy resolves to the managed principal. Thin sugar
|
|
36
|
+
* over {@link selectStorageBackendKind} for the common boolean check. */
|
|
37
|
+
export function isManagedSelection(opts = {}) {
|
|
38
|
+
return selectStorageBackendKind(opts) === 'managed';
|
|
39
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE visibility model, identical on every surface that publishes to managed
|
|
3
|
+
* storage. Three levels the operator ever chooses between:
|
|
4
|
+
*
|
|
5
|
+
* - PRIVATE = `me` — owner-only, Phoenix-gated. THE DEFAULT for a new
|
|
6
|
+
* managed share (see {@link MANAGED_DEFAULT_VISIBILITY}).
|
|
7
|
+
* - TEAM = `org` — everyone at the sharer's signed-in email DOMAIN,
|
|
8
|
+
* Phoenix-gated. Automatic from the domain — there is
|
|
9
|
+
* no organization to create and no member to add.
|
|
10
|
+
* - PUBLIC = `public` — explicit opt-in; listed in the gallery, gets an OG
|
|
11
|
+
* card.
|
|
12
|
+
*
|
|
13
|
+
* Two capability-URL levels remain for the power path (unguessable link, not a
|
|
14
|
+
* login gate): `unlisted` (obscurity — noindex, gallery-hidden, still
|
|
15
|
+
* world-readable) and `private`-token-gated (`--protected`: a `?k=` key the
|
|
16
|
+
* Worker checks, 404 without it). `me`/`org` require a Phoenix session; the
|
|
17
|
+
* Worker refuses them for a bare WRITE_TOKEN (BYO) publish, which is why the BYO
|
|
18
|
+
* default stays `public`.
|
|
19
|
+
*
|
|
20
|
+
* The names match the Worker's own metadata vocabulary (`lib/share/worker-template.ts`),
|
|
21
|
+
* so this module is the single client-side source of truth for the level set and
|
|
22
|
+
* the DEFAULT, reusable by any surface.
|
|
23
|
+
*/
|
|
24
|
+
/** Every visibility level the Worker understands. `me`/`org` are the
|
|
25
|
+
* Phoenix-gated (login-required) levels; `public`/`unlisted`/`private` are the
|
|
26
|
+
* link-reachable levels. */
|
|
27
|
+
export type ShareVisibility = 'public' | 'unlisted' | 'private' | 'me' | 'org';
|
|
28
|
+
/** The levels a publish (`share <file> --visibility`) may select. */
|
|
29
|
+
export declare const PUBLISH_VISIBILITY_LEVELS: readonly ShareVisibility[];
|
|
30
|
+
/** The levels an ALREADY-published page may be re-scoped to in place
|
|
31
|
+
* (`share visibility <target> <level>`). Excludes `private`: re-scoping to
|
|
32
|
+
* token-gated needs a fresh viewer token, which only the publish path mints. */
|
|
33
|
+
export declare const EDITABLE_VISIBILITY_LEVELS: readonly ShareVisibility[];
|
|
34
|
+
/**
|
|
35
|
+
* The product default for a MANAGED (signed-in) share: PRIVATE = owner-only,
|
|
36
|
+
* Phoenix-gated. A publish with no visibility flag lands here.
|
|
37
|
+
*/
|
|
38
|
+
export declare const MANAGED_DEFAULT_VISIBILITY: ShareVisibility;
|
|
39
|
+
/**
|
|
40
|
+
* The default for a BYO (bring-your-own bucket) publish. `me`/`org` are refused
|
|
41
|
+
* server-side for a WRITE_TOKEN publish — there is no Phoenix owner to gate on —
|
|
42
|
+
* so a BYO share with no flag stays `public`, matching the pre-managed behavior.
|
|
43
|
+
*/
|
|
44
|
+
export declare const BYO_DEFAULT_VISIBILITY: ShareVisibility;
|
|
45
|
+
import type { StorageBackendKind } from './selection.js';
|
|
46
|
+
/** The no-flags default for a given storage backend: `me` on managed,
|
|
47
|
+
* `public` on BYO. */
|
|
48
|
+
export declare function defaultVisibilityForBackend(kind: StorageBackendKind): ShareVisibility;
|
|
49
|
+
export interface VisibilityFlags {
|
|
50
|
+
/** An explicit `--visibility <level>`. */
|
|
51
|
+
visibility?: ShareVisibility;
|
|
52
|
+
/** `--unlisted` / `--private` (obscurity, not read-auth). */
|
|
53
|
+
unlisted?: boolean;
|
|
54
|
+
/** `--protected` — token-gated read auth (maps to `private`). */
|
|
55
|
+
protected?: boolean;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The visibility the caller EXPLICITLY asked for, or `undefined` when they
|
|
59
|
+
* passed no visibility signal at all. `--protected` wins over `--unlisted`
|
|
60
|
+
* (stronger control), which wins over an explicit `--visibility`.
|
|
61
|
+
*
|
|
62
|
+
* The distinction between "explicit" and "no preference" is what lets a caller
|
|
63
|
+
* apply the product default only when nothing was asked — a caller that passes
|
|
64
|
+
* `--visibility public` gets `public`, never the `me` default.
|
|
65
|
+
*/
|
|
66
|
+
export declare function explicitVisibility(opts?: VisibilityFlags): ShareVisibility | undefined;
|
|
67
|
+
/**
|
|
68
|
+
* Resolve visibility from the caller's flags, falling back to `fallback` when no
|
|
69
|
+
* explicit signal was given. The library fallback stays `public` so a caller
|
|
70
|
+
* that hasn't opted into the managed private default (e.g. an existing lib
|
|
71
|
+
* consumer) is never silently flipped; the surface applies the product default
|
|
72
|
+
* itself via {@link defaultVisibilityForBackend}.
|
|
73
|
+
*/
|
|
74
|
+
export declare function resolveVisibility(opts?: VisibilityFlags, fallback?: ShareVisibility): ShareVisibility;
|
|
75
|
+
/**
|
|
76
|
+
* The visibility a PUBLISH should stamp: the caller's explicit flag if any, else
|
|
77
|
+
* the product default for the resolved backend (`me` on managed, `public` on
|
|
78
|
+
* BYO). This is the one call a publishing surface makes — `agents artifacts
|
|
79
|
+
* share` today, `agents sessions` sync next — so "private by default when signed
|
|
80
|
+
* in" is decided in exactly one place.
|
|
81
|
+
*/
|
|
82
|
+
export declare function publishVisibility(opts: VisibilityFlags, kind: StorageBackendKind): ShareVisibility;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE visibility model, identical on every surface that publishes to managed
|
|
3
|
+
* storage. Three levels the operator ever chooses between:
|
|
4
|
+
*
|
|
5
|
+
* - PRIVATE = `me` — owner-only, Phoenix-gated. THE DEFAULT for a new
|
|
6
|
+
* managed share (see {@link MANAGED_DEFAULT_VISIBILITY}).
|
|
7
|
+
* - TEAM = `org` — everyone at the sharer's signed-in email DOMAIN,
|
|
8
|
+
* Phoenix-gated. Automatic from the domain — there is
|
|
9
|
+
* no organization to create and no member to add.
|
|
10
|
+
* - PUBLIC = `public` — explicit opt-in; listed in the gallery, gets an OG
|
|
11
|
+
* card.
|
|
12
|
+
*
|
|
13
|
+
* Two capability-URL levels remain for the power path (unguessable link, not a
|
|
14
|
+
* login gate): `unlisted` (obscurity — noindex, gallery-hidden, still
|
|
15
|
+
* world-readable) and `private`-token-gated (`--protected`: a `?k=` key the
|
|
16
|
+
* Worker checks, 404 without it). `me`/`org` require a Phoenix session; the
|
|
17
|
+
* Worker refuses them for a bare WRITE_TOKEN (BYO) publish, which is why the BYO
|
|
18
|
+
* default stays `public`.
|
|
19
|
+
*
|
|
20
|
+
* The names match the Worker's own metadata vocabulary (`lib/share/worker-template.ts`),
|
|
21
|
+
* so this module is the single client-side source of truth for the level set and
|
|
22
|
+
* the DEFAULT, reusable by any surface.
|
|
23
|
+
*/
|
|
24
|
+
/** The levels a publish (`share <file> --visibility`) may select. */
|
|
25
|
+
export const PUBLISH_VISIBILITY_LEVELS = [
|
|
26
|
+
'public',
|
|
27
|
+
'unlisted',
|
|
28
|
+
'private',
|
|
29
|
+
'me',
|
|
30
|
+
'org',
|
|
31
|
+
];
|
|
32
|
+
/** The levels an ALREADY-published page may be re-scoped to in place
|
|
33
|
+
* (`share visibility <target> <level>`). Excludes `private`: re-scoping to
|
|
34
|
+
* token-gated needs a fresh viewer token, which only the publish path mints. */
|
|
35
|
+
export const EDITABLE_VISIBILITY_LEVELS = [
|
|
36
|
+
'public',
|
|
37
|
+
'unlisted',
|
|
38
|
+
'me',
|
|
39
|
+
'org',
|
|
40
|
+
];
|
|
41
|
+
/**
|
|
42
|
+
* The product default for a MANAGED (signed-in) share: PRIVATE = owner-only,
|
|
43
|
+
* Phoenix-gated. A publish with no visibility flag lands here.
|
|
44
|
+
*/
|
|
45
|
+
export const MANAGED_DEFAULT_VISIBILITY = 'me';
|
|
46
|
+
/**
|
|
47
|
+
* The default for a BYO (bring-your-own bucket) publish. `me`/`org` are refused
|
|
48
|
+
* server-side for a WRITE_TOKEN publish — there is no Phoenix owner to gate on —
|
|
49
|
+
* so a BYO share with no flag stays `public`, matching the pre-managed behavior.
|
|
50
|
+
*/
|
|
51
|
+
export const BYO_DEFAULT_VISIBILITY = 'public';
|
|
52
|
+
/** The no-flags default for a given storage backend: `me` on managed,
|
|
53
|
+
* `public` on BYO. */
|
|
54
|
+
export function defaultVisibilityForBackend(kind) {
|
|
55
|
+
return kind === 'managed' ? MANAGED_DEFAULT_VISIBILITY : BYO_DEFAULT_VISIBILITY;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The visibility the caller EXPLICITLY asked for, or `undefined` when they
|
|
59
|
+
* passed no visibility signal at all. `--protected` wins over `--unlisted`
|
|
60
|
+
* (stronger control), which wins over an explicit `--visibility`.
|
|
61
|
+
*
|
|
62
|
+
* The distinction between "explicit" and "no preference" is what lets a caller
|
|
63
|
+
* apply the product default only when nothing was asked — a caller that passes
|
|
64
|
+
* `--visibility public` gets `public`, never the `me` default.
|
|
65
|
+
*/
|
|
66
|
+
export function explicitVisibility(opts = {}) {
|
|
67
|
+
if (opts.protected === true)
|
|
68
|
+
return 'private';
|
|
69
|
+
if (opts.unlisted === true)
|
|
70
|
+
return 'unlisted';
|
|
71
|
+
if (opts.visibility === 'public' ||
|
|
72
|
+
opts.visibility === 'unlisted' ||
|
|
73
|
+
opts.visibility === 'private' ||
|
|
74
|
+
opts.visibility === 'me' ||
|
|
75
|
+
opts.visibility === 'org') {
|
|
76
|
+
return opts.visibility;
|
|
77
|
+
}
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Resolve visibility from the caller's flags, falling back to `fallback` when no
|
|
82
|
+
* explicit signal was given. The library fallback stays `public` so a caller
|
|
83
|
+
* that hasn't opted into the managed private default (e.g. an existing lib
|
|
84
|
+
* consumer) is never silently flipped; the surface applies the product default
|
|
85
|
+
* itself via {@link defaultVisibilityForBackend}.
|
|
86
|
+
*/
|
|
87
|
+
export function resolveVisibility(opts = {}, fallback = 'public') {
|
|
88
|
+
return explicitVisibility(opts) ?? fallback;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The visibility a PUBLISH should stamp: the caller's explicit flag if any, else
|
|
92
|
+
* the product default for the resolved backend (`me` on managed, `public` on
|
|
93
|
+
* BYO). This is the one call a publishing surface makes — `agents artifacts
|
|
94
|
+
* share` today, `agents sessions` sync next — so "private by default when signed
|
|
95
|
+
* in" is decided in exactly one place.
|
|
96
|
+
*/
|
|
97
|
+
export function publishVisibility(opts, kind) {
|
|
98
|
+
return explicitVisibility(opts) ?? defaultVisibilityForBackend(kind);
|
|
99
|
+
}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* - `flatFile` one `<name><ext>` file, body from a `transform` fn.
|
|
17
17
|
* (claude, grok, pi, droid, codex, opencode, copilot,
|
|
18
|
-
* cursor,
|
|
18
|
+
* cursor, goose, kimi)
|
|
19
19
|
* - `dirFile` a `<name>/` directory holding one generated `<file>`.
|
|
20
20
|
* (antigravity: `<name>/agent.md`)
|
|
21
21
|
* - `dirCopy` copy the whole source directory to `<name>/`, applying
|
|
@@ -35,7 +35,7 @@ import * as TOML from 'smol-toml';
|
|
|
35
35
|
import * as yaml from 'yaml';
|
|
36
36
|
import { safeJoin } from './paths.js';
|
|
37
37
|
import { filesContentMatch, normalizeResourceContent } from './resource-content-diff.js';
|
|
38
|
-
import { parseSubagentFrontmatter, transformSubagentForClaude, transformSubagentForCodex, transformSubagentForCopilot, transformSubagentForCursor, transformSubagentForDroid, transformSubagentForGoose,
|
|
38
|
+
import { parseSubagentFrontmatter, transformSubagentForClaude, transformSubagentForCodex, transformSubagentForCopilot, transformSubagentForCursor, transformSubagentForDroid, transformSubagentForGoose, transformSubagentForOpenCode, transformSubagentForAntigravity, } from './subagents.js';
|
|
39
39
|
/** Read a file's UTF-8 content, or null when it is missing/unreadable. */
|
|
40
40
|
function readFileSafe(filePath) {
|
|
41
41
|
try {
|
|
@@ -54,7 +54,6 @@ function metaFrontmatterSkip(filePath) {
|
|
|
54
54
|
function metaFrontmatterFallback(filePath, name) {
|
|
55
55
|
return parseSubagentFrontmatter(filePath) ?? { name, description: '' };
|
|
56
56
|
}
|
|
57
|
-
/** Kiro custom-agent JSON: read name/description/model; skip on parse error. */
|
|
58
57
|
function metaJson(filePath, name) {
|
|
59
58
|
try {
|
|
60
59
|
const cfg = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
@@ -283,9 +282,6 @@ export const SUBAGENT_TARGETS = {
|
|
|
283
282
|
// Tier 1 -- flat markdown, Claude-compatible flatten.
|
|
284
283
|
claude: flatFile({ subdir: ['.claude', 'agents'], ext: '.md', transform: transformSubagentForClaude }),
|
|
285
284
|
grok: flatFile({ subdir: ['.grok', 'agents'], ext: '.md', transform: transformSubagentForClaude }),
|
|
286
|
-
// Oh My Pi discovers Claude-shaped agent markdown from ~/.omp/agent/agents/
|
|
287
|
-
// (`omp agents unpack` writes there); frontmatter name/description + body.
|
|
288
|
-
pi: flatFile({ subdir: ['.omp', 'agent', 'agents'], ext: '.md', transform: transformSubagentForClaude, readMeta: metaFrontmatterFallback }),
|
|
289
285
|
droid: flatFile({ subdir: ['.factory', 'droids'], ext: '.md', transform: transformSubagentForDroid }),
|
|
290
286
|
// Bespoke frontmatter/format, still one flat file.
|
|
291
287
|
codex: flatFile({
|
|
@@ -312,12 +308,6 @@ export const SUBAGENT_TARGETS = {
|
|
|
312
308
|
transform: transformSubagentForCursor,
|
|
313
309
|
readMeta: metaFrontmatterFallback,
|
|
314
310
|
}),
|
|
315
|
-
kiro: flatFile({
|
|
316
|
-
subdir: ['.kiro', 'agents'],
|
|
317
|
-
ext: '.json',
|
|
318
|
-
transform: transformSubagentForKiro,
|
|
319
|
-
readMeta: metaJson,
|
|
320
|
-
}),
|
|
321
311
|
goose: flatFile({
|
|
322
312
|
subdir: ['.config', 'goose', 'agents'],
|
|
323
313
|
ext: '.yaml',
|
package/dist/lib/subagents.d.ts
CHANGED
|
@@ -106,16 +106,6 @@ export declare function transformSubagentForOpenCode(subagentDir: string): strin
|
|
|
106
106
|
* https://developers.openai.com/codex/subagents (custom agents section)
|
|
107
107
|
*/
|
|
108
108
|
export declare function transformSubagentForCodex(subagentDir: string): string;
|
|
109
|
-
/**
|
|
110
|
-
* Transform a subagent into a Kiro CLI custom-agent JSON file.
|
|
111
|
-
*
|
|
112
|
-
* Kiro custom agents live in `~/.kiro/agents/<name>.json` (or `.kiro/agents/`
|
|
113
|
-
* workspace-local) and declare name, description, prompt, tools, and optional
|
|
114
|
-
* model. We flatten the AGENT.md frontmatter + body plus any sibling .md files
|
|
115
|
-
* as sections into a single `prompt`, and expose the standard built-in tool
|
|
116
|
-
* set so the subagent can actually run.
|
|
117
|
-
*/
|
|
118
|
-
export declare function transformSubagentForKiro(subagentDir: string): string;
|
|
119
109
|
/**
|
|
120
110
|
* Transform a subagent into a Goose recipe YAML file.
|
|
121
111
|
*
|
package/dist/lib/subagents.js
CHANGED
|
@@ -403,43 +403,6 @@ function flattenSubagentInstructions(subagentDir) {
|
|
|
403
403
|
}
|
|
404
404
|
return instructions;
|
|
405
405
|
}
|
|
406
|
-
/**
|
|
407
|
-
* Transform a subagent into a Kiro CLI custom-agent JSON file.
|
|
408
|
-
*
|
|
409
|
-
* Kiro custom agents live in `~/.kiro/agents/<name>.json` (or `.kiro/agents/`
|
|
410
|
-
* workspace-local) and declare name, description, prompt, tools, and optional
|
|
411
|
-
* model. We flatten the AGENT.md frontmatter + body plus any sibling .md files
|
|
412
|
-
* as sections into a single `prompt`, and expose the standard built-in tool
|
|
413
|
-
* set so the subagent can actually run.
|
|
414
|
-
*/
|
|
415
|
-
export function transformSubagentForKiro(subagentDir) {
|
|
416
|
-
const agentMd = path.join(subagentDir, 'AGENT.md');
|
|
417
|
-
const frontmatter = parseSubagentFrontmatter(agentMd);
|
|
418
|
-
const body = getSubagentBody(agentMd);
|
|
419
|
-
if (!frontmatter) {
|
|
420
|
-
throw new Error(`Invalid AGENT.md in ${subagentDir}`);
|
|
421
|
-
}
|
|
422
|
-
const files = fs.readdirSync(subagentDir)
|
|
423
|
-
.filter(f => f.endsWith('.md') && f !== 'AGENT.md')
|
|
424
|
-
.sort();
|
|
425
|
-
let prompt = body;
|
|
426
|
-
for (const file of files) {
|
|
427
|
-
const content = fs.readFileSync(path.join(subagentDir, file), 'utf-8').trim();
|
|
428
|
-
const sectionName = file.replace('.md', '');
|
|
429
|
-
const title = sectionName.charAt(0).toUpperCase() + sectionName.slice(1).toLowerCase();
|
|
430
|
-
prompt += `\n\n## ${title}\n\n${content}`;
|
|
431
|
-
}
|
|
432
|
-
const config = {
|
|
433
|
-
name: frontmatter.name,
|
|
434
|
-
description: frontmatter.description,
|
|
435
|
-
prompt,
|
|
436
|
-
tools: ['read', 'write', 'shell', 'web_search', 'web_fetch'],
|
|
437
|
-
};
|
|
438
|
-
if (frontmatter.model) {
|
|
439
|
-
config.model = frontmatter.model;
|
|
440
|
-
}
|
|
441
|
-
return JSON.stringify(config, null, 2);
|
|
442
|
-
}
|
|
443
406
|
/**
|
|
444
407
|
* Transform a subagent into a Goose recipe YAML file.
|
|
445
408
|
*
|
package/dist/lib/teams/agents.js
CHANGED
|
@@ -2361,7 +2361,9 @@ export class AgentManager {
|
|
|
2361
2361
|
? `at its agents.max-concurrent cap (${e.detail} running)`
|
|
2362
2362
|
: e.reason === 'not-installed'
|
|
2363
2363
|
? `does not have ${this.placementAgentLabel(agent)} installed`
|
|
2364
|
-
: e.reason
|
|
2364
|
+
: e.reason === 'probe-timed-out'
|
|
2365
|
+
? 'did not answer the probe in time (likely up but on a slow/relayed link)'
|
|
2366
|
+
: e.reason;
|
|
2365
2367
|
console.error(chalk.dim(`[placement] '${e.device}' excluded from auto-pick — ${why}`));
|
|
2366
2368
|
}
|
|
2367
2369
|
}
|
|
@@ -137,6 +137,7 @@ export async function probePoolSignals(pool, agent, opts = {}) {
|
|
|
137
137
|
continue; // fully unknown device — leave it out of the map
|
|
138
138
|
signals.set(name, {
|
|
139
139
|
reachable: s?.reachable,
|
|
140
|
+
timedOut: s?.timedOut,
|
|
140
141
|
headroom: s ? headroom(s) : undefined,
|
|
141
142
|
loadPercent: s?.loadPercent,
|
|
142
143
|
memPercent: s?.memPercent,
|
|
@@ -10,6 +10,13 @@ import type { Headroom } from '../devices/health.js';
|
|
|
10
10
|
export interface DevicePlacementSignal {
|
|
11
11
|
/** SSH probe answered. `false` → excluded (unreachable). undefined → unknown. */
|
|
12
12
|
reachable?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* The probe was killed for exceeding its budget rather than failing to
|
|
15
|
+
* connect. Ranking treats it exactly like `reachable:false` — an
|
|
16
|
+
* unresponsive box is still not placeable — but the operator-facing
|
|
17
|
+
* exclusion reason says "probe timed out", not "unreachable" (PHNX-3682).
|
|
18
|
+
*/
|
|
19
|
+
timedOut?: boolean;
|
|
13
20
|
/** Headroom bucket from load+memory. `'loaded'` → excluded (overloaded). */
|
|
14
21
|
headroom?: Headroom;
|
|
15
22
|
/** Normalized CPU load percent (finer rank tiebreak within a headroom tier). */
|
|
@@ -60,7 +67,7 @@ export interface PlacementOptions {
|
|
|
60
67
|
preferred?: ReadonlySet<string>;
|
|
61
68
|
}
|
|
62
69
|
/** Why a device was excluded from the viable set, for the fail-loud message. */
|
|
63
|
-
export type ExclusionReason = 'unreachable' | 'overloaded' | 'capped' | 'not-installed';
|
|
70
|
+
export type ExclusionReason = 'unreachable' | 'probe-timed-out' | 'overloaded' | 'capped' | 'not-installed';
|
|
64
71
|
/** A pool device dropped from the auto-pick, with the reason + live detail. */
|
|
65
72
|
export interface ExcludedDevice {
|
|
66
73
|
device: string;
|
|
@@ -199,7 +199,10 @@ export function classifyExclusions(devices, roster, opts) {
|
|
|
199
199
|
for (const d of devices) {
|
|
200
200
|
const s = signals?.get(d);
|
|
201
201
|
if (s?.reachable === false) {
|
|
202
|
-
|
|
202
|
+
// A probe killed for exceeding its budget is a slow link, not a box that
|
|
203
|
+
// is down. Same exclusion either way — an unresponsive device is still not
|
|
204
|
+
// placeable — but the operator sees which one it was (PHNX-3682).
|
|
205
|
+
excluded.push({ device: d, reason: s.timedOut ? 'probe-timed-out' : 'unreachable' });
|
|
203
206
|
continue;
|
|
204
207
|
}
|
|
205
208
|
if (s?.installed === false) {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* `agents artifacts setup`.
|
|
11
11
|
*/
|
|
12
12
|
import { readSession } from '../identity/client.js';
|
|
13
|
+
import { selectStorageBackendKind } from '../storage/selection.js';
|
|
13
14
|
export const DEFAULT_TRACES_DOMAIN = 'traces.agents-cli.sh';
|
|
14
15
|
/**
|
|
15
16
|
* Resolve the backend for the current machine. Throws when not signed in.
|
|
@@ -21,11 +22,21 @@ export const DEFAULT_TRACES_DOMAIN = 'traces.agents-cli.sh';
|
|
|
21
22
|
export function resolveTracesBackend() {
|
|
22
23
|
const envBase = (process.env['AGENTS_TRACES_BASE_URL'] ?? '').replace(/\/+$/, '').trim();
|
|
23
24
|
const envToken = (process.env['AGENTS_TRACES_WRITE_TOKEN'] ?? '').trim();
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
// The traces surface's only BYO signal is the full BASE_URL + WRITE_TOKEN env
|
|
26
|
+
// pair; the managed-vs-BYO decision itself is the shared selection policy.
|
|
27
|
+
const byoOverride = Boolean(envBase && envToken);
|
|
28
|
+
if (selectStorageBackendKind({ byoOverride }) === 'byo') {
|
|
29
|
+
if (byoOverride) {
|
|
30
|
+
return { baseUrl: envBase, token: envToken, userId: 'byo' };
|
|
31
|
+
}
|
|
32
|
+
// Not signed in and no BYO env pair — the managed principal is the only one
|
|
33
|
+
// this surface exposes, so fail loud with the login hint.
|
|
34
|
+
throw new Error("Not signed in. Run 'agents auth login' to sync traces to your Phoenix account.");
|
|
26
35
|
}
|
|
27
36
|
const session = readSession();
|
|
28
37
|
if (!session) {
|
|
38
|
+
// selectStorageBackendKind read the same session and returned 'managed', so a
|
|
39
|
+
// null here means it was cleared between the two reads — treat as signed out.
|
|
29
40
|
throw new Error("Not signed in. Run 'agents auth login' to sync traces to your Phoenix account.");
|
|
30
41
|
}
|
|
31
42
|
if (!session.access_token) {
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import type { CloudProviderId } from './cloud/types.js';
|
|
9
9
|
import type { FeedBroadcastConfig } from './feed-broadcast.js';
|
|
10
10
|
/** Unique identifier for a current or legacy AI coding agent. */
|
|
11
|
-
export type AgentId = 'claude' | 'codex' | 'gemini' | 'cursor' | 'opencode' | 'openclaw' | 'copilot' | 'amp' | '
|
|
11
|
+
export type AgentId = 'claude' | 'codex' | 'gemini' | 'cursor' | 'opencode' | 'openclaw' | 'copilot' | 'amp' | 'goose' | 'antigravity' | 'grok' | 'kimi' | 'droid' | 'hermes' | 'muse' | 'warp';
|
|
12
12
|
/** How `agents run <agent>` chooses an installed version when none is pinned. */
|
|
13
13
|
export type RunStrategy = 'pinned' | 'available' | 'balanced';
|
|
14
14
|
export type RunEffort = 'low' | 'medium' | 'high' | 'xhigh' | 'max' | 'auto';
|