@phnx-labs/agents-cli 1.20.21 → 1.20.22
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 +14 -0
- package/dist/commands/cloud.js +16 -7
- package/dist/commands/menubar.d.ts +10 -0
- package/dist/commands/menubar.js +83 -0
- package/dist/commands/routines.js +34 -1
- package/dist/commands/secrets.d.ts +1 -1
- package/dist/commands/secrets.js +95 -38
- package/dist/index.js +28 -3
- package/dist/lib/agents.js +8 -0
- package/dist/lib/cloud/antigravity.d.ts +70 -0
- package/dist/lib/cloud/antigravity.js +196 -0
- package/dist/lib/cloud/factory.d.ts +68 -18
- package/dist/lib/cloud/factory.js +269 -26
- package/dist/lib/cloud/registry.d.ts +18 -2
- package/dist/lib/cloud/registry.js +28 -4
- package/dist/lib/cloud/types.d.ts +32 -2
- package/dist/lib/menubar/install-menubar.d.ts +57 -0
- package/dist/lib/menubar/install-menubar.js +291 -0
- package/dist/lib/secrets/agent.d.ts +9 -1
- package/dist/lib/secrets/agent.js +91 -10
- package/dist/lib/secrets/bundles.d.ts +19 -12
- package/dist/lib/secrets/bundles.js +22 -14
- package/dist/lib/self-update.d.ts +34 -0
- package/dist/lib/self-update.js +63 -2
- package/dist/lib/types.d.ts +8 -0
- package/dist/lib/version.d.ts +11 -0
- package/dist/lib/version.js +20 -0
- package/package.json +3 -2
- package/scripts/postinstall.js +35 -0
|
@@ -12,6 +12,31 @@
|
|
|
12
12
|
* to PATH resolution.
|
|
13
13
|
*/
|
|
14
14
|
export declare const NPM_PACKAGE_NAME = "@phnx-labs/agents-cli";
|
|
15
|
+
export type PackageManager = 'npm' | 'bun';
|
|
16
|
+
/**
|
|
17
|
+
* The directory bun installs global packages into:
|
|
18
|
+
* <BUN_INSTALL>/install/global (BUN_INSTALL defaults to ~/.bun)
|
|
19
|
+
*
|
|
20
|
+
* A globally-installed scoped package then lives at
|
|
21
|
+
* `<bunGlobalDir>/node_modules/@phnx-labs/agents-cli` — note there is NO `lib`
|
|
22
|
+
* segment, unlike npm's POSIX layout. That single difference is why an
|
|
23
|
+
* npm-based upgrade silently misses a bun install (see deriveGlobalPrefix).
|
|
24
|
+
*/
|
|
25
|
+
export declare function bunGlobalDir(): string;
|
|
26
|
+
/**
|
|
27
|
+
* Identify which package manager owns the install at `packageRoot`, so the
|
|
28
|
+
* upgrade can shell out to the one that actually replaces this copy.
|
|
29
|
+
*
|
|
30
|
+
* bun lays a global package out as `<bunGlobalDir>/node_modules/<scoped pkg>`,
|
|
31
|
+
* so the prefix (the parent of `node_modules`) is the bun global dir itself.
|
|
32
|
+
* Everything else — npm's `<prefix>/lib/node_modules` and the Windows
|
|
33
|
+
* `<prefix>/node_modules` — is treated as npm.
|
|
34
|
+
*
|
|
35
|
+
* Detection is path-based (no subprocess): it matches the resolved bun global
|
|
36
|
+
* dir from BUN_INSTALL/$HOME, and falls back to the structural `.bun/install/
|
|
37
|
+
* global` tail for a relocated BUN_INSTALL not exported into this process.
|
|
38
|
+
*/
|
|
39
|
+
export declare function detectPackageManager(packageRoot: string): PackageManager;
|
|
15
40
|
export interface UpdateCheckCache {
|
|
16
41
|
lastCheck: number;
|
|
17
42
|
latestVersion: string;
|
|
@@ -49,6 +74,15 @@ export declare function deriveGlobalPrefix(packageRoot: string): string;
|
|
|
49
74
|
* refreshAliasShims().
|
|
50
75
|
*/
|
|
51
76
|
export declare function installPackageIntoPrefix(spec: string, prefix: string): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Install `spec` into bun's global store with `bun add -g`. bun writes to
|
|
79
|
+
* `<bunGlobalDir>/node_modules/<pkg>`, which is exactly the running package
|
|
80
|
+
* root for a bun install — so verifyInstalledVersion() sees the new version
|
|
81
|
+
* in place. bun skips untrusted lifecycle scripts, so the caller refreshes
|
|
82
|
+
* alias shims afterwards via refreshAliasShims() rather than relying on the
|
|
83
|
+
* package's postinstall hook.
|
|
84
|
+
*/
|
|
85
|
+
export declare function installPackageWithBun(spec: string): Promise<void>;
|
|
52
86
|
/** Read the version field of the package.json at `packageRoot`, fresh from disk. */
|
|
53
87
|
export declare function readInstalledVersion(packageRoot: string): string;
|
|
54
88
|
/**
|
package/dist/lib/self-update.js
CHANGED
|
@@ -12,10 +12,55 @@
|
|
|
12
12
|
* to PATH resolution.
|
|
13
13
|
*/
|
|
14
14
|
import * as fs from 'fs';
|
|
15
|
+
import * as os from 'os';
|
|
15
16
|
import * as path from 'path';
|
|
16
17
|
import { spawnSync } from 'child_process';
|
|
17
18
|
import { compareVersions } from './versions.js';
|
|
18
19
|
export const NPM_PACKAGE_NAME = '@phnx-labs/agents-cli';
|
|
20
|
+
/**
|
|
21
|
+
* The directory bun installs global packages into:
|
|
22
|
+
* <BUN_INSTALL>/install/global (BUN_INSTALL defaults to ~/.bun)
|
|
23
|
+
*
|
|
24
|
+
* A globally-installed scoped package then lives at
|
|
25
|
+
* `<bunGlobalDir>/node_modules/@phnx-labs/agents-cli` — note there is NO `lib`
|
|
26
|
+
* segment, unlike npm's POSIX layout. That single difference is why an
|
|
27
|
+
* npm-based upgrade silently misses a bun install (see deriveGlobalPrefix).
|
|
28
|
+
*/
|
|
29
|
+
export function bunGlobalDir() {
|
|
30
|
+
const bunInstall = process.env.BUN_INSTALL || path.join(os.homedir(), '.bun');
|
|
31
|
+
return path.join(bunInstall, 'install', 'global');
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Identify which package manager owns the install at `packageRoot`, so the
|
|
35
|
+
* upgrade can shell out to the one that actually replaces this copy.
|
|
36
|
+
*
|
|
37
|
+
* bun lays a global package out as `<bunGlobalDir>/node_modules/<scoped pkg>`,
|
|
38
|
+
* so the prefix (the parent of `node_modules`) is the bun global dir itself.
|
|
39
|
+
* Everything else — npm's `<prefix>/lib/node_modules` and the Windows
|
|
40
|
+
* `<prefix>/node_modules` — is treated as npm.
|
|
41
|
+
*
|
|
42
|
+
* Detection is path-based (no subprocess): it matches the resolved bun global
|
|
43
|
+
* dir from BUN_INSTALL/$HOME, and falls back to the structural `.bun/install/
|
|
44
|
+
* global` tail for a relocated BUN_INSTALL not exported into this process.
|
|
45
|
+
*/
|
|
46
|
+
export function detectPackageManager(packageRoot) {
|
|
47
|
+
const resolved = path.resolve(packageRoot);
|
|
48
|
+
const prefix = path.dirname(path.dirname(path.dirname(resolved))); // strip <scope>/<pkg>/node_modules
|
|
49
|
+
if (prefix === path.resolve(bunGlobalDir()))
|
|
50
|
+
return 'bun';
|
|
51
|
+
const parts = prefix.split(path.sep);
|
|
52
|
+
const n = parts.length;
|
|
53
|
+
if (n >= 3 && parts[n - 1] === 'global' && parts[n - 2] === 'install' && parts[n - 3] === '.bun') {
|
|
54
|
+
return 'bun';
|
|
55
|
+
}
|
|
56
|
+
return 'npm';
|
|
57
|
+
}
|
|
58
|
+
/** The shell command a user can run by hand to reproduce the upgrade for `manager`. */
|
|
59
|
+
function manualInstallHint(manager, packageRoot, spec) {
|
|
60
|
+
if (manager === 'bun')
|
|
61
|
+
return `bun add -g ${spec}`;
|
|
62
|
+
return `npm install -g --prefix ${deriveGlobalPrefix(packageRoot)} ${spec}`;
|
|
63
|
+
}
|
|
19
64
|
/** Read the cached update-check state from disk. Returns null if the file is missing or corrupt. */
|
|
20
65
|
export function readUpdateCache(file) {
|
|
21
66
|
try {
|
|
@@ -102,6 +147,20 @@ export async function installPackageIntoPrefix(spec, prefix) {
|
|
|
102
147
|
const execFileAsync = promisify(execFile);
|
|
103
148
|
await execFileAsync('npm', ['install', '-g', '--prefix', prefix, spec, '--ignore-scripts']);
|
|
104
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Install `spec` into bun's global store with `bun add -g`. bun writes to
|
|
152
|
+
* `<bunGlobalDir>/node_modules/<pkg>`, which is exactly the running package
|
|
153
|
+
* root for a bun install — so verifyInstalledVersion() sees the new version
|
|
154
|
+
* in place. bun skips untrusted lifecycle scripts, so the caller refreshes
|
|
155
|
+
* alias shims afterwards via refreshAliasShims() rather than relying on the
|
|
156
|
+
* package's postinstall hook.
|
|
157
|
+
*/
|
|
158
|
+
export async function installPackageWithBun(spec) {
|
|
159
|
+
const { execFile } = await import('child_process');
|
|
160
|
+
const { promisify } = await import('util');
|
|
161
|
+
const execFileAsync = promisify(execFile);
|
|
162
|
+
await execFileAsync('bun', ['add', '-g', spec]);
|
|
163
|
+
}
|
|
105
164
|
/** Read the version field of the package.json at `packageRoot`, fresh from disk. */
|
|
106
165
|
export function readInstalledVersion(packageRoot) {
|
|
107
166
|
return JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf-8')).version;
|
|
@@ -113,8 +172,10 @@ export function readInstalledVersion(packageRoot) {
|
|
|
113
172
|
export function verifyInstalledVersion(packageRoot, expectedVersion) {
|
|
114
173
|
const actual = readInstalledVersion(packageRoot);
|
|
115
174
|
if (actual !== expectedVersion) {
|
|
116
|
-
|
|
117
|
-
|
|
175
|
+
const manager = detectPackageManager(packageRoot);
|
|
176
|
+
const hint = manualInstallHint(manager, packageRoot, `${NPM_PACKAGE_NAME}@${expectedVersion}`);
|
|
177
|
+
throw new Error(`the package manager reported success but ${packageRoot} is still ${actual} (expected ${expectedVersion}). ` +
|
|
178
|
+
`Run manually: ${hint}`);
|
|
118
179
|
}
|
|
119
180
|
}
|
|
120
181
|
/**
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* configuration schemas, resource tracking, registry types, and permission
|
|
6
6
|
* formats for each supported agent.
|
|
7
7
|
*/
|
|
8
|
+
import type { CloudProviderId } from './cloud/types.js';
|
|
8
9
|
/** Unique identifier for a supported AI coding agent. */
|
|
9
10
|
export type AgentId = 'claude' | 'codex' | 'gemini' | 'cursor' | 'opencode' | 'openclaw' | 'copilot' | 'amp' | 'kiro' | 'goose' | 'roo' | 'antigravity' | 'grok' | 'kimi' | 'droid';
|
|
10
11
|
/** How `agents run <agent>` chooses an installed version when none is pinned. */
|
|
@@ -83,6 +84,13 @@ export interface AgentConfig {
|
|
|
83
84
|
variableSyntax: string;
|
|
84
85
|
supportsHooks: boolean;
|
|
85
86
|
nativeAgentsSkillsDir?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* This agent's *own* cloud backend. `agents cloud run --agent <id>` routes
|
|
89
|
+
* here when no `--provider` is given (precedence: --provider > this >
|
|
90
|
+
* cloud.default_provider > rush). Undefined means the agent has no native
|
|
91
|
+
* cloud and falls back to the configured default.
|
|
92
|
+
*/
|
|
93
|
+
cloudProvider?: CloudProviderId;
|
|
86
94
|
capabilities: {
|
|
87
95
|
hooks: Capability;
|
|
88
96
|
mcp: Capability;
|
package/dist/lib/version.d.ts
CHANGED
|
@@ -5,3 +5,14 @@
|
|
|
5
5
|
* get stale behavior without this check.
|
|
6
6
|
*/
|
|
7
7
|
export declare function getCliVersion(): string;
|
|
8
|
+
/**
|
|
9
|
+
* Read the version from package.json on disk every call, bypassing the cache.
|
|
10
|
+
*
|
|
11
|
+
* `getCliVersion()` memoizes the version a long-running process *started* with.
|
|
12
|
+
* After `npm i -g` overwrites the install in place, the on-disk package.json
|
|
13
|
+
* changes but the running process keeps its old in-memory code. Comparing this
|
|
14
|
+
* fresh read against the cached startup value is how a daemon/broker detects it
|
|
15
|
+
* is now stale and should reload onto the new code (self-healing). Returns
|
|
16
|
+
* 'unknown' on any error.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getCliVersionFresh(): string;
|
package/dist/lib/version.js
CHANGED
|
@@ -23,3 +23,23 @@ export function getCliVersion() {
|
|
|
23
23
|
}
|
|
24
24
|
return cached;
|
|
25
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Read the version from package.json on disk every call, bypassing the cache.
|
|
28
|
+
*
|
|
29
|
+
* `getCliVersion()` memoizes the version a long-running process *started* with.
|
|
30
|
+
* After `npm i -g` overwrites the install in place, the on-disk package.json
|
|
31
|
+
* changes but the running process keeps its old in-memory code. Comparing this
|
|
32
|
+
* fresh read against the cached startup value is how a daemon/broker detects it
|
|
33
|
+
* is now stale and should reload onto the new code (self-healing). Returns
|
|
34
|
+
* 'unknown' on any error.
|
|
35
|
+
*/
|
|
36
|
+
export function getCliVersionFresh() {
|
|
37
|
+
try {
|
|
38
|
+
const pkgPath = path.join(__dirname, '..', '..', 'package.json');
|
|
39
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
40
|
+
return String(pkg.version || 'unknown');
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return 'unknown';
|
|
44
|
+
}
|
|
45
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phnx-labs/agents-cli",
|
|
3
|
-
"version": "1.20.
|
|
3
|
+
"version": "1.20.22",
|
|
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",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"dist/**/*.d.ts",
|
|
26
26
|
"dist/**/*.json",
|
|
27
27
|
"dist/lib/secrets/Agents CLI.app/**",
|
|
28
|
+
"dist/lib/menubar/MenubarHelper.app/**",
|
|
28
29
|
"scripts/postinstall.js",
|
|
29
30
|
"scripts/install-helper.js",
|
|
30
31
|
"CHANGELOG.md",
|
|
@@ -43,7 +44,7 @@
|
|
|
43
44
|
"url": "https://github.com/phnx-labs/agents-cli/issues"
|
|
44
45
|
},
|
|
45
46
|
"scripts": {
|
|
46
|
-
"build": "tsc && rm -rf 'dist/lib/secrets/AgentsKeychain.app' 'dist/lib/secrets/Agents CLI.app' && ([ \"$(uname)\" = \"Darwin\" ] && cp -R 'bin/Agents CLI.app' 'dist/lib/secrets/Agents CLI.app' || true)",
|
|
47
|
+
"build": "tsc && rm -rf 'dist/lib/secrets/AgentsKeychain.app' 'dist/lib/secrets/Agents CLI.app' 'dist/lib/menubar/MenubarHelper.app' && ([ \"$(uname)\" = \"Darwin\" ] && cp -R 'bin/Agents CLI.app' 'dist/lib/secrets/Agents CLI.app' || true) && ([ \"$(uname)\" = \"Darwin\" ] && [ -d 'bin/MenubarHelper.app' ] && mkdir -p 'dist/lib/menubar' && cp -R 'bin/MenubarHelper.app' 'dist/lib/menubar/MenubarHelper.app' || true)",
|
|
47
48
|
"prepack": "scripts/verify-keychain-helper.sh",
|
|
48
49
|
"postinstall": "node scripts/postinstall.js",
|
|
49
50
|
"dev": "tsx src/index.ts",
|
package/scripts/postinstall.js
CHANGED
|
@@ -239,6 +239,8 @@ To enable version-aware shims, add this to your shell config:
|
|
|
239
239
|
console.log(` Installed shorthands: ${written.join(', ')}`);
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
+
await healLongRunningProcesses();
|
|
243
|
+
|
|
242
244
|
const version = getVersion();
|
|
243
245
|
if (version) {
|
|
244
246
|
const section = getChangelogSection(version);
|
|
@@ -250,6 +252,39 @@ To enable version-aware shims, add this to your shell config:
|
|
|
250
252
|
}
|
|
251
253
|
}
|
|
252
254
|
|
|
255
|
+
/**
|
|
256
|
+
* Self-heal long-running processes onto the just-installed code (macOS).
|
|
257
|
+
*
|
|
258
|
+
* The root cause behind stale-behavior bugs is a daemon/broker that keeps
|
|
259
|
+
* running pre-upgrade code for days. An in-place `npm i -g` swaps the files but
|
|
260
|
+
* not the running processes — so we bounce them here, the one moment we know the
|
|
261
|
+
* code just changed. Best-effort and non-fatal: a failure must never break the
|
|
262
|
+
* install. Skipped in CI and when AGENTS_NO_HEAL=1.
|
|
263
|
+
*/
|
|
264
|
+
async function healLongRunningProcesses() {
|
|
265
|
+
if (process.platform !== 'darwin') return;
|
|
266
|
+
if (process.env.CI || process.env.AGENTS_NO_HEAL === '1') return;
|
|
267
|
+
// Routines daemon: restart so it reloads new code (e.g. picks up keychain
|
|
268
|
+
// read-memoization / broker fast-path that a stale daemon wouldn't have).
|
|
269
|
+
try {
|
|
270
|
+
const d = await import('../dist/lib/daemon.js');
|
|
271
|
+
if (d.isDaemonRunning?.()) {
|
|
272
|
+
d.stopDaemon?.();
|
|
273
|
+
d.startDaemon?.();
|
|
274
|
+
console.log(' Restarted the routines daemon onto this version.');
|
|
275
|
+
}
|
|
276
|
+
} catch { /* best effort */ }
|
|
277
|
+
// Persistent secrets-agent broker: kickstart so launchd relaunches it on the
|
|
278
|
+
// new code. No-op if the service isn't installed; never blocks.
|
|
279
|
+
try {
|
|
280
|
+
const a = await import('../dist/lib/secrets/agent.js');
|
|
281
|
+
if (a.secretsAgentServiceInstalled?.()) {
|
|
282
|
+
a.kickstartSecretsAgentService?.();
|
|
283
|
+
console.log(' Reloaded the secrets-agent service onto this version.');
|
|
284
|
+
}
|
|
285
|
+
} catch { /* best effort */ }
|
|
286
|
+
}
|
|
287
|
+
|
|
253
288
|
main().catch((err) => {
|
|
254
289
|
console.error(err);
|
|
255
290
|
process.exit(0);
|