@phnx-labs/agents-cli 1.22.41 → 1.22.42
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 +14 -0
- package/README.md +9 -3
- package/dist/bin/agents +0 -0
- package/dist/cli/command-registry.d.ts +2 -0
- package/dist/cli/command-registry.js +4 -0
- package/dist/commands/accounts.d.ts +29 -0
- package/dist/commands/accounts.js +220 -29
- package/dist/commands/alias.js +1 -1
- package/dist/commands/auth.d.ts +9 -0
- package/dist/commands/auth.js +104 -0
- package/dist/commands/browser-sessions-picker.js +42 -62
- package/dist/commands/browser.js +30 -38
- package/dist/commands/computer-actions.d.ts +1 -1
- package/dist/commands/computer-actions.js +1 -1
- package/dist/commands/computer-sessions-picker.js +32 -55
- package/dist/commands/computer.d.ts +1 -1
- package/dist/commands/computer.js +2 -2
- package/dist/commands/doctor.d.ts +1 -1
- package/dist/commands/doctor.js +3 -3
- package/dist/commands/feed.js +1 -1
- package/dist/commands/hooks.js +1 -1
- package/dist/commands/import.js +1 -1
- package/dist/commands/insights.js +163 -85
- package/dist/commands/inspect.js +2 -2
- package/dist/commands/mine.js +1 -1
- package/dist/commands/org.d.ts +6 -0
- package/dist/commands/org.js +174 -0
- package/dist/commands/packages.js +1 -1
- package/dist/commands/prune.js +1 -1
- package/dist/commands/routines.js +1 -1
- package/dist/commands/run-account-picker.d.ts +19 -0
- package/dist/commands/run-account-picker.js +81 -0
- package/dist/commands/sessions-picker-factory.d.ts +40 -0
- package/dist/commands/sessions-picker-factory.js +67 -0
- package/dist/commands/setup-browser.js +4 -4
- package/dist/commands/setup-mine.js +1 -1
- package/dist/commands/setup-preferences.js +2 -2
- package/dist/commands/setup.js +5 -3
- package/dist/commands/sync.js +1 -1
- package/dist/commands/versions.js +1 -1
- package/dist/commands/view.js +1 -1
- package/dist/lib/account-capabilities.d.ts +10 -0
- package/dist/lib/account-capabilities.js +34 -0
- package/dist/lib/agent-spec/agents.d.ts +584 -0
- package/dist/lib/agent-spec/agents.js +3127 -0
- package/dist/lib/agent-spec/provider.js +1 -1
- package/dist/lib/agents.d.ts +2 -584
- package/dist/lib/agents.js +2 -3127
- package/dist/lib/browser/drivers/local.d.ts +8 -2
- package/dist/lib/browser/drivers/local.js +8 -2
- package/dist/lib/browser/drivers/ssh.d.ts +8 -2
- package/dist/lib/browser/drivers/ssh.js +10 -4
- package/dist/lib/browser/hygiene.d.ts +1 -1
- package/dist/lib/browser/hygiene.js +5 -1
- package/dist/lib/browser/profiles.d.ts +74 -1
- package/dist/lib/browser/profiles.js +114 -5
- package/dist/lib/browser/runtime-state.d.ts +11 -5
- package/dist/lib/browser/runtime-state.js +13 -9
- package/dist/lib/browser/service.d.ts +68 -30
- package/dist/lib/browser/service.js +305 -194
- package/dist/lib/browser/types.d.ts +95 -3
- package/dist/lib/browser/types.js +51 -0
- package/dist/lib/catchup.js +1 -1
- package/dist/lib/computer/actions.d.ts +1 -1
- package/dist/lib/computer/actions.js +1 -1
- package/dist/lib/{computer-rpc.js → computer/computer-rpc.js} +5 -5
- package/dist/lib/computer/dispatch.d.ts +1 -1
- package/dist/lib/computer/download.d.ts +1 -1
- package/dist/lib/computer/download.js +3 -3
- package/dist/lib/{ssh-tunnel.d.ts → computer/ssh-tunnel.d.ts} +1 -1
- package/dist/lib/{ssh-tunnel.js → computer/ssh-tunnel.js} +12 -12
- package/dist/lib/daemon/daemon.js +1 -1
- package/dist/lib/{runner.d.ts → daemon/runner.d.ts} +10 -10
- package/dist/lib/{runner.js → daemon/runner.js} +40 -114
- package/dist/lib/devices/doctor-findings.d.ts +1 -1
- package/dist/lib/devices/doctor-findings.js +3 -3
- package/dist/lib/devices/fleet-inventory.js +1 -1
- package/dist/lib/devices/harness-inventory.js +1 -1
- package/dist/lib/devices/registry.js +4 -22
- package/dist/lib/doctor-diff.d.ts +1 -1
- package/dist/lib/doctor-diff.js +1 -1
- package/dist/lib/drift.js +1 -1
- package/dist/lib/entitlement.d.ts +31 -0
- package/dist/lib/entitlement.js +137 -0
- package/dist/lib/exec.js +39 -202
- package/dist/lib/feed/feed.js +2 -8
- package/dist/lib/fs-atomic.d.ts +7 -0
- package/dist/lib/fs-atomic.js +9 -0
- package/dist/lib/harness/adapter.d.ts +160 -0
- package/dist/lib/harness/adapter.js +47 -0
- package/dist/lib/harness/adapters/claude.d.ts +2 -0
- package/dist/lib/harness/adapters/claude.js +110 -0
- package/dist/lib/harness/adapters/codex.d.ts +2 -0
- package/dist/lib/harness/adapters/codex.js +83 -0
- package/dist/lib/harness/adapters/copilot.d.ts +2 -0
- package/dist/lib/harness/adapters/copilot.js +23 -0
- package/dist/lib/harness/adapters/cursor.d.ts +2 -0
- package/dist/lib/harness/adapters/cursor.js +38 -0
- package/dist/lib/harness/adapters/droid.d.ts +2 -0
- package/dist/lib/harness/adapters/droid.js +17 -0
- package/dist/lib/harness/adapters/grok.d.ts +2 -0
- package/dist/lib/harness/adapters/grok.js +14 -0
- package/dist/lib/harness/adapters/kimi.d.ts +2 -0
- package/dist/lib/harness/adapters/kimi.js +49 -0
- package/dist/lib/harness/adapters/muse.d.ts +2 -0
- package/dist/lib/harness/adapters/muse.js +44 -0
- package/dist/lib/harness/adapters/opencode.d.ts +2 -0
- package/dist/lib/harness/adapters/opencode.js +14 -0
- package/dist/lib/harness/exec-config-version.d.ts +8 -0
- package/dist/lib/harness/exec-config-version.js +22 -0
- package/dist/lib/harness/index.d.ts +1 -0
- package/dist/lib/harness/index.js +34 -0
- package/dist/lib/{hooks.d.ts → hooks/install.d.ts} +1 -1
- package/dist/lib/{hooks.js → hooks/install.js} +11 -11
- package/dist/lib/import.js +1 -1
- package/dist/lib/installations/index.d.ts +4 -4
- package/dist/lib/installations/index.js +3 -4
- package/dist/lib/installations/migrate.js +6 -6
- package/dist/lib/{shims.d.ts → installations/shims.d.ts} +2 -2
- package/dist/lib/{shims.js → installations/shims.js} +12 -114
- package/dist/lib/installations/store.d.ts +141 -3
- package/dist/lib/installations/store.js +475 -5
- package/dist/lib/installations/versions.d.ts +1 -126
- package/dist/lib/installations/versions.js +5 -465
- package/dist/lib/isolation-boundary-report.d.ts +1 -1
- package/dist/lib/isolation-boundary-report.js +1 -1
- package/dist/lib/mailbox-gc.js +2 -3
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/monitors/dispatch.d.ts +1 -1
- package/dist/lib/monitors/dispatch.js +2 -2
- package/dist/lib/monitors/state.d.ts +1 -1
- package/dist/lib/plugins/plugins.js +1 -1
- package/dist/lib/plugins/skills.js +1 -1
- package/dist/lib/prix-account.d.ts +158 -0
- package/dist/lib/prix-account.js +214 -0
- package/dist/lib/project-key.js +2 -2
- package/dist/lib/project-launch.js +1 -1
- package/dist/lib/refresh.js +2 -2
- package/dist/lib/resource-inventory.d.ts +1 -1
- package/dist/lib/resource-inventory.js +1 -1
- package/dist/lib/rules/rules.js +1 -1
- package/dist/lib/scheduling/routines.js +1 -1
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/self-heal/checks/hook-runtime.js +1 -1
- package/dist/lib/self-heal/checks/path.js +1 -1
- package/dist/lib/self-heal/checks/shadowing.js +1 -1
- package/dist/lib/self-heal/checks/shims.js +1 -1
- package/dist/lib/session/discover.d.ts +39 -0
- package/dist/lib/session/discover.js +3 -3
- package/dist/lib/session/parse.js +24 -42
- package/dist/lib/session/recovery.js +1 -1
- package/dist/lib/staleness/prune.d.ts +1 -1
- package/dist/lib/staleness/prune.js +1 -1
- package/dist/lib/staleness/writers/hooks.js +1 -1
- package/dist/lib/startup/command-registry.js +1 -1
- package/dist/lib/teams/agents.js +2 -19
- package/dist/lib/teams/parsers.js +20 -26
- package/dist/lib/teams/registry.js +2 -21
- package/dist/lib/triggers/handlers.js +1 -1
- package/dist/lib/triggers/webhook.js +1 -1
- package/dist/lib/uninstall.js +1 -1
- package/dist/lib/version.d.ts +9 -2
- package/dist/lib/version.js +11 -9
- package/package.json +1 -1
- /package/dist/lib/{computer-rpc.d.ts → computer/computer-rpc.d.ts} +0 -0
|
@@ -49,7 +49,24 @@ import { terminalWidth, truncateToWidth, stringWidth, padToWidth } from '../lib/
|
|
|
49
49
|
import { registerMixCommands } from '../lib/analytics/mix-commands.js';
|
|
50
50
|
import { registerCostCommand } from './cost.js';
|
|
51
51
|
import { registerOutputCommand } from './output.js';
|
|
52
|
+
import { getTier } from '../lib/entitlement.js';
|
|
52
53
|
const execFileAsync = promisify(execFile);
|
|
54
|
+
/**
|
|
55
|
+
* Plan-tier gate for the behavioural report (RUSH-2424). Free keeps top-line
|
|
56
|
+
* counts and the harness mix (and `insights mix` / `agents perf`, which never
|
|
57
|
+
* enter this file's gating since they're separate command trees); the
|
|
58
|
+
* friction/correction-signal sections, grouping `--by account`, and
|
|
59
|
+
* `--narrative` are paid. `insights mix`/`cost`/`output` are unaffected — this
|
|
60
|
+
* gate applies only to the default behavioural report.
|
|
61
|
+
*/
|
|
62
|
+
const PAID_PLAN_NOTICE = 'Friction and account-split analysis are on the paid plan.';
|
|
63
|
+
function resolveInsightsGate(tier, dim) {
|
|
64
|
+
return {
|
|
65
|
+
tier,
|
|
66
|
+
groupGated: !tier.isPaid && dim === 'account',
|
|
67
|
+
frictionGated: !tier.isPaid,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
53
70
|
function collectAgent(value, previous) {
|
|
54
71
|
return [...previous, value];
|
|
55
72
|
}
|
|
@@ -208,7 +225,7 @@ function renderHours(hours, out) {
|
|
|
208
225
|
out.push(` ${chalk.cyan(spark)}`);
|
|
209
226
|
out.push(` ${chalk.gray('0h'.padEnd(6))}${chalk.gray('6h'.padEnd(6))}${chalk.gray('12h'.padEnd(6))}${chalk.gray('18h'.padEnd(5))}${chalk.gray('23h')}`);
|
|
210
227
|
}
|
|
211
|
-
function renderReport(groups, dim, meta, actions, harnesses) {
|
|
228
|
+
function renderReport(groups, dim, meta, actions, harnesses, gate) {
|
|
212
229
|
const out = [];
|
|
213
230
|
const scope = meta.since ? `last ${meta.since}` : 'all time';
|
|
214
231
|
out.push(chalk.bold('Insights') + chalk.gray(` ${scope} · ${meta.analyzed} of ${meta.scanned} sessions`));
|
|
@@ -218,28 +235,44 @@ function renderReport(groups, dim, meta, actions, harnesses) {
|
|
|
218
235
|
console.log(out.join('\n'));
|
|
219
236
|
return;
|
|
220
237
|
}
|
|
238
|
+
let noticePrinted = false;
|
|
239
|
+
const printPlanNotice = () => {
|
|
240
|
+
if (noticePrinted)
|
|
241
|
+
return;
|
|
242
|
+
noticePrinted = true;
|
|
243
|
+
out.push('');
|
|
244
|
+
out.push(chalk.gray(` ${PAID_PLAN_NOTICE}`));
|
|
245
|
+
};
|
|
221
246
|
// Per-group table — the headline, and the thing no sibling command produces.
|
|
222
247
|
// Includes silent-stall counts so harness/account laziness is visible without --json.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
.
|
|
229
|
-
.
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
const
|
|
238
|
-
const
|
|
239
|
-
out.push(` ${padToWidth(
|
|
240
|
-
`${
|
|
241
|
-
|
|
242
|
-
|
|
248
|
+
// Gated on the free plan when grouped `--by account` (the default) — see resolveInsightsGate.
|
|
249
|
+
if (gate.groupGated) {
|
|
250
|
+
printPlanNotice();
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
out.push('');
|
|
254
|
+
out.push(chalk.bold(`By ${dim}`));
|
|
255
|
+
const labelW = Math.min(Math.max(...groups.map((g) => stringWidth(g.label)), 5), Math.max(16, terminalWidth() - 58));
|
|
256
|
+
const sessW = Math.max(...groups.map((g) => String(g.sessions).length), 3);
|
|
257
|
+
// Friction-derived — never shown on the free plan, even when grouping by
|
|
258
|
+
// something other than account (gate.groupGated only covers `--by account`).
|
|
259
|
+
const stallOf = (g) => Object.entries(g.facets.frictionSignals)
|
|
260
|
+
.filter(([k]) => k.startsWith('silent stall:'))
|
|
261
|
+
.reduce((n, [, c]) => n + c, 0);
|
|
262
|
+
const resumeOf = (g) => g.facets.correctionSignals['resume after silent stall'] ?? 0;
|
|
263
|
+
const stallW = gate.frictionGated ? 6 : Math.max(...groups.map((g) => String(stallOf(g)).length), 5);
|
|
264
|
+
out.push(chalk.gray(` ${padToWidth('', labelW)} ${''.padStart(sessW)} ` +
|
|
265
|
+
`${''.padStart(9)} ${''.padStart(8)} ${gate.frictionGated ? ''.padStart(stallW) : 'stalls'.padStart(stallW)} ${gate.frictionGated ? '' : 'resume'}`));
|
|
266
|
+
for (const g of groups) {
|
|
267
|
+
const cost = g.costUsd > 0 ? formatUsd(g.costUsd) : '—';
|
|
268
|
+
const dur = g.durationMs > 0 ? formatDuration(g.durationMs) : '—';
|
|
269
|
+
const stalls = gate.frictionGated ? '—' : String(stallOf(g));
|
|
270
|
+
const resumes = gate.frictionGated ? '' : String(resumeOf(g));
|
|
271
|
+
out.push(` ${padToWidth(truncateToWidth(g.label, labelW), labelW)} ` +
|
|
272
|
+
`${chalk.gray(String(g.sessions).padStart(sessW))} ${chalk.gray('sess')} ` +
|
|
273
|
+
`${chalk.green(padToWidth(cost, 9))} ${chalk.gray(padToWidth(dur, 8))} ` +
|
|
274
|
+
`${chalk.cyan(stalls.padStart(stallW))} ${chalk.cyan(resumes)}`);
|
|
275
|
+
}
|
|
243
276
|
}
|
|
244
277
|
// Everything below is the whole scope folded together; per-group detail is in --json.
|
|
245
278
|
const all = newFacetAccumulator();
|
|
@@ -248,52 +281,64 @@ function renderReport(groups, dim, meta, actions, harnesses) {
|
|
|
248
281
|
renderCounts('Top tools', topEntries(all.toolCounts, 8), out);
|
|
249
282
|
renderCounts('Languages', topEntries(all.languages, 6), out);
|
|
250
283
|
renderCounts('Models', topEntries(all.models, 6), out);
|
|
251
|
-
|
|
252
|
-
//
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
.filter(([k]) => k.startsWith('silent stall:'))
|
|
256
|
-
.reduce((n, [, c]) => n + c, 0);
|
|
257
|
-
const resumeNudges = all.correctionSignals['resume after silent stall'] ?? 0;
|
|
258
|
-
out.push('');
|
|
259
|
-
out.push(chalk.bold('Friction'));
|
|
260
|
-
out.push(` ${padToWidth('interruptions', 18)} ${chalk.cyan(String(all.interruptions))}` +
|
|
261
|
-
chalk.gray(' turns you cut short'));
|
|
262
|
-
out.push(` ${padToWidth('tool errors', 18)} ${chalk.cyan(String(all.errorCount))}`);
|
|
263
|
-
if (gaps.length > 0) {
|
|
264
|
-
// Same timestamps as silent stalls; this line is the distribution. Silent
|
|
265
|
-
// stalls (below) are the agent-attributed long gaps after the model stopped.
|
|
266
|
-
out.push(` ${padToWidth('gap until next msg', 18)} ` +
|
|
267
|
-
chalk.cyan(`p50 ${Math.round(percentile(gaps, 50))}s`) + chalk.gray(` · p90 ${Math.round(percentile(gaps, 90))}s`) +
|
|
268
|
-
chalk.gray(' after assistant last spoke'));
|
|
269
|
-
}
|
|
270
|
-
if (silentStalls > 0) {
|
|
271
|
-
out.push(` ${padToWidth('silent stalls', 18)} ${chalk.cyan(String(silentStalls))}` +
|
|
272
|
-
chalk.gray(' agent idle ≥5m until you resumed (also in By ' + dim + ' table)'));
|
|
284
|
+
// Friction — the section that earns the command. Paid plan only (RUSH-2424);
|
|
285
|
+
// top-line counts and harness mix above/below stay free.
|
|
286
|
+
if (gate.frictionGated) {
|
|
287
|
+
printPlanNotice();
|
|
273
288
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
289
|
+
else {
|
|
290
|
+
renderCounts('Silent stalls by model', topEntries(all.silentStallsByModel ?? {}, 8), out);
|
|
291
|
+
const gaps = all.responseGaps;
|
|
292
|
+
const silentStalls = Object.entries(all.frictionSignals)
|
|
293
|
+
.filter(([k]) => k.startsWith('silent stall:'))
|
|
294
|
+
.reduce((n, [, c]) => n + c, 0);
|
|
295
|
+
const resumeNudges = all.correctionSignals['resume after silent stall'] ?? 0;
|
|
296
|
+
out.push('');
|
|
297
|
+
out.push(chalk.bold('Friction'));
|
|
298
|
+
out.push(` ${padToWidth('interruptions', 18)} ${chalk.cyan(String(all.interruptions))}` +
|
|
299
|
+
chalk.gray(' turns you cut short'));
|
|
300
|
+
out.push(` ${padToWidth('tool errors', 18)} ${chalk.cyan(String(all.errorCount))}`);
|
|
301
|
+
if (gaps.length > 0) {
|
|
302
|
+
// Same timestamps as silent stalls; this line is the distribution. Silent
|
|
303
|
+
// stalls (below) are the agent-attributed long gaps after the model stopped.
|
|
304
|
+
out.push(` ${padToWidth('gap until next msg', 18)} ` +
|
|
305
|
+
chalk.cyan(`p50 ${Math.round(percentile(gaps, 50))}s`) + chalk.gray(` · p90 ${Math.round(percentile(gaps, 90))}s`) +
|
|
306
|
+
chalk.gray(' after assistant last spoke'));
|
|
307
|
+
}
|
|
308
|
+
if (silentStalls > 0) {
|
|
309
|
+
out.push(` ${padToWidth('silent stalls', 18)} ${chalk.cyan(String(silentStalls))}` +
|
|
310
|
+
chalk.gray(' agent idle ≥5m until you resumed (also in By ' + dim + ' table)'));
|
|
311
|
+
}
|
|
312
|
+
if (resumeNudges > 0) {
|
|
313
|
+
out.push(` ${padToWidth('resume nudges', 18)} ${chalk.cyan(String(resumeNudges))}` +
|
|
314
|
+
chalk.gray(' "continue"/"keep going" after a silent stall'));
|
|
315
|
+
}
|
|
316
|
+
const errs = topEntries(all.errorCategories, 6);
|
|
317
|
+
if (errs.length > 0) {
|
|
318
|
+
for (const e of errs)
|
|
319
|
+
out.push(` ${chalk.gray('·')} ${padToWidth(e.name, 16)} ${chalk.gray(String(e.count))}`);
|
|
320
|
+
}
|
|
321
|
+
renderCounts('Friction / thrash', topEntries(all.frictionSignals, 10), out);
|
|
322
|
+
renderCounts('Dissatisfaction / corrections', topEntries(all.correctionSignals, 10), out);
|
|
282
323
|
}
|
|
283
|
-
renderCounts('Friction / thrash', topEntries(all.frictionSignals, 10), out);
|
|
284
|
-
renderCounts('Dissatisfaction / corrections', topEntries(all.correctionSignals, 10), out);
|
|
285
324
|
renderCounts('Automatable repeats', topEntries(all.automationSignals, 10), out);
|
|
286
325
|
renderCounts('Harness split', harnesses, out);
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
out.push(chalk.
|
|
294
|
-
|
|
295
|
-
out.push(
|
|
296
|
-
|
|
326
|
+
// Actions are built from frictionSignals/correctionSignals/automationSignals
|
|
327
|
+
// together (buildInsightActions) — evidence counts, sample session ids, and
|
|
328
|
+
// the action text itself describe the same paid friction/correction
|
|
329
|
+
// categories gated above, so the whole section is paid too (RUSH-2424).
|
|
330
|
+
if (!gate.frictionGated) {
|
|
331
|
+
out.push('');
|
|
332
|
+
out.push(chalk.bold('Actions'));
|
|
333
|
+
if (actions.length === 0) {
|
|
334
|
+
out.push(chalk.gray(' No repeated action pattern met the evidence threshold in this window.'));
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
out.push(chalk.gray(' pri category evidence sample sessions action'));
|
|
338
|
+
for (const action of actions.slice(0, 12)) {
|
|
339
|
+
out.push(` ${padToWidth(action.priority, 7)} ${padToWidth(action.category, 11)} ` +
|
|
340
|
+
`${String(action.evidenceCount).padStart(8)} ${padToWidth(action.sampleSessionIds.join(', '), 25)} ${action.action}`);
|
|
341
|
+
}
|
|
297
342
|
}
|
|
298
343
|
}
|
|
299
344
|
// Output
|
|
@@ -349,7 +394,9 @@ function renderReport(groups, dim, meta, actions, harnesses) {
|
|
|
349
394
|
out.push('');
|
|
350
395
|
out.push(chalk.yellow(` ${meta.unreadable} transcripts could not be read; their behaviour is missing from these totals.`));
|
|
351
396
|
}
|
|
352
|
-
|
|
397
|
+
// Friction-derived (gapsOverCeiling is a PAID_FACET_KEYS entry) and names
|
|
398
|
+
// "silent stall" outright — must not render on the free plan.
|
|
399
|
+
if (!gate.frictionGated && all.gapsOverCeiling > 0) {
|
|
353
400
|
out.push(chalk.gray(` ${all.gapsOverCeiling} gaps over an hour excluded from p50/p90 (still counted as silent stall: 1h+ when the assistant last spoke).`));
|
|
354
401
|
}
|
|
355
402
|
out.push('');
|
|
@@ -404,8 +451,23 @@ async function renderNarrative(payload) {
|
|
|
404
451
|
process.exitCode = 1;
|
|
405
452
|
}
|
|
406
453
|
}
|
|
454
|
+
/** Facet keys that belong to the paid friction/correction sections — stripped from `--json` on free (RUSH-2424). */
|
|
455
|
+
const PAID_FACET_KEYS = new Set([
|
|
456
|
+
'frictionSignals', 'correctionSignals', 'silentStallsByModel',
|
|
457
|
+
'interruptions', 'errorCount', 'errorCategories', 'responseGaps', 'gapsOverCeiling',
|
|
458
|
+
]);
|
|
459
|
+
function freeFacetSubset(facets) {
|
|
460
|
+
const out = {};
|
|
461
|
+
for (const [key, value] of Object.entries(facets)) {
|
|
462
|
+
if (!PAID_FACET_KEYS.has(key))
|
|
463
|
+
out[key] = value;
|
|
464
|
+
}
|
|
465
|
+
return out;
|
|
466
|
+
}
|
|
407
467
|
async function insightsAction(options) {
|
|
408
468
|
const dim = resolveGroup(options.by);
|
|
469
|
+
const tier = await getTier();
|
|
470
|
+
const gate = resolveInsightsGate(tier, dim);
|
|
409
471
|
const minMessages = Number.parseInt(options.minMessages ?? '2', 10);
|
|
410
472
|
if (!Number.isFinite(minMessages) || minMessages < 0) {
|
|
411
473
|
console.error(chalk.red('error: --min-messages must be a non-negative integer'));
|
|
@@ -471,27 +533,37 @@ async function insightsAction(options) {
|
|
|
471
533
|
unreadable,
|
|
472
534
|
minMessages,
|
|
473
535
|
by: dim,
|
|
536
|
+
plan: { tierName: tier.tierName, isPaid: tier.isPaid },
|
|
537
|
+
...(gate.groupGated || gate.frictionGated ? { notice: PAID_PLAN_NOTICE } : {}),
|
|
474
538
|
overlap,
|
|
475
|
-
|
|
539
|
+
// Built from frictionSignals/correctionSignals/automationSignals together
|
|
540
|
+
// (buildInsightActions) — same paid friction/correction data as above.
|
|
541
|
+
actions: gate.frictionGated ? null : actions,
|
|
476
542
|
harnesses,
|
|
477
|
-
groups: groups.map((g) => ({
|
|
543
|
+
groups: gate.groupGated ? null : groups.map((g) => ({
|
|
478
544
|
key: g.key,
|
|
479
545
|
label: g.label,
|
|
480
546
|
sessions: g.sessions,
|
|
481
547
|
costUsd: g.costUsd,
|
|
482
548
|
durationMs: g.durationMs,
|
|
483
549
|
outputTokens: g.outputTokens,
|
|
484
|
-
...g.facets
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
550
|
+
...(gate.frictionGated ? freeFacetSubset(g.facets) : {
|
|
551
|
+
...g.facets,
|
|
552
|
+
responseGapP50: Math.round(percentile(g.facets.responseGaps, 50)),
|
|
553
|
+
responseGapP90: Math.round(percentile(g.facets.responseGaps, 90)),
|
|
554
|
+
responseGapBuckets: bucketGaps(g.facets.responseGaps),
|
|
555
|
+
// The raw sample is large and uninteresting once bucketed.
|
|
556
|
+
responseGaps: undefined,
|
|
557
|
+
}),
|
|
490
558
|
})),
|
|
491
559
|
};
|
|
492
560
|
console.log(JSON.stringify(payload, null, 2));
|
|
493
|
-
if (options.narrative)
|
|
494
|
-
|
|
561
|
+
if (options.narrative) {
|
|
562
|
+
if (!tier.isPaid)
|
|
563
|
+
console.error(chalk.gray(` ${PAID_PLAN_NOTICE}`));
|
|
564
|
+
else
|
|
565
|
+
await renderNarrative(payload);
|
|
566
|
+
}
|
|
495
567
|
return;
|
|
496
568
|
}
|
|
497
569
|
renderReport(groups, dim, {
|
|
@@ -502,18 +574,24 @@ async function insightsAction(options) {
|
|
|
502
574
|
unreadable,
|
|
503
575
|
minMessages,
|
|
504
576
|
overlap,
|
|
505
|
-
}, actions, harnesses);
|
|
577
|
+
}, actions, harnesses, gate);
|
|
506
578
|
if (options.narrative) {
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
579
|
+
if (!tier.isPaid) {
|
|
580
|
+
console.log('');
|
|
581
|
+
console.log(chalk.gray(` ${PAID_PLAN_NOTICE}`));
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
await renderNarrative(groups.map((g) => ({
|
|
585
|
+
account: g.label, sessions: g.sessions, costUsd: g.costUsd,
|
|
586
|
+
topTools: topEntries(g.facets.toolCounts, 8),
|
|
587
|
+
languages: topEntries(g.facets.languages, 6),
|
|
588
|
+
errorCategories: topEntries(g.facets.errorCategories, 6),
|
|
589
|
+
interruptions: g.facets.interruptions,
|
|
590
|
+
linesTouchedAfter: g.facets.linesTouchedAfter, linesTouchedBefore: g.facets.linesTouchedBefore,
|
|
591
|
+
gitCommits: g.facets.gitCommits,
|
|
592
|
+
replyP50s: Math.round(percentile(g.facets.responseGaps, 50)),
|
|
593
|
+
})));
|
|
594
|
+
}
|
|
517
595
|
}
|
|
518
596
|
}
|
|
519
597
|
function configureInsightsCommand(cmd) {
|
package/dist/commands/inspect.js
CHANGED
|
@@ -26,9 +26,9 @@ import { getAgentModesCatalog } from '../lib/agent-modes.js';
|
|
|
26
26
|
import { resolveSingleAgentTarget, AgentSpecError } from '../lib/agent-spec/index.js';
|
|
27
27
|
import { readMeta, getUserAgentsDir, getSystemAgentsDir, getProjectAgentsDir, getEnabledExtraRepos, } from '../lib/state.js';
|
|
28
28
|
import { getVersionHomePath, isVersionIsolated, getIsolatedDefault, } from '../lib/installations/versions.js';
|
|
29
|
-
import { getShimsDir, getVersionedAliasPath } from '../lib/shims.js';
|
|
29
|
+
import { getShimsDir, getVersionedAliasPath } from '../lib/installations/shims.js';
|
|
30
30
|
import { getAgentResources, isDirectoryDoc, listResources, } from '../lib/resources.js';
|
|
31
|
-
import { listHookEntriesFromDir } from '../lib/hooks.js';
|
|
31
|
+
import { listHookEntriesFromDir } from '../lib/hooks/install.js';
|
|
32
32
|
import { getResourceInventory } from '../lib/resource-inventory.js';
|
|
33
33
|
import { listMcpServerConfigs, discoverMcpConfigsFromRepo } from '../lib/mcp.js';
|
|
34
34
|
import { discoverPlugins, discoverPluginsInDir, pluginResourceGroups, inspectPluginCapabilities, pluginCapabilityLabels } from '../lib/plugins/plugins.js';
|
package/dist/commands/mine.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { validateBrandName, listBrands, getBrandConfig, upsertBrand, removeBrand, brandPresetName, } from '../lib/brand.js';
|
|
3
|
-
import { createBrandShim, removeBrandShim, isShimsInPath } from '../lib/shims.js';
|
|
3
|
+
import { createBrandShim, removeBrandShim, isShimsInPath } from '../lib/installations/shims.js';
|
|
4
4
|
import { updateMeta } from '../lib/state.js';
|
|
5
5
|
import { KNOWN_TOP_LEVEL_COMMANDS } from '../lib/startup/command-registry.js';
|
|
6
6
|
/** Built-in top-level command names, for validating `--disable <cmd>`. */
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
/** `--role` defaults to member when omitted; anything present must be a real role — never silently coerced. */
|
|
3
|
+
export declare function resolveInviteRole(raw: string | undefined): 'admin' | 'member';
|
|
4
|
+
/** Validate a role argument before any network call — same rule the backend enforces server-side. */
|
|
5
|
+
export declare function parseRole(raw: string): 'admin' | 'member';
|
|
6
|
+
export declare function registerOrgCommand(program: Command): void;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { setHelpSections } from '../lib/help.js';
|
|
3
|
+
import { createSpace, createSpaceInvite, fetchWhoAmI, listSpaceMembers, listSpaces, removeSpaceMember, resolveMemberFromList, resolvePrixToken, resolveSpaceFromList, slugify, updateSpaceMemberRole, } from '../lib/prix-account.js';
|
|
4
|
+
/** Every `agents org` subcommand needs a token up front — one place to say so. */
|
|
5
|
+
function requireToken() {
|
|
6
|
+
if (!resolvePrixToken())
|
|
7
|
+
throw new Error("Not signed in. Run 'agents auth login' first.");
|
|
8
|
+
}
|
|
9
|
+
async function resolveSpace(explicit) {
|
|
10
|
+
const spaces = await listSpaces();
|
|
11
|
+
return resolveSpaceFromList(spaces, explicit);
|
|
12
|
+
}
|
|
13
|
+
function printSpace(space) {
|
|
14
|
+
console.log(`${chalk.bold(space.name)} ${chalk.gray(space.slug)} ${chalk.gray(space.id)}`);
|
|
15
|
+
console.log(` role: ${space.user_role}${space.organization_id ? ` org: ${space.organization_id}` : ''}`);
|
|
16
|
+
}
|
|
17
|
+
function printMembers(members) {
|
|
18
|
+
if (!members.length) {
|
|
19
|
+
console.log(chalk.gray(' No members.'));
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
for (const m of members)
|
|
23
|
+
console.log(` ${chalk.cyan(m.email)} ${m.role} ${chalk.gray(m.user_id)}`);
|
|
24
|
+
}
|
|
25
|
+
async function runCreate(name, o) {
|
|
26
|
+
requireToken();
|
|
27
|
+
const space = await createSpace({ name, slug: o.slug ?? slugify(name), description: o.description });
|
|
28
|
+
if (o.json) {
|
|
29
|
+
console.log(JSON.stringify(space, null, 2));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
console.log(chalk.green(`Created space '${space.name}' (${space.slug}).`));
|
|
33
|
+
printSpace(space);
|
|
34
|
+
}
|
|
35
|
+
async function runList(o) {
|
|
36
|
+
requireToken();
|
|
37
|
+
const spaces = await listSpaces();
|
|
38
|
+
if (o.json) {
|
|
39
|
+
console.log(JSON.stringify(spaces, null, 2));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (!spaces.length) {
|
|
43
|
+
console.log(chalk.gray("No spaces. Create one with 'agents org create <name>'."));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
for (const space of spaces)
|
|
47
|
+
printSpace(space);
|
|
48
|
+
}
|
|
49
|
+
async function runView(spaceArg, o) {
|
|
50
|
+
requireToken();
|
|
51
|
+
const space = await resolveSpace(spaceArg);
|
|
52
|
+
if (o.json) {
|
|
53
|
+
console.log(JSON.stringify(space, null, 2));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
printSpace(space);
|
|
57
|
+
}
|
|
58
|
+
/** `--role` defaults to member when omitted; anything present must be a real role — never silently coerced. */
|
|
59
|
+
export function resolveInviteRole(raw) {
|
|
60
|
+
return raw === undefined ? 'member' : parseRole(raw);
|
|
61
|
+
}
|
|
62
|
+
async function runInvite(email, o) {
|
|
63
|
+
requireToken();
|
|
64
|
+
const role = resolveInviteRole(o.role);
|
|
65
|
+
const space = await resolveSpace(o.space);
|
|
66
|
+
const result = await createSpaceInvite(space.id, email, role);
|
|
67
|
+
if (o.json) {
|
|
68
|
+
console.log(JSON.stringify(result, null, 2));
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (result.member_added)
|
|
72
|
+
console.log(chalk.green(`Added ${email} to '${space.name}' as ${role}.`));
|
|
73
|
+
else
|
|
74
|
+
console.log(chalk.green(`Invited ${email} to '${space.name}' as ${role}. They'll get an email.`));
|
|
75
|
+
}
|
|
76
|
+
async function runMembers(spaceArg, o) {
|
|
77
|
+
requireToken();
|
|
78
|
+
const space = await resolveSpace(spaceArg);
|
|
79
|
+
const members = await listSpaceMembers(space.id);
|
|
80
|
+
if (o.json) {
|
|
81
|
+
console.log(JSON.stringify(members, null, 2));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
console.log(chalk.bold(`${space.name} (${members.length} member${members.length === 1 ? '' : 's'})`));
|
|
85
|
+
printMembers(members);
|
|
86
|
+
}
|
|
87
|
+
/** Validate a role argument before any network call — same rule the backend enforces server-side. */
|
|
88
|
+
export function parseRole(raw) {
|
|
89
|
+
if (raw === 'admin' || raw === 'member')
|
|
90
|
+
return raw;
|
|
91
|
+
throw new Error(`role must be 'admin' or 'member', got '${raw}'.`);
|
|
92
|
+
}
|
|
93
|
+
async function runRole(email, roleRaw, o) {
|
|
94
|
+
requireToken();
|
|
95
|
+
const role = parseRole(roleRaw);
|
|
96
|
+
const space = await resolveSpace(o.space);
|
|
97
|
+
const members = await listSpaceMembers(space.id);
|
|
98
|
+
const member = resolveMemberFromList(members, email);
|
|
99
|
+
const result = await updateSpaceMemberRole(space.id, member.user_id, role);
|
|
100
|
+
if (o.json) {
|
|
101
|
+
console.log(JSON.stringify(result, null, 2));
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
console.log(chalk.green(`${email} is now ${role} in '${space.name}'.`));
|
|
105
|
+
}
|
|
106
|
+
async function runRemove(email, o) {
|
|
107
|
+
requireToken();
|
|
108
|
+
const space = await resolveSpace(o.space);
|
|
109
|
+
const members = await listSpaceMembers(space.id);
|
|
110
|
+
const member = resolveMemberFromList(members, email);
|
|
111
|
+
await removeSpaceMember(space.id, member.user_id);
|
|
112
|
+
if (o.json) {
|
|
113
|
+
console.log(JSON.stringify({ removed: email, space: space.slug }, null, 2));
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
console.log(chalk.green(`Removed ${email} from '${space.name}'.`));
|
|
117
|
+
}
|
|
118
|
+
async function runLeave(spaceArg, o) {
|
|
119
|
+
requireToken();
|
|
120
|
+
const resolved = resolvePrixToken();
|
|
121
|
+
if (!resolved)
|
|
122
|
+
throw new Error("Not signed in. Run 'agents auth login' first.");
|
|
123
|
+
const who = await fetchWhoAmI(resolved.token);
|
|
124
|
+
const space = await resolveSpace(spaceArg);
|
|
125
|
+
if (space.owner_user_id === who.userId) {
|
|
126
|
+
throw new Error(`You own '${space.name}'. Transfer ownership or delete the space instead of leaving it.`);
|
|
127
|
+
}
|
|
128
|
+
await removeSpaceMember(space.id, who.userId);
|
|
129
|
+
if (o.json) {
|
|
130
|
+
console.log(JSON.stringify({ left: space.slug }, null, 2));
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
console.log(chalk.green(`Left '${space.name}'.`));
|
|
134
|
+
}
|
|
135
|
+
export function registerOrgCommand(program) {
|
|
136
|
+
const org = program.command('org').description('Create and manage a team (a Rush "space") you can share with `agents auth login` collaborators');
|
|
137
|
+
org.command('create <name>').description('Create a space (free tier: 1 owned space)')
|
|
138
|
+
.option('--slug <slug>', 'Override the derived slug')
|
|
139
|
+
.option('--description <text>', 'Optional description')
|
|
140
|
+
.option('--json', 'Machine-readable output')
|
|
141
|
+
.action((name, o, command) => runCreate(name, { ...o, json: !!(o.json || command.optsWithGlobals().json) }));
|
|
142
|
+
org.command('list').description('List spaces you own or belong to').option('--json', 'Machine-readable output')
|
|
143
|
+
.action((o, command) => runList({ json: !!(o.json || command.optsWithGlobals().json) }));
|
|
144
|
+
org.command('view [space]').description('Show one space (defaults to your only space)').option('--json', 'Machine-readable output')
|
|
145
|
+
.action((space, o, command) => runView(space, { json: !!(o.json || command.optsWithGlobals().json) }));
|
|
146
|
+
org.command('invite <email>').description('Invite (or directly add) a member')
|
|
147
|
+
.option('--role <role>', 'admin | member', 'member')
|
|
148
|
+
.option('--space <id-or-slug>', 'Space to invite into (defaults to your only space)')
|
|
149
|
+
.option('--json', 'Machine-readable output')
|
|
150
|
+
.action((email, o, command) => runInvite(email, { ...o, json: !!(o.json || command.optsWithGlobals().json) }));
|
|
151
|
+
org.command('members [space]').description('List a space\'s members').option('--json', 'Machine-readable output')
|
|
152
|
+
.action((space, o, command) => runMembers(space, { json: !!(o.json || command.optsWithGlobals().json) }));
|
|
153
|
+
org.command('role <email> <role>').description('Change a member\'s role (owner-only for admin)')
|
|
154
|
+
.option('--space <id-or-slug>', 'Space to change (defaults to your only space)')
|
|
155
|
+
.option('--json', 'Machine-readable output')
|
|
156
|
+
.action((email, role, o, command) => runRole(email, role, { ...o, json: !!(o.json || command.optsWithGlobals().json) }));
|
|
157
|
+
org.command('remove <email>').description('Remove a member from a space')
|
|
158
|
+
.option('--space <id-or-slug>', 'Space to remove from (defaults to your only space)')
|
|
159
|
+
.option('--json', 'Machine-readable output')
|
|
160
|
+
.action((email, o, command) => runRemove(email, { ...o, json: !!(o.json || command.optsWithGlobals().json) }));
|
|
161
|
+
org.command('leave [space]').description('Leave a space you do not own').option('--json', 'Machine-readable output')
|
|
162
|
+
.action((space, o, command) => runLeave(space, { json: !!(o.json || command.optsWithGlobals().json) }));
|
|
163
|
+
setHelpSections(org, {
|
|
164
|
+
examples: `agents org create acme-team
|
|
165
|
+
agents org list
|
|
166
|
+
agents org view acme-team
|
|
167
|
+
agents org invite dev@example.com --role admin
|
|
168
|
+
agents org members
|
|
169
|
+
agents org role dev@example.com admin
|
|
170
|
+
agents org remove dev@example.com
|
|
171
|
+
agents org leave acme-team`,
|
|
172
|
+
notes: 'Maps to the Rush backend\'s /api/v1/spaces (the free-tier team primitive), not /api/v1/orgs. Free tier: 1 owned space, 3 members per space. Every command needs `agents auth login` (or a `rush login` session) first. `--space` is only needed once you belong to more than one space.',
|
|
173
|
+
});
|
|
174
|
+
}
|
|
@@ -15,7 +15,7 @@ import { getRegistries, setRegistry, removeRegistry, search as searchRegistries,
|
|
|
15
15
|
import { cloneRepo } from '../lib/git.js';
|
|
16
16
|
import { discoverCommands, resolveCommandSource, installCommand, installCommandCentrally, } from '../lib/commands.js';
|
|
17
17
|
import { discoverSkillsFromRepo, installSkill, installSkillCentrally, } from '../lib/plugins/skills.js';
|
|
18
|
-
import { discoverHooksFromRepo, installHooks, installHooksCentrally, } from '../lib/hooks.js';
|
|
18
|
+
import { discoverHooksFromRepo, installHooks, installHooksCentrally, } from '../lib/hooks/install.js';
|
|
19
19
|
import { discoverWorkflowsFromRepo, installWorkflowCentrally, } from '../lib/workflows.js';
|
|
20
20
|
import { discoverSubagentsFromRepo, installSubagentCentrally, } from '../lib/subagents.js';
|
|
21
21
|
import { discoverPermissionsFromRepo, installPermissionSet, } from '../lib/permissions.js';
|
package/dist/commands/prune.js
CHANGED
|
@@ -27,7 +27,7 @@ import { formatBytes } from '../lib/format.js';
|
|
|
27
27
|
import { confirm } from '@inquirer/prompts';
|
|
28
28
|
import { diffVersionCommands, iterCommandsCapableVersions, removeCommandFromVersion, } from '../lib/commands.js';
|
|
29
29
|
import { diffVersionSkills, iterSkillsCapableVersions, removeSkillFromVersion, } from '../lib/plugins/skills.js';
|
|
30
|
-
import { listUnmanagedHooksInVersionHome, iterHooksCapableVersions, removeHookFromVersion, } from '../lib/hooks.js';
|
|
30
|
+
import { listUnmanagedHooksInVersionHome, iterHooksCapableVersions, removeHookFromVersion, } from '../lib/hooks/install.js';
|
|
31
31
|
import { diffVersionPlugins, iterPluginsCapableVersions, removePluginSkillFromVersion, } from '../lib/plugins/plugins.js';
|
|
32
32
|
import { diffVersionSubagents, iterSubagentsCapableVersions, removeSubagentFromVersion, } from '../lib/subagents.js';
|
|
33
33
|
import { getGlobalDefault } from '../lib/installations/versions.js';
|
|
@@ -24,7 +24,7 @@ import { fireWebhookJobs, matchJobsToWebhook } from '../lib/triggers/webhook.js'
|
|
|
24
24
|
import { getRoutinesDir } from '../lib/state.js';
|
|
25
25
|
import { IS_WINDOWS } from '../lib/platform/index.js';
|
|
26
26
|
import { safeJoin } from '../lib/paths.js';
|
|
27
|
-
import { executeJob, monitorRunningJobs } from '../lib/runner.js';
|
|
27
|
+
import { executeJob, monitorRunningJobs } from '../lib/daemon/runner.js';
|
|
28
28
|
import { JobScheduler } from '../lib/scheduler.js';
|
|
29
29
|
import { detectOverdueJobs } from '../lib/overdue.js';
|
|
30
30
|
import { runCatchup } from '../lib/catchup.js';
|
|
@@ -12,10 +12,29 @@ export interface RunAccountChoice {
|
|
|
12
12
|
*/
|
|
13
13
|
signInRequired: boolean;
|
|
14
14
|
}
|
|
15
|
+
/** One named account row for `agents accounts switch` (reuses this picker's layout). */
|
|
16
|
+
export interface SwitchAccountRow {
|
|
17
|
+
accountName: string;
|
|
18
|
+
kind: 'provider' | 'native';
|
|
19
|
+
detail: string;
|
|
20
|
+
current: boolean;
|
|
21
|
+
candidate: RotateCandidate | null;
|
|
22
|
+
}
|
|
15
23
|
/** Human-readable remaining capacity for every window the provider exposes. */
|
|
16
24
|
export declare function formatAccountLimits(candidate: RotateCandidate): string;
|
|
17
25
|
/** Build aligned picker rows with usable accounts first and unsafe rows disabled. */
|
|
18
26
|
export declare function buildRunAccountChoices(candidates: RotateCandidate[], globalDefault: string | null): RunAccountChoice[];
|
|
27
|
+
/**
|
|
28
|
+
* Aligned picker rows for `accounts switch`. Same columns as the run picker
|
|
29
|
+
* (identity, status, limits) but the value is the named account to set-default.
|
|
30
|
+
* Rows stay selectable: setting a default is not a launch.
|
|
31
|
+
*/
|
|
32
|
+
export declare function buildSwitchAccountChoices(rows: SwitchAccountRow[]): RunAccountChoice[];
|
|
33
|
+
/**
|
|
34
|
+
* Prompt for the named account that becomes this harness's default.
|
|
35
|
+
* A cancelled picker writes nothing.
|
|
36
|
+
*/
|
|
37
|
+
export declare function pickSwitchAccount(agent: AgentId, rows: SwitchAccountRow[]): Promise<string | null>;
|
|
19
38
|
/**
|
|
20
39
|
* Whether a zero-healthy run may recover by launching for a login, or must keep
|
|
21
40
|
* failing loud. Three inputs, all of which have to hold:
|