@phnx-labs/agents-cli 1.20.49 → 1.20.51
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 +31 -0
- package/README.md +3 -0
- package/dist/commands/browser-picker.js +1 -18
- package/dist/commands/cloud.js +1 -25
- package/dist/commands/computer.d.ts +1 -0
- package/dist/commands/computer.js +129 -8
- package/dist/commands/doctor.js +133 -2
- package/dist/commands/exec.js +49 -6
- package/dist/commands/factory.js +1 -4
- package/dist/commands/inspect.js +1 -11
- package/dist/commands/mcp.js +2 -6
- package/dist/commands/message.js +1 -4
- package/dist/commands/profiles.js +1 -18
- package/dist/commands/repo.js +33 -14
- package/dist/commands/resource-view.d.ts +1 -0
- package/dist/commands/resource-view.js +5 -17
- package/dist/commands/secrets.d.ts +1 -0
- package/dist/commands/secrets.js +1 -28
- package/dist/commands/sessions-picker.js +1 -18
- package/dist/commands/sessions.js +6 -8
- package/dist/commands/teams-picker.js +1 -32
- package/dist/commands/teams.js +218 -97
- package/dist/commands/tmux.js +1 -3
- package/dist/commands/view.js +1 -9
- package/dist/commands/worktree.js +1 -4
- package/dist/lib/agents.d.ts +0 -4
- package/dist/lib/agents.js +20 -33
- package/dist/lib/auto-dispatch-linear.d.ts +18 -0
- package/dist/lib/auto-dispatch-linear.js +107 -0
- package/dist/lib/auto-dispatch-provider.d.ts +10 -0
- package/dist/lib/auto-dispatch-provider.js +25 -0
- package/dist/lib/auto-dispatch.d.ts +87 -0
- package/dist/lib/auto-dispatch.js +142 -0
- package/dist/lib/browser/cdp.js +11 -2
- package/dist/lib/browser/drivers/ssh.d.ts +28 -10
- package/dist/lib/browser/drivers/ssh.js +57 -18
- package/dist/lib/browser/refs.js +1 -5
- package/dist/lib/cli-resources.d.ts +0 -2
- package/dist/lib/cli-resources.js +30 -13
- package/dist/lib/cloud/rush.d.ts +0 -24
- package/dist/lib/cloud/rush.js +0 -31
- package/dist/lib/crabbox/cli.js +4 -1
- package/dist/lib/crabbox/lease.js +29 -1
- package/dist/lib/daemon.js +41 -0
- package/dist/lib/exec.js +43 -18
- package/dist/lib/format.d.ts +38 -0
- package/dist/lib/format.js +108 -0
- package/dist/lib/git.d.ts +21 -0
- package/dist/lib/git.js +92 -0
- package/dist/lib/hooks/cache.d.ts +9 -2
- package/dist/lib/hooks/cache.js +220 -8
- package/dist/lib/hooks.js +17 -8
- package/dist/lib/hosts/passthrough.js +30 -1
- package/dist/lib/hosts/progress.d.ts +31 -0
- package/dist/lib/hosts/progress.js +35 -0
- package/dist/lib/hosts/remote-cmd.d.ts +1 -1
- package/dist/lib/hosts/remote-cmd.js +13 -3
- package/dist/lib/platform/exec.d.ts +4 -1
- package/dist/lib/platform/exec.js +8 -2
- package/dist/lib/resources.d.ts +0 -8
- package/dist/lib/resources.js +0 -10
- package/dist/lib/runner.js +10 -2
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/session/active.d.ts +11 -1
- package/dist/lib/session/active.js +3 -0
- package/dist/lib/session/db.d.ts +1 -4
- package/dist/lib/session/db.js +20 -25
- package/dist/lib/session/discover.d.ts +2 -2
- package/dist/lib/session/discover.js +61 -48
- package/dist/lib/session/parse.js +35 -34
- package/dist/lib/session/render.d.ts +7 -3
- package/dist/lib/session/render.js +15 -9
- package/dist/lib/session/state.d.ts +55 -0
- package/dist/lib/session/state.js +87 -10
- package/dist/lib/session/types.d.ts +9 -0
- package/dist/lib/shims.d.ts +25 -2
- package/dist/lib/shims.js +73 -8
- package/dist/lib/ssh-tunnel.d.ts +33 -2
- package/dist/lib/ssh-tunnel.js +94 -7
- package/dist/lib/staleness/types.d.ts +0 -1
- package/dist/lib/teams/agents.d.ts +108 -1
- package/dist/lib/teams/agents.js +511 -11
- package/dist/lib/teams/api.d.ts +7 -1
- package/dist/lib/teams/api.js +5 -2
- package/dist/lib/teams/registry.d.ts +17 -0
- package/dist/lib/teams/registry.js +2 -0
- package/dist/lib/teams/remoteWorktree.d.ts +57 -0
- package/dist/lib/teams/remoteWorktree.js +213 -0
- package/dist/lib/teams/scheduler.d.ts +29 -0
- package/dist/lib/teams/scheduler.js +78 -0
- package/dist/lib/teams/supervisor.js +7 -0
- package/dist/lib/types.d.ts +14 -1
- package/dist/lib/versions.d.ts +7 -26
- package/dist/lib/versions.js +44 -146
- package/dist/lib/warn-unpushed.d.ts +40 -0
- package/dist/lib/warn-unpushed.js +128 -0
- package/package.json +3 -1
- package/dist/lib/resources/index.d.ts +0 -53
- package/dist/lib/resources/index.js +0 -76
package/dist/lib/ssh-tunnel.d.ts
CHANGED
|
@@ -50,10 +50,41 @@ export declare const REMOTE_TASK_NAME = "AgentsComputerHelper";
|
|
|
50
50
|
/** Basename of the cross-published exe under native/computer-win/dist. */
|
|
51
51
|
export declare const WIN_HELPER_EXE = "computer-helper-win.exe";
|
|
52
52
|
/**
|
|
53
|
-
* Locate
|
|
54
|
-
*
|
|
53
|
+
* Locate a locally built Windows daemon exe — a repo-checkout build output from
|
|
54
|
+
* `scripts/build-win.sh`, or one bundled next to the package. Local paths are
|
|
55
|
+
* only the first candidate; npm-installed CLIs have neither and fall through to
|
|
56
|
+
* the release-asset download (`ensureWinHelperExe`).
|
|
55
57
|
*/
|
|
56
58
|
export declare function resolveWinHelperExe(): string | null;
|
|
59
|
+
/** GitHub repo whose `v<version>` releases carry the exe as an asset. */
|
|
60
|
+
export declare const WIN_HELPER_RELEASE_REPO = "phnx-labs/agents-cli";
|
|
61
|
+
/** Cache dir for downloaded helper exes, one subdir per release tag. */
|
|
62
|
+
export declare function winHelperCacheDir(version: string): string;
|
|
63
|
+
/** Release-asset URLs for the exe + its checksum at one exact `v<version>` tag. */
|
|
64
|
+
export declare function winHelperAssetUrls(version: string): {
|
|
65
|
+
exe: string;
|
|
66
|
+
sha256: string;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Parse the published `.sha256` asset — `sha256sum` format (`<hex> <name>`) or
|
|
70
|
+
* a bare hex digest. Throws on anything that does not lead with 64 hex chars.
|
|
71
|
+
*/
|
|
72
|
+
export declare function parseSha256Asset(text: string): string;
|
|
73
|
+
/** Stream a file through sha256 — the exe is ~157MB, never read it whole. */
|
|
74
|
+
export declare function sha256File(file: string): Promise<string>;
|
|
75
|
+
/**
|
|
76
|
+
* Download the exe release asset for this CLI version, verify its sha256
|
|
77
|
+
* against the published `.sha256` asset, and cache it under the agents cache
|
|
78
|
+
* dir. Only the exact `v<version>` tag is consulted — a missing asset is a
|
|
79
|
+
* hard error naming that tag, never a silent fallback to another release.
|
|
80
|
+
*/
|
|
81
|
+
export declare function downloadWinHelperExe(version: string): Promise<string>;
|
|
82
|
+
/**
|
|
83
|
+
* Resolve the helper exe for `setup --host`: local build outputs first (repo
|
|
84
|
+
* checkout / bundled), then the checksum-verified release-asset download for
|
|
85
|
+
* the running CLI version. Throws with the tag it checked when neither exists.
|
|
86
|
+
*/
|
|
87
|
+
export declare function ensureWinHelperExe(version?: string): Promise<string>;
|
|
57
88
|
/** Persisted per-device tunnel state so verbs can reconnect after `start --host`. */
|
|
58
89
|
export interface RemoteTunnelState {
|
|
59
90
|
device: string;
|
package/dist/lib/ssh-tunnel.js
CHANGED
|
@@ -21,7 +21,9 @@ import * as net from 'net';
|
|
|
21
21
|
import * as fs from 'fs';
|
|
22
22
|
import * as path from 'path';
|
|
23
23
|
import { fileURLToPath } from 'url';
|
|
24
|
-
import { randomBytes } from 'crypto';
|
|
24
|
+
import { randomBytes, createHash } from 'crypto';
|
|
25
|
+
import { Readable } from 'stream';
|
|
26
|
+
import { pipeline } from 'stream/promises';
|
|
25
27
|
import { sshExec, SSH_OPTS } from './ssh-exec.js';
|
|
26
28
|
import { backgroundSpawnOptions } from './platform/process.js';
|
|
27
29
|
import { encodePowerShell } from './browser/drivers/ssh.js';
|
|
@@ -29,6 +31,7 @@ import { getDevice } from './devices/registry.js';
|
|
|
29
31
|
import { sshTargetFor } from './devices/connect.js';
|
|
30
32
|
import { hostNameFor } from './devices/ssh-config.js';
|
|
31
33
|
import { getCacheDir } from './state.js';
|
|
34
|
+
import { getCliVersion } from './version.js';
|
|
32
35
|
import { openComputerClient, resolveTcpEndpoint } from './computer-rpc.js';
|
|
33
36
|
/** Build the ssh argv (after the `ssh` program name) for an `-L` tunnel. Pure.
|
|
34
37
|
*
|
|
@@ -89,8 +92,10 @@ export const REMOTE_TASK_NAME = 'AgentsComputerHelper';
|
|
|
89
92
|
/** Basename of the cross-published exe under native/computer-win/dist. */
|
|
90
93
|
export const WIN_HELPER_EXE = 'computer-helper-win.exe';
|
|
91
94
|
/**
|
|
92
|
-
* Locate
|
|
93
|
-
*
|
|
95
|
+
* Locate a locally built Windows daemon exe — a repo-checkout build output from
|
|
96
|
+
* `scripts/build-win.sh`, or one bundled next to the package. Local paths are
|
|
97
|
+
* only the first candidate; npm-installed CLIs have neither and fall through to
|
|
98
|
+
* the release-asset download (`ensureWinHelperExe`).
|
|
94
99
|
*/
|
|
95
100
|
export function resolveWinHelperExe() {
|
|
96
101
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -106,6 +111,89 @@ export function resolveWinHelperExe() {
|
|
|
106
111
|
}
|
|
107
112
|
return null;
|
|
108
113
|
}
|
|
114
|
+
/** GitHub repo whose `v<version>` releases carry the exe as an asset. */
|
|
115
|
+
export const WIN_HELPER_RELEASE_REPO = 'phnx-labs/agents-cli';
|
|
116
|
+
/** Cache dir for downloaded helper exes, one subdir per release tag. */
|
|
117
|
+
export function winHelperCacheDir(version) {
|
|
118
|
+
return path.join(getCacheDir(), 'computer', 'win-helper', `v${version}`);
|
|
119
|
+
}
|
|
120
|
+
/** Release-asset URLs for the exe + its checksum at one exact `v<version>` tag. */
|
|
121
|
+
export function winHelperAssetUrls(version) {
|
|
122
|
+
const base = `https://github.com/${WIN_HELPER_RELEASE_REPO}/releases/download/v${version}`;
|
|
123
|
+
return { exe: `${base}/${WIN_HELPER_EXE}`, sha256: `${base}/${WIN_HELPER_EXE}.sha256` };
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Parse the published `.sha256` asset — `sha256sum` format (`<hex> <name>`) or
|
|
127
|
+
* a bare hex digest. Throws on anything that does not lead with 64 hex chars.
|
|
128
|
+
*/
|
|
129
|
+
export function parseSha256Asset(text) {
|
|
130
|
+
const m = text.trim().match(/^([A-Fa-f0-9]{64})(\s|$)/);
|
|
131
|
+
if (!m)
|
|
132
|
+
throw new Error(`malformed .sha256 release asset: ${JSON.stringify(text.slice(0, 80))}`);
|
|
133
|
+
return m[1].toLowerCase();
|
|
134
|
+
}
|
|
135
|
+
/** Stream a file through sha256 — the exe is ~157MB, never read it whole. */
|
|
136
|
+
export function sha256File(file) {
|
|
137
|
+
return new Promise((resolve, reject) => {
|
|
138
|
+
const hash = createHash('sha256');
|
|
139
|
+
fs.createReadStream(file)
|
|
140
|
+
.on('error', reject)
|
|
141
|
+
.on('data', (d) => hash.update(d))
|
|
142
|
+
.on('end', () => resolve(hash.digest('hex')));
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Download the exe release asset for this CLI version, verify its sha256
|
|
147
|
+
* against the published `.sha256` asset, and cache it under the agents cache
|
|
148
|
+
* dir. Only the exact `v<version>` tag is consulted — a missing asset is a
|
|
149
|
+
* hard error naming that tag, never a silent fallback to another release.
|
|
150
|
+
*/
|
|
151
|
+
export async function downloadWinHelperExe(version) {
|
|
152
|
+
const cached = path.join(winHelperCacheDir(version), WIN_HELPER_EXE);
|
|
153
|
+
if (fs.existsSync(cached))
|
|
154
|
+
return cached;
|
|
155
|
+
const tag = `v${version}`;
|
|
156
|
+
const { exe: exeUrl, sha256: shaUrl } = winHelperAssetUrls(version);
|
|
157
|
+
const missing = (status, url) => new Error(`no ${WIN_HELPER_EXE} release asset for tag ${tag} (HTTP ${status} on ${url}). ` +
|
|
158
|
+
`The Windows helper ships as a GitHub release asset per tagged CLI version; ` +
|
|
159
|
+
`from a repo checkout you can build it locally instead: bash scripts/build-win.sh`);
|
|
160
|
+
// Checksum first: it is tiny and 404s fast when the tag has no assets.
|
|
161
|
+
const shaRes = await fetch(shaUrl, { signal: AbortSignal.timeout(30_000) });
|
|
162
|
+
if (!shaRes.ok)
|
|
163
|
+
throw missing(shaRes.status, shaUrl);
|
|
164
|
+
const expected = parseSha256Asset(await shaRes.text());
|
|
165
|
+
console.error(`Downloading ${WIN_HELPER_EXE} ${tag} from GitHub releases (~160 MB)...`);
|
|
166
|
+
const exeRes = await fetch(exeUrl, { signal: AbortSignal.timeout(15 * 60_000) });
|
|
167
|
+
if (!exeRes.ok || !exeRes.body)
|
|
168
|
+
throw missing(exeRes.status, exeUrl);
|
|
169
|
+
fs.mkdirSync(path.dirname(cached), { recursive: true });
|
|
170
|
+
// Stream to a partial file and rename only after the checksum passes, so an
|
|
171
|
+
// interrupted download can never be picked up as a valid cache hit.
|
|
172
|
+
const partial = `${cached}.download`;
|
|
173
|
+
try {
|
|
174
|
+
await pipeline(Readable.fromWeb(exeRes.body), fs.createWriteStream(partial));
|
|
175
|
+
const actual = await sha256File(partial);
|
|
176
|
+
if (actual !== expected) {
|
|
177
|
+
throw new Error(`sha256 mismatch for ${exeUrl}: expected ${expected}, got ${actual}`);
|
|
178
|
+
}
|
|
179
|
+
fs.renameSync(partial, cached);
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
fs.rmSync(partial, { force: true });
|
|
183
|
+
}
|
|
184
|
+
return cached;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Resolve the helper exe for `setup --host`: local build outputs first (repo
|
|
188
|
+
* checkout / bundled), then the checksum-verified release-asset download for
|
|
189
|
+
* the running CLI version. Throws with the tag it checked when neither exists.
|
|
190
|
+
*/
|
|
191
|
+
export async function ensureWinHelperExe(version = getCliVersion()) {
|
|
192
|
+
const local = resolveWinHelperExe();
|
|
193
|
+
if (local)
|
|
194
|
+
return local;
|
|
195
|
+
return downloadWinHelperExe(version);
|
|
196
|
+
}
|
|
109
197
|
function remoteStateDir() {
|
|
110
198
|
return path.join(getCacheDir(), 'computer', 'remote');
|
|
111
199
|
}
|
|
@@ -249,10 +337,9 @@ function copyFileOverScp(target, remotePath, filePath, timeoutMs = 600_000) {
|
|
|
249
337
|
*/
|
|
250
338
|
export async function setupRemoteHelper(name) {
|
|
251
339
|
const { target } = await resolveRemoteDevice(name);
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
}
|
|
340
|
+
// Local build output, else the checksum-verified GitHub release asset for
|
|
341
|
+
// this CLI version. Throws naming the tag it checked when neither exists.
|
|
342
|
+
const exe = await ensureWinHelperExe();
|
|
256
343
|
const prep = sshExec(target, encodePowerShell(buildPushScript()), { timeoutMs: 60_000 });
|
|
257
344
|
if (prep.code !== 0) {
|
|
258
345
|
throw new Error(`preparing helper exe path on '${name}' failed (exit ${prep.code ?? 'null'}): ${prep.stderr.trim() || prep.stdout.trim()}`);
|
|
@@ -92,6 +92,21 @@ export interface SignInAdvisory {
|
|
|
92
92
|
* probe). Never flips the authoritative installed/ready column.
|
|
93
93
|
*/
|
|
94
94
|
export declare function resolveSignInAdvisory(installed: boolean, running: boolean, probeSignedIn: boolean): SignInAdvisory;
|
|
95
|
+
/** One row of `agents teams doctor --json` output. */
|
|
96
|
+
export interface TeamsDoctorEntry {
|
|
97
|
+
installed: boolean;
|
|
98
|
+
path: string | null;
|
|
99
|
+
error: string | null;
|
|
100
|
+
signedIn: boolean | null;
|
|
101
|
+
running: boolean;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Collect the same data `agents teams doctor` prints: per-agent install status,
|
|
105
|
+
* launch health, and advisory sign-in state. Kept in one place so `agents doctor
|
|
106
|
+
* --devices` can run it locally or compare it against remote JSON without
|
|
107
|
+
* duplicating the probe logic.
|
|
108
|
+
*/
|
|
109
|
+
export declare function collectTeamsDoctorData(): Promise<Record<string, TeamsDoctorEntry>>;
|
|
95
110
|
/** Resolve and cache the base directory where teammate process data is stored. */
|
|
96
111
|
export declare function getAgentsDir(): Promise<string>;
|
|
97
112
|
/**
|
|
@@ -131,6 +146,17 @@ export declare class AgentProcess {
|
|
|
131
146
|
cloudBranch: string | null;
|
|
132
147
|
worktreeName: string | null;
|
|
133
148
|
worktreePath: string | null;
|
|
149
|
+
hostName: string | null;
|
|
150
|
+
hostTarget: string | null;
|
|
151
|
+
repoPath: string | null;
|
|
152
|
+
remotePid: number | null;
|
|
153
|
+
remoteLog: string | null;
|
|
154
|
+
remoteExit: string | null;
|
|
155
|
+
remoteLogOffset: number;
|
|
156
|
+
remotePollSnapshot: {
|
|
157
|
+
alive: boolean;
|
|
158
|
+
exit: string | null;
|
|
159
|
+
} | null;
|
|
134
160
|
private eventsCache;
|
|
135
161
|
private lastReadPos;
|
|
136
162
|
private baseDir;
|
|
@@ -175,7 +201,35 @@ export declare class AgentProcess {
|
|
|
175
201
|
* Falls back to null when none are available.
|
|
176
202
|
*/
|
|
177
203
|
private getLatestEventTime;
|
|
204
|
+
/**
|
|
205
|
+
* For a distributed (remote-host) teammate, pull NEW bytes of the host's log
|
|
206
|
+
* into the LOCAL mirror the parser consumes, advance the remote offset, and
|
|
207
|
+
* resolve terminal status from the remote `.exit` sentinel. Runs BEFORE the
|
|
208
|
+
* local read in readNewEvents(), so the existing stream-json parse path then
|
|
209
|
+
* runs unchanged over the freshly-mirrored bytes.
|
|
210
|
+
*
|
|
211
|
+
* Uses a per-wave batched snapshot (remotePollSnapshot) when the supervisor's
|
|
212
|
+
* one-ssh-per-host pre-pass populated it; otherwise falls back to its own
|
|
213
|
+
* round-trips so a bare `teams status`/`teams logs` is still correct.
|
|
214
|
+
*/
|
|
215
|
+
private syncRemoteMirror;
|
|
178
216
|
readNewEvents(): Promise<void>;
|
|
217
|
+
/**
|
|
218
|
+
* Truncate the local mirror to its trailing REMOTE_MIRROR_MAX_BYTES and reset
|
|
219
|
+
* lastReadPos to the new (smaller) size so the parser doesn't re-read the kept
|
|
220
|
+
* tail. Only trims when over the cap — a normal-length log is untouched.
|
|
221
|
+
*/
|
|
222
|
+
private capMirrorToTail;
|
|
223
|
+
/** Cap on the in-memory event backlog kept per remote teammate. */
|
|
224
|
+
private static readonly REMOTE_EVENTS_MAX;
|
|
225
|
+
/**
|
|
226
|
+
* Drop the oldest cached events for a remote teammate once past the cap. The
|
|
227
|
+
* status path only needs recent events (last N messages, recentToolCalls,
|
|
228
|
+
* terminal status) and the getDelta cursor filters by timestamp, so a bounded
|
|
229
|
+
* recent window preserves the digest while bounding the heap. Terminal status
|
|
230
|
+
* is already latched onto `this.status`, so trimming can't lose it.
|
|
231
|
+
*/
|
|
232
|
+
private capEventsCache;
|
|
179
233
|
saveMeta(): Promise<void>;
|
|
180
234
|
static loadFromDisk(agentId: string, baseDir?: string | null): Promise<AgentProcess | null>;
|
|
181
235
|
isProcessAlive(): boolean;
|
|
@@ -246,12 +300,51 @@ export declare class AgentManager {
|
|
|
246
300
|
*/
|
|
247
301
|
rescanFromDisk(): Promise<number>;
|
|
248
302
|
private loadExistingAgents;
|
|
249
|
-
spawn(taskName: string, agentType: AgentType, prompt: string, cwd?: string | null, mode?: Mode | null, effort?: EffortLevel, parentSessionId?: string | null, workspaceDir?: string | null, version?: string | null, name?: string | null, after?: string[], model?: string | null, envOverrides?: Record<string, string> | null, taskType?: TaskType | null, cloudProvider?: string | null, cloudSessionId?: string | null, cloudRepo?: string | null, cloudBranch?: string | null, worktreeName?: string | null, worktreePath?: string | null, profileName?: string | null): Promise<AgentProcess>;
|
|
303
|
+
spawn(taskName: string, agentType: AgentType, prompt: string, cwd?: string | null, mode?: Mode | null, effort?: EffortLevel, parentSessionId?: string | null, workspaceDir?: string | null, version?: string | null, name?: string | null, after?: string[], model?: string | null, envOverrides?: Record<string, string> | null, taskType?: TaskType | null, cloudProvider?: string | null, cloudSessionId?: string | null, cloudRepo?: string | null, cloudBranch?: string | null, worktreeName?: string | null, worktreePath?: string | null, profileName?: string | null, hostName?: string | null, hostTarget?: string | null, repoPath?: string | null): Promise<AgentProcess>;
|
|
250
304
|
/**
|
|
251
305
|
* Actually spawn the OS process for a teammate. Extracted from spawn() so
|
|
252
306
|
* staged teammates can be launched later by startReady().
|
|
253
307
|
*/
|
|
254
308
|
private launchProcess;
|
|
309
|
+
/**
|
|
310
|
+
* Dispatch a distributed teammate onto its host over SSH — the remote-host
|
|
311
|
+
* analog of launchProcess(). Symmetric to the cloud path: no local process; the
|
|
312
|
+
* lifecycle lives on the host and is polled (isProcessAlive/readNewEvents over
|
|
313
|
+
* SSH via the remote `.exit` sentinel + offset-tailed log).
|
|
314
|
+
*
|
|
315
|
+
* When the team uses worktrees (agent.worktreeName set), a git worktree is first
|
|
316
|
+
* created ON THE HOST off the freshly-fetched default branch; the teammate runs
|
|
317
|
+
* there. Otherwise it runs in the host repo path directly.
|
|
318
|
+
*/
|
|
319
|
+
private launchRemoteProcess;
|
|
320
|
+
/**
|
|
321
|
+
* Resolve a scheduler-picked device to host placement fields on an unpinned
|
|
322
|
+
* teammate at LAUNCH time (the same resolution `teams add --device` runs, minus
|
|
323
|
+
* the fatal `die()` — a scheduling failure here is per-teammate, not per-add).
|
|
324
|
+
* Sets hostName/hostTarget/repoPath + persists, so the subsequent
|
|
325
|
+
* launchRemoteProcess dispatches over SSH. Mirrors the `add`-time pin path:
|
|
326
|
+
* resolve device → reject Windows (POSIX-only) → ssh target → ensure the repo
|
|
327
|
+
* is present on the host from the team's --repo (ensureRemoteRepo).
|
|
328
|
+
*/
|
|
329
|
+
private resolveScheduledPlacement;
|
|
330
|
+
/**
|
|
331
|
+
* Place an UNPINNED, non-cloud teammate onto the team pool via the cascade
|
|
332
|
+
* (least-loaded), if the team declares one. A no-op for a pinned teammate
|
|
333
|
+
* (hostName already set from `--device`), a cloud teammate, or a poolless team —
|
|
334
|
+
* leaving hostName null so the local spawn runs unchanged. Shared by spawn()
|
|
335
|
+
* (immediate add-launch) and startReady() (staged launch) so an unpinned pool
|
|
336
|
+
* teammate schedules identically no matter how it was fired.
|
|
337
|
+
*/
|
|
338
|
+
private maybeSchedulePlacement;
|
|
339
|
+
/**
|
|
340
|
+
* One-ssh-per-host batched liveness/exit pre-pass for a team's remote teammates.
|
|
341
|
+
* The supervisor calls this each wave BEFORE listByTask() so the per-teammate
|
|
342
|
+
* isProcessAlive()/readNewEvents() consume a cached snapshot instead of each
|
|
343
|
+
* issuing its own SSH handshake — avoiding N round-trips per wave at 10+ remote
|
|
344
|
+
* teammates. Groups by hostTarget and, for each host, checks every teammate's
|
|
345
|
+
* `.exit` + `kill -0` in a single ssh call over the shared ControlMaster socket.
|
|
346
|
+
*/
|
|
347
|
+
prefetchRemoteStatus(taskName: string): Promise<void>;
|
|
255
348
|
/**
|
|
256
349
|
* Fire any pending teammates in the given team whose `after` deps have all
|
|
257
350
|
* completed. Returns the list of teammates just launched. Repeatable:
|
|
@@ -266,6 +359,20 @@ export declare class AgentManager {
|
|
|
266
359
|
* exec path (src/lib/exec.ts). The team runner just supplies prompt + mode
|
|
267
360
|
* and reads stream-json events off stdout.
|
|
268
361
|
*/
|
|
362
|
+
/**
|
|
363
|
+
* Build the `agents run …` argv AFTER the `agents` binary — the flags + prompt
|
|
364
|
+
* scaffolding shared by the LOCAL launch (buildCommand, which prefixes
|
|
365
|
+
* process.execPath + the agents CLI path) and the REMOTE launch
|
|
366
|
+
* (launchRemoteProcess, which prefixes `agents` on the host via dispatch). Kept
|
|
367
|
+
* in one place so the PROMPT_SUFFIX / CLAUDE_PLAN_MODE_PREFIX scaffolding and the
|
|
368
|
+
* flag set can never drift between the two backends.
|
|
369
|
+
*
|
|
370
|
+
* `cwd` is intentionally NOT emitted here: the local path passes it as
|
|
371
|
+
* `--cwd`/`--add-dir` (below), while the remote path `cd`s into the host cwd
|
|
372
|
+
* before invoking `agents`. `sessionId` is likewise local-only (the remote run
|
|
373
|
+
* mints its own session on the host).
|
|
374
|
+
*/
|
|
375
|
+
private buildRunArgv;
|
|
269
376
|
private buildCommand;
|
|
270
377
|
get(agentId: string): Promise<AgentProcess | null>;
|
|
271
378
|
/**
|