@phnx-labs/agents-cli 1.20.26 → 1.20.28
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 +29 -0
- package/dist/commands/doctor.d.ts +5 -2
- package/dist/commands/doctor.js +182 -30
- package/dist/commands/exec.d.ts +1 -1
- package/dist/commands/exec.js +177 -6
- package/dist/commands/hosts.d.ts +11 -0
- package/dist/commands/hosts.js +229 -0
- package/dist/commands/repo.d.ts +29 -0
- package/dist/commands/repo.js +174 -38
- package/dist/commands/secrets.d.ts +2 -7
- package/dist/commands/secrets.js +15 -23
- package/dist/commands/sessions.d.ts +2 -0
- package/dist/commands/sessions.js +27 -25
- package/dist/commands/sync.d.ts +2 -0
- package/dist/commands/sync.js +22 -5
- package/dist/commands/view.js +27 -11
- package/dist/index.js +4 -13
- package/dist/lib/agent-spec.d.ts +36 -0
- package/dist/lib/agent-spec.js +157 -0
- package/dist/lib/agents.d.ts +1 -0
- package/dist/lib/agents.js +45 -4
- package/dist/lib/browser/drivers/ssh.d.ts +47 -2
- package/dist/lib/browser/drivers/ssh.js +113 -24
- package/dist/lib/browser/profiles.js +28 -1
- package/dist/lib/browser/runtime-state.js +28 -8
- package/dist/lib/browser/types.d.ts +10 -1
- package/dist/lib/cli-resources.js +10 -1
- package/dist/lib/daemon.js +32 -0
- package/dist/lib/doctor-diff.d.ts +19 -0
- package/dist/lib/doctor-diff.js +107 -15
- package/dist/lib/exec.d.ts +27 -0
- package/dist/lib/exec.js +62 -19
- package/dist/lib/heal.d.ts +107 -0
- package/dist/lib/heal.js +279 -0
- package/dist/lib/hooks.d.ts +17 -0
- package/dist/lib/hooks.js +127 -3
- package/dist/lib/hosts/dispatch.d.ts +26 -0
- package/dist/lib/hosts/dispatch.js +71 -0
- package/dist/lib/hosts/progress.d.ts +21 -0
- package/dist/lib/hosts/progress.js +49 -0
- package/dist/lib/hosts/providers/local.d.ts +17 -0
- package/dist/lib/hosts/providers/local.js +81 -0
- package/dist/lib/hosts/ready.d.ts +37 -0
- package/dist/lib/hosts/ready.js +88 -0
- package/dist/lib/hosts/registry.d.ts +22 -0
- package/dist/lib/hosts/registry.js +65 -0
- package/dist/lib/hosts/ssh-config.d.ts +37 -0
- package/dist/lib/hosts/ssh-config.js +157 -0
- package/dist/lib/hosts/tasks.d.ts +32 -0
- package/dist/lib/hosts/tasks.js +58 -0
- package/dist/lib/hosts/types.d.ts +51 -0
- package/dist/lib/hosts/types.js +21 -0
- package/dist/lib/loop.d.ts +9 -0
- package/dist/lib/loop.js +13 -1
- package/dist/lib/mcp.js +12 -3
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/migrate.js +9 -5
- package/dist/lib/platform/exec.d.ts +10 -0
- package/dist/lib/platform/exec.js +17 -0
- package/dist/lib/platform/index.d.ts +1 -0
- package/dist/lib/platform/index.js +1 -0
- package/dist/lib/platform/links.d.ts +15 -0
- package/dist/lib/platform/links.js +42 -0
- package/dist/lib/platform/paths.d.ts +18 -0
- package/dist/lib/platform/paths.js +22 -0
- package/dist/lib/platform/posixpath.d.ts +28 -0
- package/dist/lib/platform/posixpath.js +153 -0
- package/dist/lib/plugin-marketplace.d.ts +18 -0
- package/dist/lib/plugin-marketplace.js +67 -1
- package/dist/lib/plugins.d.ts +33 -1
- package/dist/lib/plugins.js +56 -11
- package/dist/lib/project-launch.js +6 -3
- package/dist/lib/sandbox.js +5 -2
- package/dist/lib/self-update.js +7 -2
- package/dist/lib/session/db.d.ts +23 -0
- package/dist/lib/session/db.js +76 -1
- package/dist/lib/session/discover.d.ts +26 -0
- package/dist/lib/session/discover.js +75 -4
- package/dist/lib/session/relative-time.d.ts +7 -0
- package/dist/lib/session/relative-time.js +28 -0
- package/dist/lib/session/remote.d.ts +61 -0
- package/dist/lib/session/remote.js +221 -0
- package/dist/lib/ssh-exec.d.ts +45 -0
- package/dist/lib/ssh-exec.js +61 -0
- package/dist/lib/staleness/detectors/commands.js +7 -6
- package/dist/lib/staleness/writers/commands.js +7 -12
- package/dist/lib/startup/command-registry.d.ts +1 -0
- package/dist/lib/startup/command-registry.js +2 -0
- package/dist/lib/startup/dev-build.d.ts +22 -0
- package/dist/lib/startup/dev-build.js +41 -0
- package/dist/lib/types.d.ts +28 -0
- package/dist/lib/versions.d.ts +9 -3
- package/dist/lib/versions.js +43 -7
- package/package.json +3 -3
- package/scripts/postinstall.js +62 -0
package/dist/lib/versions.js
CHANGED
|
@@ -898,14 +898,36 @@ export async function isOldestInstalled(agent) {
|
|
|
898
898
|
}
|
|
899
899
|
return { installed: isVersionInstalled(agent, oldestVersion), version: oldestVersion };
|
|
900
900
|
}
|
|
901
|
+
// Per-process cache for listInstalledVersions. The agent's versions dir mtime
|
|
902
|
+
// changes whenever a version dir is added or removed (install/remove), so a
|
|
903
|
+
// stamp match means the installed set is unchanged and we skip the readdir +
|
|
904
|
+
// N binary stats. Mirrors the readMeta() cache in state.ts. Hot path:
|
|
905
|
+
// resolveAgentTargets and every enumerate-style consumer hit this.
|
|
906
|
+
const installedVersionsCache = new Map();
|
|
907
|
+
/** Drop the installed-versions cache (call after install/remove mutations). */
|
|
908
|
+
export function invalidateInstalledVersionsCache(agent) {
|
|
909
|
+
if (agent)
|
|
910
|
+
installedVersionsCache.delete(agent);
|
|
911
|
+
else
|
|
912
|
+
installedVersionsCache.clear();
|
|
913
|
+
}
|
|
901
914
|
/**
|
|
902
|
-
* List all installed versions for an agent.
|
|
915
|
+
* List all installed versions for an agent (cached by versions-dir mtime).
|
|
903
916
|
*/
|
|
904
917
|
export function listInstalledVersions(agent) {
|
|
905
918
|
const agentVersionsDir = path.join(getVersionsDir(), agent);
|
|
906
|
-
|
|
919
|
+
let stamp;
|
|
920
|
+
try {
|
|
921
|
+
stamp = fs.statSync(agentVersionsDir).mtimeMs;
|
|
922
|
+
}
|
|
923
|
+
catch {
|
|
924
|
+
installedVersionsCache.set(agent, { stamp: 0, versions: [] });
|
|
907
925
|
return [];
|
|
908
926
|
}
|
|
927
|
+
const cached = installedVersionsCache.get(agent);
|
|
928
|
+
if (cached && cached.stamp === stamp) {
|
|
929
|
+
return cached.versions;
|
|
930
|
+
}
|
|
909
931
|
const entries = fs.readdirSync(agentVersionsDir, { withFileTypes: true });
|
|
910
932
|
const versions = [];
|
|
911
933
|
for (const entry of entries) {
|
|
@@ -916,7 +938,9 @@ export function listInstalledVersions(agent) {
|
|
|
916
938
|
}
|
|
917
939
|
}
|
|
918
940
|
}
|
|
919
|
-
|
|
941
|
+
versions.sort(compareVersions);
|
|
942
|
+
installedVersionsCache.set(agent, { stamp, versions });
|
|
943
|
+
return versions;
|
|
920
944
|
}
|
|
921
945
|
/**
|
|
922
946
|
* List every version directory for an agent, including ones missing the
|
|
@@ -1339,19 +1363,23 @@ export function resolveVersion(agent, projectPath) {
|
|
|
1339
1363
|
/**
|
|
1340
1364
|
* Normalize a user-supplied @version token across CLI subcommands.
|
|
1341
1365
|
*
|
|
1342
|
-
* undefined / "" / "default"
|
|
1366
|
+
* undefined / "" / "default" / "pinned" -> undefined (caller falls back to project pin or global default)
|
|
1367
|
+
* "any" -> undefined (caller imposes no version constraint — e.g. resume across any version)
|
|
1343
1368
|
* "latest" -> highest installed version (process.exit if none installed)
|
|
1344
1369
|
* "oldest" -> lowest installed version (process.exit if none installed)
|
|
1345
1370
|
* "x.y.z" (installed) -> "x.y.z"
|
|
1346
1371
|
* "x.y.z" (not installed) -> process.exit with installed-list hint
|
|
1347
1372
|
*
|
|
1373
|
+
* `pinned` is a synonym for `default`: both name the project pin / global
|
|
1374
|
+
* default, which the caller resolves.
|
|
1375
|
+
*
|
|
1348
1376
|
* Use this anywhere the user can type `agents <cmd> claude@<token>` to keep the
|
|
1349
1377
|
* vocabulary consistent. Subcommands with different semantics for `latest`
|
|
1350
1378
|
* (install/remove/use, where `latest` means npm-latest) keep their existing
|
|
1351
1379
|
* parsing.
|
|
1352
1380
|
*/
|
|
1353
1381
|
export function resolveVersionAlias(agent, raw) {
|
|
1354
|
-
if (!raw || raw === 'default')
|
|
1382
|
+
if (!raw || raw === 'default' || raw === 'pinned' || raw === 'any')
|
|
1355
1383
|
return undefined;
|
|
1356
1384
|
if (raw === 'latest' || raw === 'oldest') {
|
|
1357
1385
|
const installed = listInstalledVersions(agent);
|
|
@@ -1375,12 +1403,12 @@ export function resolveVersionAlias(agent, raw) {
|
|
|
1375
1403
|
}
|
|
1376
1404
|
/**
|
|
1377
1405
|
* Loose variant of resolveVersionAlias for record-filter contexts (sessions,
|
|
1378
|
-
* team history). Same `default`/`latest`/`oldest` semantics, but explicit
|
|
1406
|
+
* team history). Same `default`/`pinned`/`latest`/`oldest` semantics, but explicit
|
|
1379
1407
|
* versions pass through unchanged so historical records of uninstalled versions
|
|
1380
1408
|
* remain queryable.
|
|
1381
1409
|
*/
|
|
1382
1410
|
export function resolveVersionAliasLoose(agent, raw) {
|
|
1383
|
-
if (!raw || raw === 'default')
|
|
1411
|
+
if (!raw || raw === 'default' || raw === 'pinned' || raw === 'any')
|
|
1384
1412
|
return undefined;
|
|
1385
1413
|
if (raw === 'latest' || raw === 'oldest') {
|
|
1386
1414
|
const installed = listInstalledVersions(agent);
|
|
@@ -1831,7 +1859,15 @@ export function syncResourcesToVersion(agent, version, selection, options = {})
|
|
|
1831
1859
|
// dot-dirs to keep plugin-managed subtrees (.plugins/, .promptcuts) intact.
|
|
1832
1860
|
const skillsTargetSweep = path.join(agentDir, 'skills');
|
|
1833
1861
|
if (!userPassedSelection && fs.existsSync(skillsTargetSweep) && !fs.lstatSync(skillsTargetSweep).isSymbolicLink()) {
|
|
1862
|
+
// Trust real skills AND command-skills: when commandsAsSkills, the
|
|
1863
|
+
// commands writer (above) materialized each command as a skill dir under
|
|
1864
|
+
// skills/. Those names are not in skillsToSync, so without this they'd be
|
|
1865
|
+
// swept as orphans — silently deleting every converted command (e.g.
|
|
1866
|
+
// /recap on kimi/grok).
|
|
1834
1867
|
const trustedSkills = new Set(skillsToSync);
|
|
1868
|
+
if (commandsAsSkills)
|
|
1869
|
+
for (const cmd of commandsToSync)
|
|
1870
|
+
trustedSkills.add(cmd);
|
|
1835
1871
|
for (const entry of fs.readdirSync(skillsTargetSweep, { withFileTypes: true })) {
|
|
1836
1872
|
if (!entry.isDirectory() || entry.name.startsWith('.'))
|
|
1837
1873
|
continue;
|
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.28",
|
|
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",
|
|
@@ -92,10 +92,10 @@
|
|
|
92
92
|
"diff": "9.0.0",
|
|
93
93
|
"marked": "15.0.12",
|
|
94
94
|
"marked-terminal": "7.3.0",
|
|
95
|
-
"ora": "9.4.
|
|
95
|
+
"ora": "9.4.1",
|
|
96
96
|
"proper-lockfile": "4.1.2",
|
|
97
97
|
"simple-git": "3.36.0",
|
|
98
|
-
"smol-toml": "1.
|
|
98
|
+
"smol-toml": "1.7.0",
|
|
99
99
|
"yaml": "2.9.0"
|
|
100
100
|
},
|
|
101
101
|
"devDependencies": {
|
package/scripts/postinstall.js
CHANGED
|
@@ -239,6 +239,10 @@ To enable version-aware shims, add this to your shell config:
|
|
|
239
239
|
console.log(` Installed shorthands: ${written.join(', ')}`);
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
+
if (process.platform !== 'win32') {
|
|
243
|
+
await ensureAgentsResolvablePosix();
|
|
244
|
+
}
|
|
245
|
+
|
|
242
246
|
await healLongRunningProcesses();
|
|
243
247
|
|
|
244
248
|
const version = getVersion();
|
|
@@ -252,6 +256,64 @@ To enable version-aware shims, add this to your shell config:
|
|
|
252
256
|
}
|
|
253
257
|
}
|
|
254
258
|
|
|
259
|
+
/**
|
|
260
|
+
* Make the `agents` command resolvable in a *login* shell on POSIX.
|
|
261
|
+
*
|
|
262
|
+
* `agents`/`ag` reach PATH only through npm's bin symlink in the npm global-bin
|
|
263
|
+
* dir. Under nvm (and other per-user node prefixes) that dir is missing from a
|
|
264
|
+
* non-interactive login shell's PATH, so `bash -lc 'agents …'` fails with
|
|
265
|
+
* command-not-found — which breaks `agents secrets export --host` (it runs
|
|
266
|
+
* `bash -lc 'agents secrets import …'` on the remote) and the routines daemon
|
|
267
|
+
* (src/lib/daemon.ts falls back to bare `agents`). This is the POSIX symmetric
|
|
268
|
+
* counterpart of the Windows branch in main() that registers npm's global-bin
|
|
269
|
+
* dir on the user PATH.
|
|
270
|
+
*
|
|
271
|
+
* Self-heal, not a prompt: it fires ONLY when `agents` is otherwise
|
|
272
|
+
* unresolvable — the genuinely-broken state — so it acts decisively, exactly
|
|
273
|
+
* like the Windows PATH registration. The symlink never clobbers a dev build
|
|
274
|
+
* (scripts/install.sh) or any real file. Skipped in CI (ephemeral homes) and
|
|
275
|
+
* when AGENTS_NO_HEAL=1.
|
|
276
|
+
*/
|
|
277
|
+
async function ensureAgentsResolvablePosix() {
|
|
278
|
+
if (process.env.CI || process.env.AGENTS_NO_HEAL === '1') return;
|
|
279
|
+
try {
|
|
280
|
+
const { localBinDir, ensureLocalBinSymlink, loginShellResolves, dirOnLoginPath } =
|
|
281
|
+
await import('../dist/lib/platform/posixpath.js');
|
|
282
|
+
|
|
283
|
+
// macOS/homebrew, system-node Linux, and dev-build users already resolve it.
|
|
284
|
+
if (loginShellResolves('agents')) return;
|
|
285
|
+
|
|
286
|
+
const binDir = localBinDir();
|
|
287
|
+
const results = ['agents', 'ag'].map((name) => ensureLocalBinSymlink(name, AGENTS_BIN, binDir));
|
|
288
|
+
if (!results.some((r) => r.created)) return; // nothing we could safely link
|
|
289
|
+
|
|
290
|
+
if (dirOnLoginPath(binDir)) {
|
|
291
|
+
console.log(`\n Linked 'agents' into ${binDir} (already on the login PATH) so 'bash -lc agents' resolves.`);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// ~/.local/bin isn't on the *bash* login PATH yet. The consumers run
|
|
296
|
+
// `bash -lc`, so add it to the file a bash login shell reads (~/.bash_profile
|
|
297
|
+
// when present, else ~/.profile) — not the interactive $SHELL rc, which for a
|
|
298
|
+
// zsh user (.zshrc) bash would never source.
|
|
299
|
+
const bashRc = fs.existsSync(path.join(HOME, '.bash_profile'))
|
|
300
|
+
? path.join(HOME, '.bash_profile')
|
|
301
|
+
: path.join(HOME, '.profile');
|
|
302
|
+
const marker = '# agents-cli: ensure ~/.local/bin on PATH (so the agents command resolves)';
|
|
303
|
+
let already = false;
|
|
304
|
+
try {
|
|
305
|
+
already = fs.existsSync(bashRc) && fs.readFileSync(bashRc, 'utf-8').includes(marker);
|
|
306
|
+
} catch { /* unreadable rc — fall through and append */ }
|
|
307
|
+
if (!already) {
|
|
308
|
+
fs.appendFileSync(bashRc, `\n${marker}\nexport PATH="${binDir}:$PATH"\n`);
|
|
309
|
+
}
|
|
310
|
+
console.log(`\n Linked 'agents' into ${binDir} and added it to PATH in ${path.basename(bashRc)}.`);
|
|
311
|
+
console.log(` Restart your shell (or run: source ~/${path.basename(bashRc)}) to pick it up.`);
|
|
312
|
+
} catch {
|
|
313
|
+
/* best-effort: a failure here must never break the install */
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
255
317
|
/**
|
|
256
318
|
* Self-heal long-running processes onto the just-installed code (macOS).
|
|
257
319
|
*
|