@phnx-labs/agents-cli 1.19.1 → 1.20.0
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 +67 -0
- package/README.md +70 -10
- package/dist/commands/browser.js +88 -16
- package/dist/commands/cli.d.ts +14 -0
- package/dist/commands/cli.js +244 -0
- package/dist/commands/commands.js +3 -3
- package/dist/commands/computer.js +18 -1
- package/dist/commands/doctor.d.ts +1 -1
- package/dist/commands/doctor.js +2 -2
- package/dist/commands/exec.js +3 -3
- package/dist/commands/factory.d.ts +3 -14
- package/dist/commands/factory.js +3 -3
- package/dist/commands/hooks.js +3 -3
- package/dist/commands/mcp.js +29 -0
- package/dist/commands/plugins.js +11 -4
- package/dist/commands/profiles.js +1 -1
- package/dist/commands/prune.js +39 -160
- package/dist/commands/pull.js +56 -3
- package/dist/commands/routines.js +106 -13
- package/dist/commands/secrets.js +6 -8
- package/dist/commands/sessions.d.ts +36 -7
- package/dist/commands/sessions.js +130 -53
- package/dist/commands/setup.d.ts +1 -0
- package/dist/commands/setup.js +37 -28
- package/dist/commands/skills.js +3 -3
- package/dist/commands/teams.js +13 -0
- package/dist/commands/versions.d.ts +4 -3
- package/dist/commands/versions.js +147 -124
- package/dist/commands/view.js +12 -12
- package/dist/index.js +34 -6
- package/dist/lib/acp/harnesses.js +8 -0
- package/dist/lib/agents.js +162 -9
- package/dist/lib/browser/cdp.d.ts +8 -1
- package/dist/lib/browser/cdp.js +40 -3
- package/dist/lib/browser/chrome.d.ts +13 -0
- package/dist/lib/browser/chrome.js +42 -3
- package/dist/lib/browser/domain-skills.d.ts +51 -0
- package/dist/lib/browser/domain-skills.js +157 -0
- package/dist/lib/browser/drivers/local.js +45 -4
- package/dist/lib/browser/drivers/ssh.js +1 -1
- package/dist/lib/browser/ipc.d.ts +8 -1
- package/dist/lib/browser/ipc.js +37 -28
- package/dist/lib/browser/profiles.d.ts +13 -0
- package/dist/lib/browser/profiles.js +41 -1
- package/dist/lib/browser/service.d.ts +3 -0
- package/dist/lib/browser/service.js +21 -5
- package/dist/lib/browser/types.d.ts +7 -0
- package/dist/lib/cli-resources.d.ts +109 -0
- package/dist/lib/cli-resources.js +255 -0
- package/dist/lib/cloud/rush.js +5 -5
- package/dist/lib/command-skills.js +0 -2
- package/dist/lib/computer-rpc.d.ts +3 -0
- package/dist/lib/computer-rpc.js +53 -0
- package/dist/lib/daemon.js +20 -0
- package/dist/lib/exec.d.ts +3 -2
- package/dist/lib/exec.js +62 -6
- package/dist/lib/hooks.js +182 -0
- package/dist/lib/mcp.js +6 -0
- package/dist/lib/migrate.js +1 -1
- package/dist/lib/overdue.d.ts +26 -0
- package/dist/lib/overdue.js +101 -0
- package/dist/lib/permissions.js +5 -1
- package/dist/lib/plugin-marketplace.js +1 -1
- package/dist/lib/profiles-presets.js +37 -0
- package/dist/lib/registry.d.ts +18 -0
- package/dist/lib/registry.js +44 -0
- package/dist/lib/resources/mcp.js +43 -1
- package/dist/lib/resources/types.d.ts +1 -1
- package/dist/lib/resources.d.ts +1 -1
- package/dist/lib/rotate.js +10 -4
- package/dist/lib/routines-format.d.ts +35 -0
- package/dist/lib/routines-format.js +173 -0
- package/dist/lib/routines.d.ts +7 -1
- package/dist/lib/routines.js +32 -12
- package/dist/lib/runner.js +19 -5
- package/dist/lib/scheduler.js +8 -1
- package/dist/lib/secrets/{AgentsKeychain.app → Agents CLI.app}/Contents/CodeResources +0 -0
- package/dist/lib/secrets/{AgentsKeychain.app/Contents/Info.plist → Agents CLI.app/Contents/Info.plist } +4 -2
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/bundles.d.ts +33 -2
- package/dist/lib/secrets/bundles.js +249 -26
- package/dist/lib/secrets/index.d.ts +10 -1
- package/dist/lib/secrets/index.js +143 -48
- package/dist/lib/session/active.d.ts +8 -0
- package/dist/lib/session/active.js +3 -2
- package/dist/lib/session/db.d.ts +10 -4
- package/dist/lib/session/db.js +16 -16
- package/dist/lib/session/parse.d.ts +1 -0
- package/dist/lib/session/parse.js +44 -0
- package/dist/lib/session/types.d.ts +1 -1
- package/dist/lib/session/types.js +1 -1
- package/dist/lib/shims.d.ts +6 -2
- package/dist/lib/shims.js +88 -10
- package/dist/lib/state.d.ts +0 -1
- package/dist/lib/state.js +2 -15
- package/dist/lib/teams/agents.js +1 -1
- package/dist/lib/teams/parsers.d.ts +1 -1
- package/dist/lib/teams/parsers.js +153 -3
- package/dist/lib/teams/summarizer.js +18 -2
- package/dist/lib/teams/worktree.js +14 -3
- package/dist/lib/types.d.ts +7 -4
- package/dist/lib/types.js +6 -3
- package/dist/lib/versions.d.ts +10 -2
- package/dist/lib/versions.js +227 -35
- package/package.json +9 -9
- package/dist/lib/secrets/AgentsKeychain.app/Contents/MacOS/AgentsKeychain +0 -0
- package/npm-shrinkwrap.json +0 -3162
- /package/dist/lib/secrets/{AgentsKeychain.app → Agents CLI.app}/Contents/_CodeSignature/CodeResources +0 -0
- /package/dist/lib/secrets/{AgentsKeychain.app → Agents CLI.app}/Contents/embedded.provisionprofile +0 -0
|
@@ -8,7 +8,9 @@ import { execFile } from 'child_process';
|
|
|
8
8
|
import { promisify } from 'util';
|
|
9
9
|
import * as fs from 'fs/promises';
|
|
10
10
|
import * as path from 'path';
|
|
11
|
+
import { safeJoin } from '../paths.js';
|
|
11
12
|
const execFileAsync = promisify(execFile);
|
|
13
|
+
const WORKTREE_NAME_RE = /^[A-Za-z0-9_-]+$/;
|
|
12
14
|
export async function isGitRepo(dir) {
|
|
13
15
|
try {
|
|
14
16
|
await execFileAsync('git', ['rev-parse', '--git-dir'], { cwd: dir });
|
|
@@ -42,8 +44,11 @@ export async function hasUncommittedChanges(worktreePath) {
|
|
|
42
44
|
* @returns The absolute path to the created worktree
|
|
43
45
|
*/
|
|
44
46
|
export async function createWorktree(repoDir, worktreeName) {
|
|
47
|
+
if (!WORKTREE_NAME_RE.test(worktreeName)) {
|
|
48
|
+
throw new Error(`Invalid worktree name: ${worktreeName}`);
|
|
49
|
+
}
|
|
45
50
|
const gitRoot = await getGitRoot(repoDir);
|
|
46
|
-
const worktreePath = path.join(gitRoot, '.agents', 'worktrees', worktreeName);
|
|
51
|
+
const worktreePath = safeJoin(path.join(gitRoot, '.agents', 'worktrees'), worktreeName);
|
|
47
52
|
const branchName = `agents/${worktreeName}`;
|
|
48
53
|
await fs.mkdir(path.dirname(worktreePath), { recursive: true });
|
|
49
54
|
await execFileAsync('git', ['worktree', 'add', '-b', branchName, worktreePath, 'HEAD'], {
|
|
@@ -59,8 +64,11 @@ export async function createWorktree(repoDir, worktreeName) {
|
|
|
59
64
|
* @param deleteBranch - Whether to delete the associated branch
|
|
60
65
|
*/
|
|
61
66
|
export async function removeWorktree(repoDir, worktreeName, deleteBranch = true) {
|
|
67
|
+
if (!WORKTREE_NAME_RE.test(worktreeName)) {
|
|
68
|
+
throw new Error(`Invalid worktree name: ${worktreeName}`);
|
|
69
|
+
}
|
|
62
70
|
const gitRoot = await getGitRoot(repoDir);
|
|
63
|
-
const worktreePath = path.join(gitRoot, '.agents', 'worktrees', worktreeName);
|
|
71
|
+
const worktreePath = safeJoin(path.join(gitRoot, '.agents', 'worktrees'), worktreeName);
|
|
64
72
|
const branchName = `agents/${worktreeName}`;
|
|
65
73
|
try {
|
|
66
74
|
await execFileAsync('git', ['worktree', 'remove', '--force', worktreePath], { cwd: gitRoot });
|
|
@@ -86,7 +94,10 @@ export async function removeWorktree(repoDir, worktreeName, deleteBranch = true)
|
|
|
86
94
|
* Get the worktree path for a given name.
|
|
87
95
|
*/
|
|
88
96
|
export function getWorktreePath(gitRoot, worktreeName) {
|
|
89
|
-
|
|
97
|
+
if (!WORKTREE_NAME_RE.test(worktreeName)) {
|
|
98
|
+
throw new Error(`Invalid worktree name: ${worktreeName}`);
|
|
99
|
+
}
|
|
100
|
+
return safeJoin(path.join(gitRoot, '.agents', 'worktrees'), worktreeName);
|
|
90
101
|
}
|
|
91
102
|
/**
|
|
92
103
|
* Get the branch name for a worktree.
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* formats for each supported agent.
|
|
7
7
|
*/
|
|
8
8
|
/** Unique identifier for a supported AI coding agent. */
|
|
9
|
-
export type AgentId = 'claude' | 'codex' | 'gemini' | 'cursor' | 'opencode' | 'openclaw' | 'copilot' | 'amp' | 'kiro' | 'goose' | 'roo';
|
|
9
|
+
export type AgentId = 'claude' | 'codex' | 'gemini' | 'cursor' | 'opencode' | 'openclaw' | 'copilot' | 'amp' | 'kiro' | 'goose' | 'roo' | 'antigravity' | 'grok';
|
|
10
10
|
/** How `agents run <agent>` chooses an installed version when none is pinned. */
|
|
11
11
|
export type RunStrategy = 'pinned' | 'available' | 'balanced';
|
|
12
12
|
/** Preview features that users can opt into via `agents beta`. */
|
|
@@ -203,9 +203,12 @@ export interface RegistryConfig {
|
|
|
203
203
|
/** Built-in registry endpoints shipped with agents-cli. */
|
|
204
204
|
export declare const DEFAULT_REGISTRIES: Record<RegistryType, Record<string, RegistryConfig>>;
|
|
205
205
|
/**
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
206
|
+
* Third-party registries pre-seeded on first install for discoverability.
|
|
207
|
+
*
|
|
208
|
+
* These ship into new users' agents.yaml once, but are not "defaults" — after
|
|
209
|
+
* seeding they behave like any user-added registry (listable, disable-able,
|
|
210
|
+
* removable). Removed users can `agents registry remove <name>` to opt out;
|
|
211
|
+
* once removed they don't come back.
|
|
209
212
|
*/
|
|
210
213
|
export declare const SEEDED_REGISTRIES: Record<RegistryType, Record<string, RegistryConfig>>;
|
|
211
214
|
/** A single installable package within an MCP server entry. */
|
package/dist/lib/types.js
CHANGED
|
@@ -22,9 +22,12 @@ export const DEFAULT_REGISTRIES = {
|
|
|
22
22
|
skill: {},
|
|
23
23
|
};
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
* Third-party registries pre-seeded on first install for discoverability.
|
|
26
|
+
*
|
|
27
|
+
* These ship into new users' agents.yaml once, but are not "defaults" — after
|
|
28
|
+
* seeding they behave like any user-added registry (listable, disable-able,
|
|
29
|
+
* removable). Removed users can `agents registry remove <name>` to opt out;
|
|
30
|
+
* once removed they don't come back.
|
|
28
31
|
*/
|
|
29
32
|
export const SEEDED_REGISTRIES = {
|
|
30
33
|
mcp: {},
|
package/dist/lib/versions.d.ts
CHANGED
|
@@ -63,7 +63,7 @@ export declare function hasNewResources(diff: AvailableResources, agent?: AgentI
|
|
|
63
63
|
* Prompt user to select which NEW resources to sync.
|
|
64
64
|
* Only shows resources that haven't been synced yet.
|
|
65
65
|
*/
|
|
66
|
-
export declare function promptNewResourceSelection(agent: AgentId, newResources: AvailableResources): Promise<ResourceSelection | null>;
|
|
66
|
+
export declare function promptNewResourceSelection(agent: AgentId, newResources: AvailableResources, version?: string): Promise<ResourceSelection | null>;
|
|
67
67
|
/**
|
|
68
68
|
* Prompt user to select which resources to sync from ~/.agents/.
|
|
69
69
|
* Returns the selection, or null if user cancels.
|
|
@@ -118,7 +118,7 @@ export declare function listInstalledVersions(agent: AgentId): string[];
|
|
|
118
118
|
* List every version directory for an agent, including ones missing the
|
|
119
119
|
* binary (typically home-only leftovers from a prior `removeVersion`).
|
|
120
120
|
*
|
|
121
|
-
* Used by `agents prune` to surface stale installs that the regular
|
|
121
|
+
* Used by `agents prune cleanup` to surface stale installs that the regular
|
|
122
122
|
* `listInstalledVersions` filters out. Do NOT use elsewhere — every other
|
|
123
123
|
* call site assumes a working binary.
|
|
124
124
|
*/
|
|
@@ -163,6 +163,14 @@ export declare function softDeleteVersionDir(agent: AgentId, version: string): s
|
|
|
163
163
|
* Nothing is hard-deleted.
|
|
164
164
|
*/
|
|
165
165
|
export declare function removeVersion(agent: AgentId, version: string): boolean;
|
|
166
|
+
/**
|
|
167
|
+
* Print the standard footer after one or more versions were soft-deleted to
|
|
168
|
+
* trash. Reminds the user that sessions stay readable and how to restore.
|
|
169
|
+
*/
|
|
170
|
+
export declare function printTrashFooter(moved: Array<{
|
|
171
|
+
agent: AgentId;
|
|
172
|
+
version: string;
|
|
173
|
+
}>): void;
|
|
166
174
|
/**
|
|
167
175
|
* Remove all versions of an agent. Preserves each version's `home/` directory
|
|
168
176
|
* so conversation history is never deleted; the per-version folders (now
|
package/dist/lib/versions.js
CHANGED
|
@@ -23,9 +23,9 @@ import { promisify } from 'util';
|
|
|
23
23
|
import chalk from 'chalk';
|
|
24
24
|
import * as TOML from 'smol-toml';
|
|
25
25
|
import { checkbox, select } from '@inquirer/prompts';
|
|
26
|
-
import { getVersionsDir, ensureAgentsDir, readMeta, writeMeta, getCommandsDir, getSkillsDir, getHooksDir, getResolvedRulesDir, getUserRulesDir,
|
|
26
|
+
import { getVersionsDir, ensureAgentsDir, readMeta, writeMeta, getCommandsDir, getSkillsDir, getHooksDir, getResolvedRulesDir, getUserRulesDir, getVersionResources, ensureVersionResourcePatterns, getProjectAgentsDir, getPromptcutsPath, getUserPromptcutsPath, getEnabledExtraRepos, getAgentsDir, getUserAgentsDir, getTrashVersionsDir, getActiveRulesPreset } from './state.js';
|
|
27
27
|
import { defaultPatterns, expandPatterns } from './resource-patterns.js';
|
|
28
|
-
import {
|
|
28
|
+
import { listResources } from './resources.js';
|
|
29
29
|
import { AGENTS, getAccountEmail, MCP_CAPABLE_AGENTS, COMMANDS_CAPABLE_AGENTS, getMcpConfigPathForHome, parseMcpConfig, resolveAgentName, formatAgentError } from './agents.js';
|
|
30
30
|
import { applyPermissionsToVersion as applyPermsToVersion, PERMISSIONS_CAPABLE_AGENTS, discoverPermissionGroups, buildPermissionsFromGroups, CODEX_RULES_FILENAME, getActivePermissionPresetName, readPermissionPresetRecipe, PERMISSION_PRESET_ENV_VAR } from './permissions.js';
|
|
31
31
|
import { installMcpServers, parseMcpServerConfig } from './mcp.js';
|
|
@@ -296,13 +296,21 @@ export function getActuallySyncedResources(agent, version, options = {}) {
|
|
|
296
296
|
workflows: [],
|
|
297
297
|
promptcuts: false,
|
|
298
298
|
};
|
|
299
|
-
// Commands - check what files exist in version home
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
299
|
+
// Commands - check what files exist in version home.
|
|
300
|
+
// For agent/version pairs that store commands as converted skills (e.g. Codex >= 0.117.0),
|
|
301
|
+
// detect them via the agents_command marker in skills/<name>/SKILL.md — otherwise the
|
|
302
|
+
// diff falsely reports every command as "new" every run and re-prompts on `agents view`.
|
|
303
|
+
if (shouldInstallCommandAsSkill(agent, version)) {
|
|
304
|
+
result.commands = listCommandSkillsInVersion(path.join(configDir));
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
const commandsDir = path.join(configDir, agentConfig.commandsSubdir);
|
|
308
|
+
if (fs.existsSync(commandsDir)) {
|
|
309
|
+
const ext = agentConfig.format === 'toml' ? '.toml' : '.md';
|
|
310
|
+
result.commands = fs.readdirSync(commandsDir)
|
|
311
|
+
.filter(f => f.endsWith(ext))
|
|
312
|
+
.map(f => f.replace(new RegExp(`\\${ext}$`), ''));
|
|
313
|
+
}
|
|
306
314
|
}
|
|
307
315
|
// Skills - check what directories exist AND content matches central source
|
|
308
316
|
const skillsDir = path.join(configDir, 'skills');
|
|
@@ -554,10 +562,15 @@ export function hasNewResources(diff, agent, version) {
|
|
|
554
562
|
* Build a summary string of new resources.
|
|
555
563
|
* E.g., "2 commands, 5 permission groups"
|
|
556
564
|
*/
|
|
557
|
-
function buildNewResourcesSummary(newResources, agent) {
|
|
565
|
+
function buildNewResourcesSummary(newResources, agent, version) {
|
|
558
566
|
const agentConfig = AGENTS[agent];
|
|
559
567
|
const parts = [];
|
|
560
|
-
|
|
568
|
+
// Use version-aware gates so Codex >= 0.117.0 (which converts commands to skills) doesn't
|
|
569
|
+
// double-count and so "16 commands" never appears in the summary when commands have
|
|
570
|
+
// already been emitted as skills in the version home.
|
|
571
|
+
const commandsApply = version ? supports(agent, 'commands', version).ok : COMMANDS_CAPABLE_AGENTS.includes(agent);
|
|
572
|
+
const commandsAsSkills = version ? shouldInstallCommandAsSkill(agent, version) : false;
|
|
573
|
+
if (newResources.commands.length > 0 && (commandsApply || commandsAsSkills)) {
|
|
561
574
|
parts.push(`${newResources.commands.length} command${newResources.commands.length === 1 ? '' : 's'}`);
|
|
562
575
|
}
|
|
563
576
|
if (newResources.skills.length > 0) {
|
|
@@ -566,7 +579,7 @@ function buildNewResourcesSummary(newResources, agent) {
|
|
|
566
579
|
if (newResources.hooks.length > 0 && agentConfig.supportsHooks) {
|
|
567
580
|
parts.push(`${newResources.hooks.length} hook${newResources.hooks.length === 1 ? '' : 's'}`);
|
|
568
581
|
}
|
|
569
|
-
if (newResources.memory.length > 0 &&
|
|
582
|
+
if (newResources.memory.length > 0 && (commandsApply || commandsAsSkills)) {
|
|
570
583
|
parts.push(`${newResources.memory.length} rule file${newResources.memory.length === 1 ? '' : 's'}`);
|
|
571
584
|
}
|
|
572
585
|
if (newResources.mcp.length > 0 && MCP_CAPABLE_AGENTS.includes(agent)) {
|
|
@@ -590,15 +603,21 @@ function buildNewResourcesSummary(newResources, agent) {
|
|
|
590
603
|
* Prompt user to select which NEW resources to sync.
|
|
591
604
|
* Only shows resources that haven't been synced yet.
|
|
592
605
|
*/
|
|
593
|
-
export async function promptNewResourceSelection(agent, newResources) {
|
|
606
|
+
export async function promptNewResourceSelection(agent, newResources, version) {
|
|
594
607
|
const agentConfig = AGENTS[agent];
|
|
595
608
|
const selection = {};
|
|
609
|
+
// Version-aware gates. When version is known, prefer per-version capability checks; the
|
|
610
|
+
// commands branch is allowed when either native commands are supported OR when the
|
|
611
|
+
// version emits commands as converted skills (Codex >= 0.117.0).
|
|
612
|
+
const commandsApply = version ? supports(agent, 'commands', version).ok : COMMANDS_CAPABLE_AGENTS.includes(agent);
|
|
613
|
+
const commandsAsSkills = version ? shouldInstallCommandAsSkill(agent, version) : false;
|
|
614
|
+
const commandsBranch = commandsApply || commandsAsSkills;
|
|
596
615
|
// Get permission group info for display
|
|
597
616
|
const permissionGroups = discoverPermissionGroups();
|
|
598
617
|
const newPermissionGroups = permissionGroups.filter(g => newResources.permissions.includes(g.name));
|
|
599
618
|
const totalNewPermissionRules = newPermissionGroups.reduce((sum, g) => sum + g.ruleCount, 0);
|
|
600
619
|
// Build the summary
|
|
601
|
-
const summary = buildNewResourcesSummary(newResources, agent);
|
|
620
|
+
const summary = buildNewResourcesSummary(newResources, agent, version);
|
|
602
621
|
console.log(chalk.cyan(`\nNew resources available:`));
|
|
603
622
|
console.log(chalk.gray(` ${summary}`));
|
|
604
623
|
// Ask how to handle new resources
|
|
@@ -616,13 +635,13 @@ export async function promptNewResourceSelection(agent, newResources) {
|
|
|
616
635
|
}
|
|
617
636
|
if (action === 'all') {
|
|
618
637
|
// Sync all new resources
|
|
619
|
-
if (newResources.commands.length > 0 &&
|
|
638
|
+
if (newResources.commands.length > 0 && commandsBranch)
|
|
620
639
|
selection.commands = newResources.commands;
|
|
621
640
|
if (newResources.skills.length > 0)
|
|
622
641
|
selection.skills = newResources.skills;
|
|
623
642
|
if (newResources.hooks.length > 0 && agentConfig.supportsHooks)
|
|
624
643
|
selection.hooks = newResources.hooks;
|
|
625
|
-
if (newResources.memory.length > 0 &&
|
|
644
|
+
if (newResources.memory.length > 0 && commandsBranch)
|
|
626
645
|
selection.memory = newResources.memory;
|
|
627
646
|
if (newResources.mcp.length > 0 && MCP_CAPABLE_AGENTS.includes(agent))
|
|
628
647
|
selection.mcp = newResources.mcp;
|
|
@@ -637,7 +656,7 @@ export async function promptNewResourceSelection(agent, newResources) {
|
|
|
637
656
|
return selection;
|
|
638
657
|
}
|
|
639
658
|
// Select specific items for each category
|
|
640
|
-
if (newResources.commands.length > 0 &&
|
|
659
|
+
if (newResources.commands.length > 0 && commandsBranch) {
|
|
641
660
|
const selected = await checkbox({
|
|
642
661
|
message: 'Select new commands to sync:',
|
|
643
662
|
choices: newResources.commands.map(c => ({ name: c, value: c, checked: true })),
|
|
@@ -661,7 +680,7 @@ export async function promptNewResourceSelection(agent, newResources) {
|
|
|
661
680
|
if (selected.length > 0)
|
|
662
681
|
selection.hooks = selected;
|
|
663
682
|
}
|
|
664
|
-
if (newResources.memory.length > 0 &&
|
|
683
|
+
if (newResources.memory.length > 0 && commandsBranch) {
|
|
665
684
|
const selected = await checkbox({
|
|
666
685
|
message: 'Select new rule files to sync:',
|
|
667
686
|
choices: newResources.memory.map(m => ({ name: m, value: m, checked: true })),
|
|
@@ -873,8 +892,26 @@ export function getVersionDir(agent, version) {
|
|
|
873
892
|
* Get the binary path for a specific agent version.
|
|
874
893
|
*/
|
|
875
894
|
export function getBinaryPath(agent, version) {
|
|
876
|
-
const versionDir = getVersionDir(agent, version);
|
|
877
895
|
const agentConfig = AGENTS[agent];
|
|
896
|
+
if (agent === 'grok') {
|
|
897
|
+
// Grok binaries live in the global ~/.grok/downloads, not per-version node_modules.
|
|
898
|
+
// We return a best-effort path (used for display / checks). Real resolution
|
|
899
|
+
// happens in agents.ts resolveGrokBinary + the generated shims.
|
|
900
|
+
const grokDownloads = path.join(os.homedir(), '.grok', 'downloads');
|
|
901
|
+
// Best effort: first matching file for this version
|
|
902
|
+
try {
|
|
903
|
+
const entries = fs.readdirSync(grokDownloads);
|
|
904
|
+
const match = entries.find((e) => e.includes(version) && e.startsWith('grok-'));
|
|
905
|
+
if (match)
|
|
906
|
+
return path.join(grokDownloads, match);
|
|
907
|
+
const first = entries.find((e) => e.startsWith('grok-'));
|
|
908
|
+
if (first)
|
|
909
|
+
return path.join(grokDownloads, first);
|
|
910
|
+
}
|
|
911
|
+
catch { }
|
|
912
|
+
return path.join(grokDownloads, `grok-${version}`);
|
|
913
|
+
}
|
|
914
|
+
const versionDir = getVersionDir(agent, version);
|
|
878
915
|
return path.join(versionDir, 'node_modules', '.bin', agentConfig.cliCommand);
|
|
879
916
|
}
|
|
880
917
|
/**
|
|
@@ -940,7 +977,7 @@ export function listInstalledVersions(agent) {
|
|
|
940
977
|
* List every version directory for an agent, including ones missing the
|
|
941
978
|
* binary (typically home-only leftovers from a prior `removeVersion`).
|
|
942
979
|
*
|
|
943
|
-
* Used by `agents prune` to surface stale installs that the regular
|
|
980
|
+
* Used by `agents prune cleanup` to surface stale installs that the regular
|
|
944
981
|
* `listInstalledVersions` filters out. Do NOT use elsewhere — every other
|
|
945
982
|
* call site assumes a working binary.
|
|
946
983
|
*/
|
|
@@ -991,7 +1028,35 @@ export function setGlobalDefault(agent, version) {
|
|
|
991
1028
|
export async function installVersion(agent, version, onProgress) {
|
|
992
1029
|
const agentConfig = AGENTS[agent];
|
|
993
1030
|
if (!agentConfig.npmPackage) {
|
|
994
|
-
|
|
1031
|
+
// Support agents that provide an installScript (cursor, roo, goose, kiro, grok, etc.)
|
|
1032
|
+
if (agentConfig.installScript) {
|
|
1033
|
+
// For grok we give special love because the user asked for first-class support
|
|
1034
|
+
if (agent === 'grok') {
|
|
1035
|
+
onProgress?.(`Installing Grok ${version} via official installer...`);
|
|
1036
|
+
try {
|
|
1037
|
+
const script = agentConfig.installScript.replace('VERSION', version);
|
|
1038
|
+
// The official installer supports -s <version>
|
|
1039
|
+
const { exec } = await import('child_process');
|
|
1040
|
+
const { promisify } = await import('util');
|
|
1041
|
+
const execAsync = promisify(exec);
|
|
1042
|
+
await execAsync(script, { timeout: 120000 });
|
|
1043
|
+
onProgress?.('Grok binary installed. Setting up agents-cli version home for isolation...');
|
|
1044
|
+
}
|
|
1045
|
+
catch (err) {
|
|
1046
|
+
return { success: false, installedVersion: version, error: `Grok installer failed: ${err.message}` };
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
else {
|
|
1050
|
+
return {
|
|
1051
|
+
success: false,
|
|
1052
|
+
installedVersion: version,
|
|
1053
|
+
error: `${agent} uses an external installer. Run: ${agentConfig.installScript}`,
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
else {
|
|
1058
|
+
return { success: false, installedVersion: version, error: 'Agent has no npm package' };
|
|
1059
|
+
}
|
|
995
1060
|
}
|
|
996
1061
|
// Validate before deriving filesystem paths or npm package specs. The CLI
|
|
997
1062
|
// parser already enforces this for user input; this guard protects direct
|
|
@@ -1004,7 +1069,15 @@ export async function installVersion(agent, version, onProgress) {
|
|
|
1004
1069
|
// Create version directory and isolated home
|
|
1005
1070
|
fs.mkdirSync(versionDir, { recursive: true });
|
|
1006
1071
|
fs.mkdirSync(path.join(versionDir, 'home'), { recursive: true });
|
|
1007
|
-
//
|
|
1072
|
+
// For agents using external installers (especially grok), we don't do npm install.
|
|
1073
|
+
// The binary is managed by the agent's own installer; we only manage the isolated home + resources.
|
|
1074
|
+
if (agent === 'grok' || !agentConfig.npmPackage) {
|
|
1075
|
+
// Grok (and similar) — binary already installed by the step above (or user ran external installer).
|
|
1076
|
+
// We still want to record the version for config isolation.
|
|
1077
|
+
createVersionedAlias(agent, version);
|
|
1078
|
+
return { success: true, installedVersion: version };
|
|
1079
|
+
}
|
|
1080
|
+
// Initialize package.json (only for real npm agents)
|
|
1008
1081
|
const packageJson = {
|
|
1009
1082
|
name: `agents-${agent}-${version}`,
|
|
1010
1083
|
version: '1.0.0',
|
|
@@ -1147,8 +1220,6 @@ export function removeVersion(agent, version) {
|
|
|
1147
1220
|
}
|
|
1148
1221
|
// Remove versioned alias (e.g., claude@2.0.65)
|
|
1149
1222
|
removeVersionedAlias(agent, version);
|
|
1150
|
-
// Clear resource tracking for this version
|
|
1151
|
-
clearVersionResources(agent, version);
|
|
1152
1223
|
// Clear default if it was the removed version - user must explicitly pick a new one
|
|
1153
1224
|
if (getGlobalDefault(agent) === version) {
|
|
1154
1225
|
const meta = readMeta();
|
|
@@ -1175,6 +1246,23 @@ export function removeVersion(agent, version) {
|
|
|
1175
1246
|
emit('version.remove', { agent, version });
|
|
1176
1247
|
return true;
|
|
1177
1248
|
}
|
|
1249
|
+
/**
|
|
1250
|
+
* Print the standard footer after one or more versions were soft-deleted to
|
|
1251
|
+
* trash. Reminds the user that sessions stay readable and how to restore.
|
|
1252
|
+
*/
|
|
1253
|
+
export function printTrashFooter(moved) {
|
|
1254
|
+
if (moved.length === 0)
|
|
1255
|
+
return;
|
|
1256
|
+
console.log();
|
|
1257
|
+
console.log(chalk.gray('Sessions remain accessible via `agents sessions`.'));
|
|
1258
|
+
if (moved.length === 1) {
|
|
1259
|
+
const { agent, version } = moved[0];
|
|
1260
|
+
console.log(chalk.gray(`Restore with: agents trash restore ${agent}@${version}`));
|
|
1261
|
+
}
|
|
1262
|
+
else {
|
|
1263
|
+
console.log(chalk.gray('Restore with: agents trash restore <agent>@<version> (run `agents trash list` to see)'));
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1178
1266
|
/**
|
|
1179
1267
|
* Remove all versions of an agent. Preserves each version's `home/` directory
|
|
1180
1268
|
* so conversation history is never deleted; the per-version folders (now
|
|
@@ -1626,13 +1714,25 @@ export function syncResourcesToVersion(agent, version, selection, options = {})
|
|
|
1626
1714
|
}
|
|
1627
1715
|
const syncedCommands = [];
|
|
1628
1716
|
for (const cmd of commandsToSync) {
|
|
1629
|
-
|
|
1630
|
-
|
|
1717
|
+
// Commands are content that gets injected into the agent's prompt
|
|
1718
|
+
// surface (slash commands, skill bodies). We intentionally do NOT pull
|
|
1719
|
+
// from the project's own .agents/commands/ directory: a cloned public
|
|
1720
|
+
// repo could ship a command whose body instructs the agent to do
|
|
1721
|
+
// something harmful the next time the user invokes it. Commands must
|
|
1722
|
+
// come from the user's central ~/.agents/commands/, the system layer,
|
|
1723
|
+
// or an explicitly enabled extra repo. Same defense as hooks below.
|
|
1724
|
+
const candidates = [
|
|
1725
|
+
safeJoin(path.join(userAgentsDir, 'commands'), `${cmd}.md`),
|
|
1726
|
+
safeJoin(getCommandsDir(), `${cmd}.md`),
|
|
1727
|
+
...extraRepos.map((e) => safeJoin(path.join(e.dir, 'commands'), `${cmd}.md`)),
|
|
1728
|
+
];
|
|
1729
|
+
const srcFile = candidates.find((p) => p && fs.existsSync(p) && !fs.lstatSync(p).isSymbolicLink()) || null;
|
|
1730
|
+
if (!srcFile)
|
|
1631
1731
|
continue;
|
|
1632
|
-
const srcFile = resolved.path;
|
|
1633
1732
|
if (commandsAsSkills) {
|
|
1733
|
+
// Project skills dir is intentionally excluded for the same reason
|
|
1734
|
+
// commands are: the body of a project skill becomes agent context.
|
|
1634
1735
|
const skillSourceDirs = [
|
|
1635
|
-
projectAgentsDir ? path.join(projectAgentsDir, 'skills') : null,
|
|
1636
1736
|
path.join(userAgentsDir, 'skills'),
|
|
1637
1737
|
getSkillsDir(),
|
|
1638
1738
|
...extraRepos.map((e) => path.join(e.dir, 'skills')),
|
|
@@ -1653,6 +1753,30 @@ export function syncResourcesToVersion(agent, version, selection, options = {})
|
|
|
1653
1753
|
}
|
|
1654
1754
|
result.commands = syncedCommands.length > 0;
|
|
1655
1755
|
}
|
|
1756
|
+
// Orphan-sweep stale top-level command files from previous syncs under a
|
|
1757
|
+
// different cwd. Only runs in "full sync" mode — i.e. when the caller did
|
|
1758
|
+
// not pass an explicit `selection`. Callers that pass explicit selections
|
|
1759
|
+
// are using the incremental/additive API (sync exactly these; leave others
|
|
1760
|
+
// alone), so the sweep would be a contract violation there. The
|
|
1761
|
+
// cross-project leak fixed by RUSH-670 always comes from the no-selection
|
|
1762
|
+
// shim auto-sync at launch.
|
|
1763
|
+
if (!userPassedSelection && COMMANDS_CAPABLE_AGENTS.includes(agent) && !shouldInstallCommandAsSkill(agent, version)) {
|
|
1764
|
+
const commandsTargetSweep = path.join(agentDir, agentConfig.commandsSubdir);
|
|
1765
|
+
if (fs.existsSync(commandsTargetSweep)) {
|
|
1766
|
+
const ext = agentConfig.format === 'toml' ? '.toml' : '.md';
|
|
1767
|
+
const trustedCommands = new Set(commandsToSync);
|
|
1768
|
+
for (const entry of fs.readdirSync(commandsTargetSweep, { withFileTypes: true })) {
|
|
1769
|
+
if (!entry.isFile() || entry.name.startsWith('.'))
|
|
1770
|
+
continue;
|
|
1771
|
+
if (!entry.name.endsWith(ext))
|
|
1772
|
+
continue;
|
|
1773
|
+
const name = entry.name.slice(0, -ext.length);
|
|
1774
|
+
if (!trustedCommands.has(name)) {
|
|
1775
|
+
removePath(safeJoin(commandsTargetSweep, entry.name));
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1656
1780
|
// Sync skills (skip if agent natively reads ~/.agents/skills/)
|
|
1657
1781
|
if (agentConfig.nativeAgentsSkillsDir) {
|
|
1658
1782
|
// Clean up stale skills symlink/dir — agent reads from ~/.agents/skills/ directly
|
|
@@ -1677,10 +1801,19 @@ export function syncResourcesToVersion(agent, version, selection, options = {})
|
|
|
1677
1801
|
fs.mkdirSync(skillsTarget, { recursive: true });
|
|
1678
1802
|
const syncedSkills = [];
|
|
1679
1803
|
for (const skill of skillsToSync) {
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1804
|
+
// Same defense as commands and hooks: don't pull skills from the
|
|
1805
|
+
// project's .agents/skills/ directory. A skill's contents (SKILL.md
|
|
1806
|
+
// and any auxiliary scripts) get loaded into the agent's tool/context
|
|
1807
|
+
// surface, and a malicious public repo could ship a SKILL.md whose
|
|
1808
|
+
// body coerces the agent. Trusted layers only.
|
|
1809
|
+
const skillCandidates = [
|
|
1810
|
+
safeJoin(path.join(userAgentsDir, 'skills'), skill),
|
|
1811
|
+
safeJoin(getSkillsDir(), skill),
|
|
1812
|
+
...extraRepos.map((e) => safeJoin(path.join(e.dir, 'skills'), skill)),
|
|
1813
|
+
];
|
|
1814
|
+
const srcDir = skillCandidates.find((p) => fs.existsSync(p) &&
|
|
1815
|
+
!fs.lstatSync(p).isSymbolicLink() &&
|
|
1816
|
+
fs.lstatSync(p).isDirectory()) || null;
|
|
1684
1817
|
if (!srcDir)
|
|
1685
1818
|
continue;
|
|
1686
1819
|
const destDir = safeJoin(skillsTarget, skill);
|
|
@@ -1690,6 +1823,21 @@ export function syncResourcesToVersion(agent, version, selection, options = {})
|
|
|
1690
1823
|
}
|
|
1691
1824
|
result.skills = syncedSkills.length > 0;
|
|
1692
1825
|
}
|
|
1826
|
+
// Orphan-sweep stale skill directories from previous syncs under a
|
|
1827
|
+
// different cwd. Only runs in "full sync" mode (no explicit selection) —
|
|
1828
|
+
// see the matching guard on the commands sweep above for why. Skip
|
|
1829
|
+
// dot-dirs to keep plugin-managed subtrees (.plugins/, .promptcuts) intact.
|
|
1830
|
+
const skillsTargetSweep = path.join(agentDir, 'skills');
|
|
1831
|
+
if (!userPassedSelection && fs.existsSync(skillsTargetSweep) && !fs.lstatSync(skillsTargetSweep).isSymbolicLink()) {
|
|
1832
|
+
const trustedSkills = new Set(skillsToSync);
|
|
1833
|
+
for (const entry of fs.readdirSync(skillsTargetSweep, { withFileTypes: true })) {
|
|
1834
|
+
if (!entry.isDirectory() || entry.name.startsWith('.'))
|
|
1835
|
+
continue;
|
|
1836
|
+
if (!trustedSkills.has(entry.name)) {
|
|
1837
|
+
removePath(safeJoin(skillsTargetSweep, entry.name));
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1693
1841
|
}
|
|
1694
1842
|
// Sync hooks (if agent supports them at this version)
|
|
1695
1843
|
const hooksGate = supports(agent, 'hooks', version);
|
|
@@ -1742,7 +1890,9 @@ export function syncResourcesToVersion(agent, version, selection, options = {})
|
|
|
1742
1890
|
result.hooks = syncedHooks.length > 0;
|
|
1743
1891
|
// Register hooks into agent-native settings.json/hooks.json. Gemini
|
|
1744
1892
|
// shipped hooks in 0.26.0; gate already passed above so this is safe.
|
|
1745
|
-
|
|
1893
|
+
// Grok auto-discovers from ~/.grok/hooks/ so the script copy above
|
|
1894
|
+
// is sufficient — no settings.json registration needed.
|
|
1895
|
+
if (agent === 'claude' || agent === 'codex' || agent === 'gemini' || agent === 'antigravity') {
|
|
1746
1896
|
registerHooksToSettings(agent, versionHome);
|
|
1747
1897
|
}
|
|
1748
1898
|
}
|
|
@@ -1781,6 +1931,10 @@ export function syncResourcesToVersion(agent, version, selection, options = {})
|
|
|
1781
1931
|
// ~/.agents/permissions/presets/<name>.yaml pick a subset via `includes:`.
|
|
1782
1932
|
// If AGENTS_PERMISSION_PRESET is set, we resolve that recipe and use its
|
|
1783
1933
|
// includes list as the group filter (intersected with groups on disk).
|
|
1934
|
+
// Note: discoverPermissionGroups intentionally reads from user + system
|
|
1935
|
+
// only — never from a project's .agents/permissions/. Permissions gate
|
|
1936
|
+
// every other action, so a cloned public repo must not be able to widen
|
|
1937
|
+
// its own sandbox by shipping a permissions group. Same defense as hooks.
|
|
1784
1938
|
const permissionGroups = discoverPermissionGroups();
|
|
1785
1939
|
const allGroupNames = permissionGroups.map(g => g.name);
|
|
1786
1940
|
const activePresetName = getActivePermissionPresetName();
|
|
@@ -1825,15 +1979,30 @@ export function syncResourcesToVersion(agent, version, selection, options = {})
|
|
|
1825
1979
|
// Install MCP servers (if agent supports them)
|
|
1826
1980
|
// For Claude/Codex: uses CLI commands (claude mcp add, codex mcp add)
|
|
1827
1981
|
// For others: edits config files directly
|
|
1828
|
-
|
|
1982
|
+
//
|
|
1983
|
+
// Mirror the hooks defense: exclude project-scoped MCPs from the sync. An
|
|
1984
|
+
// MCP server is an executable invoked under the agent's authority, so a
|
|
1985
|
+
// cloned public repo's .agents/mcp/foo.yaml could install an arbitrary
|
|
1986
|
+
// command. We pre-compute the set of project-scoped names and drop them
|
|
1987
|
+
// before handing the list to installMcpServers. (The deeper helper-side
|
|
1988
|
+
// dedup in lib/mcp.ts still lets a project entry shadow a same-named
|
|
1989
|
+
// user entry, so name-collision shadowing is not fully closed here —
|
|
1990
|
+
// tracked separately for a follow-up in lib/mcp.ts.)
|
|
1991
|
+
const projectScopedMcpNames = new Set(getScopedMcpResources(cwd).filter(r => r.scope === 'project').map(r => r.name));
|
|
1992
|
+
const mcpToSyncAll = selection
|
|
1829
1993
|
? resolveSelection(selection.mcp, available.mcp)
|
|
1830
1994
|
: (MCP_CAPABLE_AGENTS.includes(agent) ? available.mcp : []);
|
|
1995
|
+
const mcpToSync = mcpToSyncAll.filter(n => !projectScopedMcpNames.has(n));
|
|
1831
1996
|
if (mcpToSync.length > 0 && MCP_CAPABLE_AGENTS.includes(agent)) {
|
|
1832
1997
|
const mcpResult = installMcpServers(agent, version, versionHome, mcpToSync, { cwd });
|
|
1833
1998
|
result.mcp = mcpResult.applied;
|
|
1834
1999
|
// mcp patterns already written via ensureVersionResourcePatterns above.
|
|
1835
2000
|
}
|
|
1836
|
-
// Sync subagents (claude and openclaw only)
|
|
2001
|
+
// Sync subagents (claude and openclaw only).
|
|
2002
|
+
// Note: listInstalledSubagents (used to populate the map below) reads only
|
|
2003
|
+
// user + system layers — never project. Subagents bundle prompts that fire
|
|
2004
|
+
// when the agent delegates work, so a cloned public repo must not be able
|
|
2005
|
+
// to plant a subagent the user later invokes. Same defense as hooks.
|
|
1837
2006
|
const subagentsToSync = selection
|
|
1838
2007
|
? resolveSelection(selection.subagents, available.subagents)
|
|
1839
2008
|
: (SUBAGENT_CAPABLE_AGENTS.includes(agent) ? available.subagents : []);
|
|
@@ -1864,6 +2033,29 @@ export function syncResourcesToVersion(agent, version, selection, options = {})
|
|
|
1864
2033
|
}
|
|
1865
2034
|
catch { /* resource sync failed for this item */ }
|
|
1866
2035
|
}
|
|
2036
|
+
// Orphan-sweep stale subagents. Same selection-mode guard as the
|
|
2037
|
+
// commands/skills sweeps above. Claude stores them as flat .md files
|
|
2038
|
+
// under `<agentDir>/agents/`; OpenClaw stores them as subdirs at the
|
|
2039
|
+
// same level as commands/skills/hooks/plugins (no isolated parent dir),
|
|
2040
|
+
// which means a directory-readdir sweep would unsafely hit unrelated
|
|
2041
|
+
// resources. For OpenClaw we lean on the existing per-name copy path —
|
|
2042
|
+
// if the user wants strict isolation on OpenClaw, track via manifest.
|
|
2043
|
+
if (!userPassedSelection && agent === 'claude') {
|
|
2044
|
+
const claudeAgentsDir = path.join(agentDir, 'agents');
|
|
2045
|
+
if (fs.existsSync(claudeAgentsDir)) {
|
|
2046
|
+
const trustedSubagents = new Set(subagentsToSync);
|
|
2047
|
+
for (const entry of fs.readdirSync(claudeAgentsDir, { withFileTypes: true })) {
|
|
2048
|
+
if (!entry.isFile() || entry.name.startsWith('.'))
|
|
2049
|
+
continue;
|
|
2050
|
+
if (!entry.name.endsWith('.md'))
|
|
2051
|
+
continue;
|
|
2052
|
+
const name = entry.name.slice(0, -'.md'.length);
|
|
2053
|
+
if (!trustedSubagents.has(name)) {
|
|
2054
|
+
removePath(safeJoin(claudeAgentsDir, entry.name));
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
1867
2059
|
// subagent patterns already written via ensureVersionResourcePatterns above.
|
|
1868
2060
|
}
|
|
1869
2061
|
// Sync plugins (claude and openclaw)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phnx-labs/agents-cli",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "One CLI for all your AI coding agents - versions, config, cloud dispatch, sessions, and teams",
|
|
3
|
+
"version": "1.20.0",
|
|
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",
|
|
7
7
|
"exports": {
|
|
@@ -23,8 +23,7 @@
|
|
|
23
23
|
"files": [
|
|
24
24
|
"dist/**/*.js",
|
|
25
25
|
"dist/**/*.d.ts",
|
|
26
|
-
"dist/lib/secrets/
|
|
27
|
-
"npm-shrinkwrap.json",
|
|
26
|
+
"dist/lib/secrets/Agents CLI.app/**",
|
|
28
27
|
"scripts/postinstall.js",
|
|
29
28
|
"CHANGELOG.md",
|
|
30
29
|
"README.md",
|
|
@@ -42,7 +41,7 @@
|
|
|
42
41
|
"url": "https://github.com/phnx-labs/agents-cli/issues"
|
|
43
42
|
},
|
|
44
43
|
"scripts": {
|
|
45
|
-
"build": "tsc && rm -rf dist/lib/secrets/AgentsKeychain.app && ([ \"$(uname)\" = \"Darwin\" ] && cp -R bin/
|
|
44
|
+
"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)",
|
|
46
45
|
"prepack": "scripts/verify-keychain-helper.sh",
|
|
47
46
|
"postinstall": "node scripts/postinstall.js",
|
|
48
47
|
"dev": "tsx src/index.ts",
|
|
@@ -59,6 +58,8 @@
|
|
|
59
58
|
"gemini",
|
|
60
59
|
"cursor",
|
|
61
60
|
"opencode",
|
|
61
|
+
"grok",
|
|
62
|
+
"xai",
|
|
62
63
|
"mcp",
|
|
63
64
|
"skills",
|
|
64
65
|
"ai",
|
|
@@ -72,14 +73,14 @@
|
|
|
72
73
|
"npm": ">=9"
|
|
73
74
|
},
|
|
74
75
|
"dependencies": {
|
|
75
|
-
"@inquirer/prompts": "
|
|
76
|
+
"@inquirer/prompts": "8.5.1",
|
|
76
77
|
"@types/proper-lockfile": "4.1.4",
|
|
77
78
|
"@xterm/headless": "6.0.0",
|
|
78
79
|
"@zed-industries/agent-client-protocol": "0.4.5",
|
|
79
80
|
"chalk": "5.6.2",
|
|
80
81
|
"commander": "12.1.0",
|
|
81
82
|
"croner": "9.1.0",
|
|
82
|
-
"diff": "
|
|
83
|
+
"diff": "9.0.0",
|
|
83
84
|
"marked": "15.0.12",
|
|
84
85
|
"marked-terminal": "7.3.0",
|
|
85
86
|
"node-pty": "1.1.0",
|
|
@@ -93,8 +94,7 @@
|
|
|
93
94
|
"@types/diff": "6.0.0",
|
|
94
95
|
"@types/marked-terminal": "6.1.1",
|
|
95
96
|
"@types/node": "22.19.10",
|
|
96
|
-
"
|
|
97
|
-
"tsx": "4.22.2",
|
|
97
|
+
"tsx": "4.22.3",
|
|
98
98
|
"typescript": "5.9.3",
|
|
99
99
|
"vitest": "4.1.6"
|
|
100
100
|
}
|
|
Binary file
|