@phnx-labs/agents-cli 1.20.71 → 1.20.73
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 +325 -1
- package/README.md +40 -4
- package/dist/bin/agents +0 -0
- package/dist/commands/activity.d.ts +12 -0
- package/dist/commands/activity.js +68 -0
- package/dist/commands/apply.d.ts +13 -0
- package/dist/commands/apply.js +28 -3
- package/dist/commands/browser.js +1 -1
- package/dist/commands/cloud.js +21 -11
- package/dist/commands/commands.js +2 -0
- package/dist/commands/doctor.js +8 -4
- package/dist/commands/events.d.ts +11 -10
- package/dist/commands/events.js +30 -21
- package/dist/commands/exec.d.ts +34 -0
- package/dist/commands/exec.js +337 -39
- package/dist/commands/feed.d.ts +13 -0
- package/dist/commands/feed.js +130 -29
- package/dist/commands/hq.d.ts +2 -0
- package/dist/commands/hq.js +58 -0
- package/dist/commands/lease.d.ts +19 -0
- package/dist/commands/lease.js +138 -11
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +123 -0
- package/dist/commands/logs.js +39 -10
- package/dist/commands/mcp.js +2 -0
- package/dist/commands/mine.d.ts +27 -0
- package/dist/commands/mine.js +207 -0
- package/dist/commands/monitors.js +79 -49
- package/dist/commands/plugins.js +1 -0
- package/dist/commands/profiles.js +158 -0
- package/dist/commands/repo.js +2 -60
- package/dist/commands/resource-view.d.ts +2 -0
- package/dist/commands/resource-view.js +8 -0
- package/dist/commands/resources.d.ts +5 -0
- package/dist/commands/resources.js +95 -0
- package/dist/commands/routines.d.ts +2 -0
- package/dist/commands/routines.js +139 -37
- package/dist/commands/secrets.js +234 -47
- package/dist/commands/send.d.ts +15 -0
- package/dist/commands/send.js +62 -0
- package/dist/commands/sessions-tail.d.ts +1 -0
- package/dist/commands/sessions-tail.js +20 -9
- package/dist/commands/sessions.d.ts +6 -0
- package/dist/commands/sessions.js +26 -3
- package/dist/commands/setup-mine.d.ts +18 -0
- package/dist/commands/setup-mine.js +106 -0
- package/dist/commands/setup-share.js +2 -2
- package/dist/commands/setup.js +3 -1
- package/dist/commands/share.d.ts +8 -1
- package/dist/commands/share.js +122 -37
- package/dist/commands/skills.js +2 -0
- package/dist/commands/ssh.d.ts +9 -0
- package/dist/commands/ssh.js +196 -26
- package/dist/commands/status.js +8 -2
- package/dist/commands/subagents.js +3 -1
- package/dist/commands/sync.js +1 -1
- package/dist/commands/teams.js +11 -2
- package/dist/commands/uninstall.d.ts +11 -0
- package/dist/commands/uninstall.js +158 -0
- package/dist/commands/utils.d.ts +29 -0
- package/dist/commands/utils.js +24 -0
- package/dist/commands/versions.js +120 -11
- package/dist/index.js +83 -12
- package/dist/lib/activity.d.ts +124 -0
- package/dist/lib/activity.js +542 -0
- package/dist/lib/agents.js +16 -5
- package/dist/lib/artifact-actions.d.ts +1 -1
- package/dist/lib/artifact-actions.js +1 -1
- package/dist/lib/ask-classifier.d.ts +2 -1
- package/dist/lib/ask-classifier.js +3 -3
- package/dist/lib/auth-health.d.ts +32 -4
- package/dist/lib/auth-health.js +40 -1
- package/dist/lib/auto-pull.js +8 -1
- package/dist/lib/brand.d.ts +40 -0
- package/dist/lib/brand.js +122 -0
- package/dist/lib/browser/drivers/ssh.js +4 -7
- package/dist/lib/browser/service.js +6 -8
- package/dist/lib/channels/providers/index.d.ts +2 -0
- package/dist/lib/channels/providers/index.js +20 -0
- package/dist/lib/channels/providers/mailbox.d.ts +2 -0
- package/dist/lib/channels/providers/mailbox.js +26 -0
- package/dist/lib/channels/providers/openclaw-telegram.d.ts +2 -0
- package/dist/lib/channels/providers/openclaw-telegram.js +34 -0
- package/dist/lib/channels/providers/rush.d.ts +6 -0
- package/dist/lib/channels/providers/rush.js +55 -0
- package/dist/lib/channels/registry.d.ts +42 -0
- package/dist/lib/channels/registry.js +20 -0
- package/dist/lib/channels/resolve.d.ts +11 -0
- package/dist/lib/channels/resolve.js +12 -0
- package/dist/lib/cli-resources.d.ts +18 -0
- package/dist/lib/cli-resources.js +53 -4
- package/dist/lib/cloud/codex.js +6 -3
- package/dist/lib/cloud/factory.d.ts +1 -0
- package/dist/lib/cloud/factory.js +10 -4
- package/dist/lib/cloud/rush.d.ts +3 -1
- package/dist/lib/cloud/rush.js +6 -1
- package/dist/lib/cloud/types.d.ts +2 -0
- package/dist/lib/codex-home.d.ts +35 -0
- package/dist/lib/codex-home.js +136 -0
- package/dist/lib/crabbox/cli.d.ts +44 -0
- package/dist/lib/crabbox/cli.js +120 -20
- package/dist/lib/crabbox/lease.d.ts +52 -1
- package/dist/lib/crabbox/lease.js +117 -16
- package/dist/lib/crabbox/progress.d.ts +31 -0
- package/dist/lib/crabbox/progress.js +76 -0
- package/dist/lib/crabbox/runtimes.d.ts +4 -0
- package/dist/lib/crabbox/runtimes.js +33 -8
- package/dist/lib/crabbox/setup-copy.d.ts +87 -0
- package/dist/lib/crabbox/setup-copy.js +127 -0
- package/dist/lib/daemon.d.ts +14 -5
- package/dist/lib/daemon.js +52 -9
- package/dist/lib/drive-sync.js +6 -3
- package/dist/lib/event-stream.d.ts +36 -0
- package/dist/lib/event-stream.js +68 -0
- package/dist/lib/events.d.ts +1 -1
- package/dist/lib/exec.d.ts +11 -0
- package/dist/lib/exec.js +23 -2
- package/dist/lib/feed-policy.d.ts +1 -1
- package/dist/lib/feed-policy.js +14 -9
- package/dist/lib/feed-ranking.d.ts +32 -0
- package/dist/lib/feed-ranking.js +224 -0
- package/dist/lib/feed.d.ts +35 -2
- package/dist/lib/feed.js +66 -3
- package/dist/lib/fleet/auth-sync.d.ts +53 -0
- package/dist/lib/fleet/auth-sync.js +92 -0
- package/dist/lib/fleet/remote-login.d.ts +187 -0
- package/dist/lib/fleet/remote-login.js +556 -0
- package/dist/lib/format.d.ts +30 -3
- package/dist/lib/format.js +34 -5
- package/dist/lib/fs-atomic.d.ts +7 -2
- package/dist/lib/fs-atomic.js +8 -12
- package/dist/lib/git.d.ts +16 -0
- package/dist/lib/git.js +79 -2
- package/dist/lib/heal.js +11 -3
- package/dist/lib/hosts/logs.d.ts +12 -0
- package/dist/lib/hosts/logs.js +18 -0
- package/dist/lib/hosts/progress.d.ts +28 -10
- package/dist/lib/hosts/progress.js +79 -22
- package/dist/lib/hosts/remote-cmd.js +4 -0
- package/dist/lib/hq/floor.d.ts +87 -0
- package/dist/lib/hq/floor.js +226 -0
- package/dist/lib/menubar/install-menubar.js +14 -20
- package/dist/lib/notify.d.ts +1 -0
- package/dist/lib/notify.js +3 -3
- package/dist/lib/open-url.d.ts +2 -0
- package/dist/lib/open-url.js +19 -0
- package/dist/lib/openclaw-keychain.d.ts +56 -0
- package/dist/lib/openclaw-keychain.js +236 -0
- package/dist/lib/overdue.js +10 -0
- package/dist/lib/permissions.d.ts +44 -1
- package/dist/lib/permissions.js +284 -7
- package/dist/lib/project-launch.d.ts +6 -12
- package/dist/lib/project-launch.js +13 -228
- package/dist/lib/project-resources.d.ts +7 -0
- package/dist/lib/project-resources.js +291 -0
- package/dist/lib/pty-client.d.ts +27 -0
- package/dist/lib/pty-client.js +136 -10
- package/dist/lib/refresh.js +14 -10
- package/dist/lib/resource-profiles.d.ts +26 -0
- package/dist/lib/resource-profiles.js +157 -0
- package/dist/lib/resources/permissions.js +7 -1
- package/dist/lib/resources/types.d.ts +1 -1
- package/dist/lib/resources.d.ts +1 -1
- package/dist/lib/resources.js +32 -3
- package/dist/lib/routines.d.ts +11 -0
- package/dist/lib/routines.js +56 -15
- package/dist/lib/runner.d.ts +1 -0
- package/dist/lib/runner.js +66 -5
- package/dist/lib/secrets/bundles.d.ts +16 -3
- package/dist/lib/secrets/bundles.js +206 -37
- package/dist/lib/secrets/icloud-import.d.ts +2 -2
- package/dist/lib/secrets/icloud-import.js +9 -6
- package/dist/lib/secrets/mcp.js +1 -1
- package/dist/lib/secrets/vault-age-helper.d.ts +1 -0
- package/dist/lib/secrets/vault-age-helper.js +34 -0
- package/dist/lib/secrets/vault.d.ts +49 -0
- package/dist/lib/secrets/vault.js +397 -0
- package/dist/lib/self-heal/checks/path.js +3 -1
- package/dist/lib/self-heal/checks/shadowing.js +10 -2
- package/dist/lib/self-heal/checks/shims.js +19 -11
- package/dist/lib/session/cloud.d.ts +2 -2
- package/dist/lib/session/cloud.js +2 -2
- package/dist/lib/session/db.d.ts +4 -0
- package/dist/lib/session/db.js +44 -7
- package/dist/lib/session/discover.d.ts +2 -0
- package/dist/lib/session/discover.js +114 -3
- package/dist/lib/session/stream-render.d.ts +3 -0
- package/dist/lib/session/stream-render.js +130 -0
- package/dist/lib/session/types.d.ts +6 -0
- package/dist/lib/share/analytics.d.ts +13 -0
- package/dist/lib/share/analytics.js +45 -0
- package/dist/lib/share/config.d.ts +19 -5
- package/dist/lib/share/config.js +44 -8
- package/dist/lib/share/provision.d.ts +58 -6
- package/dist/lib/share/provision.js +97 -22
- package/dist/lib/share/publish.d.ts +36 -13
- package/dist/lib/share/publish.js +55 -8
- package/dist/lib/share/worker-template.js +83 -17
- package/dist/lib/shims.d.ts +36 -0
- package/dist/lib/shims.js +120 -16
- package/dist/lib/ssh-exec.d.ts +14 -0
- package/dist/lib/ssh-exec.js +57 -0
- package/dist/lib/staleness/detectors/hooks.js +25 -1
- package/dist/lib/staleness/detectors/permissions.js +66 -0
- package/dist/lib/staleness/detectors/workflows.js +20 -0
- package/dist/lib/staleness/writers/hooks.js +58 -4
- package/dist/lib/staleness/writers/permissions.js +2 -2
- package/dist/lib/staleness/writers/skills.js +1 -1
- package/dist/lib/staleness/writers/sources.d.ts +10 -1
- package/dist/lib/staleness/writers/sources.js +68 -1
- package/dist/lib/star-nudge.d.ts +45 -0
- package/dist/lib/star-nudge.js +91 -0
- package/dist/lib/startup/command-registry.d.ts +7 -1
- package/dist/lib/startup/command-registry.js +19 -3
- package/dist/lib/state.d.ts +2 -0
- package/dist/lib/state.js +3 -0
- package/dist/lib/subagents-registry.d.ts +2 -0
- package/dist/lib/subagents-registry.js +3 -0
- package/dist/lib/teams/parsers.js +214 -6
- package/dist/lib/teams/supervisor.d.ts +7 -0
- package/dist/lib/teams/supervisor.js +2 -1
- package/dist/lib/template.d.ts +1 -1
- package/dist/lib/template.js +1 -1
- package/dist/lib/triggers/webhook.js +36 -3
- package/dist/lib/types.d.ts +73 -0
- package/dist/lib/uninstall.d.ts +84 -0
- package/dist/lib/uninstall.js +347 -0
- package/dist/lib/usage.d.ts +13 -1
- package/dist/lib/usage.js +32 -14
- package/dist/lib/version.d.ts +40 -0
- package/dist/lib/version.js +94 -16
- package/dist/lib/versions.d.ts +27 -0
- package/dist/lib/versions.js +248 -79
- package/dist/lib/workflows.d.ts +2 -0
- package/dist/lib/workflows.js +88 -0
- package/package.json +2 -1
- package/dist/commands/daemon.d.ts +0 -10
- package/dist/commands/daemon.js +0 -121
|
@@ -77,18 +77,46 @@ function linearTeamKey(payload) {
|
|
|
77
77
|
return typeof team?.key === 'string' ? team.key : null;
|
|
78
78
|
}
|
|
79
79
|
function linearLabels(payload) {
|
|
80
|
+
// Linear webhook bodies flatten list relations: an Issue event carries
|
|
81
|
+
// `data.labels` as a flat array of label objects (`[{ id, name, color }]`),
|
|
82
|
+
// NOT the `{ nodes: [...] }` connection shape returned by the GraphQL API.
|
|
83
|
+
// Reading `.nodes` here made every `--label` filter match nothing.
|
|
80
84
|
const data = payload.data;
|
|
81
|
-
const labels = data?.labels;
|
|
82
|
-
|
|
83
|
-
return nodes
|
|
85
|
+
const labels = Array.isArray(data?.labels) ? data?.labels : [];
|
|
86
|
+
return labels
|
|
84
87
|
.map((n) => n.name)
|
|
85
88
|
.filter((n) => typeof n === 'string' && n.length > 0);
|
|
86
89
|
}
|
|
90
|
+
function githubAction(payload) {
|
|
91
|
+
return typeof payload.action === 'string' ? payload.action : null;
|
|
92
|
+
}
|
|
93
|
+
function githubLabels(payload) {
|
|
94
|
+
const names = new Set();
|
|
95
|
+
const add = (value) => {
|
|
96
|
+
if (typeof value === 'string' && value.length > 0)
|
|
97
|
+
names.add(value);
|
|
98
|
+
};
|
|
99
|
+
const deliveryLabel = payload.label;
|
|
100
|
+
add(deliveryLabel?.name);
|
|
101
|
+
const pr = payload.pull_request;
|
|
102
|
+
const prLabels = Array.isArray(pr?.labels) ? pr.labels : [];
|
|
103
|
+
for (const label of prLabels) {
|
|
104
|
+
add(label.name);
|
|
105
|
+
}
|
|
106
|
+
const issue = payload.issue;
|
|
107
|
+
const issueLabels = Array.isArray(issue?.labels) ? issue.labels : [];
|
|
108
|
+
for (const label of issueLabels) {
|
|
109
|
+
add(label.name);
|
|
110
|
+
}
|
|
111
|
+
return [...names];
|
|
112
|
+
}
|
|
87
113
|
function githubTriggerMatches(trigger, webhook) {
|
|
88
114
|
if (webhook.source !== 'github')
|
|
89
115
|
return false;
|
|
90
116
|
if (trigger.event !== webhook.event)
|
|
91
117
|
return false;
|
|
118
|
+
if (trigger.action && githubAction(webhook.payload) !== trigger.action)
|
|
119
|
+
return false;
|
|
92
120
|
if (trigger.repo) {
|
|
93
121
|
const repo = webhookRepo(webhook.payload);
|
|
94
122
|
if (!repo || repo.toLowerCase() !== trigger.repo.toLowerCase())
|
|
@@ -99,6 +127,11 @@ function githubTriggerMatches(trigger, webhook) {
|
|
|
99
127
|
if (!branches.some((b) => b === trigger.branch))
|
|
100
128
|
return false;
|
|
101
129
|
}
|
|
130
|
+
if (trigger.label) {
|
|
131
|
+
const expected = trigger.label.toLowerCase();
|
|
132
|
+
if (!githubLabels(webhook.payload).some((name) => name.toLowerCase() === expected))
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
102
135
|
return true;
|
|
103
136
|
}
|
|
104
137
|
function linearTriggerMatches(trigger, webhook) {
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -508,6 +508,29 @@ export interface VersionResources {
|
|
|
508
508
|
permissions?: ResourcePattern[];
|
|
509
509
|
mcp?: ResourcePattern[];
|
|
510
510
|
}
|
|
511
|
+
/** Resource-kind selectors controlled by top-level resource profiles. */
|
|
512
|
+
export interface ResourceProfilePreset {
|
|
513
|
+
description?: string;
|
|
514
|
+
commands?: ResourcePattern[];
|
|
515
|
+
skills?: ResourcePattern[];
|
|
516
|
+
hooks?: ResourcePattern[];
|
|
517
|
+
subagents?: ResourcePattern[];
|
|
518
|
+
plugins?: ResourcePattern[];
|
|
519
|
+
workflows?: ResourcePattern[];
|
|
520
|
+
permissions?: ResourcePattern[];
|
|
521
|
+
mcp?: ResourcePattern[];
|
|
522
|
+
/** Rule preset name to compose while this profile is active. */
|
|
523
|
+
rules?: string;
|
|
524
|
+
/** Alias for rules, accepted so YAML can mirror VersionResources naming. */
|
|
525
|
+
rulesPreset?: string;
|
|
526
|
+
/** Secrets bundle names, or "*" for every bundle. */
|
|
527
|
+
secrets?: string[];
|
|
528
|
+
}
|
|
529
|
+
/** Top-level profiles/presets that switch the resolved resource view. */
|
|
530
|
+
export interface ResourceProfilesConfig {
|
|
531
|
+
active?: string;
|
|
532
|
+
presets?: Record<string, ResourceProfilePreset>;
|
|
533
|
+
}
|
|
511
534
|
/** A userConfig field declared in a plugin manifest. */
|
|
512
535
|
export interface PluginUserConfigField {
|
|
513
536
|
key: string;
|
|
@@ -644,6 +667,28 @@ export interface ExtraRepoConfig {
|
|
|
644
667
|
path?: string;
|
|
645
668
|
enabled: boolean;
|
|
646
669
|
}
|
|
670
|
+
/**
|
|
671
|
+
* A white-label brand — a personally-named CLI (e.g. `jack`) that IS agents-cli,
|
|
672
|
+
* minted by `agents setup mine` / `agents mine`. The brand's shim exports
|
|
673
|
+
* `AGENTS_BRAND=<name>`; the entrypoint reads it to present under this name and
|
|
674
|
+
* apply the customization below. Portable user config — rides `agents repo
|
|
675
|
+
* push/pull`. See lib/brand.ts.
|
|
676
|
+
*/
|
|
677
|
+
export interface BrandConfig {
|
|
678
|
+
/** The brand name; also the binary name on PATH. */
|
|
679
|
+
name: string;
|
|
680
|
+
/** Built-in top-level commands this brand hides/disables (e.g. `["teams"]`). */
|
|
681
|
+
disabledCommands?: string[];
|
|
682
|
+
/**
|
|
683
|
+
* Resource-profile preset this brand pins (a key in `profiles.presets`). When
|
|
684
|
+
* the CLI runs under this brand, that preset becomes the active profile, so
|
|
685
|
+
* skills/plugins/mcp/hooks/etc. filter to the brand's curated set. Defaults to
|
|
686
|
+
* `mine-<name>`.
|
|
687
|
+
*/
|
|
688
|
+
profile?: string;
|
|
689
|
+
/** False to keep the config but stop minting/using the brand. */
|
|
690
|
+
enabled: boolean;
|
|
691
|
+
}
|
|
647
692
|
/** Top-level structure of ~/.agents/.system/agents.yaml -- the CLI's persistent state. */
|
|
648
693
|
export interface Meta {
|
|
649
694
|
agents?: Partial<Record<AgentId, string>>;
|
|
@@ -682,6 +727,12 @@ export interface Meta {
|
|
|
682
727
|
enabled?: BetaFeatureName[];
|
|
683
728
|
};
|
|
684
729
|
registries?: Record<RegistryType, Record<string, RegistryConfig>>;
|
|
730
|
+
/**
|
|
731
|
+
* Top-level resource profiles. Activating one filters the resolved resource
|
|
732
|
+
* set across commands, skills, hooks, rules, MCP, permissions, and secrets.
|
|
733
|
+
* Model-provider run profiles are separate YAML files under profiles/.
|
|
734
|
+
*/
|
|
735
|
+
profiles?: ResourceProfilesConfig;
|
|
685
736
|
versions?: Partial<Record<AgentId, Record<string, VersionResources>>>;
|
|
686
737
|
source?: string;
|
|
687
738
|
/**
|
|
@@ -696,6 +747,12 @@ export interface Meta {
|
|
|
696
747
|
* via the `path` field.
|
|
697
748
|
*/
|
|
698
749
|
extraRepos?: Record<string, ExtraRepoConfig>;
|
|
750
|
+
/**
|
|
751
|
+
* White-label brands keyed by name. Each mints a personally-named binary
|
|
752
|
+
* (e.g. `jack`) that runs agents-cli under that name with its own disabled
|
|
753
|
+
* commands + curated resource profile. See lib/brand.ts.
|
|
754
|
+
*/
|
|
755
|
+
brands?: Record<string, BrandConfig>;
|
|
699
756
|
/**
|
|
700
757
|
* Keys like `skill.hermes` — registries seeded from SEEDED_REGISTRIES exactly
|
|
701
758
|
* once. Tracked so a user `registry remove` won't silently re-seed.
|
|
@@ -746,6 +803,22 @@ export interface Meta {
|
|
|
746
803
|
workerName?: string;
|
|
747
804
|
bucketName?: string;
|
|
748
805
|
domain?: string;
|
|
806
|
+
/** Cloudflare Web Analytics token injected into published HTML pages. */
|
|
807
|
+
analyticsToken?: string;
|
|
808
|
+
};
|
|
809
|
+
/**
|
|
810
|
+
* Owner/channel notification config for `agents send` / `agents notify`.
|
|
811
|
+
* `owner` is the default recipient for `agents notify` (channel + target).
|
|
812
|
+
* `transports` maps a user-facing channel name to the provider that actually
|
|
813
|
+
* delivers it — explicit, one provider per channel, no fallback. Omitted keys
|
|
814
|
+
* default to name-identity (channel `slack` -> provider `slack`).
|
|
815
|
+
*/
|
|
816
|
+
notify?: {
|
|
817
|
+
owner?: {
|
|
818
|
+
channel: string;
|
|
819
|
+
to: string;
|
|
820
|
+
};
|
|
821
|
+
transports?: Record<string, string>;
|
|
749
822
|
};
|
|
750
823
|
}
|
|
751
824
|
/** Persisted agent-host entry in agents.yaml (overlay or inline). */
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { AgentId } from './types.js';
|
|
2
|
+
/** What the uninstall intends to do with one agent's config directory. */
|
|
3
|
+
export type ConfigAction = {
|
|
4
|
+
agent: AgentId;
|
|
5
|
+
realPath: string;
|
|
6
|
+
kind: 'restore-backup';
|
|
7
|
+
source: string;
|
|
8
|
+
} | {
|
|
9
|
+
agent: AgentId;
|
|
10
|
+
realPath: string;
|
|
11
|
+
kind: 'restore-version-home';
|
|
12
|
+
source: string;
|
|
13
|
+
} | {
|
|
14
|
+
agent: AgentId;
|
|
15
|
+
realPath: string;
|
|
16
|
+
kind: 'remove-dangling';
|
|
17
|
+
} | {
|
|
18
|
+
agent: AgentId;
|
|
19
|
+
realPath: string;
|
|
20
|
+
kind: 'leave-real';
|
|
21
|
+
} | {
|
|
22
|
+
agent: AgentId;
|
|
23
|
+
realPath: string;
|
|
24
|
+
kind: 'leave-foreign';
|
|
25
|
+
} | {
|
|
26
|
+
agent: AgentId;
|
|
27
|
+
realPath: string;
|
|
28
|
+
kind: 'absent';
|
|
29
|
+
};
|
|
30
|
+
/** A home-level file symlink (e.g. `~/.claude.json`) agents-cli owns. */
|
|
31
|
+
export interface HomeFileAction {
|
|
32
|
+
realPath: string;
|
|
33
|
+
/** Resolved symlink target whose contents are copied back to `realPath`. */
|
|
34
|
+
source: string;
|
|
35
|
+
}
|
|
36
|
+
/** The full, read-only plan describing what an uninstall would change. */
|
|
37
|
+
export interface UninstallPlan {
|
|
38
|
+
isInstalled: boolean;
|
|
39
|
+
agentsDir: string;
|
|
40
|
+
legacySymlink: string | null;
|
|
41
|
+
configs: ConfigAction[];
|
|
42
|
+
homeFiles: HomeFileAction[];
|
|
43
|
+
launchers: string[];
|
|
44
|
+
rcFiles: string[];
|
|
45
|
+
}
|
|
46
|
+
/** Structured result of an executed uninstall (for reporting). */
|
|
47
|
+
export interface UninstallResult {
|
|
48
|
+
restoredConfigs: Array<{
|
|
49
|
+
agent: AgentId;
|
|
50
|
+
realPath: string;
|
|
51
|
+
}>;
|
|
52
|
+
removedDanglingConfigs: Array<{
|
|
53
|
+
agent: AgentId;
|
|
54
|
+
realPath: string;
|
|
55
|
+
}>;
|
|
56
|
+
restoredHomeFiles: string[];
|
|
57
|
+
releasedLaunchers: string[];
|
|
58
|
+
cleanedRcFiles: string[];
|
|
59
|
+
agentsDir: {
|
|
60
|
+
path: string;
|
|
61
|
+
disposition: 'moved' | 'purged' | 'absent';
|
|
62
|
+
movedTo?: string;
|
|
63
|
+
};
|
|
64
|
+
legacySymlinkRemoved: boolean;
|
|
65
|
+
/** True when `--purge` was requested but downgraded to move-aside after errors. */
|
|
66
|
+
purgeDowngraded: boolean;
|
|
67
|
+
errors: string[];
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Build a read-only plan of everything a complete uninstall would change.
|
|
71
|
+
* Performs no mutations; safe to run for `--dry-run` and to print for confirm.
|
|
72
|
+
*/
|
|
73
|
+
export declare function planUninstall(): UninstallPlan;
|
|
74
|
+
/**
|
|
75
|
+
* Execute a plan built by {@link planUninstall}. Restores adopted config dirs
|
|
76
|
+
* and home files, releases adopted launchers, strips shim PATH lines, then
|
|
77
|
+
* disposes of `~/.agents` — moved aside to `~/.agents.removed-<ts>` (recoverable)
|
|
78
|
+
* by default, or hard-deleted when `purge` is set. Config restore always runs
|
|
79
|
+
* before disposal because the backups live inside `~/.agents`.
|
|
80
|
+
*/
|
|
81
|
+
export declare function executeUninstall(plan: UninstallPlan, opts: {
|
|
82
|
+
purge?: boolean;
|
|
83
|
+
timestamp: number;
|
|
84
|
+
}): UninstallResult;
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Complete teardown of agents-cli — the reverse of `agents setup`.
|
|
3
|
+
*
|
|
4
|
+
* The hard part is undoing "adoption": normal installs move the user's real
|
|
5
|
+
* `~/.<agent>` aside and replace it with a symlink into agents-cli's version
|
|
6
|
+
* homes (see `switchConfigSymlink` / `importAgent`). A clean uninstall must put
|
|
7
|
+
* those real directories back, release any adopted launchers, strip the shim
|
|
8
|
+
* directory from the user's PATH, and only then dispose of `~/.agents`.
|
|
9
|
+
*
|
|
10
|
+
* Safety invariant: a `~/.<agent>` that agents-cli never adopted is a REAL user
|
|
11
|
+
* directory and is never touched. Ownership is decided structurally by
|
|
12
|
+
* `getConfigSymlinkVersion` (non-null only for a symlink into our versions dir),
|
|
13
|
+
* exactly as `removeVersion` does it — no marker files, no guessing.
|
|
14
|
+
*
|
|
15
|
+
* This module is split into a read-only {@link planUninstall} and a mutating
|
|
16
|
+
* {@link executeUninstall} so `--dry-run` and the real run share one code path.
|
|
17
|
+
*/
|
|
18
|
+
import * as fs from 'fs';
|
|
19
|
+
import * as os from 'os';
|
|
20
|
+
import * as path from 'path';
|
|
21
|
+
import { AGENTS, ALL_AGENT_IDS } from './agents.js';
|
|
22
|
+
import { getAgentConfigPath, getConfigSymlinkVersion, stripShimPathLines, releaseAdoptedLauncher, } from './shims.js';
|
|
23
|
+
import { getUserAgentsDir, getBackupsDir, getHistoryDir, getShimsDir, getLegacySystemAgentsDir, } from './state.js';
|
|
24
|
+
/** Home dir honoring the AGENTS_REAL_HOME test/override, mirroring shims.ts. */
|
|
25
|
+
function realHome() {
|
|
26
|
+
return process.env.AGENTS_REAL_HOME || os.homedir();
|
|
27
|
+
}
|
|
28
|
+
/** Newest timestamped backup dir under `<backups>/<agent>/`, or null. */
|
|
29
|
+
function newestBackupDir(agent) {
|
|
30
|
+
const dir = path.join(getBackupsDir(), agent);
|
|
31
|
+
let entries;
|
|
32
|
+
try {
|
|
33
|
+
entries = fs.readdirSync(dir).filter((n) => /^\d+$/.test(n));
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
if (entries.length === 0)
|
|
39
|
+
return null;
|
|
40
|
+
entries.sort((a, b) => Number(a) - Number(b));
|
|
41
|
+
return path.join(dir, entries[entries.length - 1]);
|
|
42
|
+
}
|
|
43
|
+
/** Absolute target of a symlink, or null if `p` is not a readable symlink. */
|
|
44
|
+
function symlinkTarget(p) {
|
|
45
|
+
try {
|
|
46
|
+
const raw = fs.readlinkSync(p);
|
|
47
|
+
return path.resolve(path.dirname(p), raw);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Remove a symlink/junction at `p` without following into its target. On POSIX
|
|
55
|
+
* this is a plain `unlinkSync`; on Windows the same call correctly deletes a
|
|
56
|
+
* junction or directory-symlink reparse point while leaving the target intact —
|
|
57
|
+
* verified on a real Windows host, where `fs.rmSync(p, { force: true })` instead
|
|
58
|
+
* throws `EFAULT` on a reparse point. `rmSync` is deliberately NOT used here.
|
|
59
|
+
*/
|
|
60
|
+
function removeLink(p) {
|
|
61
|
+
fs.unlinkSync(p);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Move `source` onto `dest` across possibly-different volumes. `renameSync` is
|
|
65
|
+
* atomic but throws EXDEV when `~/.agents` lives on a different filesystem than
|
|
66
|
+
* `$HOME`; fall back to copy-then-remove so the restore still completes. The
|
|
67
|
+
* source (a backup inside `~/.agents`) is removed only after the copy succeeds,
|
|
68
|
+
* so a mid-copy failure never destroys the sole surviving copy.
|
|
69
|
+
*/
|
|
70
|
+
function moveDirCrossDevice(source, dest) {
|
|
71
|
+
try {
|
|
72
|
+
fs.renameSync(source, dest);
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
if (err.code !== 'EXDEV')
|
|
76
|
+
throw err;
|
|
77
|
+
fs.cpSync(source, dest, { recursive: true });
|
|
78
|
+
fs.rmSync(source, { recursive: true, force: true });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Copy `source` to `dest`, dropping any symlink whose target resolves back into
|
|
83
|
+
* `~/.agents`. Adoption syncs managed resources (skills/commands) into the
|
|
84
|
+
* version home as symlinks into `~/.agents`; copying them verbatim would leave
|
|
85
|
+
* the restored config full of links that dangle the moment `~/.agents` is
|
|
86
|
+
* disposed. Stripping them yields a clean, self-contained restore.
|
|
87
|
+
*/
|
|
88
|
+
function copyDirStrippingAgentsSymlinks(source, dest, agentsDir) {
|
|
89
|
+
const inside = agentsDir + path.sep;
|
|
90
|
+
fs.cpSync(source, dest, {
|
|
91
|
+
recursive: true,
|
|
92
|
+
filter: (src) => {
|
|
93
|
+
try {
|
|
94
|
+
const st = fs.lstatSync(src);
|
|
95
|
+
if (st.isSymbolicLink()) {
|
|
96
|
+
const tgt = path.resolve(path.dirname(src), fs.readlinkSync(src));
|
|
97
|
+
if (tgt === agentsDir || tgt.startsWith(inside))
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
/* unreadable entry — let cpSync surface it on the real copy */
|
|
103
|
+
}
|
|
104
|
+
return true;
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/** Classify one agent's config dir without mutating anything. */
|
|
109
|
+
function planConfig(agent) {
|
|
110
|
+
const realPath = getAgentConfigPath(agent);
|
|
111
|
+
let stat;
|
|
112
|
+
try {
|
|
113
|
+
stat = fs.lstatSync(realPath);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return { agent, realPath, kind: 'absent' };
|
|
117
|
+
}
|
|
118
|
+
// A real directory means agents-cli never adopted it — leave it alone.
|
|
119
|
+
if (!stat.isSymbolicLink())
|
|
120
|
+
return { agent, realPath, kind: 'leave-real' };
|
|
121
|
+
// A symlink we don't own (target not under our versions dir) — leave it alone.
|
|
122
|
+
if (getConfigSymlinkVersion(agent) === null)
|
|
123
|
+
return { agent, realPath, kind: 'leave-foreign' };
|
|
124
|
+
// Owned symlink: prefer the timestamped backup (switchConfigSymlink moved the
|
|
125
|
+
// real dir there); otherwise the symlink target itself holds the user's data
|
|
126
|
+
// (importAgent renamed the real dir INTO the version home).
|
|
127
|
+
const backup = newestBackupDir(agent);
|
|
128
|
+
if (backup)
|
|
129
|
+
return { agent, realPath, kind: 'restore-backup', source: backup };
|
|
130
|
+
const target = symlinkTarget(realPath);
|
|
131
|
+
if (target && fs.existsSync(target)) {
|
|
132
|
+
return { agent, realPath, kind: 'restore-version-home', source: target };
|
|
133
|
+
}
|
|
134
|
+
return { agent, realPath, kind: 'remove-dangling' };
|
|
135
|
+
}
|
|
136
|
+
/** Owned home-file symlinks (e.g. `~/.claude.json`) to copy back as real files. */
|
|
137
|
+
function planHomeFiles() {
|
|
138
|
+
const home = realHome();
|
|
139
|
+
const userDir = getUserAgentsDir();
|
|
140
|
+
const out = [];
|
|
141
|
+
for (const agent of ALL_AGENT_IDS) {
|
|
142
|
+
const homeFiles = AGENTS[agent].homeFiles;
|
|
143
|
+
if (!homeFiles)
|
|
144
|
+
continue;
|
|
145
|
+
for (const fileName of homeFiles) {
|
|
146
|
+
const realPath = path.join(home, fileName);
|
|
147
|
+
let stat;
|
|
148
|
+
try {
|
|
149
|
+
stat = fs.lstatSync(realPath);
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
if (!stat.isSymbolicLink())
|
|
155
|
+
continue;
|
|
156
|
+
const target = symlinkTarget(realPath);
|
|
157
|
+
// Only ours (points into ~/.agents) and only if the target still exists.
|
|
158
|
+
if (target && target.startsWith(userDir + path.sep) && fs.existsSync(target)) {
|
|
159
|
+
out.push({ realPath, source: target });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return out;
|
|
164
|
+
}
|
|
165
|
+
/** cliCommand basenames that have an adopted-launcher record to release. */
|
|
166
|
+
function planLaunchers() {
|
|
167
|
+
const dir = path.join(getHistoryDir(), 'adopted-launchers');
|
|
168
|
+
try {
|
|
169
|
+
return fs.readdirSync(dir).filter((n) => !n.startsWith('.'));
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return [];
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/** Candidate shell rc files that currently contain a shim PATH entry. */
|
|
176
|
+
function planRcFiles() {
|
|
177
|
+
const home = realHome();
|
|
178
|
+
const shimsDir = getShimsDir();
|
|
179
|
+
const candidates = ['.zshrc', '.bashrc', '.bash_profile', '.profile', path.join('.config', 'fish', 'config.fish')];
|
|
180
|
+
const out = [];
|
|
181
|
+
for (const rel of candidates) {
|
|
182
|
+
const rc = path.join(home, rel);
|
|
183
|
+
let content;
|
|
184
|
+
try {
|
|
185
|
+
content = fs.readFileSync(rc, 'utf-8');
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (stripShimPathLines(content, shimsDir) !== content)
|
|
191
|
+
out.push(rc);
|
|
192
|
+
}
|
|
193
|
+
return out;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Build a read-only plan of everything a complete uninstall would change.
|
|
197
|
+
* Performs no mutations; safe to run for `--dry-run` and to print for confirm.
|
|
198
|
+
*/
|
|
199
|
+
export function planUninstall() {
|
|
200
|
+
const agentsDir = getUserAgentsDir();
|
|
201
|
+
const legacy = getLegacySystemAgentsDir();
|
|
202
|
+
let legacySymlink = null;
|
|
203
|
+
try {
|
|
204
|
+
// Only claim it if it's actually a link (symlink on POSIX, junction on Windows —
|
|
205
|
+
// both report isSymbolicLink()); a real directory here is left alone so removeLink
|
|
206
|
+
// (unlinkSync) is always the correct primitive for what we captured.
|
|
207
|
+
if (fs.lstatSync(legacy).isSymbolicLink())
|
|
208
|
+
legacySymlink = legacy;
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
legacySymlink = null;
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
isInstalled: fs.existsSync(agentsDir),
|
|
215
|
+
agentsDir,
|
|
216
|
+
legacySymlink,
|
|
217
|
+
configs: ALL_AGENT_IDS.map(planConfig),
|
|
218
|
+
homeFiles: planHomeFiles(),
|
|
219
|
+
launchers: planLaunchers(),
|
|
220
|
+
rcFiles: planRcFiles(),
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Execute a plan built by {@link planUninstall}. Restores adopted config dirs
|
|
225
|
+
* and home files, releases adopted launchers, strips shim PATH lines, then
|
|
226
|
+
* disposes of `~/.agents` — moved aside to `~/.agents.removed-<ts>` (recoverable)
|
|
227
|
+
* by default, or hard-deleted when `purge` is set. Config restore always runs
|
|
228
|
+
* before disposal because the backups live inside `~/.agents`.
|
|
229
|
+
*/
|
|
230
|
+
export function executeUninstall(plan, opts) {
|
|
231
|
+
const result = {
|
|
232
|
+
restoredConfigs: [],
|
|
233
|
+
removedDanglingConfigs: [],
|
|
234
|
+
restoredHomeFiles: [],
|
|
235
|
+
releasedLaunchers: [],
|
|
236
|
+
cleanedRcFiles: [],
|
|
237
|
+
agentsDir: { path: plan.agentsDir, disposition: 'absent' },
|
|
238
|
+
legacySymlinkRemoved: false,
|
|
239
|
+
purgeDowngraded: false,
|
|
240
|
+
errors: [],
|
|
241
|
+
};
|
|
242
|
+
// 1. Restore adopted config directories (reads backups inside ~/.agents).
|
|
243
|
+
for (const c of plan.configs) {
|
|
244
|
+
try {
|
|
245
|
+
if (c.kind === 'restore-backup') {
|
|
246
|
+
// The adopted link carries no data (the real dir is the backup); drop it,
|
|
247
|
+
// then move the backup out of ~/.agents onto the real path — EXDEV-safe so a
|
|
248
|
+
// cross-volume ~/.agents can't strand the backup mid-restore. unlinkSync (not
|
|
249
|
+
// rmSync) is deliberate: it removes a POSIX symlink AND a Windows junction/
|
|
250
|
+
// dir-symlink without following into the target, whereas rmSync throws EFAULT
|
|
251
|
+
// on a Windows reparse point.
|
|
252
|
+
removeLink(c.realPath);
|
|
253
|
+
moveDirCrossDevice(c.source, c.realPath);
|
|
254
|
+
result.restoredConfigs.push({ agent: c.agent, realPath: c.realPath });
|
|
255
|
+
}
|
|
256
|
+
else if (c.kind === 'restore-version-home') {
|
|
257
|
+
// importAgent renamed the real dir INTO the version home; copy it back
|
|
258
|
+
// (step 6 disposes the original) while stripping resource symlinks that
|
|
259
|
+
// would dangle once ~/.agents is gone.
|
|
260
|
+
removeLink(c.realPath);
|
|
261
|
+
copyDirStrippingAgentsSymlinks(c.source, c.realPath, plan.agentsDir);
|
|
262
|
+
result.restoredConfigs.push({ agent: c.agent, realPath: c.realPath });
|
|
263
|
+
}
|
|
264
|
+
else if (c.kind === 'remove-dangling') {
|
|
265
|
+
removeLink(c.realPath);
|
|
266
|
+
result.removedDanglingConfigs.push({ agent: c.agent, realPath: c.realPath });
|
|
267
|
+
}
|
|
268
|
+
// leave-real / leave-foreign / absent: intentionally untouched.
|
|
269
|
+
}
|
|
270
|
+
catch (err) {
|
|
271
|
+
result.errors.push(`config ${c.agent} (${c.realPath}): ${err.message}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
// 2. Restore owned home-file symlinks as real files (e.g. ~/.claude.json).
|
|
275
|
+
for (const hf of plan.homeFiles) {
|
|
276
|
+
try {
|
|
277
|
+
removeLink(hf.realPath);
|
|
278
|
+
fs.cpSync(hf.source, hf.realPath, { recursive: true });
|
|
279
|
+
result.restoredHomeFiles.push(hf.realPath);
|
|
280
|
+
}
|
|
281
|
+
catch (err) {
|
|
282
|
+
result.errors.push(`home file ${hf.realPath}: ${err.message}`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
// 3. Release adopted launchers (reads records inside ~/.agents).
|
|
286
|
+
const byCli = new Map(ALL_AGENT_IDS.map((a) => [AGENTS[a].cliCommand, a]));
|
|
287
|
+
for (const cli of plan.launchers) {
|
|
288
|
+
const agent = byCli.get(cli);
|
|
289
|
+
if (!agent)
|
|
290
|
+
continue;
|
|
291
|
+
try {
|
|
292
|
+
releaseAdoptedLauncher(agent);
|
|
293
|
+
result.releasedLaunchers.push(cli);
|
|
294
|
+
}
|
|
295
|
+
catch (err) {
|
|
296
|
+
result.errors.push(`launcher ${cli}: ${err.message}`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
// 4. Strip the shim directory from the user's PATH across all rc files.
|
|
300
|
+
const shimsDir = getShimsDir();
|
|
301
|
+
for (const rc of plan.rcFiles) {
|
|
302
|
+
try {
|
|
303
|
+
const content = fs.readFileSync(rc, 'utf-8');
|
|
304
|
+
fs.writeFileSync(rc, stripShimPathLines(content, shimsDir));
|
|
305
|
+
result.cleanedRcFiles.push(rc);
|
|
306
|
+
}
|
|
307
|
+
catch (err) {
|
|
308
|
+
result.errors.push(`rc file ${rc}: ${err.message}`);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
// 5. Remove the legacy back-compat symlink, if present. `~/.agents-system` is a
|
|
312
|
+
// link (junction on Windows — createLink uses 'junction' for a dir source), so it
|
|
313
|
+
// goes through removeLink for the same reason as the config links: rmSync throws
|
|
314
|
+
// EFAULT on a Windows reparse point.
|
|
315
|
+
if (plan.legacySymlink) {
|
|
316
|
+
try {
|
|
317
|
+
removeLink(plan.legacySymlink);
|
|
318
|
+
result.legacySymlinkRemoved = true;
|
|
319
|
+
}
|
|
320
|
+
catch (err) {
|
|
321
|
+
result.errors.push(`legacy ${plan.legacySymlink}: ${err.message}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
// 6. Dispose of ~/.agents LAST (its backups fed step 1). If any restore above
|
|
325
|
+
// failed, downgrade a --purge to a recoverable move-aside: a swallowed restore
|
|
326
|
+
// error must never let the hard-delete take the user's only copy with it.
|
|
327
|
+
if (fs.existsSync(plan.agentsDir)) {
|
|
328
|
+
const purge = !!opts.purge && result.errors.length === 0;
|
|
329
|
+
if (opts.purge && !purge)
|
|
330
|
+
result.purgeDowngraded = true;
|
|
331
|
+
try {
|
|
332
|
+
if (purge) {
|
|
333
|
+
fs.rmSync(plan.agentsDir, { recursive: true, force: true });
|
|
334
|
+
result.agentsDir = { path: plan.agentsDir, disposition: 'purged' };
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
const movedTo = `${plan.agentsDir}.removed-${opts.timestamp}`;
|
|
338
|
+
fs.renameSync(plan.agentsDir, movedTo);
|
|
339
|
+
result.agentsDir = { path: plan.agentsDir, disposition: 'moved', movedTo };
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
catch (err) {
|
|
343
|
+
result.errors.push(`dispose ${plan.agentsDir}: ${err.message}`);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return result;
|
|
347
|
+
}
|
package/dist/lib/usage.d.ts
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import { type AccountInfo } from './agents.js';
|
|
2
2
|
import type { AgentId } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* True when a Claude OAuth access token is within the refresh leeway of expiry
|
|
5
|
+
* (or already expired) — i.e. it "would need a refresh" before the next use.
|
|
6
|
+
*
|
|
7
|
+
* Single source of truth for the expiry gate, shared by the two callers that
|
|
8
|
+
* must agree on it but act differently: the run/usage hot path
|
|
9
|
+
* (`getClaudeAccessToken`) refreshes when this is true; the health probe
|
|
10
|
+
* (`probeClaudeStatus`) must NOT refresh and instead reports the non-fatal
|
|
11
|
+
* `expired` state (RUSH-1822). A missing `expiresAt` is treated as "still
|
|
12
|
+
* fresh" (never force a refresh on a token with no known expiry).
|
|
13
|
+
*/
|
|
14
|
+
export declare function claudeAccessTokenNeedsRefresh(expiresAt: number | null | undefined, nowMs?: number): boolean;
|
|
3
15
|
/** Discriminator for usage window types. */
|
|
4
16
|
export type UsageWindowKey = 'session' | 'week' | 'sonnet_week' | 'month';
|
|
5
17
|
/** A single rate-limit window with utilization percentage and reset time. */
|
|
@@ -201,7 +213,7 @@ export interface ProviderProbe {
|
|
|
201
213
|
/** Network/parse error message when status is null but a token was present. */
|
|
202
214
|
error?: string;
|
|
203
215
|
}
|
|
204
|
-
/** Probe Claude's OAuth token against the usage endpoint.
|
|
216
|
+
/** Probe Claude's OAuth token against the usage endpoint. Never refreshes — reports `expired` for a near-expiry token; see the comment below (RUSH-1822). */
|
|
205
217
|
export declare function probeClaudeStatus(home?: string, cliVersion?: string | null): Promise<ProviderProbe>;
|
|
206
218
|
/** Probe Kimi's OAuth token against the /usages endpoint. Never refreshes (single-use rotation — see getKimiUsageInfo). */
|
|
207
219
|
export declare function probeKimiStatus(home?: string): Promise<ProviderProbe>;
|