@phnx-labs/agents-cli 1.20.51 → 1.20.53
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 +71 -0
- package/README.md +12 -0
- package/dist/bin/agents +0 -0
- package/dist/commands/browser.js +215 -7
- package/dist/commands/cloud.d.ts +3 -0
- package/dist/commands/cloud.js +8 -1
- package/dist/commands/events.d.ts +1 -1
- package/dist/commands/events.js +2 -3
- package/dist/commands/exec.js +82 -3
- package/dist/commands/factory.js +8 -0
- package/dist/commands/feed.d.ts +38 -0
- package/dist/commands/feed.js +274 -0
- package/dist/commands/logs.d.ts +5 -1
- package/dist/commands/logs.js +248 -3
- package/dist/commands/mcp.js +7 -0
- package/dist/commands/memory.d.ts +9 -0
- package/dist/commands/memory.js +164 -0
- package/dist/commands/message.d.ts +11 -6
- package/dist/commands/message.js +140 -5
- package/dist/commands/routines.js +12 -0
- package/dist/commands/secrets-migrate.d.ts +2 -1
- package/dist/commands/secrets-migrate.js +88 -13
- package/dist/commands/secrets.d.ts +22 -0
- package/dist/commands/secrets.js +176 -42
- package/dist/commands/sessions.js +10 -1
- package/dist/commands/teams.js +4 -0
- package/dist/commands/worktree.js +4 -2
- package/dist/index.js +21 -22
- package/dist/lib/agents.js +249 -17
- package/dist/lib/answer-router.d.ts +75 -0
- package/dist/lib/answer-router.js +149 -0
- package/dist/lib/ask-classifier.d.ts +71 -0
- package/dist/lib/ask-classifier.js +197 -0
- package/dist/lib/browser/login-detection.d.ts +94 -0
- package/dist/lib/browser/login-detection.js +274 -0
- package/dist/lib/browser/profiles.d.ts +17 -8
- package/dist/lib/browser/profiles.js +27 -8
- package/dist/lib/browser/secret-ref.d.ts +10 -0
- package/dist/lib/browser/secret-ref.js +14 -0
- package/dist/lib/browser/service.js +14 -12
- package/dist/lib/cloud/antigravity.d.ts +0 -2
- package/dist/lib/cloud/antigravity.js +2 -17
- package/dist/lib/cloud/codex.js +3 -18
- package/dist/lib/cloud/rush.d.ts +15 -0
- package/dist/lib/cloud/rush.js +10 -16
- package/dist/lib/cloud/stream.js +2 -0
- package/dist/lib/cloud/types.d.ts +21 -0
- package/dist/lib/cloud/types.js +81 -0
- package/dist/lib/crabbox/cli.d.ts +1 -1
- package/dist/lib/crabbox/cli.js +12 -2
- package/dist/lib/crabbox/lease.d.ts +19 -0
- package/dist/lib/crabbox/lease.js +22 -11
- package/dist/lib/crabbox/progress.d.ts +62 -0
- package/dist/lib/crabbox/progress.js +129 -0
- package/dist/lib/crabbox/runtimes.d.ts +38 -1
- package/dist/lib/crabbox/runtimes.js +98 -5
- package/dist/lib/daemon.d.ts +12 -9
- package/dist/lib/daemon.js +32 -17
- package/dist/lib/events.d.ts +31 -5
- package/dist/lib/events.js +291 -101
- package/dist/lib/exec.js +20 -1
- package/dist/lib/feed-outcome.d.ts +101 -0
- package/dist/lib/feed-outcome.js +244 -0
- package/dist/lib/feed-policy.d.ts +30 -0
- package/dist/lib/feed-policy.js +133 -0
- package/dist/lib/feed.d.ts +180 -0
- package/dist/lib/feed.js +627 -0
- package/dist/lib/git.d.ts +17 -1
- package/dist/lib/git.js +20 -1
- package/dist/lib/hooks.js +529 -14
- package/dist/lib/hosts/passthrough.d.ts +3 -3
- package/dist/lib/hosts/passthrough.js +3 -3
- package/dist/lib/mailbox-gc.d.ts +22 -0
- package/dist/lib/mailbox-gc.js +161 -0
- package/dist/lib/mailbox.d.ts +26 -2
- package/dist/lib/mailbox.js +80 -5
- package/dist/lib/mcp.js +82 -0
- package/dist/lib/memory.d.ts +55 -0
- package/dist/lib/memory.js +274 -0
- package/dist/lib/notify.d.ts +16 -0
- package/dist/lib/notify.js +61 -0
- package/dist/lib/operator.d.ts +26 -0
- package/dist/lib/operator.js +107 -0
- package/dist/lib/plugins.d.ts +35 -0
- package/dist/lib/plugins.js +217 -0
- package/dist/lib/remote-agents-json.d.ts +14 -0
- package/dist/lib/remote-agents-json.js +94 -0
- package/dist/lib/resources/mcp.js +44 -0
- package/dist/lib/resources/memory.d.ts +15 -0
- package/dist/lib/resources/memory.js +46 -0
- package/dist/lib/resources/types.d.ts +2 -2
- package/dist/lib/rotate.js +2 -0
- package/dist/lib/runner.d.ts +43 -0
- package/dist/lib/runner.js +323 -74
- package/dist/lib/sandbox.js +6 -0
- 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/secrets/agent.d.ts +21 -0
- package/dist/lib/secrets/agent.js +63 -1
- package/dist/lib/secrets/bundles.d.ts +33 -1
- package/dist/lib/secrets/bundles.js +76 -21
- package/dist/lib/secrets/icloud-import.d.ts +79 -0
- package/dist/lib/secrets/icloud-import.js +203 -0
- package/dist/lib/secrets/index.d.ts +142 -2
- package/dist/lib/secrets/index.js +695 -30
- package/dist/lib/secrets/remote.js +1 -1
- package/dist/lib/secrets/sync.js +1 -1
- package/dist/lib/session/active.d.ts +18 -0
- package/dist/lib/session/active.js +47 -17
- package/dist/lib/session/db.d.ts +9 -1
- package/dist/lib/session/db.js +18 -3
- package/dist/lib/session/discover.d.ts +13 -0
- package/dist/lib/session/discover.js +32 -2
- package/dist/lib/session/parse.d.ts +8 -0
- package/dist/lib/session/parse.js +42 -21
- package/dist/lib/session/remote-active.js +8 -89
- package/dist/lib/session/state.d.ts +11 -0
- package/dist/lib/session/state.js +50 -1
- package/dist/lib/session/tail.d.ts +23 -4
- package/dist/lib/session/tail.js +34 -16
- package/dist/lib/session/throughput.d.ts +30 -0
- package/dist/lib/session/throughput.js +86 -0
- package/dist/lib/shim-heal.d.ts +12 -3
- package/dist/lib/shim-heal.js +12 -6
- package/dist/lib/staleness/detectors/subagents.js +57 -3
- package/dist/lib/staleness/writers/hooks.js +7 -3
- package/dist/lib/staleness/writers/subagents.js +37 -6
- package/dist/lib/startup/command-registry.d.ts +2 -0
- package/dist/lib/startup/command-registry.js +4 -0
- package/dist/lib/state.d.ts +2 -0
- package/dist/lib/state.js +25 -8
- package/dist/lib/subagents.d.ts +52 -0
- package/dist/lib/subagents.js +315 -12
- package/dist/lib/teams/agents.js +6 -3
- package/dist/lib/teams/worktree.d.ts +8 -0
- package/dist/lib/teams/worktree.js +8 -0
- package/dist/lib/types.d.ts +20 -2
- package/dist/lib/versions.js +38 -48
- package/dist/lib/whats-new.d.ts +5 -3
- package/dist/lib/whats-new.js +25 -5
- package/package.json +4 -3
- package/scripts/postinstall.js +61 -1
package/dist/lib/versions.js
CHANGED
|
@@ -42,6 +42,7 @@ import { emit } from './events.js';
|
|
|
42
42
|
import { safeJoin } from './paths.js';
|
|
43
43
|
import { readSkillSourceCommandMarker, shouldInstallCommandAsSkill } from './command-skills.js';
|
|
44
44
|
import { getWriter, getDetector } from './staleness/registry.js';
|
|
45
|
+
import { syncMemoryToVersionHome } from './memory.js';
|
|
45
46
|
/** Promisified exec for running shell commands. */
|
|
46
47
|
const execAsync = promisify(exec);
|
|
47
48
|
const execFileAsync = promisify(execFile);
|
|
@@ -1127,19 +1128,28 @@ export async function installVersion(agent, version, onProgress, opts) {
|
|
|
1127
1128
|
emit('version.install', { agent, version: installedVersion });
|
|
1128
1129
|
return { success: true, installedVersion };
|
|
1129
1130
|
}
|
|
1130
|
-
// Resolve the `oldest`
|
|
1131
|
-
// of the install path treats
|
|
1132
|
-
// keeps
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1131
|
+
// Resolve the `latest`/`oldest` aliases to a concrete npm version up front so
|
|
1132
|
+
// the rest of the install path treats them as an ordinary pinned install.
|
|
1133
|
+
// This is what keeps concurrent installs safe: resolving `latest` only AFTER
|
|
1134
|
+
// npm finished meant the install ran in a shared, well-known
|
|
1135
|
+
// `versions/<agent>/latest/` scratch dir that was renamed to the real version
|
|
1136
|
+
// at the end — so a concurrent `agents view` reconcile
|
|
1137
|
+
// (reconcileStaleLatestForAgent) or a second `latest` install could rename
|
|
1138
|
+
// that dir out from under npm mid-extraction and corrupt the install (the
|
|
1139
|
+
// seeded package.json and half-extracted node_modules would vanish, yielding
|
|
1140
|
+
// ENOENT). A concrete dir per version has no shared name to race on.
|
|
1141
|
+
if (version === 'latest' || version === 'oldest') {
|
|
1142
|
+
const resolved = version === 'latest'
|
|
1143
|
+
? await getLatestNpmVersion(agent)
|
|
1144
|
+
: await getOldestNpmVersion(agent);
|
|
1145
|
+
if (!resolved) {
|
|
1136
1146
|
return {
|
|
1137
1147
|
success: false,
|
|
1138
1148
|
installedVersion: version,
|
|
1139
|
-
error: `Could not resolve the
|
|
1149
|
+
error: `Could not resolve the ${version} published version for ${agentConfig.name} from npm.`,
|
|
1140
1150
|
};
|
|
1141
1151
|
}
|
|
1142
|
-
version =
|
|
1152
|
+
version = resolved;
|
|
1143
1153
|
}
|
|
1144
1154
|
ensureAgentsDir();
|
|
1145
1155
|
const versionDir = getVersionDir(agent, version);
|
|
@@ -1161,12 +1171,11 @@ export async function installVersion(agent, version, onProgress, opts) {
|
|
|
1161
1171
|
private: true,
|
|
1162
1172
|
};
|
|
1163
1173
|
fs.writeFileSync(path.join(versionDir, 'package.json'), JSON.stringify(packageJson, null, 2));
|
|
1164
|
-
// Install the package
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
// (which VERSION_RE permits to start with `-`) is never passed as a standalone npm CLI flag.
|
|
1174
|
+
// Install the package. `version` is always concrete here (`latest`/`oldest`
|
|
1175
|
+
// were resolved above), so the spec is always pinned. The `@` prefix is
|
|
1176
|
+
// load-bearing: it ensures `version` (which VERSION_RE permits to start with
|
|
1177
|
+
// `-`) is never passed as a standalone npm CLI flag.
|
|
1178
|
+
const packageSpec = `${agentConfig.npmPackage}@${version}`;
|
|
1170
1179
|
try {
|
|
1171
1180
|
// Check npm is available
|
|
1172
1181
|
const winShell = process.platform === 'win32';
|
|
@@ -1181,37 +1190,12 @@ export async function installVersion(agent, version, onProgress, opts) {
|
|
|
1181
1190
|
};
|
|
1182
1191
|
}
|
|
1183
1192
|
onProgress?.(`Installing ${packageSpec}...`);
|
|
1184
|
-
|
|
1185
|
-
//
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
try {
|
|
1191
|
-
const installedPkgPath = path.join(versionDir, 'node_modules', agentConfig.npmPackage, 'package.json');
|
|
1192
|
-
if (fs.existsSync(installedPkgPath)) {
|
|
1193
|
-
const installedPkg = JSON.parse(fs.readFileSync(installedPkgPath, 'utf-8'));
|
|
1194
|
-
installedVersion = installedPkg.version;
|
|
1195
|
-
// Rename the directory to the actual version
|
|
1196
|
-
if (installedVersion !== 'latest') {
|
|
1197
|
-
const actualVersionDir = getVersionDir(agent, installedVersion);
|
|
1198
|
-
if (!fs.existsSync(actualVersionDir)) {
|
|
1199
|
-
fs.renameSync(versionDir, actualVersionDir);
|
|
1200
|
-
}
|
|
1201
|
-
else {
|
|
1202
|
-
// Already exists — drop the 'latest' install artifacts but keep
|
|
1203
|
-
// `home/` (may contain conversation history from sessions that
|
|
1204
|
-
// ran while the user was on `latest`).
|
|
1205
|
-
removeInstallArtifacts(versionDir);
|
|
1206
|
-
}
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
}
|
|
1210
|
-
catch (e) {
|
|
1211
|
-
// Failed to determine version - this shouldn't happen
|
|
1212
|
-
throw new Error(`Failed to determine installed version: ${e.message}`);
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1193
|
+
await execFileAsync('npm', ['install', packageSpec, '--ignore-scripts'], { cwd: versionDir, shell: winShell });
|
|
1194
|
+
// `version` is concrete (the `latest`/`oldest` aliases were resolved up
|
|
1195
|
+
// front), so the package installed directly into its final versioned dir —
|
|
1196
|
+
// no post-install rename, and no shared `latest/` dir for a concurrent
|
|
1197
|
+
// process to move out from under us.
|
|
1198
|
+
const installedVersion = version;
|
|
1215
1199
|
// Create versioned alias (e.g., claude@2.0.65)
|
|
1216
1200
|
createVersionedAlias(agent, installedVersion);
|
|
1217
1201
|
// Claude reads its global config from CLAUDE_CONFIG_DIR/.claude.json —
|
|
@@ -1241,9 +1225,9 @@ export async function installVersion(agent, version, onProgress, opts) {
|
|
|
1241
1225
|
// binary (postinstall failed, or a platform with no published native dep)
|
|
1242
1226
|
// fails there with the correct message rather than throwing here.
|
|
1243
1227
|
if (agentConfig.npmPackage) {
|
|
1244
|
-
//
|
|
1245
|
-
//
|
|
1246
|
-
const pkgRoot = path.join(
|
|
1228
|
+
// `installedVersion === version`, so this is exactly `versionDir` — the
|
|
1229
|
+
// install landed in its final dir with no rename to chase.
|
|
1230
|
+
const pkgRoot = path.join(versionDir, 'node_modules', agentConfig.npmPackage);
|
|
1247
1231
|
try {
|
|
1248
1232
|
const pkg = JSON.parse(fs.readFileSync(path.join(pkgRoot, 'package.json'), 'utf-8'));
|
|
1249
1233
|
const postinstall = pkg?.scripts?.postinstall;
|
|
@@ -2335,6 +2319,12 @@ export function syncResourcesToVersion(agent, version, selection, options = {})
|
|
|
2335
2319
|
const r = workflowsWriter.write({ version, versionHome, selection: workflowsToSync, cwd });
|
|
2336
2320
|
result.workflows.push(...r.synced);
|
|
2337
2321
|
}
|
|
2322
|
+
// Knowledge memory (RUSH-1330) — distinct from selection.memory which still
|
|
2323
|
+
// means the composed *rules* file. Always fan out ~/.agents/memory/ facts
|
|
2324
|
+
// into capable agent version homes on every full or partial sync.
|
|
2325
|
+
if (supports(agent, 'memory', version).ok) {
|
|
2326
|
+
syncMemoryToVersionHome(agent, versionHome, cwd);
|
|
2327
|
+
}
|
|
2338
2328
|
// Write manifest after a full sync (no user-passed selection) so the next
|
|
2339
2329
|
// launch can skip the slow path. Pattern-derived selections still count as
|
|
2340
2330
|
// "full" — the agents.yaml patterns describe the intended scope, not a
|
package/dist/lib/whats-new.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Render a compact "What's new" summary from a CHANGELOG.md body: one bullet
|
|
3
|
-
* per feature/fix heading
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* per feature/fix heading for each version in the range the user actually
|
|
4
|
+
* moved through, `(fromVersion, toVersion]`. Headings are recognized in both
|
|
5
|
+
* changelog formats — the current `- **Title.** prose…` single-line bullets
|
|
6
|
+
* and the older standalone `**Heading**` lines. The verbose prose/sub-bullets
|
|
7
|
+
* are intentionally dropped — the full notes live in the changelog.
|
|
6
8
|
*
|
|
7
9
|
* Returns colored lines ready to print, empty when nothing is in range.
|
|
8
10
|
*/
|
package/dist/lib/whats-new.js
CHANGED
|
@@ -2,15 +2,23 @@ import chalk from 'chalk';
|
|
|
2
2
|
import { compareVersions } from './agent-spec/primitives.js';
|
|
3
3
|
/**
|
|
4
4
|
* Render a compact "What's new" summary from a CHANGELOG.md body: one bullet
|
|
5
|
-
* per feature/fix heading
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* per feature/fix heading for each version in the range the user actually
|
|
6
|
+
* moved through, `(fromVersion, toVersion]`. Headings are recognized in both
|
|
7
|
+
* changelog formats — the current `- **Title.** prose…` single-line bullets
|
|
8
|
+
* and the older standalone `**Heading**` lines. The verbose prose/sub-bullets
|
|
9
|
+
* are intentionally dropped — the full notes live in the changelog.
|
|
8
10
|
*
|
|
9
11
|
* Returns colored lines ready to print, empty when nothing is in range.
|
|
10
12
|
*/
|
|
11
13
|
export function renderWhatsNew(changelog, fromVersion, toVersion) {
|
|
12
14
|
const out = [];
|
|
13
15
|
let inRelevantSection = false;
|
|
16
|
+
// Whether the CURRENT version section uses the old standalone-heading format.
|
|
17
|
+
// Old sections nest `-` sub-bullets under each `**Heading**` line, and some
|
|
18
|
+
// sub-bullets are themselves bold-led (`- **Claim.** detail…`) — once a
|
|
19
|
+
// standalone heading is seen, `- **` lines in that section are sub-bullets,
|
|
20
|
+
// not entries, and must not render.
|
|
21
|
+
let sectionUsesStandaloneHeadings = false;
|
|
14
22
|
for (const line of changelog.split('\n')) {
|
|
15
23
|
const versionMatch = line.match(/^## (\d+\.\d+\.\d+)/);
|
|
16
24
|
if (versionMatch) {
|
|
@@ -20,15 +28,27 @@ export function renderWhatsNew(changelog, fromVersion, toVersion) {
|
|
|
20
28
|
inRelevantSection =
|
|
21
29
|
compareVersions(currentVersion, fromVersion) > 0 &&
|
|
22
30
|
compareVersions(currentVersion, toVersion) <= 0;
|
|
31
|
+
sectionUsesStandaloneHeadings = false;
|
|
23
32
|
if (inRelevantSection) {
|
|
24
33
|
out.push('');
|
|
25
34
|
out.push(chalk.bold(`v${currentVersion}`));
|
|
26
35
|
}
|
|
27
36
|
continue;
|
|
28
37
|
}
|
|
29
|
-
// Only the
|
|
30
|
-
|
|
38
|
+
// Only the entry headings — one bullet per feature/fix. Two formats exist
|
|
39
|
+
// across the changelog's history: the current single-line bullets
|
|
40
|
+
// (`- **Title.** verbose prose…`, heading kept, prose dropped) and the
|
|
41
|
+
// older standalone `**Heading**` lines with `-` sub-bullets beneath.
|
|
42
|
+
if (!inRelevantSection)
|
|
43
|
+
continue;
|
|
44
|
+
if (line.startsWith('**') && line.endsWith('**')) {
|
|
45
|
+
sectionUsesStandaloneHeadings = true;
|
|
31
46
|
out.push(` ${chalk.cyan('•')} ${line.replace(/\*\*/g, '')}`);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const entryBullet = sectionUsesStandaloneHeadings ? null : line.match(/^- \*\*(.+?)\*\*/);
|
|
50
|
+
if (entryBullet) {
|
|
51
|
+
out.push(` ${chalk.cyan('•')} ${entryBullet[1].replace(/\*\*/g, '')}`);
|
|
32
52
|
}
|
|
33
53
|
}
|
|
34
54
|
return out;
|
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.53",
|
|
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",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"dist/**/*.js",
|
|
25
25
|
"dist/**/*.d.ts",
|
|
26
26
|
"dist/**/*.json",
|
|
27
|
+
"dist/bin/**",
|
|
27
28
|
"dist/lib/secrets/Agents CLI.app/**",
|
|
28
29
|
"dist/lib/menubar/MenubarHelper.app/**",
|
|
29
30
|
"scripts/postinstall.js",
|
|
@@ -44,10 +45,10 @@
|
|
|
44
45
|
"url": "https://github.com/phnx-labs/agents-cli/issues"
|
|
45
46
|
},
|
|
46
47
|
"scripts": {
|
|
47
|
-
"build": "tsc && rm -rf 'dist/lib/secrets/AgentsKeychain.app' 'dist/lib/secrets/Agents CLI.app' 'dist/lib/menubar/MenubarHelper.app' && ([ -d 'bin/Agents CLI.app' ] && cp -R 'bin/Agents CLI.app' 'dist/lib/secrets/Agents CLI.app' || true) && ([ -d 'bin/MenubarHelper.app' ] && mkdir -p 'dist/lib/menubar' && cp -R 'bin/MenubarHelper.app' 'dist/lib/menubar/MenubarHelper.app' || true)",
|
|
48
|
+
"build": "tsc && rm -rf 'dist/lib/secrets/AgentsKeychain.app' 'dist/lib/secrets/Agents CLI.app' 'dist/lib/menubar/MenubarHelper.app' && ([ -d 'bin/Agents CLI.app' ] && cp -R 'bin/Agents CLI.app' 'dist/lib/secrets/Agents CLI.app' || true) && ([ -d 'bin/MenubarHelper.app' ] && mkdir -p 'dist/lib/menubar' && cp -R 'bin/MenubarHelper.app' 'dist/lib/menubar/MenubarHelper.app' || true) && ([ -f 'bin/agents-macos' ] && mkdir -p dist/bin && cp -f 'bin/agents-macos' 'dist/bin/agents' && chmod 755 'dist/bin/agents' || true)",
|
|
48
49
|
"build:bin": "scripts/build-bin.sh",
|
|
49
50
|
"prepare": "npm run build",
|
|
50
|
-
"prepack": "cp ../../README.md README.md && scripts/verify-keychain-helper.sh && scripts/verify-menubar-helper.sh",
|
|
51
|
+
"prepack": "cp ../../README.md README.md && scripts/verify-keychain-helper.sh && scripts/verify-menubar-helper.sh && scripts/verify-cli-binary.sh",
|
|
51
52
|
"postinstall": "node scripts/postinstall.js",
|
|
52
53
|
"dev": "tsx src/index.ts",
|
|
53
54
|
"start": "node dist/index.js",
|
package/scripts/postinstall.js
CHANGED
|
@@ -16,9 +16,36 @@ const SHIMS_DIR = path.join(USER_DIR, '.cache', 'shims');
|
|
|
16
16
|
// System repo lives inside the user repo (folded in v1.21). Legacy installs at
|
|
17
17
|
// ~/.agents-system/ are migrated by src/lib/migrate.ts on first CLI invocation.
|
|
18
18
|
const SYSTEM_DIR = path.join(USER_DIR, '.system');
|
|
19
|
-
const
|
|
19
|
+
const AGENTS_JS_ENTRYPOINT = fileURLToPath(new URL('../dist/index.js', import.meta.url));
|
|
20
|
+
// Signed + notarized standalone Mach-O, macOS only (scripts/sign-cli-binary.sh).
|
|
21
|
+
// Preferred over the node-shebang JS entrypoint on darwin: the unsigned JS shim
|
|
22
|
+
// is what EDR (CrowdStrike Falcon) flags when an editor child spawns it (#315).
|
|
23
|
+
const AGENTS_NATIVE_MACOS_BIN = fileURLToPath(new URL('../dist/bin/agents', import.meta.url));
|
|
24
|
+
const AGENTS_BIN = resolveAgentsBin();
|
|
20
25
|
const INSTALL_HELPER_SCRIPT = fileURLToPath(new URL('./install-helper.js', import.meta.url));
|
|
21
26
|
|
|
27
|
+
function resolveAgentsBin() {
|
|
28
|
+
if (process.platform !== 'darwin') return AGENTS_JS_ENTRYPOINT;
|
|
29
|
+
try {
|
|
30
|
+
fs.accessSync(AGENTS_NATIVE_MACOS_BIN, fs.constants.X_OK);
|
|
31
|
+
} catch {
|
|
32
|
+
return AGENTS_JS_ENTRYPOINT; // no native binary in this install (dev build, arch without one)
|
|
33
|
+
}
|
|
34
|
+
// Real execution probe, not just a stat: catches a quarantined, EDR-blocked,
|
|
35
|
+
// or wrong-arch (Intel) binary at install time, where we can still fall back
|
|
36
|
+
// loudly, instead of breaking every later `agents` call.
|
|
37
|
+
const probe = spawnSync(AGENTS_NATIVE_MACOS_BIN, ['--version'], {
|
|
38
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
39
|
+
timeout: 15000,
|
|
40
|
+
encoding: 'utf-8',
|
|
41
|
+
});
|
|
42
|
+
if (probe.status === 0) return AGENTS_NATIVE_MACOS_BIN;
|
|
43
|
+
const why = probe.error ? probe.error.message : `exit status ${probe.status}`;
|
|
44
|
+
console.warn(` warning: the signed agents binary at ${AGENTS_NATIVE_MACOS_BIN} failed to run (${why}).`);
|
|
45
|
+
console.warn(` Falling back to the JS entrypoint; 'agents' still works but is not code-signed.`);
|
|
46
|
+
return AGENTS_JS_ENTRYPOINT;
|
|
47
|
+
}
|
|
48
|
+
|
|
22
49
|
function installKeychainHelper() {
|
|
23
50
|
if (process.platform !== 'darwin') return;
|
|
24
51
|
if (!fs.existsSync(INSTALL_HELPER_SCRIPT)) return;
|
|
@@ -276,6 +303,7 @@ To enable version-aware shims, add this to your shell config:
|
|
|
276
303
|
*/
|
|
277
304
|
async function ensureAgentsResolvablePosix() {
|
|
278
305
|
if (process.env.CI || process.env.AGENTS_NO_HEAL === '1') return;
|
|
306
|
+
retargetManagedLinksToNativeBin();
|
|
279
307
|
try {
|
|
280
308
|
const { localBinDir, ensureLocalBinSymlink, loginShellResolves, dirOnLoginPath } =
|
|
281
309
|
await import('../dist/lib/platform/posixpath.js');
|
|
@@ -314,6 +342,38 @@ async function ensureAgentsResolvablePosix() {
|
|
|
314
342
|
}
|
|
315
343
|
}
|
|
316
344
|
|
|
345
|
+
/**
|
|
346
|
+
* Upgrade path for #315: an earlier install symlinked ~/.local/bin/agents at
|
|
347
|
+
* the JS entrypoint. ensureLocalBinSymlink never repoints an existing link,
|
|
348
|
+
* and the loginShellResolves() early-return means ensureAgentsResolvablePosix
|
|
349
|
+
* would not even try - so without this, a machine healed before the signed
|
|
350
|
+
* binary existed keeps the unsigned JS shim forever. Repoint ONLY symlinks
|
|
351
|
+
* that resolve exactly to OUR dist/index.js; a dev build or foreign link is
|
|
352
|
+
* never touched.
|
|
353
|
+
*/
|
|
354
|
+
function retargetManagedLinksToNativeBin() {
|
|
355
|
+
if (AGENTS_BIN === AGENTS_JS_ENTRYPOINT) return;
|
|
356
|
+
const binDir = path.join(HOME, '.local', 'bin');
|
|
357
|
+
// Compare realpaths: dist/index.js can be reached through path aliases
|
|
358
|
+
// (/var vs /private/var on macOS) depending on who created the link.
|
|
359
|
+
let want = AGENTS_JS_ENTRYPOINT;
|
|
360
|
+
try { want = fs.realpathSync(AGENTS_JS_ENTRYPOINT); } catch { /* keep the literal path */ }
|
|
361
|
+
for (const name of ['agents', 'ag']) {
|
|
362
|
+
const linkPath = path.join(binDir, name);
|
|
363
|
+
try {
|
|
364
|
+
const current = fs.readlinkSync(linkPath); // throws unless a symlink
|
|
365
|
+
let resolved = path.isAbsolute(current) ? current : path.resolve(binDir, current);
|
|
366
|
+
try { resolved = fs.realpathSync(resolved); } catch { /* dangling - compare as-is */ }
|
|
367
|
+
if (resolved !== want) continue;
|
|
368
|
+
fs.unlinkSync(linkPath);
|
|
369
|
+
fs.symlinkSync(AGENTS_BIN, linkPath);
|
|
370
|
+
console.log(` Repointed ${linkPath} at the signed agents binary.`);
|
|
371
|
+
} catch {
|
|
372
|
+
/* absent, unreadable, or not a symlink - nothing to retarget */
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
317
377
|
/**
|
|
318
378
|
* Self-heal long-running processes onto the just-installed code (macOS).
|
|
319
379
|
*
|