@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
|
@@ -39,6 +39,98 @@ export const KEYCHAIN_BOUND_ON_MAC = new Set(['claude', 'antigravity']);
|
|
|
39
39
|
export function isPropagatableAgent(agent) {
|
|
40
40
|
return agent in FLEET_AUTH_FILES;
|
|
41
41
|
}
|
|
42
|
+
/** The success-file for an agent — the primary portable credential (first spec). */
|
|
43
|
+
function successFileFor(agent) {
|
|
44
|
+
const specs = FLEET_AUTH_FILES[agent];
|
|
45
|
+
if (!specs || specs.length === 0)
|
|
46
|
+
throw new Error(`no auth file spec for agent '${agent}'`);
|
|
47
|
+
return specs[0].rel;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Per-agent login flows, populated from live login-output captures (the only
|
|
51
|
+
* ground truth — no fixtures exist upstream). Agents whose real device-code
|
|
52
|
+
* output has not been captured are marked honestly (`unknown` / no regexes) so
|
|
53
|
+
* `fleet login` flags them non-remotable instead of guessing.
|
|
54
|
+
*
|
|
55
|
+
* Only the `device-code` entries are ones `fleet login` drives; the rest are
|
|
56
|
+
* carried so the command can explain WHY a logged-out pair is not remotable.
|
|
57
|
+
*/
|
|
58
|
+
export const FLEET_LOGIN_FLOWS = {
|
|
59
|
+
// droid: launches its TUI and prints, verbatim:
|
|
60
|
+
// "If the link does not open automatically, please visit
|
|
61
|
+
// https://auth.factory.ai/device and enter code MJQW-NQRM to complete
|
|
62
|
+
// authentication." then "Waiting for authentication to complete...".
|
|
63
|
+
droid: {
|
|
64
|
+
loginCommand: 'droid',
|
|
65
|
+
flowType: 'device-code',
|
|
66
|
+
verificationUrlRegex: /please visit\s+(https:\/\/\S+?)\s+and enter code/i,
|
|
67
|
+
userCodeRegex: /enter code\s+([A-Z0-9]{4}-[A-Z0-9]{4})/i,
|
|
68
|
+
successFile: successFileFor('droid'),
|
|
69
|
+
},
|
|
70
|
+
// codex login shows a numbered menu; option 2 ("Sign in with Device Code",
|
|
71
|
+
// "Sign in from another device with a one-time code") is the remotable one.
|
|
72
|
+
// The post-selection URL/code output was not captured this session, so the
|
|
73
|
+
// regexes are best-effort generic device-code patterns — TODO: tighten once a
|
|
74
|
+
// real codex device-code screen is captured.
|
|
75
|
+
codex: {
|
|
76
|
+
loginCommand: 'codex login',
|
|
77
|
+
flowType: 'device-code',
|
|
78
|
+
deviceCodeSelect: '\x1b[B\r', // down-arrow once (to option 2) + Enter
|
|
79
|
+
verificationUrlRegex: /(https:\/\/\S*(?:device|activate|login|auth)\S*)/i,
|
|
80
|
+
userCodeRegex: /\b([A-Z0-9]{4}-[A-Z0-9]{4})\b/,
|
|
81
|
+
successFile: successFileFor('codex'),
|
|
82
|
+
},
|
|
83
|
+
// kimi: launch bare `kimi`, then `/login` inside the TUI, which prints
|
|
84
|
+
// "Select a platform and authenticate". Post-selection URL/code not captured —
|
|
85
|
+
// best-effort regexes, TODO: tighten with a real capture.
|
|
86
|
+
kimi: {
|
|
87
|
+
loginCommand: 'kimi',
|
|
88
|
+
flowType: 'device-code',
|
|
89
|
+
deviceCodeSelect: '/login\r',
|
|
90
|
+
verificationUrlRegex: /(https:\/\/\S+)/i,
|
|
91
|
+
userCodeRegex: /\b([A-Z0-9]{4}-[A-Z0-9]{4})\b/,
|
|
92
|
+
successFile: successFileFor('kimi'),
|
|
93
|
+
},
|
|
94
|
+
// grok: `grok login`. No captured pattern this session — flowType is
|
|
95
|
+
// device-code (best guess for the remotable path) but regexes are left unset
|
|
96
|
+
// (TODO: capture grok's login output), so scrapeLogin yields nothing until a
|
|
97
|
+
// real pattern is added and driveRemoteLogin will time out rather than guess.
|
|
98
|
+
grok: {
|
|
99
|
+
loginCommand: 'grok login',
|
|
100
|
+
flowType: 'device-code',
|
|
101
|
+
successFile: successFileFor('grok'),
|
|
102
|
+
},
|
|
103
|
+
// antigravity: bare `agy`, Google OAuth. Keychain-bound on macOS and loopback
|
|
104
|
+
// (browser + 127.0.0.1 listener on the box itself) — non-remotable.
|
|
105
|
+
antigravity: {
|
|
106
|
+
loginCommand: 'agy',
|
|
107
|
+
flowType: 'loopback',
|
|
108
|
+
successFile: successFileFor('antigravity'),
|
|
109
|
+
},
|
|
110
|
+
// gemini: bare `gemini`, Google login on launch. Not characterized as a
|
|
111
|
+
// device-code flow (typically loopback) and no captured pattern — mark unknown
|
|
112
|
+
// so it is flagged non-remotable rather than mis-driven.
|
|
113
|
+
gemini: {
|
|
114
|
+
loginCommand: 'gemini',
|
|
115
|
+
flowType: 'unknown',
|
|
116
|
+
successFile: successFileFor('gemini'),
|
|
117
|
+
},
|
|
118
|
+
// opencode: `opencode auth login`. No captured pattern — unknown/non-remotable.
|
|
119
|
+
opencode: {
|
|
120
|
+
loginCommand: 'opencode auth login',
|
|
121
|
+
flowType: 'unknown',
|
|
122
|
+
successFile: successFileFor('opencode'),
|
|
123
|
+
},
|
|
124
|
+
// claude: interactive `/login` inside the TUI is a loopback browser flow, and
|
|
125
|
+
// the token is keychain-bound on macOS. A headless `claude setup-token` device
|
|
126
|
+
// variant exists (TODO: wire as a device-code flow with a captured pattern);
|
|
127
|
+
// until then claude is flagged non-remotable.
|
|
128
|
+
claude: {
|
|
129
|
+
loginCommand: 'claude',
|
|
130
|
+
flowType: 'loopback',
|
|
131
|
+
successFile: successFileFor('claude'),
|
|
132
|
+
},
|
|
133
|
+
};
|
|
42
134
|
/**
|
|
43
135
|
* Capture portable credential files for the given agents from a source home.
|
|
44
136
|
* Returns the readable file payloads plus the list of agents whose auth is
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import type { AgentId } from '../types.js';
|
|
2
|
+
import type { DeviceProfile } from '../devices/registry.js';
|
|
3
|
+
import { type AuthVerdict, type AuthHealth } from '../auth-health.js';
|
|
4
|
+
import { type LoginFlow } from './auth-sync.js';
|
|
5
|
+
/** A verification URL + user code scraped from a device-code login screen. */
|
|
6
|
+
export interface ScrapedLogin {
|
|
7
|
+
url?: string;
|
|
8
|
+
code?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Extract the verification URL and user code from an ANSI-stripped login screen
|
|
12
|
+
* using the flow's regexes. Pure — no I/O, so it is the highest-value unit test
|
|
13
|
+
* target (a wrong code boundary or a missed URL is exactly the bug class this
|
|
14
|
+
* whole feature turns on). Group 1 is preferred over the whole match so a
|
|
15
|
+
* surrounding phrase ("enter code XXXX-XXXX") never leaks into the captured
|
|
16
|
+
* value. A flow with no regex for a field yields `undefined` for that field.
|
|
17
|
+
*/
|
|
18
|
+
export declare function scrapeLogin(screenText: string, flow: LoginFlow): ScrapedLogin;
|
|
19
|
+
/** Why a logged-out (agent, device) pair can or cannot be driven remotely. */
|
|
20
|
+
export interface FlowClassification {
|
|
21
|
+
flow: LoginFlow | null;
|
|
22
|
+
remotable: boolean;
|
|
23
|
+
reason?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Decide whether `agent`'s login can be driven on a box of `platform`. Only a
|
|
27
|
+
* `device-code` flow is remotable; loopback (browser + 127.0.0.1 on the box),
|
|
28
|
+
* api-key, unknown, or a macOS keychain-bound token are surfaced with an honest
|
|
29
|
+
* reason instead of a mis-drive. Pure.
|
|
30
|
+
*/
|
|
31
|
+
export declare function classifyLoginFlow(agent: AgentId | string, platform: string | undefined): FlowClassification;
|
|
32
|
+
/**
|
|
33
|
+
* Does a cached auth verdict mean "this (host, agent) needs an interactive
|
|
34
|
+
* login"? A missing row (never signed in / credential absent) and a `revoked`
|
|
35
|
+
* token do; `live`, `unverified` (signed in, no probe), `expired`, and
|
|
36
|
+
* `rate_limited` are treated as already-logged-in (expired self-heals on next
|
|
37
|
+
* launch — never re-login on it). Pure.
|
|
38
|
+
*/
|
|
39
|
+
export declare function isPendingVerdict(verdict: AuthVerdict | undefined): boolean;
|
|
40
|
+
/** A logged-out (agent, device) pair `fleet login` will target or explain. */
|
|
41
|
+
export interface PendingLogin {
|
|
42
|
+
device: string;
|
|
43
|
+
agent: AgentId | string;
|
|
44
|
+
platform?: string;
|
|
45
|
+
/** ssh dial target for the device. */
|
|
46
|
+
target: string;
|
|
47
|
+
flow: LoginFlow;
|
|
48
|
+
/** True when a device-code flow this command can actually drive. */
|
|
49
|
+
remotable: boolean;
|
|
50
|
+
/** Present when `!remotable` — why it must be done on the box itself. */
|
|
51
|
+
reason?: string;
|
|
52
|
+
}
|
|
53
|
+
export interface SelectLoginOptions {
|
|
54
|
+
/** Include pairs already logged-in (verdict live/unverified) — for a forced re-login. */
|
|
55
|
+
includeLoggedIn?: boolean;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* From a device list, requested agents, and the auth-health cache, compute the
|
|
59
|
+
* pending logins — partitioned (via {@link classifyLoginFlow}) into remotable
|
|
60
|
+
* device-code flows and non-remotable pairs with a reason. Pure: the caller
|
|
61
|
+
* supplies the already-loaded devices + cache, so this is fully unit-testable.
|
|
62
|
+
*
|
|
63
|
+
* A pair is pending when its cached verdict {@link isPendingVerdict} (or
|
|
64
|
+
* `includeLoggedIn` forces it). Agents with no defined login flow are dropped
|
|
65
|
+
* silently (nothing to log into). Control devices are excluded by the caller.
|
|
66
|
+
*/
|
|
67
|
+
export declare function selectLoginTargets(devices: DeviceProfile[], agents: (AgentId | string)[], cache: Record<string, AuthHealth>, opts?: SelectLoginOptions): PendingLogin[];
|
|
68
|
+
/**
|
|
69
|
+
* Build the `ssh -tt <target> <loginCommand>` command string driven through the
|
|
70
|
+
* PTY sidecar. `-tt` forces a tty so the remote CLI enters its interactive
|
|
71
|
+
* device-code flow; `accept-new` learns a first-seen host key without a prompt.
|
|
72
|
+
* Both the target and the login command are shell-quoted. Pure/testable.
|
|
73
|
+
*
|
|
74
|
+
* NOTE: this uses key-based ssh auth (the tailnet fleet's norm). Password-bundle
|
|
75
|
+
* devices need the askpass shim env, which the PTY env allowlist strips — those
|
|
76
|
+
* are a follow-up (TODO), surfaced as an error rather than silently mis-driven.
|
|
77
|
+
*/
|
|
78
|
+
export declare function buildRemoteLoginSshCommand(target: string, flow: LoginFlow): string;
|
|
79
|
+
export type LoginMode = 'bulk' | 'interactive';
|
|
80
|
+
/** Per-pair status shape shared between the driver, the status endpoint, and the page. */
|
|
81
|
+
export type LoginStatusState = 'pending' | 'driving' | 'ready' | 'authorized' | 'error' | 'skipped';
|
|
82
|
+
export interface LoginStatus {
|
|
83
|
+
device: string;
|
|
84
|
+
agent: string;
|
|
85
|
+
remotable: boolean;
|
|
86
|
+
reason?: string;
|
|
87
|
+
state: LoginStatusState;
|
|
88
|
+
url?: string;
|
|
89
|
+
code?: string;
|
|
90
|
+
/** epoch ms the scraped code expires (best-effort ~15 min TTL). */
|
|
91
|
+
expiresAt?: number;
|
|
92
|
+
detail?: string;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Render the self-contained dashboard page. Inlines all CSS/JS; the page polls
|
|
96
|
+
* `/api/status` and flips rows to their live state. `bulk` shows a grid of every
|
|
97
|
+
* pending login at once; `interactive` shows a one-at-a-time wizard. Pure — a
|
|
98
|
+
* string in, a string out — so it renders (and is asserted) without a server.
|
|
99
|
+
* Terminal-coded per the agents-cli brand (#0a0a0a bg, #a3e635 lime), with a
|
|
100
|
+
* light variant via `prefers-color-scheme`.
|
|
101
|
+
*/
|
|
102
|
+
export declare function buildDashboardHtml(pending: PendingLogin[], mode: LoginMode): string;
|
|
103
|
+
/** The subset of the PTY sidecar `driveRemoteLogin` needs — faked in tests. */
|
|
104
|
+
export interface PtyDriver {
|
|
105
|
+
start(opts?: {
|
|
106
|
+
rows?: number;
|
|
107
|
+
cols?: number;
|
|
108
|
+
}): Promise<string>;
|
|
109
|
+
exec(id: string, command: string): Promise<void>;
|
|
110
|
+
write(id: string, input: string): Promise<void>;
|
|
111
|
+
screen(id: string): Promise<{
|
|
112
|
+
screen: string;
|
|
113
|
+
exited: boolean;
|
|
114
|
+
}>;
|
|
115
|
+
stop(id: string): Promise<void>;
|
|
116
|
+
}
|
|
117
|
+
/** Real driver over the pty sidecar (`ptyRequest`). */
|
|
118
|
+
export declare function defaultPtyDriver(): PtyDriver;
|
|
119
|
+
export interface DriveOptions {
|
|
120
|
+
/** Wait after launching ssh before steering / scraping (default 4000ms). */
|
|
121
|
+
initialDelayMs?: number;
|
|
122
|
+
/** Poll cadence for the scrape loop (default 1000ms). */
|
|
123
|
+
pollMs?: number;
|
|
124
|
+
/** Overall scrape deadline (default 90000ms). */
|
|
125
|
+
timeoutMs?: number;
|
|
126
|
+
}
|
|
127
|
+
export interface DriveResult extends ScrapedLogin {
|
|
128
|
+
/** True when the underlying ssh session already exited (login finished or failed). */
|
|
129
|
+
exited: boolean;
|
|
130
|
+
/** The pty session id, so the caller can keep polling / stop it. */
|
|
131
|
+
sessionId: string;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Drive one remote device-code login: launch `ssh -tt <target> <loginCommand>`
|
|
135
|
+
* in a PTY, send the flow's `deviceCodeSelect` keystrokes (if any) to reach the
|
|
136
|
+
* device-code path, then poll the screen until {@link scrapeLogin} yields both a
|
|
137
|
+
* URL and a code (or the deadline / session-exit). The human completes the code
|
|
138
|
+
* in the browser; the caller polls the credential file for completion. Testable
|
|
139
|
+
* against a fake {@link PtyDriver}.
|
|
140
|
+
*/
|
|
141
|
+
export declare function driveRemoteLogin(target: string, flow: LoginFlow, driver: PtyDriver, opts?: DriveOptions): Promise<DriveResult>;
|
|
142
|
+
export interface DetectOptions {
|
|
143
|
+
agents?: (AgentId | string)[];
|
|
144
|
+
devices?: string[];
|
|
145
|
+
includeLoggedIn?: boolean;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Resolve the online (non-control) fleet devices, then compute pending logins
|
|
149
|
+
* from the shared auth-health cache (populated by `agents fleet ping`). Thin I/O
|
|
150
|
+
* over the pure {@link selectLoginTargets}. Devices/agents can be narrowed by the
|
|
151
|
+
* caller's flags; the default agent set is every agent with a defined flow.
|
|
152
|
+
*/
|
|
153
|
+
export declare function detectPending(opts?: DetectOptions): Promise<PendingLogin[]>;
|
|
154
|
+
/**
|
|
155
|
+
* Best-effort epoch-seconds mtime of a home-relative file on a remote box, or 0
|
|
156
|
+
* when it is absent/unreadable. Used to detect the credential file appearing /
|
|
157
|
+
* bumping after the human completes the browser step. POSIX `stat` only (the
|
|
158
|
+
* device-code agents are all POSIX-fleet).
|
|
159
|
+
*/
|
|
160
|
+
export declare function remoteFileMtime(target: string, homeRel: string): Promise<number>;
|
|
161
|
+
export interface RunFleetLoginOptions {
|
|
162
|
+
agents?: (AgentId | string)[];
|
|
163
|
+
devices?: string[];
|
|
164
|
+
interactive?: boolean;
|
|
165
|
+
json?: boolean;
|
|
166
|
+
/** Target every device-code pair regardless of cached login state (cold cache / forced re-login). */
|
|
167
|
+
all?: boolean;
|
|
168
|
+
/** Overrides for testing / non-default cadence. */
|
|
169
|
+
driver?: PtyDriver;
|
|
170
|
+
drive?: DriveOptions;
|
|
171
|
+
/** Port for the local dashboard (0 = ephemeral). */
|
|
172
|
+
port?: number;
|
|
173
|
+
/** Open the browser (default true). */
|
|
174
|
+
open?: boolean;
|
|
175
|
+
/** Max wall-clock to wait for all logins before giving up (default 20 min). */
|
|
176
|
+
overallTimeoutMs?: number;
|
|
177
|
+
/** ~15 min device-code TTL used for the countdown. */
|
|
178
|
+
codeTtlMs?: number;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Orchestrate `agents fleet login`: detect pending -> serve the local dashboard
|
|
182
|
+
* + open the browser -> drive each box's device-code flow (concurrent in bulk,
|
|
183
|
+
* sequential just-in-time in interactive) -> poll the credential file for
|
|
184
|
+
* completion -> print a final matrix. The pure pieces above carry the logic;
|
|
185
|
+
* this wires them to the live fleet.
|
|
186
|
+
*/
|
|
187
|
+
export declare function runFleetLogin(opts?: RunFleetLoginOptions): Promise<LoginStatus[]>;
|