@phnx-labs/agents-cli 1.22.103 → 1.22.104
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 +27 -0
- package/README.md +1 -1
- package/dist/commands/accounts.js +2 -2
- package/dist/commands/computer.d.ts +100 -79
- package/dist/commands/computer.js +290 -830
- package/dist/commands/setup-computer.js +20 -1
- package/dist/commands/setup-secrets.d.ts +2 -2
- package/dist/commands/setup-secrets.js +1 -1
- package/dist/commands/view.js +4 -6
- package/dist/lib/account-catalog.d.ts +22 -1
- package/dist/lib/account-catalog.js +72 -38
- package/dist/lib/accounting/usage.js +18 -14
- package/dist/lib/agent-spec/agents.d.ts +1 -0
- package/dist/lib/agent-spec/agents.js +1 -1
- package/dist/lib/browser/drivers/ssh.js +1 -1
- package/dist/lib/computer/context.d.ts +83 -0
- package/dist/lib/computer/context.js +91 -0
- package/dist/lib/computer/policy.d.ts +46 -0
- package/dist/lib/computer/policy.js +160 -0
- package/dist/lib/computer/record.d.ts +38 -0
- package/dist/lib/computer/record.js +86 -0
- package/dist/lib/computer/sessions-list.js +6 -6
- package/dist/lib/computer-client.d.ts +150 -0
- package/dist/lib/computer-client.js +222 -0
- package/dist/lib/exec.js +35 -1
- package/dist/lib/harness/adapters/claude.d.ts +37 -0
- package/dist/lib/harness/adapters/claude.js +69 -0
- package/dist/lib/helper-download.d.ts +1 -1
- package/dist/lib/helper-download.js +1 -1
- package/dist/lib/helper-versions.d.ts +9 -4
- package/dist/lib/helper-versions.js +8 -8
- package/dist/lib/installations/shims.js +8 -4
- package/dist/lib/menubar/download-menubar.d.ts +2 -1
- package/dist/lib/menubar/download-menubar.js +2 -1
- package/dist/lib/secrets-client.d.ts +3 -3
- package/dist/lib/secrets-client.js +15 -38
- package/dist/lib/session/db.js +1 -1
- package/dist/lib/sha256-asset.d.ts +2 -1
- package/dist/lib/sha256-asset.js +2 -1
- package/dist/lib/ssh-tunnel.d.ts +61 -0
- package/dist/lib/ssh-tunnel.js +105 -0
- package/dist/lib/summarizer/summarize.d.ts +2 -2
- package/dist/lib/summarizer/summarize.js +10 -3
- package/package.json +2 -3
- package/dist/commands/computer-actions.d.ts +0 -55
- package/dist/commands/computer-actions.js +0 -594
- package/dist/computer.d.ts +0 -2
- package/dist/computer.js +0 -7
- package/dist/lib/computer/actions.d.ts +0 -36
- package/dist/lib/computer/actions.js +0 -162
- package/dist/lib/computer/computer-rpc.d.ts +0 -39
- package/dist/lib/computer/computer-rpc.js +0 -447
- package/dist/lib/computer/des.d.ts +0 -1
- package/dist/lib/computer/des.js +0 -114
- package/dist/lib/computer/dispatch.d.ts +0 -10
- package/dist/lib/computer/dispatch.js +0 -133
- package/dist/lib/computer/download.d.ts +0 -54
- package/dist/lib/computer/download.js +0 -83
- package/dist/lib/computer/loop.d.ts +0 -62
- package/dist/lib/computer/loop.js +0 -98
- package/dist/lib/computer/model.d.ts +0 -44
- package/dist/lib/computer/model.js +0 -157
- package/dist/lib/computer/rfb-client.d.ts +0 -53
- package/dist/lib/computer/rfb-client.js +0 -562
- package/dist/lib/computer/ssh-tunnel.d.ts +0 -189
- package/dist/lib/computer/ssh-tunnel.js +0 -584
package/dist/lib/sha256-asset.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* sha256 helpers for verifying downloaded release assets.
|
|
3
3
|
*
|
|
4
4
|
* These live in their own LEAF module — importing only `node:crypto` and
|
|
5
|
-
* `node:fs` — on purpose. They used to sit in
|
|
5
|
+
* `node:fs` — on purpose. They used to sit in the computer subsystem's ssh-tunnel
|
|
6
|
+
* module (since extracted, PHNX-4075), whose
|
|
6
7
|
* own import graph reached `browser/drivers/ssh.ts` -> `browser/chrome.ts` ->
|
|
7
8
|
* the in-repo secrets engine's own keychain-helper downloader, which imported
|
|
8
9
|
* back into `helper-download.ts` while it was still evaluating — before
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ssh-tunnel.ts — the generic `ssh -L localPort:127.0.0.1:remotePort -N`
|
|
3
|
+
* port-forward, plus the fleet-device resolution that names its far end.
|
|
4
|
+
*
|
|
5
|
+
* WHY IT LIVES HERE. These primitives used to sit in `lib/computer/ssh-tunnel.ts`
|
|
6
|
+
* alongside the Windows computer-helper provisioning, because `agents computer
|
|
7
|
+
* --device` was their second caller after the browser CDP driver. The computer
|
|
8
|
+
* engine has since moved to the standalone `computer` CLI (PHNX-4075), so a
|
|
9
|
+
* generic tunnel parked in a deleted subsystem's directory would have gone with
|
|
10
|
+
* it and taken `agents browser`'s remote path down. It is fleet plumbing — the
|
|
11
|
+
* devices registry, the hardened ssh baseline, a local loopback port — and
|
|
12
|
+
* belongs in the fleet layer, not under a feature.
|
|
13
|
+
*
|
|
14
|
+
* Its callers are thin: `browser/drivers/ssh.ts` holds a tunnel for one CDP
|
|
15
|
+
* session, and `lib/computer/context.ts` uses `resolveRemoteDevice` alone —
|
|
16
|
+
* `agents computer --device` resolves the fleet name here and forwards the
|
|
17
|
+
* answer to the standalone engine, which opens and owns its own tunnel (it
|
|
18
|
+
* holds the helper token that tunnel's transport needs).
|
|
19
|
+
*/
|
|
20
|
+
import { type ChildProcess } from 'child_process';
|
|
21
|
+
import { type DeviceProfile } from './devices/registry.js';
|
|
22
|
+
export interface StartTunnelOptions {
|
|
23
|
+
extraSshArgs?: string[];
|
|
24
|
+
}
|
|
25
|
+
/** Build the ssh argv (after the `ssh` program name) for an `-L` tunnel. Pure.
|
|
26
|
+
*
|
|
27
|
+
* Composes the shared hardened baseline (`SSH_OPTS`) rather than re-listing it,
|
|
28
|
+
* so the tunnel inherits the same options — crucially the keepalive, which lets
|
|
29
|
+
* a dropped `-N` tunnel exit instead of lingering as a zombie on the laptop. */
|
|
30
|
+
export declare function buildTunnelArgs(user: string, host: string, localPort: number, remotePort: number, extraSshArgs?: string[]): string[];
|
|
31
|
+
/**
|
|
32
|
+
* Spawn `ssh -L localPort:127.0.0.1:remotePort -N user@host`.
|
|
33
|
+
*
|
|
34
|
+
* stderr is captured so a tunnel that dies inside 500ms rejects with the ssh
|
|
35
|
+
* error — the browser driver's original contract. The tunnel is held by this
|
|
36
|
+
* process for the lifetime of the session that opened it.
|
|
37
|
+
*/
|
|
38
|
+
export declare function startSSHTunnel(user: string, host: string, localPort: number, remotePort: number, opts?: StartTunnelOptions): Promise<ChildProcess>;
|
|
39
|
+
/** One registered device, resolved to everything an ssh invocation needs. */
|
|
40
|
+
export interface ResolvedRemoteDevice {
|
|
41
|
+
device: DeviceProfile;
|
|
42
|
+
target: string;
|
|
43
|
+
user: string;
|
|
44
|
+
host: string;
|
|
45
|
+
/** Per-device identity flags (`-i <key> -o IdentitiesOnly=yes`), possibly empty. */
|
|
46
|
+
identityArgs: string[];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Resolve a registered device to its ssh pieces, or throw a clear error.
|
|
50
|
+
*
|
|
51
|
+
* `expectPlatform` is how a caller keeps a platform requirement it used to
|
|
52
|
+
* hard-code: `agents computer --device` drives the Windows helper daemon, so it
|
|
53
|
+
* passes `'windows'` and gets the same refusal as before. Callers with no
|
|
54
|
+
* platform requirement (the browser driver) omit it. The gate is a parameter
|
|
55
|
+
* rather than a baked-in check so this module stays fleet-generic — a
|
|
56
|
+
* hard-coded `windows` here would be a feature rule in shared plumbing.
|
|
57
|
+
*/
|
|
58
|
+
export declare function resolveRemoteDevice(name: string, opts?: {
|
|
59
|
+
expectPlatform?: DeviceProfile['platform'];
|
|
60
|
+
forWhat?: string;
|
|
61
|
+
}): Promise<ResolvedRemoteDevice>;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ssh-tunnel.ts — the generic `ssh -L localPort:127.0.0.1:remotePort -N`
|
|
3
|
+
* port-forward, plus the fleet-device resolution that names its far end.
|
|
4
|
+
*
|
|
5
|
+
* WHY IT LIVES HERE. These primitives used to sit in `lib/computer/ssh-tunnel.ts`
|
|
6
|
+
* alongside the Windows computer-helper provisioning, because `agents computer
|
|
7
|
+
* --device` was their second caller after the browser CDP driver. The computer
|
|
8
|
+
* engine has since moved to the standalone `computer` CLI (PHNX-4075), so a
|
|
9
|
+
* generic tunnel parked in a deleted subsystem's directory would have gone with
|
|
10
|
+
* it and taken `agents browser`'s remote path down. It is fleet plumbing — the
|
|
11
|
+
* devices registry, the hardened ssh baseline, a local loopback port — and
|
|
12
|
+
* belongs in the fleet layer, not under a feature.
|
|
13
|
+
*
|
|
14
|
+
* Its callers are thin: `browser/drivers/ssh.ts` holds a tunnel for one CDP
|
|
15
|
+
* session, and `lib/computer/context.ts` uses `resolveRemoteDevice` alone —
|
|
16
|
+
* `agents computer --device` resolves the fleet name here and forwards the
|
|
17
|
+
* answer to the standalone engine, which opens and owns its own tunnel (it
|
|
18
|
+
* holds the helper token that tunnel's transport needs).
|
|
19
|
+
*/
|
|
20
|
+
import { spawn } from 'child_process';
|
|
21
|
+
import { SSH_OPTS, assertValidSshTarget } from './ssh-exec.js';
|
|
22
|
+
import { getDevice } from './devices/registry.js';
|
|
23
|
+
import { deviceIdentityArgs, sshTargetFor } from './devices/connect.js';
|
|
24
|
+
import { hostNameFor } from './devices/ssh-config.js';
|
|
25
|
+
/** Build the ssh argv (after the `ssh` program name) for an `-L` tunnel. Pure.
|
|
26
|
+
*
|
|
27
|
+
* Composes the shared hardened baseline (`SSH_OPTS`) rather than re-listing it,
|
|
28
|
+
* so the tunnel inherits the same options — crucially the keepalive, which lets
|
|
29
|
+
* a dropped `-N` tunnel exit instead of lingering as a zombie on the laptop. */
|
|
30
|
+
export function buildTunnelArgs(user, host, localPort, remotePort, extraSshArgs = []) {
|
|
31
|
+
return [
|
|
32
|
+
'-L',
|
|
33
|
+
`${localPort}:127.0.0.1:${remotePort}`,
|
|
34
|
+
`${user}@${host}`,
|
|
35
|
+
'-N',
|
|
36
|
+
...extraSshArgs,
|
|
37
|
+
...SSH_OPTS,
|
|
38
|
+
];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Spawn `ssh -L localPort:127.0.0.1:remotePort -N user@host`.
|
|
42
|
+
*
|
|
43
|
+
* stderr is captured so a tunnel that dies inside 500ms rejects with the ssh
|
|
44
|
+
* error — the browser driver's original contract. The tunnel is held by this
|
|
45
|
+
* process for the lifetime of the session that opened it.
|
|
46
|
+
*/
|
|
47
|
+
export function startSSHTunnel(user, host, localPort, remotePort, opts = {}) {
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
// `user`/`host` can originate from a browser ssh:// profile or a device
|
|
50
|
+
// record. buildTunnelArgs places `${user}@${host}` before `-N`/SSH_OPTS, so
|
|
51
|
+
// a `-`-leading user would be parsed as an ssh option flag (option
|
|
52
|
+
// injection). Validate at the spawn sink so every caller is covered; reject
|
|
53
|
+
// (rather than throw synchronously) to keep the Promise contract.
|
|
54
|
+
try {
|
|
55
|
+
assertValidSshTarget(`${user}@${host}`);
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
reject(err);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const args = buildTunnelArgs(user, host, localPort, remotePort, opts.extraSshArgs);
|
|
62
|
+
const tunnel = spawn('ssh', args, {
|
|
63
|
+
stdio: ['ignore', 'ignore', 'pipe'],
|
|
64
|
+
detached: false,
|
|
65
|
+
windowsHide: true,
|
|
66
|
+
});
|
|
67
|
+
let stderr = '';
|
|
68
|
+
tunnel.stderr?.on('data', (data) => {
|
|
69
|
+
stderr += data.toString();
|
|
70
|
+
});
|
|
71
|
+
tunnel.on('error', (err) => {
|
|
72
|
+
reject(new Error(`SSH tunnel failed: ${err.message}`));
|
|
73
|
+
});
|
|
74
|
+
setTimeout(() => {
|
|
75
|
+
if (tunnel.killed)
|
|
76
|
+
reject(new Error(`SSH tunnel died: ${stderr}`));
|
|
77
|
+
else
|
|
78
|
+
resolve(tunnel);
|
|
79
|
+
}, 500);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Resolve a registered device to its ssh pieces, or throw a clear error.
|
|
84
|
+
*
|
|
85
|
+
* `expectPlatform` is how a caller keeps a platform requirement it used to
|
|
86
|
+
* hard-code: `agents computer --device` drives the Windows helper daemon, so it
|
|
87
|
+
* passes `'windows'` and gets the same refusal as before. Callers with no
|
|
88
|
+
* platform requirement (the browser driver) omit it. The gate is a parameter
|
|
89
|
+
* rather than a baked-in check so this module stays fleet-generic — a
|
|
90
|
+
* hard-coded `windows` here would be a feature rule in shared plumbing.
|
|
91
|
+
*/
|
|
92
|
+
export async function resolveRemoteDevice(name, opts = {}) {
|
|
93
|
+
const device = await getDevice(name);
|
|
94
|
+
if (!device) {
|
|
95
|
+
throw new Error(`Unknown device '${name}'. Register it with \`agents devices add\` / \`agents devices sync\`, then retry.`);
|
|
96
|
+
}
|
|
97
|
+
if (opts.expectPlatform && device.platform !== opts.expectPlatform) {
|
|
98
|
+
const what = opts.forWhat ?? `this command`;
|
|
99
|
+
throw new Error(`Device '${name}' is ${device.platform}, not ${opts.expectPlatform}. ${what} needs a ${opts.expectPlatform} device.`);
|
|
100
|
+
}
|
|
101
|
+
const target = sshTargetFor(device); // validates address + injection guard
|
|
102
|
+
const host = hostNameFor(device); // sshTargetFor already threw if absent
|
|
103
|
+
const user = device.user || process.env.USER || 'Administrator';
|
|
104
|
+
return { device, target, user, host, identityArgs: deviceIdentityArgs(device) };
|
|
105
|
+
}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* A pure boundary: given the session's first user turn (the goal source) and its
|
|
5
5
|
* live progress (todos / plan / phase off the state engine), it asks a local
|
|
6
|
-
* Anthropic-wire endpoint (Ollama / vLLM / LiteLLM
|
|
7
|
-
*
|
|
6
|
+
* Anthropic-wire endpoint (Ollama / vLLM / LiteLLM) for a strict JSON
|
|
7
|
+
* `{goal, checkpoints, checklist}`
|
|
8
8
|
* and validates the shape. On ANY failure — network, non-2xx, non-JSON, wrong
|
|
9
9
|
* shape — it returns `undefined`, and the caller records `summaryState: 'skipped'`.
|
|
10
10
|
*
|
|
@@ -3,15 +3,22 @@
|
|
|
3
3
|
*
|
|
4
4
|
* A pure boundary: given the session's first user turn (the goal source) and its
|
|
5
5
|
* live progress (todos / plan / phase off the state engine), it asks a local
|
|
6
|
-
* Anthropic-wire endpoint (Ollama / vLLM / LiteLLM
|
|
7
|
-
*
|
|
6
|
+
* Anthropic-wire endpoint (Ollama / vLLM / LiteLLM) for a strict JSON
|
|
7
|
+
* `{goal, checkpoints, checklist}`
|
|
8
8
|
* and validates the shape. On ANY failure — network, non-2xx, non-JSON, wrong
|
|
9
9
|
* shape — it returns `undefined`, and the caller records `summaryState: 'skipped'`.
|
|
10
10
|
*
|
|
11
11
|
* NEVER called on the request path: only the background SessionSummarizerService
|
|
12
12
|
* invokes it, debounced and reader-gated.
|
|
13
13
|
*/
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* The `anthropic-version` header this request sends. Declared here because this
|
|
16
|
+
* is now its only caller: it used to be imported from the computer subsystem's
|
|
17
|
+
* model client, which left with the standalone `computer` engine (PHNX-4075).
|
|
18
|
+
* A shared constants module for one string used in one request would be more
|
|
19
|
+
* indirection than the string.
|
|
20
|
+
*/
|
|
21
|
+
const ANTHROPIC_VERSION = '2023-06-01';
|
|
15
22
|
const SYSTEM_PROMPT = [
|
|
16
23
|
'You summarize a coding-agent session for an operator dashboard.',
|
|
17
24
|
'Reply with ONLY a single JSON object, no prose and no code fences, of exactly this shape:',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phnx-labs/agents-cli",
|
|
3
|
-
"version": "1.22.
|
|
3
|
+
"version": "1.22.104",
|
|
4
4
|
"description": "One CLI for all your AI coding agents - versions, config, cloud dispatch, sessions, and teams (now with first-class Grok Build CLI support)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -17,8 +17,7 @@
|
|
|
17
17
|
"bin": {
|
|
18
18
|
"agents": "dist/index.js",
|
|
19
19
|
"ag": "dist/index.js",
|
|
20
|
-
"browser": "dist/browser.js"
|
|
21
|
-
"computer": "dist/computer.js"
|
|
20
|
+
"browser": "dist/browser.js"
|
|
22
21
|
},
|
|
23
22
|
"files": [
|
|
24
23
|
"dist/**/*.js",
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { type ComputerClient, type RPCResponse } from '../lib/computer/computer-rpc.js';
|
|
3
|
-
export { emitComputerAction, pickTarget, resolveTargetPidDecision, type AppInfo } from '../lib/computer/actions.js';
|
|
4
|
-
export declare function parseXY(s: string, flag: string): {
|
|
5
|
-
x: number;
|
|
6
|
-
y: number;
|
|
7
|
-
};
|
|
8
|
-
export declare function buildElementOrCoords(opts: {
|
|
9
|
-
id?: string;
|
|
10
|
-
x?: number;
|
|
11
|
-
y?: number;
|
|
12
|
-
}): {
|
|
13
|
-
ok: true;
|
|
14
|
-
params: Record<string, unknown>;
|
|
15
|
-
} | {
|
|
16
|
-
ok: false;
|
|
17
|
-
error: string;
|
|
18
|
-
};
|
|
19
|
-
export declare function buildRaiseParams(opts: {
|
|
20
|
-
windowId?: number;
|
|
21
|
-
title?: string;
|
|
22
|
-
}): Record<string, unknown>;
|
|
23
|
-
export declare const CHAR_DELAY_MIN_MS = 1;
|
|
24
|
-
export declare const CHAR_DELAY_MAX_MS = 250;
|
|
25
|
-
export declare function clampCharDelay(ms: number | undefined): number | undefined;
|
|
26
|
-
export declare function buildWaitParams(opts: {
|
|
27
|
-
duration?: number;
|
|
28
|
-
id?: string;
|
|
29
|
-
until?: string;
|
|
30
|
-
role?: string;
|
|
31
|
-
label?: string;
|
|
32
|
-
identifier?: string;
|
|
33
|
-
timeout?: number;
|
|
34
|
-
}): {
|
|
35
|
-
ok: true;
|
|
36
|
-
params: Record<string, unknown>;
|
|
37
|
-
} | {
|
|
38
|
-
ok: false;
|
|
39
|
-
error: string;
|
|
40
|
-
};
|
|
41
|
-
export declare function withClient<T>(fn: (client: ComputerClient) => Promise<T>): Promise<T>;
|
|
42
|
-
export declare function unwrap(r: RPCResponse): Record<string, unknown>;
|
|
43
|
-
export declare function focusStealNotes(opts: {
|
|
44
|
-
id?: string;
|
|
45
|
-
x?: number;
|
|
46
|
-
y?: number;
|
|
47
|
-
raise?: boolean;
|
|
48
|
-
}): string[];
|
|
49
|
-
export declare function shouldRaise(opts: {
|
|
50
|
-
id?: string;
|
|
51
|
-
raise?: boolean;
|
|
52
|
-
}): boolean;
|
|
53
|
-
export declare function appPathIsElectron(appPath: string | null, exists?: (p: string) => boolean): boolean;
|
|
54
|
-
export declare function electronWebviewTip(appLabel: string): string;
|
|
55
|
-
export declare function registerActionCommands(program: Command): void;
|