@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/commands/share.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// `agents artifacts share` — publish an HTML file to a shareable link. Signed-in
|
|
2
|
-
// users hit the managed endpoint (share.
|
|
2
|
+
// users hit the managed endpoint (share.getrush.ai) with the Phoenix bearer;
|
|
3
3
|
// otherwise the existing BYO Cloudflare R2 + Worker path. See cli/docs/observability.md.
|
|
4
4
|
//
|
|
5
5
|
// Registered under the `artifacts` group by commands/artifacts.ts; the
|
|
@@ -19,6 +19,7 @@ import { extractShareHttpError, formatShareHttpErrorDetail } from '../lib/share/
|
|
|
19
19
|
import { phoenixIdBaseForDeploy, resolveShareBackend, shouldUseManaged, } from '../lib/share/backend.js';
|
|
20
20
|
import { publishVisibility } from '../lib/storage/visibility.js';
|
|
21
21
|
import { resolveGitHubUsername } from '../lib/git.js';
|
|
22
|
+
import { refreshSessionAvatar } from '../lib/identity/index.js';
|
|
22
23
|
import { setHelpSections } from '../lib/help.js';
|
|
23
24
|
import { showUrl } from '../lib/open-url.js';
|
|
24
25
|
export function formatSharePublishResult(result, json = false) {
|
|
@@ -548,7 +549,7 @@ function registerShareDeleteOptions(cmd) {
|
|
|
548
549
|
}
|
|
549
550
|
const SHARE_DELETE_EXAMPLES = `
|
|
550
551
|
# Delete by full URL — also takes down the sibling OG cover and any retained revisions
|
|
551
|
-
agents artifacts share delete https://share.
|
|
552
|
+
agents artifacts share delete https://share.getrush.ai/octocat/my-plan-a1b2
|
|
552
553
|
|
|
553
554
|
# Delete by <user>/<slug>, or a bare slug in your own namespace
|
|
554
555
|
agents artifacts share delete octocat/my-plan-a1b2
|
|
@@ -581,7 +582,7 @@ const SHARE_DELETE_NOTES = `
|
|
|
581
582
|
`;
|
|
582
583
|
const SHARE_VISIBILITY_EXAMPLES = `
|
|
583
584
|
# Take a public page private to just you (Phoenix session required for me/org)
|
|
584
|
-
agents artifacts share visibility https://share.
|
|
585
|
+
agents artifacts share visibility https://share.getrush.ai/octocat/q3-plan me
|
|
585
586
|
|
|
586
587
|
# Make it public again — by <user>/<slug> or a bare slug in your namespace
|
|
587
588
|
agents artifacts share visibility octocat/q3-plan public
|
|
@@ -627,6 +628,7 @@ export function registerShareCommands(artifactsCmd) {
|
|
|
627
628
|
.argument('[file]', 'file to publish (HTML or any static asset)')
|
|
628
629
|
.option('--slug <slug>', 'URL slug override (default: stable slug of the artifact title, then filename)')
|
|
629
630
|
.option('--github-user <user>', 'GitHub username for the share namespace (default: resolved from gh/git config; ignored on the managed endpoint)')
|
|
631
|
+
.option('--handle <name>', 'managed only: publish under an alternate public handle instead of the email local-part (default: your email local-part). Escape hatch when your derived handle is taken, or for a vanity namespace — the Worker binds it with the same first-writer claim')
|
|
630
632
|
.option('--expire <spec>', "auto-expire (default 30d). e.g. 12h, 30d, 2026-08-01, or 'never'")
|
|
631
633
|
.addOption(new Option('--visibility <level>', 'public | unlisted | private | me | org. Default when signed in: me (owner-only, Phoenix-gated); use org for your whole email domain, public to opt into the gallery. unlisted is an UNAUTHENTICATED capability URL; private is token-gated (404 without the key). All but public are hidden from the gallery')
|
|
632
634
|
.choices([...PUBLISH_VISIBILITY_LEVELS]))
|
|
@@ -669,9 +671,16 @@ export function registerShareCommands(artifactsCmd) {
|
|
|
669
671
|
if (visibility === 'unlisted' && !opts.json) {
|
|
670
672
|
console.error(chalk.yellow(`⚠ ${unlistedNotPrivateWarning()}`));
|
|
671
673
|
}
|
|
674
|
+
// Managed publish: fill the session's hosted avatar (one /auth/me call,
|
|
675
|
+
// no-op when already known) so the attribution bar can show the OAuth
|
|
676
|
+
// profile image — sessions written before the CLI tracked avatars only
|
|
677
|
+
// carry token/email/userId (PHNX-3547).
|
|
678
|
+
if (shouldUseManaged({}))
|
|
679
|
+
await refreshSessionAvatar();
|
|
672
680
|
const result = await publishFile(file, {
|
|
673
681
|
slug: opts.slug,
|
|
674
682
|
githubUser: opts.githubUser,
|
|
683
|
+
handle: opts.handle,
|
|
675
684
|
expire: opts.expire,
|
|
676
685
|
visibility,
|
|
677
686
|
unlisted: visibility === 'unlisted',
|
|
@@ -720,18 +729,25 @@ export function registerShareCommands(artifactsCmd) {
|
|
|
720
729
|
|
|
721
730
|
# Republish the same title to the same URL without retaining a revision
|
|
722
731
|
agents artifacts share ./out/plan.html --no-revision
|
|
732
|
+
|
|
733
|
+
# Your derived handle is taken (or you want a vanity namespace)
|
|
734
|
+
agents artifacts share ./out/plan.html --handle acme-muqsit
|
|
723
735
|
${SHARE_DELETE_EXAMPLES}
|
|
724
736
|
# One-time setup (or join an existing endpoint)
|
|
725
737
|
agents artifacts setup
|
|
726
|
-
agents artifacts share join https://share.
|
|
738
|
+
agents artifacts share join https://share.getrush.ai
|
|
727
739
|
|
|
728
740
|
# Push a worker-template.ts change out to an already-provisioned endpoint
|
|
729
741
|
agents artifacts share update
|
|
730
742
|
`,
|
|
731
743
|
notes: `
|
|
732
|
-
Signed-in users publish to the managed endpoint (share.
|
|
744
|
+
Signed-in users publish to the managed endpoint (share.getrush.ai/<handle>/…)
|
|
733
745
|
with the Phoenix session — no Cloudflare account, bucket, or write token. The
|
|
734
|
-
handle is the local-part of the signed-in email
|
|
746
|
+
handle is the local-part of the signed-in email; --handle publishes under an
|
|
747
|
+
alternate public namespace instead (first-writer-claimed like the derived one —
|
|
748
|
+
the recovery path when your derived handle belongs to another account; a
|
|
749
|
+
same-email re-login re-binds your old handle automatically). The default slug
|
|
750
|
+
is derived
|
|
735
751
|
deterministically from the HTML <title> or Markdown frontmatter title, then
|
|
736
752
|
the filename, so republishing the same title updates the same URL. --slug is
|
|
737
753
|
an optional override. Without a session, the existing BYO Cloudflare path still
|
|
@@ -846,7 +862,7 @@ ${SHARE_DELETE_NOTES}
|
|
|
846
862
|
setHelpSections(shareOpenCmd, {
|
|
847
863
|
examples: `agents artifacts share open q3-plan # open your page, signed in, ready to re-scope
|
|
848
864
|
agents artifacts share open octocat/q3-plan
|
|
849
|
-
agents artifacts share open https://share.
|
|
865
|
+
agents artifacts share open https://share.getrush.ai/octocat/q3-plan --no-open`,
|
|
850
866
|
notes: `The shared page's visibility chip is an interactive control only for the signed-in owner; a plain link has no login, so the chip renders as a static cue. This mints a short-lived, single-use login ticket (self-signed by your share Worker) and opens the page with it, so the chip becomes a dropdown you can switch in place.
|
|
851
867
|
Managed (Phoenix) endpoints only — run 'agents auth login' first. If the mint 501s/404s, your Worker predates the feature: run 'agents artifacts share update' to redeploy it.
|
|
852
868
|
Prefer to change visibility without a browser? Use 'agents artifacts share visibility <target> <level>'.`,
|
|
@@ -854,7 +870,7 @@ Prefer to change visibility without a browser? Use 'agents artifacts share visib
|
|
|
854
870
|
shareCmd
|
|
855
871
|
.command('join')
|
|
856
872
|
.description('Use an existing synced share endpoint and write token (no provisioning).')
|
|
857
|
-
.argument('[baseUrl]', 'base URL of the endpoint, e.g. https://share.
|
|
873
|
+
.argument('[baseUrl]', 'base URL of the endpoint, e.g. https://share.getrush.ai')
|
|
858
874
|
.option('--token <token>', 'write token (else SHARE_WRITE_TOKEN env, existing bundle, or prompt)')
|
|
859
875
|
.action(async (baseUrl, opts) => {
|
|
860
876
|
try {
|
|
@@ -1039,7 +1055,7 @@ Prefer to change visibility without a browser? Use 'agents artifacts share visib
|
|
|
1039
1055
|
Use --scope unlisted|me|org or --all to include your hidden pages; those scopes
|
|
1040
1056
|
send the owner's bearer and a 'scope=mine' hint to the Worker's JSON listing route,
|
|
1041
1057
|
which returns hidden pages ONLY after verifying the caller owns the namespace.
|
|
1042
|
-
Signed-in users list the managed endpoint (share.
|
|
1058
|
+
Signed-in users list the managed endpoint (share.getrush.ai/<handle>); otherwise
|
|
1043
1059
|
BYO. It reads the endpoint's JSON listing route, which ships with the current
|
|
1044
1060
|
Worker template. If a BYO Worker predates this feature the command says so and
|
|
1045
1061
|
points you at 'agents artifacts share update' (RUSH-2449) rather than returning a
|
|
@@ -1138,7 +1154,7 @@ Prefer to change visibility without a browser? Use 'agents artifacts share visib
|
|
|
1138
1154
|
|
|
1139
1155
|
# By <user>/<slug> or full URL, same target forms as 'agents artifacts unshare'
|
|
1140
1156
|
agents artifacts share revisions octocat/q3-report
|
|
1141
|
-
agents artifacts share revisions https://share.
|
|
1157
|
+
agents artifacts share revisions https://share.getrush.ai/octocat/q3-report
|
|
1142
1158
|
|
|
1143
1159
|
# Machine-readable, and a bare slug resolved against another namespace
|
|
1144
1160
|
agents artifacts share revisions q3-report --revisions-json
|
package/dist/commands/skills.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { withAliases } from '../lib/verbs.js';
|
|
1
2
|
import chalk from 'chalk';
|
|
2
3
|
import ora from 'ora';
|
|
3
4
|
import * as fs from 'fs';
|
|
@@ -41,8 +42,8 @@ When to use:
|
|
|
41
42
|
- Specialization: install domain skills (rush-product-knowledge, rdev) per project
|
|
42
43
|
- Version isolation: install different skills to different versions for experimentation
|
|
43
44
|
`);
|
|
44
|
-
skillsCmd
|
|
45
|
-
.command('list [agent]')
|
|
45
|
+
withAliases(skillsCmd
|
|
46
|
+
.command('list [agent]'), 'list')
|
|
46
47
|
.description('Show which skills are installed and which agent versions they are synced to')
|
|
47
48
|
.option('-a, --agent <agent>', 'Filter to a specific agent (alternative to positional arg)')
|
|
48
49
|
.option('--json', 'Emit machine-readable JSON instead of the table/picker')
|
|
@@ -302,8 +303,8 @@ Examples:
|
|
|
302
303
|
process.exit(1);
|
|
303
304
|
}
|
|
304
305
|
});
|
|
305
|
-
skillsCmd
|
|
306
|
-
.command('remove [name]')
|
|
306
|
+
withAliases(skillsCmd
|
|
307
|
+
.command('remove [name]'), 'remove')
|
|
307
308
|
.description('Delete a skill from central storage (interactive picker if no name given)')
|
|
308
309
|
.addHelpText('after', `
|
|
309
310
|
Examples:
|
|
@@ -416,8 +417,8 @@ Examples:
|
|
|
416
417
|
console.error(chalk.gray('Use: agents prune cleanup skills (or `agents prune cleanup` for everything)'));
|
|
417
418
|
process.exit(1);
|
|
418
419
|
});
|
|
419
|
-
skillsCmd
|
|
420
|
-
.command('view [name]')
|
|
420
|
+
withAliases(skillsCmd
|
|
421
|
+
.command('view [name]'), 'view')
|
|
421
422
|
.description('Read skill metadata (name, description, rules count)')
|
|
422
423
|
.addHelpText('after', `
|
|
423
424
|
Examples:
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* installing, and removing lightweight agent definitions (AGENT.md files)
|
|
6
6
|
* that parent agents can spawn for focused subtasks.
|
|
7
7
|
*/
|
|
8
|
+
import { withAliases } from '../lib/verbs.js';
|
|
8
9
|
import chalk from 'chalk';
|
|
9
10
|
import ora from 'ora';
|
|
10
11
|
import * as fs from 'fs';
|
|
@@ -66,8 +67,8 @@ When to use:
|
|
|
66
67
|
});
|
|
67
68
|
};
|
|
68
69
|
// agents subagents list
|
|
69
|
-
subagentsCmd
|
|
70
|
-
.command('list')
|
|
70
|
+
withAliases(subagentsCmd
|
|
71
|
+
.command('list'), 'list')
|
|
71
72
|
.description('Show subagents in a table with sync status across agent versions')
|
|
72
73
|
.option('--json', 'Emit machine-readable JSON instead of the table/picker')
|
|
73
74
|
.addHelpText('after', `
|
|
@@ -77,8 +78,8 @@ Examples:
|
|
|
77
78
|
`)
|
|
78
79
|
.action(runList);
|
|
79
80
|
// agents subagents view <name>
|
|
80
|
-
subagentsCmd
|
|
81
|
-
.command('view [name]')
|
|
81
|
+
withAliases(subagentsCmd
|
|
82
|
+
.command('view [name]'), 'view')
|
|
82
83
|
.description('Show details for a specific subagent (use "list" to see all)')
|
|
83
84
|
.addHelpText('after', `
|
|
84
85
|
Examples:
|
|
@@ -236,8 +237,8 @@ Examples:
|
|
|
236
237
|
console.log();
|
|
237
238
|
});
|
|
238
239
|
// agents subagents remove [name]
|
|
239
|
-
subagentsCmd
|
|
240
|
-
.command('remove [name]')
|
|
240
|
+
withAliases(subagentsCmd
|
|
241
|
+
.command('remove [name]'), 'remove')
|
|
241
242
|
.description('Delete a subagent from central storage and unsync from all agent versions')
|
|
242
243
|
.option('-y, --yes', 'Skip confirmation prompt')
|
|
243
244
|
.addHelpText('after', `
|
package/dist/commands/sync.js
CHANGED
|
@@ -40,6 +40,7 @@ import { shouldAutoClaimCentralProfile } from '../lib/browser/profiles.js';
|
|
|
40
40
|
import { isVersionInstalled, syncResourcesToVersion, parseAgentSpec, resolveVersion, resolveVersionAlias, listInstalledVersions, healDanglingVersionPointers, getAvailableResources, getActuallySyncedResources, getProjectOnlyResources, getNewResources, hasNewResources, promptResourceSelection, promptNewResourceSelection, buildSelection, mergeRepoScopedSelections, listRepoNames, getVersionHomePath, } from '../lib/installations/versions.js';
|
|
41
41
|
import { capableAgents } from '../lib/capabilities.js';
|
|
42
42
|
import { parseHookManifest, registerHooksToSettings } from '../lib/hooks/install.js';
|
|
43
|
+
import { repairAfterSync, renderRepairAfterSync, repairHadFailures, repairChangedAnything, repairAfterSyncJson } from '../lib/reconcile-and-repair.js';
|
|
43
44
|
import { compileRulesForProject } from '../lib/rules/compile.js';
|
|
44
45
|
import { runLaunchSync } from '../lib/project-launch.js';
|
|
45
46
|
import { formatKeptProjectResources } from '../lib/project-resources.js';
|
|
@@ -197,6 +198,7 @@ export function registerSyncCommand(program) {
|
|
|
197
198
|
.option('--secrets', 'Umbrella: pull encrypted secret bundles from the remote', false)
|
|
198
199
|
.option('--cloud', 'Umbrella: fetch all remote state but skip the local reconcile', false)
|
|
199
200
|
.option('--local', "Umbrella: reconcile resources into installed agents only (no fetch)", false)
|
|
201
|
+
.option('--prune-clis', 'Umbrella: also purge stale/legacy agents-cli installs (npx-cache, pre-1.22.30, unsafe helper) when a fixed peer exists. DESTRUCTIVE and off by default — the purge never runs on a routine sync.', false)
|
|
200
202
|
.action(async (agentSpec, repo, opts) => {
|
|
201
203
|
await runSync(agentSpec, repo, opts);
|
|
202
204
|
});
|
|
@@ -412,6 +414,7 @@ async function runInteractiveReconcile(opts, outLog, errLog) {
|
|
|
412
414
|
// register hooks so synced hook scripts fire.
|
|
413
415
|
const hookManifest = parseHookManifest();
|
|
414
416
|
const hookCapable = new Set(capableAgents('hooks'));
|
|
417
|
+
const touched = [];
|
|
415
418
|
for (const agentId of agents) {
|
|
416
419
|
const version = resolveVersion(agentId, cwd) || listInstalledVersions(agentId).slice(-1)[0];
|
|
417
420
|
if (!version)
|
|
@@ -421,7 +424,24 @@ async function runInteractiveReconcile(opts, outLog, errLog) {
|
|
|
421
424
|
if (result.hooks && hookCapable.has(agentId) && Object.keys(hookManifest).length > 0) {
|
|
422
425
|
registerHooksToSettings(agentId, getVersionHomePath(agentId, version), hookManifest);
|
|
423
426
|
}
|
|
427
|
+
touched.push({ agent: agentId, version });
|
|
424
428
|
}
|
|
429
|
+
// Post-reconcile repair (the superset of the old `doctor --fix`): heal live-home
|
|
430
|
+
// gaps, re-wire hooks the diff left behind, and repair managed hook runtime
|
|
431
|
+
// shims for exactly the versions this reconcile touched. Always interactive
|
|
432
|
+
// here, so render its detail freely.
|
|
433
|
+
for (const t of touched) {
|
|
434
|
+
const repair = await repairAfterSync({ agent: t.agent, versions: [t.version], cwd });
|
|
435
|
+
renderRepairAfterSync(repair, outLog);
|
|
436
|
+
}
|
|
437
|
+
// Bare `agents sync` at a TTY is the umbrella verb — after per-agent repair,
|
|
438
|
+
// run one no-agent pass. This purges stale/legacy agents-cli copies ONLY when
|
|
439
|
+
// the user passed `--prune-clis` (the purge is never automatic); otherwise it is
|
|
440
|
+
// a cheap re-diff no-op over the just-reconciled homes.
|
|
441
|
+
const umbrellaRepair = await repairAfterSync({ cwd, pruneClis: !!opts.pruneClis });
|
|
442
|
+
renderRepairAfterSync(umbrellaRepair, outLog);
|
|
443
|
+
if (repairHadFailures(umbrellaRepair))
|
|
444
|
+
process.exitCode = 1;
|
|
425
445
|
}
|
|
426
446
|
/**
|
|
427
447
|
* Drain the legacy central `browser:` tombstone during `agents sync` (PHNX-3315).
|
|
@@ -508,11 +528,21 @@ async function runUmbrella(opts, quiet, outLog, errLog, json = false) {
|
|
|
508
528
|
const residual = result.reconciled
|
|
509
529
|
? verifyReconciled(result.reconciledVersions.map((r) => ({ agent: r.agent, version: r.version })), cwd)
|
|
510
530
|
: [];
|
|
531
|
+
// Post-reconcile repair, machine-wide: no agent scope → heal every installed
|
|
532
|
+
// agent, re-wire hooks the diff left behind, and repair managed hook runtime
|
|
533
|
+
// shims. The stale-CLI purge runs ONLY with `--prune-clis` (never automatic).
|
|
534
|
+
// Skipped under --cloud (fetch-only: nothing was reconciled to repair).
|
|
535
|
+
const repair = opts.cloud ? null : await repairAfterSync({ cwd, pruneClis: !!opts.pruneClis });
|
|
536
|
+
// A repair that left something for a human (an unresolvable shim, a failed
|
|
537
|
+
// rewire/purge) is a non-zero outcome, same as the deleted `doctor --fix`.
|
|
538
|
+
const repairFailed = repair !== null && repairHadFailures(repair);
|
|
539
|
+
if (repairFailed)
|
|
540
|
+
process.exitCode = 1;
|
|
511
541
|
if (json) {
|
|
512
542
|
emitJson({
|
|
513
|
-
// A refused resource
|
|
514
|
-
// PHNX-3186).
|
|
515
|
-
ok: result.declined.length === 0 && residual.length === 0,
|
|
543
|
+
// A refused resource, residual drift, OR a repair failure is not a clean
|
|
544
|
+
// sync (RUSH-2700 + PHNX-3186).
|
|
545
|
+
ok: result.declined.length === 0 && residual.length === 0 && !repairFailed,
|
|
516
546
|
mode: 'umbrella',
|
|
517
547
|
plan: result.plan,
|
|
518
548
|
repos: result.repos,
|
|
@@ -521,6 +551,7 @@ async function runUmbrella(opts, quiet, outLog, errLog, json = false) {
|
|
|
521
551
|
reconciled: result.reconciled,
|
|
522
552
|
declined: result.declined,
|
|
523
553
|
residualDrift: residual,
|
|
554
|
+
repair: repair ? repairAfterSyncJson(repair) : null,
|
|
524
555
|
});
|
|
525
556
|
return;
|
|
526
557
|
}
|
|
@@ -545,6 +576,8 @@ async function runUmbrella(opts, quiet, outLog, errLog, json = false) {
|
|
|
545
576
|
for (const e of errs)
|
|
546
577
|
errLog(chalk.yellow(` ! ${e}`));
|
|
547
578
|
printResidual(residual, errLog);
|
|
579
|
+
if (repair)
|
|
580
|
+
renderRepairAfterSync(repair, outLog);
|
|
548
581
|
}
|
|
549
582
|
}
|
|
550
583
|
catch (err) {
|
|
@@ -765,15 +798,25 @@ async function runSync(agentSpec, repoArg, opts) {
|
|
|
765
798
|
: verifyReconciled(versions.map(({ version: v }) => ({ agent: agentId, version: v })), cwd);
|
|
766
799
|
if (!quiet && !json)
|
|
767
800
|
printResidual(residual, errLog);
|
|
801
|
+
// Post-reconcile repair over exactly the versions just reconciled (the
|
|
802
|
+
// superset of the old `doctor --fix`). Runs under --json too (fleet fan-out);
|
|
803
|
+
// only its human detail is gated on !quiet && !json.
|
|
804
|
+
const allRepair = await repairAfterSync({ agent: agentId, versions: installed, cwd });
|
|
805
|
+
if (!quiet && !json)
|
|
806
|
+
renderRepairAfterSync(allRepair, outLog);
|
|
807
|
+
const allRepairFailed = repairHadFailures(allRepair);
|
|
808
|
+
if (allRepairFailed)
|
|
809
|
+
process.exitCode = 1;
|
|
768
810
|
if (json) {
|
|
769
811
|
emitJson({
|
|
770
|
-
// Any version that refused a write,
|
|
771
|
-
//
|
|
772
|
-
ok: versions.every(({ result }) => result.declined.length === 0) && residual.length === 0,
|
|
812
|
+
// Any version that refused a write, any residual drift, or a repair
|
|
813
|
+
// failure makes the whole run not-ok (RUSH-2700 + PHNX-3186).
|
|
814
|
+
ok: versions.every(({ result }) => result.declined.length === 0) && residual.length === 0 && !allRepairFailed,
|
|
773
815
|
mode: 'agent-all',
|
|
774
816
|
agent: agentId,
|
|
775
817
|
repo: repoScope,
|
|
776
818
|
residualDrift: residual,
|
|
819
|
+
repair: repairAfterSyncJson(allRepair),
|
|
777
820
|
...healedPointers,
|
|
778
821
|
versions: versions.map(({ version: v, result }) => ({
|
|
779
822
|
version: v,
|
|
@@ -896,11 +939,17 @@ async function runSync(agentSpec, repoArg, opts) {
|
|
|
896
939
|
return;
|
|
897
940
|
}
|
|
898
941
|
const result = syncResourcesToVersion(agentId, version, scoped, { projectDir, cwd, force, prune: !!repoScope, allowExecSurfaces: !!opts.allowExecSurfaces });
|
|
942
|
+
const scopedRepair = await repairAfterSync({ agent: agentId, versions: [version], cwd });
|
|
943
|
+
const scopedRepairFailed = repairHadFailures(scopedRepair);
|
|
944
|
+
if (scopedRepairFailed)
|
|
945
|
+
process.exitCode = 1;
|
|
899
946
|
if (json) {
|
|
900
|
-
|
|
947
|
+
const base = agentSyncJson(agentId, version, result, repoScope);
|
|
948
|
+
emitJson({ ...base, ok: base.ok === true && !scopedRepairFailed, repair: repairAfterSyncJson(scopedRepair) });
|
|
901
949
|
}
|
|
902
950
|
else if (!quiet) {
|
|
903
951
|
printSyncDetail(result, agentId, version, cwd);
|
|
952
|
+
renderRepairAfterSync(scopedRepair, outLog);
|
|
904
953
|
}
|
|
905
954
|
return;
|
|
906
955
|
}
|
|
@@ -934,8 +983,21 @@ async function runSync(agentSpec, repoArg, opts) {
|
|
|
934
983
|
selection = userSelection;
|
|
935
984
|
}
|
|
936
985
|
else if (!force) {
|
|
937
|
-
|
|
938
|
-
|
|
986
|
+
// Tracked resources match source — but a generated hook shim can still be
|
|
987
|
+
// broken on an otherwise in-sync version (the yosemite-s1 class), and
|
|
988
|
+
// syncResourcesToVersion never generates it. Run the repair pass BEFORE
|
|
989
|
+
// the early return so a broken shim is still fixed on bare
|
|
990
|
+
// `agents sync <agent>`, then report what (if anything) it touched.
|
|
991
|
+
const repair = await repairAfterSync({ agent: agentId, versions: [version], cwd });
|
|
992
|
+
if (repairChangedAnything(repair)) {
|
|
993
|
+
renderRepairAfterSync(repair, outLog);
|
|
994
|
+
}
|
|
995
|
+
else {
|
|
996
|
+
outLog(chalk.gray(`${agentLabel(agentId)}@${version} is already in sync.`));
|
|
997
|
+
outLog(chalk.gray('Run with --force to re-sync, or --yes to bypass this check.'));
|
|
998
|
+
}
|
|
999
|
+
if (repairHadFailures(repair))
|
|
1000
|
+
process.exitCode = 1;
|
|
939
1001
|
return;
|
|
940
1002
|
}
|
|
941
1003
|
// else: --force on a fully-synced version → selection stays undefined,
|
|
@@ -973,6 +1035,13 @@ async function runSync(agentSpec, repoArg, opts) {
|
|
|
973
1035
|
// picked kinds, so the rest legitimately still differs and is not this run's
|
|
974
1036
|
// failure. This is the exact path `agents sync <agent>[@version]` takes.
|
|
975
1037
|
const residual = selection ? [] : verifyReconciled([{ agent: agentId, version }], cwd);
|
|
1038
|
+
// Post-reconcile repair over the single version just reconciled (the superset
|
|
1039
|
+
// of the old `doctor --fix`). Runs under --json too; only its human detail is
|
|
1040
|
+
// gated on the non-quiet path below.
|
|
1041
|
+
const singleRepair = await repairAfterSync({ agent: agentId, versions: [version], cwd });
|
|
1042
|
+
const singleRepairFailed = repairHadFailures(singleRepair);
|
|
1043
|
+
if (singleRepairFailed)
|
|
1044
|
+
process.exitCode = 1;
|
|
976
1045
|
// Compile project-scope rules into the workspace itself so each agent's
|
|
977
1046
|
// native loader picks up cwd/<INSTRUCTIONS_FILE>. projectDir is the
|
|
978
1047
|
// .agents/ directory; the workspace root is its parent.
|
|
@@ -985,8 +1054,9 @@ async function runSync(agentSpec, repoArg, opts) {
|
|
|
985
1054
|
const base = agentSyncJson(agentId, version, result);
|
|
986
1055
|
emitJson({
|
|
987
1056
|
...base,
|
|
988
|
-
ok: base.ok === true && residual.length === 0,
|
|
1057
|
+
ok: base.ok === true && residual.length === 0 && !singleRepairFailed,
|
|
989
1058
|
residualDrift: residual,
|
|
1059
|
+
repair: repairAfterSyncJson(singleRepair),
|
|
990
1060
|
...healedPointers,
|
|
991
1061
|
projectCompile: projectCompile
|
|
992
1062
|
? {
|
|
@@ -1004,6 +1074,7 @@ async function runSync(agentSpec, repoArg, opts) {
|
|
|
1004
1074
|
// ---------- 6. Detailed output ----------
|
|
1005
1075
|
printSyncDetail(result, agentId, version, cwd);
|
|
1006
1076
|
printResidual(residual, errLog);
|
|
1077
|
+
renderRepairAfterSync(singleRepair, outLog);
|
|
1007
1078
|
if (projectCompile?.compiled) {
|
|
1008
1079
|
const linkInfo = projectCompile.symlinks.length > 0
|
|
1009
1080
|
? ` (+ ${projectCompile.symlinks.join(', ')})`
|
package/dist/commands/view.js
CHANGED
|
@@ -1287,6 +1287,7 @@ export async function collectAgentsJson(filterAgentId, resourceSections, opts) {
|
|
|
1287
1287
|
const usageKey = getUsageLookupKey(info);
|
|
1288
1288
|
const usageInfo = usageKey ? usageByKey.get(usageKey) : undefined;
|
|
1289
1289
|
const snapshot = usageInfo?.snapshot ?? null;
|
|
1290
|
+
const authHealth = authCache[authCacheKey(host, agentId, version)];
|
|
1290
1291
|
const entry = {
|
|
1291
1292
|
version,
|
|
1292
1293
|
isDefault: version === globalDefault,
|
|
@@ -1298,13 +1299,15 @@ export async function collectAgentsJson(filterAgentId, resourceSections, opts) {
|
|
|
1298
1299
|
// `collectRunCandidates` uses locally, so remote `--device auto` placement
|
|
1299
1300
|
// is gated on identical launchability (PHNX-3466).
|
|
1300
1301
|
launchable: isLaunchableSignedIn(info.signedIn, credentialPresence(agentId, home)),
|
|
1301
|
-
authVerdict:
|
|
1302
|
+
authVerdict: authHealth?.verdict ?? null,
|
|
1303
|
+
authCheckedAt: authHealth?.checkedAt ?? null,
|
|
1302
1304
|
email: info.email,
|
|
1303
1305
|
accountId: info.accountId,
|
|
1304
1306
|
organizationType: info.organizationType ?? null,
|
|
1305
1307
|
organizationName: info.organizationName ?? null,
|
|
1306
1308
|
plan: info.plan,
|
|
1307
1309
|
usageStatus: info.usageStatus,
|
|
1310
|
+
usageCapturedAt: snapshot?.capturedAt?.toISOString() ?? null,
|
|
1308
1311
|
overageCredits: info.overageCredits,
|
|
1309
1312
|
usageError: usageErrorForDisplay(usageInfo?.error),
|
|
1310
1313
|
windows: snapshot
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* agents watchdog --nudge one tick, actually injects (explicit opt-in)
|
|
11
11
|
* agents watchdog --watch manual poll loop (dry unless --nudge)
|
|
12
12
|
* agents watchdog --json machine-readable tick output (for the menu-bar)
|
|
13
|
-
* agents watchdog
|
|
13
|
+
* agents watchdog enable|disable turn the device-local daemon pass on/off
|
|
14
14
|
* agents watchdog policy <id> <p> per-session policy: off | keep | handsoff
|
|
15
15
|
*
|
|
16
16
|
* The agents daemon is the sole automatic watchdog scheduler. The menu bar reads
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* agents watchdog --nudge one tick, actually injects (explicit opt-in)
|
|
11
11
|
* agents watchdog --watch manual poll loop (dry unless --nudge)
|
|
12
12
|
* agents watchdog --json machine-readable tick output (for the menu-bar)
|
|
13
|
-
* agents watchdog
|
|
13
|
+
* agents watchdog enable|disable turn the device-local daemon pass on/off
|
|
14
14
|
* agents watchdog policy <id> <p> per-session policy: off | keep | handsoff
|
|
15
15
|
*
|
|
16
16
|
* The agents daemon is the sole automatic watchdog scheduler. The menu bar reads
|
|
@@ -138,7 +138,7 @@ export function registerWatchdogCommand(program) {
|
|
|
138
138
|
.command('watchdog')
|
|
139
139
|
.description('Auto-nudge stalled agent terminals: detect stalls, resolve the exact split, inject "Continue." — no menu-bar needed.')
|
|
140
140
|
.option('--nudge', 'Actually inject (default is a dry run that only reports what it would do)')
|
|
141
|
-
.option('--watch', 'Manual poll loop: run a tick every --interval (dry unless --nudge; the always-on path is `watchdog
|
|
141
|
+
.option('--watch', 'Manual poll loop: run a tick every --interval (dry unless --nudge; the always-on path is `watchdog enable`)')
|
|
142
142
|
.option('--interval <dur>', 'Poll interval in --watch mode (e.g. 30s, 1m)', '30s')
|
|
143
143
|
.option('--stall <dur>', 'Idle time before a session counts as stalled', humanMs(DEFAULT_THRESHOLDS.stallMs))
|
|
144
144
|
.option('--cooldown <dur>', 'Minimum time between nudges to the same session', humanMs(DEFAULT_THRESHOLDS.cooldownMs))
|
|
@@ -183,7 +183,7 @@ export function registerWatchdogCommand(program) {
|
|
|
183
183
|
const intervalMs = durationMsOr(opts.interval, 30_000);
|
|
184
184
|
if (!computeWillInject() && !opts.json) {
|
|
185
185
|
console.log(chalk.yellow(`watchdog --watch is DETECT-ONLY. Pass --nudge to inject, ` +
|
|
186
|
-
`or run 'agents watchdog
|
|
186
|
+
`or run 'agents watchdog enable' for the daemon-owned pass.`));
|
|
187
187
|
}
|
|
188
188
|
// eslint-disable-next-line no-constant-condition
|
|
189
189
|
while (true) {
|
|
@@ -213,7 +213,7 @@ export function registerWatchdogCommand(program) {
|
|
|
213
213
|
agents watchdog --json
|
|
214
214
|
|
|
215
215
|
# Turn on the daemon-owned watchdog pass (every three minutes)
|
|
216
|
-
agents watchdog
|
|
216
|
+
agents watchdog enable
|
|
217
217
|
|
|
218
218
|
# Show device enablement, rotate config, and in-flight rotates
|
|
219
219
|
agents watchdog status
|
|
@@ -261,7 +261,7 @@ export function registerWatchdogCommand(program) {
|
|
|
261
261
|
'watchdog.rotate: off' to ~/.agents/agents.yaml; nudging stays on).
|
|
262
262
|
State machine: ~/.agents/.cache/state/watchdog/rotate/<sessionId>.json.
|
|
263
263
|
|
|
264
|
-
Always-on: 'agents watchdog
|
|
264
|
+
Always-on: 'agents watchdog enable' enables one daemon-owned pass every three
|
|
265
265
|
minutes on this device and reloads the daemon; 'off' disables it here.
|
|
266
266
|
Defaults OFF. Per-session policy: off (ignore), keep (default), handsoff
|
|
267
267
|
(detect + flag).
|
|
@@ -280,21 +280,21 @@ export function registerWatchdogCommand(program) {
|
|
|
280
280
|
await reloadDaemonForRoutine(false);
|
|
281
281
|
console.log(chalk.yellow('watchdog: OFF on this device'));
|
|
282
282
|
};
|
|
283
|
-
cmd.command('
|
|
283
|
+
cmd.command('enable')
|
|
284
|
+
.alias('on')
|
|
284
285
|
.description('Enable the daemon watchdog pass on this device.')
|
|
285
286
|
.action(async () => {
|
|
286
287
|
await turnOn();
|
|
287
288
|
});
|
|
288
|
-
cmd.command('
|
|
289
|
+
cmd.command('disable')
|
|
290
|
+
.alias('off')
|
|
289
291
|
.description('Disable the daemon watchdog pass on this device.')
|
|
290
292
|
.action(async () => {
|
|
291
293
|
await turnOff();
|
|
292
294
|
});
|
|
293
|
-
cmd.command('enable', { hidden: true }).action(turnOn);
|
|
294
|
-
cmd.command('disable', { hidden: true }).action(turnOff);
|
|
295
295
|
cmd.command('rotate <state>')
|
|
296
296
|
.description('Turn in-place rotate of rate-limited sessions on|off (watchdog.rotate in agents.yaml). ' +
|
|
297
|
-
'Rotate-only: nudging stays on — unlike `watchdog
|
|
297
|
+
'Rotate-only: nudging stays on — unlike `watchdog disable`, which disables the whole watchdog on this device.')
|
|
298
298
|
.action((state) => {
|
|
299
299
|
const s = state.toLowerCase();
|
|
300
300
|
if (s !== 'on' && s !== 'off') {
|
|
@@ -6,4 +6,8 @@
|
|
|
6
6
|
* rotated without changing the Tailscale Funnel config.
|
|
7
7
|
*/
|
|
8
8
|
import type { Command } from 'commander';
|
|
9
|
+
import type { Server } from 'http';
|
|
10
|
+
import type { Socket } from 'net';
|
|
11
|
+
/** Stop accepting requests and destroy persistent connections so shutdown is bounded. */
|
|
12
|
+
export declare function closeWebhookServer(server: Server, sockets: Set<Socket>): Promise<void>;
|
|
9
13
|
export declare function registerWebhooksCommand(program: Command): void;
|
package/dist/commands/webhook.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as path from 'path';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { readAndResolveBundleEnv } from '../lib/secrets/bundles.js';
|
|
4
|
+
import { closeServerBounded } from '../lib/secrets/agent.js';
|
|
4
5
|
import { createFileDeliveryStore, startWebhookServer, waitForListening } from '../lib/triggers/webhook.js';
|
|
5
6
|
import { getRuntimeStateDir } from '../lib/state.js';
|
|
6
7
|
const DEFAULT_HOST = '127.0.0.1';
|
|
@@ -32,6 +33,13 @@ function readWebhookSecrets(bundleName) {
|
|
|
32
33
|
}
|
|
33
34
|
return secrets;
|
|
34
35
|
}
|
|
36
|
+
/** Stop accepting requests and destroy persistent connections so shutdown is bounded. */
|
|
37
|
+
export async function closeWebhookServer(server, sockets) {
|
|
38
|
+
const closing = closeServerBounded(server);
|
|
39
|
+
for (const socket of sockets)
|
|
40
|
+
socket.destroy();
|
|
41
|
+
await closing;
|
|
42
|
+
}
|
|
35
43
|
export function registerWebhooksCommand(program) {
|
|
36
44
|
const webhooks = program
|
|
37
45
|
.command('webhooks')
|
|
@@ -81,17 +89,27 @@ export function registerWebhooksCommand(program) {
|
|
|
81
89
|
console.error(chalk.red(`${new Date().toISOString()} ${webhook.source}:${webhook.event} dispatch failed after ack: ${err.message}`));
|
|
82
90
|
},
|
|
83
91
|
});
|
|
92
|
+
const sockets = new Set();
|
|
93
|
+
server.on('connection', (socket) => {
|
|
94
|
+
sockets.add(socket);
|
|
95
|
+
socket.once('close', () => sockets.delete(socket));
|
|
96
|
+
});
|
|
84
97
|
await waitForListening(server);
|
|
85
98
|
const address = server.address();
|
|
86
99
|
const bound = typeof address === 'object' && address ? address.port : port;
|
|
87
100
|
console.log(`${chalk.green('agents webhooks')} ${chalk.dim('→')} ${chalk.cyan(`http://${opts.bind ?? DEFAULT_HOST}:${bound}`)}`);
|
|
88
101
|
console.log(chalk.dim('signed · localhost by default · endpoints: /hooks/github, /hooks/linear, /hooks/slack · acks 202 then dispatches · Ctrl-C to stop'));
|
|
89
102
|
console.log(chalk.dim('for a supervised receiver that survives reboot: agents daemon webhooks add --secrets-bundle <name>'));
|
|
90
|
-
|
|
91
|
-
|
|
103
|
+
let shuttingDown = false;
|
|
104
|
+
const shutdown = async () => {
|
|
105
|
+
if (shuttingDown)
|
|
106
|
+
return;
|
|
107
|
+
shuttingDown = true;
|
|
108
|
+
await closeWebhookServer(server, sockets);
|
|
109
|
+
process.exit(0);
|
|
92
110
|
};
|
|
93
|
-
process.on('SIGINT', shutdown);
|
|
94
|
-
process.on('SIGTERM', shutdown);
|
|
111
|
+
process.on('SIGINT', () => { void shutdown(); });
|
|
112
|
+
process.on('SIGTERM', () => { void shutdown(); });
|
|
95
113
|
}
|
|
96
114
|
catch (err) {
|
|
97
115
|
console.error(chalk.red(`Could not start webhook receiver: ${err.message}`));
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { withAliases } from '../lib/verbs.js';
|
|
1
2
|
import chalk from 'chalk';
|
|
2
3
|
import ora from 'ora';
|
|
3
4
|
import * as fs from 'fs';
|
|
@@ -56,8 +57,8 @@ Examples:
|
|
|
56
57
|
# Remove from version homes (and central storage on second run)
|
|
57
58
|
agents workflows remove code-review
|
|
58
59
|
`);
|
|
59
|
-
workflowsCmd
|
|
60
|
-
.command('list [agent]')
|
|
60
|
+
withAliases(workflowsCmd
|
|
61
|
+
.command('list [agent]'), 'list')
|
|
61
62
|
.description('Show installed workflows and which agent versions they are synced to')
|
|
62
63
|
.option('-a, --agent <agent>', 'Filter to a specific agent')
|
|
63
64
|
.action(async (agentArg, options) => {
|
|
@@ -260,8 +261,8 @@ Examples:
|
|
|
260
261
|
process.exit(1);
|
|
261
262
|
}
|
|
262
263
|
});
|
|
263
|
-
workflowsCmd
|
|
264
|
-
.command('remove [name]')
|
|
264
|
+
withAliases(workflowsCmd
|
|
265
|
+
.command('remove [name]'), 'remove')
|
|
265
266
|
.description('Remove a workflow from version homes (interactive picker if no name given)')
|
|
266
267
|
.addHelpText('after', `
|
|
267
268
|
Examples:
|
|
@@ -365,8 +366,8 @@ Examples:
|
|
|
365
366
|
console.log(chalk.gray('Central source unchanged. Use "agents workflows remove <name>" again to remove from ~/.agents/workflows/.'));
|
|
366
367
|
}
|
|
367
368
|
});
|
|
368
|
-
workflowsCmd
|
|
369
|
-
.command('view [name]')
|
|
369
|
+
withAliases(workflowsCmd
|
|
370
|
+
.command('view [name]'), 'view')
|
|
370
371
|
.description('Read workflow details (description, subagents, model, MCP)')
|
|
371
372
|
.addHelpText('after', `
|
|
372
373
|
Examples:
|
|
@@ -50,6 +50,8 @@ export interface RotateCandidate {
|
|
|
50
50
|
* does not gate — a stale/absent probe never blocks a launch.
|
|
51
51
|
*/
|
|
52
52
|
authVerdict: AuthVerdict | null;
|
|
53
|
+
/** Epoch milliseconds of the auth probe behind authVerdict, when present. */
|
|
54
|
+
authCheckedAt?: number | null;
|
|
53
55
|
lastActive: Date | null;
|
|
54
56
|
/**
|
|
55
57
|
* Set only for a candidate that comes from a provider account bundle rather
|
|
@@ -243,7 +245,7 @@ export type AccountReadiness = {
|
|
|
243
245
|
* status — matching the gate — so a stale `out_of_credits` cache is not
|
|
244
246
|
* reported while the account is actually serving requests.
|
|
245
247
|
*/
|
|
246
|
-
export declare function readinessFromCandidate(candidate: RotateCandidate): AccountReadiness;
|
|
248
|
+
export declare function readinessFromCandidate(candidate: RotateCandidate, now?: number): AccountReadiness;
|
|
247
249
|
/**
|
|
248
250
|
* Whether a human sitting at a terminal can clear this exclusion by launching
|
|
249
251
|
* the agent and signing in. The two unhealthy classes are opposites, and the
|