@phnx-labs/agents-cli 1.20.4 → 1.20.5
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 +19 -0
- package/README.md +48 -17
- package/dist/commands/cli.js +1 -1
- package/dist/commands/cloud.js +1 -1
- package/dist/commands/commands.js +2 -0
- package/dist/commands/doctor.js +1 -1
- package/dist/commands/exec.js +52 -16
- package/dist/commands/hooks.js +6 -6
- package/dist/commands/inspect.d.ts +26 -0
- package/dist/commands/inspect.js +590 -0
- package/dist/commands/mcp.js +17 -16
- package/dist/commands/models.js +1 -1
- package/dist/commands/packages.js +6 -4
- package/dist/commands/permissions.js +13 -12
- package/dist/commands/plugins.d.ts +13 -0
- package/dist/commands/plugins.js +100 -11
- package/dist/commands/prune.js +3 -2
- package/dist/commands/pull.d.ts +12 -5
- package/dist/commands/pull.js +26 -422
- package/dist/commands/push.d.ts +14 -0
- package/dist/commands/push.js +30 -0
- package/dist/commands/repo.d.ts +1 -1
- package/dist/commands/repo.js +155 -112
- package/dist/commands/resource-view.d.ts +2 -0
- package/dist/commands/resource-view.js +12 -3
- package/dist/commands/routines.js +32 -7
- package/dist/commands/rules.js +1 -1
- package/dist/commands/sessions.js +1 -0
- package/dist/commands/setup.d.ts +3 -3
- package/dist/commands/setup.js +15 -15
- package/dist/commands/skills.js +6 -5
- package/dist/commands/subagents.js +5 -4
- package/dist/commands/sync.d.ts +18 -5
- package/dist/commands/sync.js +251 -65
- package/dist/commands/teams.js +1 -0
- package/dist/commands/tmux.d.ts +25 -0
- package/dist/commands/tmux.js +415 -0
- package/dist/commands/trash.d.ts +2 -2
- package/dist/commands/trash.js +1 -1
- package/dist/commands/versions.js +2 -2
- package/dist/commands/view.js +9 -4
- package/dist/commands/workflows.js +4 -3
- package/dist/commands/worktree.d.ts +4 -5
- package/dist/commands/worktree.js +4 -4
- package/dist/index.js +68 -20
- package/dist/lib/agents.d.ts +19 -10
- package/dist/lib/agents.js +79 -25
- package/dist/lib/auto-pull-worker.d.ts +1 -1
- package/dist/lib/auto-pull-worker.js +2 -2
- package/dist/lib/auto-pull.d.ts +1 -1
- package/dist/lib/auto-pull.js +1 -1
- package/dist/lib/beta.d.ts +1 -1
- package/dist/lib/beta.js +1 -1
- package/dist/lib/capabilities.js +2 -0
- package/dist/lib/commands.d.ts +28 -1
- package/dist/lib/commands.js +125 -20
- package/dist/lib/doctor-diff.js +2 -2
- package/dist/lib/exec.d.ts +14 -0
- package/dist/lib/exec.js +39 -5
- package/dist/lib/fuzzy.d.ts +12 -2
- package/dist/lib/fuzzy.js +29 -4
- package/dist/lib/git.js +8 -1
- package/dist/lib/hooks.d.ts +2 -2
- package/dist/lib/hooks.js +97 -10
- package/dist/lib/mcp.js +32 -2
- package/dist/lib/migrate.d.ts +51 -0
- package/dist/lib/migrate.js +227 -1
- package/dist/lib/models.js +62 -15
- package/dist/lib/permissions.d.ts +36 -2
- package/dist/lib/permissions.js +217 -7
- package/dist/lib/plugin-marketplace.d.ts +98 -40
- package/dist/lib/plugin-marketplace.js +196 -93
- package/dist/lib/plugins.d.ts +21 -4
- package/dist/lib/plugins.js +130 -49
- package/dist/lib/profiles-presets.js +12 -12
- package/dist/lib/project-launch.d.ts +65 -0
- package/dist/lib/project-launch.js +367 -0
- package/dist/lib/pty-client.js +1 -1
- package/dist/lib/pty-server.d.ts +1 -1
- package/dist/lib/pty-server.js +1 -1
- package/dist/lib/refresh.d.ts +26 -0
- package/dist/lib/refresh.js +315 -0
- package/dist/lib/resource-patterns.d.ts +1 -1
- package/dist/lib/resource-patterns.js +1 -1
- package/dist/lib/resources/commands.js +2 -2
- package/dist/lib/resources/hooks.d.ts +1 -1
- package/dist/lib/resources/hooks.js +1 -1
- package/dist/lib/resources/mcp.d.ts +1 -1
- package/dist/lib/resources/mcp.js +5 -6
- package/dist/lib/resources/permissions.js +5 -2
- package/dist/lib/resources/rules.js +3 -2
- package/dist/lib/resources/skills.js +3 -2
- package/dist/lib/resources/types.d.ts +1 -1
- package/dist/lib/resources.js +2 -2
- package/dist/lib/rotate.d.ts +1 -1
- package/dist/lib/rotate.js +1 -1
- package/dist/lib/routines.d.ts +16 -4
- package/dist/lib/routines.js +67 -17
- package/dist/lib/rules/compile.js +22 -10
- package/dist/lib/rules/rules.js +3 -3
- package/dist/lib/runner.js +16 -3
- package/dist/lib/scheduler.js +15 -1
- 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/Agents CLI.app/Contents/_CodeSignature/CodeResources +9 -1
- package/dist/lib/secrets/Agents CLI.app/Contents/embedded.provisionprofile +0 -0
- package/dist/lib/secrets/linux.d.ts +44 -9
- package/dist/lib/secrets/linux.js +302 -48
- package/dist/lib/session/db.js +15 -2
- package/dist/lib/session/discover.js +118 -3
- package/dist/lib/session/parse.js +3 -0
- package/dist/lib/session/types.d.ts +1 -1
- package/dist/lib/session/types.js +1 -1
- package/dist/lib/shims.d.ts +10 -9
- package/dist/lib/shims.js +101 -50
- package/dist/lib/skills.d.ts +1 -1
- package/dist/lib/skills.js +10 -9
- package/dist/lib/staleness/detectors/commands.d.ts +3 -0
- package/dist/lib/staleness/detectors/commands.js +46 -0
- package/dist/lib/staleness/detectors/hooks.d.ts +3 -0
- package/dist/lib/staleness/detectors/hooks.js +44 -0
- package/dist/lib/staleness/detectors/mcp.d.ts +3 -0
- package/dist/lib/staleness/detectors/mcp.js +31 -0
- package/dist/lib/staleness/detectors/permissions.d.ts +3 -0
- package/dist/lib/staleness/detectors/permissions.js +201 -0
- package/dist/lib/staleness/detectors/plugins.d.ts +8 -0
- package/dist/lib/staleness/detectors/plugins.js +23 -0
- package/dist/lib/staleness/detectors/rules.d.ts +3 -0
- package/dist/lib/staleness/detectors/rules.js +34 -0
- package/dist/lib/staleness/detectors/skills.d.ts +3 -0
- package/dist/lib/staleness/detectors/skills.js +71 -0
- package/dist/lib/staleness/detectors/subagents.d.ts +3 -0
- package/dist/lib/staleness/detectors/subagents.js +50 -0
- package/dist/lib/staleness/detectors/types.d.ts +22 -0
- package/dist/lib/staleness/detectors/types.js +1 -0
- package/dist/lib/staleness/detectors/workflows.d.ts +3 -0
- package/dist/lib/staleness/detectors/workflows.js +28 -0
- package/dist/lib/staleness/registry.d.ts +26 -0
- package/dist/lib/staleness/registry.js +123 -0
- package/dist/lib/staleness/writers/commands.d.ts +3 -0
- package/dist/lib/staleness/writers/commands.js +111 -0
- package/dist/lib/staleness/writers/hooks.d.ts +3 -0
- package/dist/lib/staleness/writers/hooks.js +47 -0
- package/dist/lib/staleness/writers/kinds.d.ts +10 -0
- package/dist/lib/staleness/writers/kinds.js +15 -0
- package/dist/lib/staleness/writers/lazy-map.d.ts +13 -0
- package/dist/lib/staleness/writers/lazy-map.js +19 -0
- package/dist/lib/staleness/writers/mcp.d.ts +10 -0
- package/dist/lib/staleness/writers/mcp.js +19 -0
- package/dist/lib/staleness/writers/permissions.d.ts +13 -0
- package/dist/lib/staleness/writers/permissions.js +26 -0
- package/dist/lib/staleness/writers/plugins.d.ts +7 -0
- package/dist/lib/staleness/writers/plugins.js +31 -0
- package/dist/lib/staleness/writers/rules.d.ts +7 -0
- package/dist/lib/staleness/writers/rules.js +55 -0
- package/dist/lib/staleness/writers/skills.d.ts +3 -0
- package/dist/lib/staleness/writers/skills.js +81 -0
- package/dist/lib/staleness/writers/sources.d.ts +16 -0
- package/dist/lib/staleness/writers/sources.js +72 -0
- package/dist/lib/staleness/writers/subagents.d.ts +3 -0
- package/dist/lib/staleness/writers/subagents.js +53 -0
- package/dist/lib/staleness/writers/types.d.ts +36 -0
- package/dist/lib/staleness/writers/types.js +1 -0
- package/dist/lib/staleness/writers/workflows.d.ts +7 -0
- package/dist/lib/staleness/writers/workflows.js +31 -0
- package/dist/lib/state.d.ts +34 -11
- package/dist/lib/state.js +58 -13
- package/dist/lib/subagents.d.ts +0 -2
- package/dist/lib/subagents.js +6 -6
- package/dist/lib/teams/agents.js +1 -1
- package/dist/lib/teams/parsers.d.ts +1 -1
- package/dist/lib/tmux/binary.d.ts +67 -0
- package/dist/lib/tmux/binary.js +141 -0
- package/dist/lib/tmux/index.d.ts +8 -0
- package/dist/lib/tmux/index.js +8 -0
- package/dist/lib/tmux/paths.d.ts +17 -0
- package/dist/lib/tmux/paths.js +30 -0
- package/dist/lib/tmux/session.d.ts +122 -0
- package/dist/lib/tmux/session.js +305 -0
- package/dist/lib/types.d.ts +58 -7
- package/dist/lib/types.js +1 -1
- package/dist/lib/usage.js +1 -1
- package/dist/lib/versions.d.ts +4 -4
- package/dist/lib/versions.js +135 -493
- package/dist/lib/workflows.d.ts +2 -4
- package/dist/lib/workflows.js +3 -4
- package/package.json +2 -2
- package/scripts/postinstall.js +16 -63
- package/dist/commands/status.d.ts +0 -9
- package/dist/commands/status.js +0 -25
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Materialization helpers — install manifest CLIs, register MCP servers,
|
|
3
|
+
* sync resources into installed version homes, register hooks, add shims to
|
|
4
|
+
* PATH, prompt for missing default versions, install declared host-CLIs.
|
|
5
|
+
*
|
|
6
|
+
* Used by `agents repo refresh` (user-facing) and any other caller that needs
|
|
7
|
+
* to re-derive local state from declared configuration. Does NOT do any git
|
|
8
|
+
* operations — that lives in `agents repo pull`.
|
|
9
|
+
*/
|
|
10
|
+
import * as fs from 'fs';
|
|
11
|
+
import * as path from 'path';
|
|
12
|
+
import chalk from 'chalk';
|
|
13
|
+
import ora from 'ora';
|
|
14
|
+
import { select, confirm } from '@inquirer/prompts';
|
|
15
|
+
import { capableAgents } from './capabilities.js';
|
|
16
|
+
import { AGENTS, ALL_AGENT_IDS, getAllCliStates, registerMcpToTargets, agentLabel, } from './agents.js';
|
|
17
|
+
import { readManifest, MANIFEST_FILENAME } from './manifest.js';
|
|
18
|
+
import { getUserAgentsDir } from './state.js';
|
|
19
|
+
import { installVersion, listInstalledVersions, getGlobalDefault, setGlobalDefault, getVersionHomePath, syncResourcesToVersion, getAvailableResources, getActuallySyncedResources, getNewResources, getProjectOnlyResources, hasNewResources, promptNewResourceSelection, promptResourceSelection, resolveConfiguredAgentTargets, } from './versions.js';
|
|
20
|
+
import { listCliStatus, installCli, describeMethod, describeCheck, selectInstallMethod, } from './cli-resources.js';
|
|
21
|
+
import { ensureShimCurrent, isShimsInPath, addShimsToPath, getPathSetupInstructions, switchConfigSymlink, switchHomeFileSymlinks, } from './shims.js';
|
|
22
|
+
import { parseHookManifest, registerHooksToSettings } from './hooks.js';
|
|
23
|
+
import { isPromptCancelled } from '../commands/utils.js';
|
|
24
|
+
/**
|
|
25
|
+
* Old repo layout stored promptcuts under claude/promptcuts.yaml (agent-scoped).
|
|
26
|
+
* The new layout is `~/.agents/.system/promptcuts.yaml` at the repo root — the
|
|
27
|
+
* hook reads from a fixed path so it survives version upgrades. If the root
|
|
28
|
+
* file doesn't exist yet but an agent-scoped one does, hoist the first one found.
|
|
29
|
+
*/
|
|
30
|
+
function migratePromptcutsToRoot(agentsDir) {
|
|
31
|
+
const rootPath = path.join(agentsDir, 'promptcuts.yaml');
|
|
32
|
+
if (fs.existsSync(rootPath))
|
|
33
|
+
return;
|
|
34
|
+
const agentDirs = ['claude', 'codex', 'cursor', 'gemini', 'opencode'];
|
|
35
|
+
for (const dir of agentDirs) {
|
|
36
|
+
const legacyPath = path.join(agentsDir, dir, 'promptcuts.yaml');
|
|
37
|
+
if (fs.existsSync(legacyPath)) {
|
|
38
|
+
try {
|
|
39
|
+
fs.renameSync(legacyPath, rootPath);
|
|
40
|
+
console.log(chalk.gray(`Moved ${dir}/promptcuts.yaml → promptcuts.yaml (repo root)`));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Best-effort migration; hook still works if the user moves it manually.
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Re-materialize local state from declared configuration: install CLI versions,
|
|
51
|
+
* register MCP servers, sync resources to version homes, register hooks, add
|
|
52
|
+
* shims to PATH, prompt for missing defaults, install declared host-CLIs.
|
|
53
|
+
*
|
|
54
|
+
* Idempotent — safe to run repeatedly. No network operations.
|
|
55
|
+
*/
|
|
56
|
+
export async function refresh(options = {}) {
|
|
57
|
+
const { agentFilter, skipPrompts = false, skipClis = false } = options;
|
|
58
|
+
const agentsDir = getUserAgentsDir();
|
|
59
|
+
migratePromptcutsToRoot(agentsDir);
|
|
60
|
+
const manifest = readManifest(agentsDir);
|
|
61
|
+
if (!manifest) {
|
|
62
|
+
console.log(chalk.gray(`No ${MANIFEST_FILENAME} found`));
|
|
63
|
+
}
|
|
64
|
+
// 1. Install/upgrade CLI versions from agents.yaml
|
|
65
|
+
if (!skipClis && manifest?.agents) {
|
|
66
|
+
console.log(chalk.bold('\nCLI Versions:\n'));
|
|
67
|
+
const cliAgents = Object.keys(manifest.agents);
|
|
68
|
+
for (const agentId of cliAgents) {
|
|
69
|
+
if (agentFilter && agentId !== agentFilter)
|
|
70
|
+
continue;
|
|
71
|
+
const agent = AGENTS[agentId];
|
|
72
|
+
if (!agent)
|
|
73
|
+
continue;
|
|
74
|
+
const cliSpinner = ora(`Checking ${agentLabel(agent.id)}...`).start();
|
|
75
|
+
const versions = listInstalledVersions(agentId);
|
|
76
|
+
const targetVersion = manifest.agents[agentId] || 'latest';
|
|
77
|
+
const result = await installVersion(agentId, targetVersion, (msg) => { cliSpinner.text = msg; });
|
|
78
|
+
if (result.success) {
|
|
79
|
+
const isNew = versions.length === 0;
|
|
80
|
+
if (isNew) {
|
|
81
|
+
cliSpinner.succeed(`Installed ${agentLabel(agent.id)}@${result.installedVersion}`);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
cliSpinner.succeed(`${agentLabel(agent.id)}@${result.installedVersion}`);
|
|
85
|
+
}
|
|
86
|
+
ensureShimCurrent(agentId);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
cliSpinner.warn(`${agentLabel(agent.id)}: ${result.error}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// 2. Register MCP servers
|
|
94
|
+
if (manifest?.mcp && Object.keys(manifest.mcp).length > 0) {
|
|
95
|
+
console.log(chalk.bold('\nMCP Servers:\n'));
|
|
96
|
+
for (const [name, config] of Object.entries(manifest.mcp)) {
|
|
97
|
+
if (!config.command || config.transport === 'http')
|
|
98
|
+
continue;
|
|
99
|
+
const scopedAgents = (config.agents ? [...config.agents] : [...capableAgents('mcp')]).filter((id) => !agentFilter || id === agentFilter);
|
|
100
|
+
const scopedVersions = config.agentVersions
|
|
101
|
+
? Object.fromEntries(Object.entries(config.agentVersions).filter(([agentId]) => !agentFilter || agentId === agentFilter))
|
|
102
|
+
: undefined;
|
|
103
|
+
const targets = resolveConfiguredAgentTargets(scopedAgents, scopedVersions, capableAgents('mcp'));
|
|
104
|
+
const results = await registerMcpToTargets(targets, name, config.command, config.scope || 'user', config.transport || 'stdio');
|
|
105
|
+
for (const result of results) {
|
|
106
|
+
if (result.success) {
|
|
107
|
+
const label = result.version
|
|
108
|
+
? `${agentLabel(result.agentId)}@${result.version}`
|
|
109
|
+
: agentLabel(result.agentId);
|
|
110
|
+
console.log(` ${chalk.green('+')} ${name} -> ${label}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// 3. Sync resources to default version homes
|
|
116
|
+
const cliStates = await getAllCliStates();
|
|
117
|
+
const agentsToSync = agentFilter ? [agentFilter] : ALL_AGENT_IDS;
|
|
118
|
+
const available = getAvailableResources();
|
|
119
|
+
for (const agentId of agentsToSync) {
|
|
120
|
+
if (!cliStates[agentId]?.installed && listInstalledVersions(agentId).length === 0)
|
|
121
|
+
continue;
|
|
122
|
+
const defaultVer = getGlobalDefault(agentId);
|
|
123
|
+
if (!defaultVer)
|
|
124
|
+
continue;
|
|
125
|
+
const actuallySynced = getActuallySyncedResources(agentId, defaultVer);
|
|
126
|
+
const newResources = getNewResources(available, actuallySynced, getProjectOnlyResources());
|
|
127
|
+
const hasAnySynced = actuallySynced.commands.length > 0 ||
|
|
128
|
+
actuallySynced.skills.length > 0 ||
|
|
129
|
+
actuallySynced.hooks.length > 0 ||
|
|
130
|
+
actuallySynced.memory.length > 0 ||
|
|
131
|
+
actuallySynced.mcp.length > 0 ||
|
|
132
|
+
actuallySynced.permissions.length > 0 ||
|
|
133
|
+
actuallySynced.plugins.length > 0;
|
|
134
|
+
try {
|
|
135
|
+
let selection;
|
|
136
|
+
if (skipPrompts) {
|
|
137
|
+
if (!hasAnySynced || hasNewResources(newResources, agentId)) {
|
|
138
|
+
selection = {
|
|
139
|
+
commands: 'all', skills: 'all', hooks: 'all', memory: 'all',
|
|
140
|
+
mcp: 'all', permissions: 'all', subagents: 'all', plugins: 'all',
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else if (!hasAnySynced) {
|
|
145
|
+
console.log(chalk.yellow(`\n${agentLabel(agentId)}@${defaultVer} has no synced resources.`));
|
|
146
|
+
const userSelection = await promptResourceSelection(agentId);
|
|
147
|
+
if (userSelection)
|
|
148
|
+
selection = userSelection;
|
|
149
|
+
}
|
|
150
|
+
else if (hasNewResources(newResources, agentId, defaultVer)) {
|
|
151
|
+
console.log(chalk.cyan(`\n${agentLabel(agentId)}@${defaultVer}:`));
|
|
152
|
+
const userSelection = await promptNewResourceSelection(agentId, newResources, defaultVer);
|
|
153
|
+
if (userSelection)
|
|
154
|
+
selection = userSelection;
|
|
155
|
+
}
|
|
156
|
+
if (selection && Object.keys(selection).length > 0) {
|
|
157
|
+
const syncResult = syncResourcesToVersion(agentId, defaultVer, selection);
|
|
158
|
+
const synced = [];
|
|
159
|
+
if (syncResult.commands)
|
|
160
|
+
synced.push('commands');
|
|
161
|
+
if (syncResult.skills)
|
|
162
|
+
synced.push('skills');
|
|
163
|
+
if (syncResult.hooks)
|
|
164
|
+
synced.push('hooks');
|
|
165
|
+
if (syncResult.memory.length > 0)
|
|
166
|
+
synced.push('memory');
|
|
167
|
+
if (syncResult.permissions)
|
|
168
|
+
synced.push('permissions');
|
|
169
|
+
if (syncResult.mcp.length > 0)
|
|
170
|
+
synced.push('mcp');
|
|
171
|
+
if (syncResult.plugins.length > 0)
|
|
172
|
+
synced.push('plugins');
|
|
173
|
+
if (synced.length > 0) {
|
|
174
|
+
console.log(chalk.green(` Synced: ${synced.join(', ')}`));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
catch (err) {
|
|
179
|
+
if (isPromptCancelled(err)) {
|
|
180
|
+
console.log(chalk.gray('Skipped resource selection'));
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
throw err;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// 4. Register hooks as lifecycle events
|
|
188
|
+
const hookManifest = parseHookManifest();
|
|
189
|
+
if (Object.keys(hookManifest).length > 0) {
|
|
190
|
+
let hookRegistered = 0;
|
|
191
|
+
const hookAgents = new Set(capableAgents('hooks'));
|
|
192
|
+
for (const agentId of agentsToSync) {
|
|
193
|
+
if (!hookAgents.has(agentId))
|
|
194
|
+
continue;
|
|
195
|
+
const versions = listInstalledVersions(agentId);
|
|
196
|
+
const defaultVer = getGlobalDefault(agentId);
|
|
197
|
+
const targetVersions = defaultVer ? [defaultVer] : versions.slice(-1);
|
|
198
|
+
for (const ver of targetVersions) {
|
|
199
|
+
const home = getVersionHomePath(agentId, ver);
|
|
200
|
+
const result = registerHooksToSettings(agentId, home, hookManifest);
|
|
201
|
+
hookRegistered += result.registered.length;
|
|
202
|
+
for (const error of result.errors) {
|
|
203
|
+
console.log(chalk.yellow(` Hook warning: ${error}`));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (hookRegistered > 0) {
|
|
208
|
+
console.log(chalk.green(`\nRegistered ${hookRegistered} hook lifecycle event(s)`));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// 5. Auto-add shims to PATH
|
|
212
|
+
if (!isShimsInPath()) {
|
|
213
|
+
const pathResult = addShimsToPath();
|
|
214
|
+
if (pathResult.success && !pathResult.alreadyPresent) {
|
|
215
|
+
console.log(chalk.green(`\nAdded shims to ~/${pathResult.rcFile}`));
|
|
216
|
+
console.log(chalk.gray('Restart your shell or run: source ~/' + pathResult.rcFile));
|
|
217
|
+
}
|
|
218
|
+
else if (!pathResult.success) {
|
|
219
|
+
console.log(chalk.yellow('\nCould not auto-add shims to PATH:'));
|
|
220
|
+
console.log(chalk.gray(getPathSetupInstructions()));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// 6. Prompt for missing default versions
|
|
224
|
+
if (!skipPrompts) {
|
|
225
|
+
const agentsNeedingDefault = [];
|
|
226
|
+
for (const agentId of agentsToSync) {
|
|
227
|
+
const versions = listInstalledVersions(agentId);
|
|
228
|
+
if (versions.length > 0 && !getGlobalDefault(agentId)) {
|
|
229
|
+
agentsNeedingDefault.push(agentId);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const selectedVersions = [];
|
|
233
|
+
for (const agentId of agentsNeedingDefault) {
|
|
234
|
+
const versions = listInstalledVersions(agentId);
|
|
235
|
+
const agent = AGENTS[agentId];
|
|
236
|
+
const shouldSwitch = await select({
|
|
237
|
+
message: `${agentLabel(agent.id)} has no default version. Set one now?`,
|
|
238
|
+
choices: [
|
|
239
|
+
{ name: 'Yes, pick a version', value: 'pick' },
|
|
240
|
+
{ name: 'Skip for now', value: 'skip' },
|
|
241
|
+
],
|
|
242
|
+
});
|
|
243
|
+
if (shouldSwitch === 'pick') {
|
|
244
|
+
const selectedVersion = await select({
|
|
245
|
+
message: `Select ${agentLabel(agent.id)} version:`,
|
|
246
|
+
choices: versions.map((v) => ({ name: v, value: v })),
|
|
247
|
+
});
|
|
248
|
+
selectedVersions.push({ agentId, version: selectedVersion });
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
for (const { agentId, version } of selectedVersions) {
|
|
252
|
+
const agent = AGENTS[agentId];
|
|
253
|
+
setGlobalDefault(agentId, version);
|
|
254
|
+
const symlinkResult = await switchConfigSymlink(agentId, version);
|
|
255
|
+
if (!symlinkResult.success) {
|
|
256
|
+
console.log(chalk.yellow(`Warning: ${symlinkResult.error}`));
|
|
257
|
+
}
|
|
258
|
+
else if (symlinkResult.backupPath) {
|
|
259
|
+
console.log(chalk.gray(`Backed up existing config to: ${symlinkResult.backupPath}`));
|
|
260
|
+
}
|
|
261
|
+
switchHomeFileSymlinks(agentId, version);
|
|
262
|
+
console.log(chalk.green(`Set ${agentLabel(agent.id)}@${version} as default`));
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
// 7. Install declared host-CLIs
|
|
266
|
+
try {
|
|
267
|
+
const { statuses, errors } = listCliStatus(process.cwd());
|
|
268
|
+
for (const err of errors) {
|
|
269
|
+
console.log(chalk.yellow(` CLI manifest parse error: ${err.file}: ${err.reason}`));
|
|
270
|
+
}
|
|
271
|
+
const missing = statuses.filter((s) => !s.installed);
|
|
272
|
+
if (missing.length > 0) {
|
|
273
|
+
console.log(chalk.bold('\nDeclared CLIs missing from this host:'));
|
|
274
|
+
for (const s of missing) {
|
|
275
|
+
const method = selectInstallMethod(s.manifest);
|
|
276
|
+
const action = method ? describeMethod(method) : chalk.red('no compatible install method');
|
|
277
|
+
console.log(` ${chalk.cyan(s.manifest.name.padEnd(20))} ${chalk.gray(action)}`);
|
|
278
|
+
}
|
|
279
|
+
console.log('');
|
|
280
|
+
if (!skipPrompts) {
|
|
281
|
+
const proceed = await confirm({ message: `Install ${missing.length} missing CLI(s) now?`, default: true });
|
|
282
|
+
if (proceed) {
|
|
283
|
+
for (const s of missing) {
|
|
284
|
+
console.log(chalk.bold(`\n→ ${s.manifest.name}`));
|
|
285
|
+
const result = installCli(s.manifest);
|
|
286
|
+
if (result.error) {
|
|
287
|
+
console.log(chalk.red(` ${result.error}`));
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
if (result.installed) {
|
|
291
|
+
console.log(chalk.green(` installed`));
|
|
292
|
+
if (s.manifest.postInstall) {
|
|
293
|
+
console.log(chalk.gray(s.manifest.postInstall.trim().split('\n').map((l) => ' ' + l).join('\n')));
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
console.log(chalk.yellow(` install ran but \`${describeCheck(s.manifest.check)}\` still fails`));
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
console.log(chalk.gray(`Skipped. Run 'agents cli install' later.`));
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
console.log(chalk.gray(`Run 'agents cli install' to install them.`));
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
catch (err) {
|
|
311
|
+
if (!isPromptCancelled(err)) {
|
|
312
|
+
console.log(chalk.yellow(`CLI install skipped: ${err.message}`));
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Resource selection patterns for agents.yaml versions: entries.
|
|
3
3
|
*
|
|
4
4
|
* Pattern syntax: [!]source:name
|
|
5
|
-
* "system:*" — all resources from ~/.agents
|
|
5
|
+
* "system:*" — all resources from ~/.agents/.system/
|
|
6
6
|
* "user:*" — all resources from ~/.agents/
|
|
7
7
|
* "rush:*" — all resources from ~/.agents-rush/ (extra repo alias)
|
|
8
8
|
* "project:*" — all resources from .agents/ in the project root
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Resource selection patterns for agents.yaml versions: entries.
|
|
3
3
|
*
|
|
4
4
|
* Pattern syntax: [!]source:name
|
|
5
|
-
* "system:*" — all resources from ~/.agents
|
|
5
|
+
* "system:*" — all resources from ~/.agents/.system/
|
|
6
6
|
* "user:*" — all resources from ~/.agents/
|
|
7
7
|
* "rush:*" — all resources from ~/.agents-rush/ (extra repo alias)
|
|
8
8
|
* "project:*" — all resources from .agents/ in the project root
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import * as fs from 'fs';
|
|
9
9
|
import * as path from 'path';
|
|
10
10
|
import { getProjectAgentsDir, getUserAgentsDir, getSystemAgentsDir, getEnabledExtraRepos, } from '../state.js';
|
|
11
|
-
import { AGENTS } from '../agents.js';
|
|
11
|
+
import { AGENTS, agentConfigDirName } from '../agents.js';
|
|
12
12
|
import { markdownToToml } from '../convert.js';
|
|
13
13
|
/**
|
|
14
14
|
* Get the commands directory for a given layer root.
|
|
@@ -164,7 +164,7 @@ export class CommandsHandler {
|
|
|
164
164
|
sync(agent, versionHome, cwd) {
|
|
165
165
|
const agentConfig = AGENTS[agent];
|
|
166
166
|
const targetFormat = this.format(agent);
|
|
167
|
-
const targetDir = path.join(versionHome,
|
|
167
|
+
const targetDir = path.join(versionHome, agentConfigDirName(agent), this.targetDir(agent));
|
|
168
168
|
// Ensure target directory exists
|
|
169
169
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
170
170
|
// Get all resolved commands
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* HooksHandler - ResourceHandler implementation for hooks.
|
|
3
3
|
*
|
|
4
4
|
* Hook declarations live in:
|
|
5
|
-
* - System: ~/.agents
|
|
5
|
+
* - System: ~/.agents/.system/hooks.yaml (npm-shipped defaults)
|
|
6
6
|
* - User: `hooks:` section of ~/.agents/agents.yaml
|
|
7
7
|
* - Project: <project>/.agents/hooks.yaml
|
|
8
8
|
*
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* HooksHandler - ResourceHandler implementation for hooks.
|
|
3
3
|
*
|
|
4
4
|
* Hook declarations live in:
|
|
5
|
-
* - System: ~/.agents
|
|
5
|
+
* - System: ~/.agents/.system/hooks.yaml (npm-shipped defaults)
|
|
6
6
|
* - User: `hooks:` section of ~/.agents/agents.yaml
|
|
7
7
|
* - Project: <project>/.agents/hooks.yaml
|
|
8
8
|
*
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* MCP resource handler - lists, resolves, and syncs MCP server configs across layers.
|
|
3
3
|
*
|
|
4
4
|
* MCP servers are stored as YAML files in mcp/ directories:
|
|
5
|
-
* ~/.agents
|
|
5
|
+
* ~/.agents/.system/mcp/ (system)
|
|
6
6
|
* ~/.agents/mcp/ (user)
|
|
7
7
|
* .agents/mcp/ (project)
|
|
8
8
|
*
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* MCP resource handler - lists, resolves, and syncs MCP server configs across layers.
|
|
3
3
|
*
|
|
4
4
|
* MCP servers are stored as YAML files in mcp/ directories:
|
|
5
|
-
* ~/.agents
|
|
5
|
+
* ~/.agents/.system/mcp/ (system)
|
|
6
6
|
* ~/.agents/mcp/ (user)
|
|
7
7
|
* .agents/mcp/ (project)
|
|
8
8
|
*
|
|
@@ -13,9 +13,8 @@ import * as fs from 'fs';
|
|
|
13
13
|
import * as path from 'path';
|
|
14
14
|
import * as yaml from 'yaml';
|
|
15
15
|
import * as TOML from 'smol-toml';
|
|
16
|
+
import { capableAgents } from '../capabilities.js';
|
|
16
17
|
import { getSystemMcpDir, getUserMcpDir, getProjectAgentsDir, getEnabledExtraRepos, } from '../state.js';
|
|
17
|
-
/** Agents from resources/types.ts that support MCP. */
|
|
18
|
-
const MCP_CAPABLE_AGENTS = ['claude', 'codex', 'gemini', 'cursor', 'opencode', 'openclaw', 'antigravity', 'grok'];
|
|
19
18
|
/**
|
|
20
19
|
* Parse an MCP YAML file into an McpItem.
|
|
21
20
|
*/
|
|
@@ -414,7 +413,7 @@ function syncToOpenClawConfig(configPath, items) {
|
|
|
414
413
|
export const McpHandler = {
|
|
415
414
|
kind: 'mcp',
|
|
416
415
|
listAll(agent, cwd) {
|
|
417
|
-
if (!
|
|
416
|
+
if (!capableAgents('mcp').includes(agent)) {
|
|
418
417
|
return [];
|
|
419
418
|
}
|
|
420
419
|
const results = new Map();
|
|
@@ -435,7 +434,7 @@ export const McpHandler = {
|
|
|
435
434
|
return Array.from(results.values());
|
|
436
435
|
},
|
|
437
436
|
resolve(agent, name, cwd) {
|
|
438
|
-
if (!
|
|
437
|
+
if (!capableAgents('mcp').includes(agent)) {
|
|
439
438
|
return null;
|
|
440
439
|
}
|
|
441
440
|
const layerDirs = getLayerDirs(cwd);
|
|
@@ -469,7 +468,7 @@ export const McpHandler = {
|
|
|
469
468
|
return null;
|
|
470
469
|
},
|
|
471
470
|
sync(agent, versionHome, cwd) {
|
|
472
|
-
if (!
|
|
471
|
+
if (!capableAgents('mcp').includes(agent)) {
|
|
473
472
|
return;
|
|
474
473
|
}
|
|
475
474
|
const items = this.listAll(agent, cwd);
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
import * as fs from 'fs';
|
|
10
10
|
import * as path from 'path';
|
|
11
11
|
import { getSystemAgentsDir, getUserAgentsDir, getProjectAgentsDir, getEnabledExtraRepos, } from '../state.js';
|
|
12
|
-
import { parsePermissionSet, applyPermissionsToVersion, mergePermissionSets,
|
|
12
|
+
import { parsePermissionSet, applyPermissionsToVersion, mergePermissionSets, } from '../permissions.js';
|
|
13
|
+
import { isCapable } from '../capabilities.js';
|
|
13
14
|
/**
|
|
14
15
|
* Get the permissions directory for a given layer root.
|
|
15
16
|
*/
|
|
@@ -66,6 +67,8 @@ function getAgentConfigPath(agent, versionHome) {
|
|
|
66
67
|
return path.join(versionHome, '.codex', 'config.toml');
|
|
67
68
|
case 'opencode':
|
|
68
69
|
return path.join(versionHome, '.opencode', 'opencode.jsonc');
|
|
70
|
+
case 'kimi':
|
|
71
|
+
return path.join(versionHome, '.kimi-code', 'config.toml');
|
|
69
72
|
default:
|
|
70
73
|
return null;
|
|
71
74
|
}
|
|
@@ -143,7 +146,7 @@ export const PermissionsHandler = {
|
|
|
143
146
|
*/
|
|
144
147
|
sync(agent, versionHome, cwd) {
|
|
145
148
|
// Only sync to agents that support permissions
|
|
146
|
-
if (!
|
|
149
|
+
if (!isCapable(agent, 'allowlist')) {
|
|
147
150
|
return;
|
|
148
151
|
}
|
|
149
152
|
const resolved = this.listAll(agent, cwd);
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import * as fs from 'fs';
|
|
12
12
|
import * as path from 'path';
|
|
13
13
|
import { getSystemRulesDir, getUserRulesDir, getProjectAgentsDir, getEnabledExtraRepos, } from '../state.js';
|
|
14
|
+
import { agentConfigDirName } from '../agents.js';
|
|
14
15
|
const SUBRULES_DIR = 'subrules';
|
|
15
16
|
const SUBRULES_README = 'README.md';
|
|
16
17
|
/**
|
|
@@ -131,7 +132,7 @@ export const RulesHandler = {
|
|
|
131
132
|
// Rules sync is handled by the compose module and syncResourcesToVersion.
|
|
132
133
|
// This method ensures the agent config directory exists.
|
|
133
134
|
// The actual composition and write happens in versions.ts via composeRulesFromState().
|
|
134
|
-
const targetDir = path.join(versionHome,
|
|
135
|
+
const targetDir = path.join(versionHome, agentConfigDirName(agent));
|
|
135
136
|
if (!fs.existsSync(targetDir)) {
|
|
136
137
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
137
138
|
}
|
|
@@ -141,6 +142,6 @@ export const RulesHandler = {
|
|
|
141
142
|
},
|
|
142
143
|
targetDir(agent) {
|
|
143
144
|
// Rules don't have a target subdirectory - they're written to the instructions file
|
|
144
|
-
return
|
|
145
|
+
return agentConfigDirName(agent);
|
|
145
146
|
},
|
|
146
147
|
};
|
|
@@ -8,6 +8,7 @@ import * as fs from 'fs';
|
|
|
8
8
|
import * as path from 'path';
|
|
9
9
|
import * as yaml from 'yaml';
|
|
10
10
|
import { getSystemSkillsDir, getUserSkillsDir, getProjectAgentsDir, getEnabledExtraRepos, } from '../state.js';
|
|
11
|
+
import { agentConfigDirName } from '../agents.js';
|
|
11
12
|
/** Default provider uses the real state module. */
|
|
12
13
|
const defaultProvider = {
|
|
13
14
|
getSystemSkillsDir,
|
|
@@ -200,7 +201,7 @@ export function createSkillsHandler(provider = defaultProvider) {
|
|
|
200
201
|
return null;
|
|
201
202
|
},
|
|
202
203
|
sync(agent, versionHome, cwd) {
|
|
203
|
-
const targetDir = path.join(versionHome,
|
|
204
|
+
const targetDir = path.join(versionHome, agentConfigDirName(agent), 'skills');
|
|
204
205
|
// Ensure target directory exists
|
|
205
206
|
if (!fs.existsSync(targetDir)) {
|
|
206
207
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
@@ -230,7 +231,7 @@ export function createSkillsHandler(provider = defaultProvider) {
|
|
|
230
231
|
return 'md';
|
|
231
232
|
},
|
|
232
233
|
targetDir(agent) {
|
|
233
|
-
return
|
|
234
|
+
return `${agentConfigDirName(agent)}/skills`;
|
|
234
235
|
},
|
|
235
236
|
};
|
|
236
237
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* - Union: All resources from all layers are combined
|
|
6
6
|
* - Override on name conflict: Higher layer wins (project > user > system)
|
|
7
7
|
*/
|
|
8
|
-
export type AgentId = 'claude' | 'codex' | 'gemini' | 'cursor' | 'opencode' | 'openclaw' | 'antigravity' | 'grok';
|
|
8
|
+
export type AgentId = 'claude' | 'codex' | 'gemini' | 'cursor' | 'opencode' | 'openclaw' | 'antigravity' | 'grok' | 'kimi';
|
|
9
9
|
export type Layer = 'system' | 'user' | 'project';
|
|
10
10
|
export type ResourceKind = 'command' | 'hook' | 'skill' | 'rule' | 'mcp' | 'permission' | 'subagent' | 'workflow';
|
|
11
11
|
/** A resolved resource with its origin layer. */
|
package/dist/lib/resources.js
CHANGED
|
@@ -12,7 +12,7 @@ import { listInstalledInstructionsWithScope } from './rules/rules.js';
|
|
|
12
12
|
import { getEffectiveHome } from './versions.js';
|
|
13
13
|
import { listMcpServerConfigs } from './mcp.js';
|
|
14
14
|
import { WorkflowsHandler } from './resources/workflows.js';
|
|
15
|
-
import {
|
|
15
|
+
import { isCapable } from './capabilities.js';
|
|
16
16
|
import { getProjectAgentsDir, getUserAgentsDir, getSystemAgentsDir, getEnabledExtraRepos, } from './state.js';
|
|
17
17
|
/**
|
|
18
18
|
* Resolve a single resource by kind + name using project > user > system precedence.
|
|
@@ -163,7 +163,7 @@ export function getAgentResources(agentId, options = {}) {
|
|
|
163
163
|
}
|
|
164
164
|
// Workflows (claude only)
|
|
165
165
|
const workflows = [];
|
|
166
|
-
if (
|
|
166
|
+
if (isCapable(agentId, 'workflows')) {
|
|
167
167
|
for (const w of WorkflowsHandler.listAll(agentId, cwd)) {
|
|
168
168
|
workflows.push({ name: w.name, path: w.path, scope: w.layer === 'project' ? 'project' : 'user' });
|
|
169
169
|
}
|
package/dist/lib/rotate.d.ts
CHANGED
|
@@ -38,7 +38,7 @@ export declare function getProjectRunStrategy(agent: AgentId, startPath: string)
|
|
|
38
38
|
/**
|
|
39
39
|
* Resolve the configured strategy. Lookup order:
|
|
40
40
|
* 1. project-local agents.yaml (nearest to `startPath`)
|
|
41
|
-
* 2. ~/.agents
|
|
41
|
+
* 2. ~/.agents/.system/agents.yaml
|
|
42
42
|
* 3. default: `available` (use the pinned default version when healthy,
|
|
43
43
|
* otherwise fall through to a healthy account so a single rate-limited
|
|
44
44
|
* account doesn't block the run).
|
package/dist/lib/rotate.js
CHANGED
|
@@ -55,7 +55,7 @@ export function getProjectRunStrategy(agent, startPath) {
|
|
|
55
55
|
/**
|
|
56
56
|
* Resolve the configured strategy. Lookup order:
|
|
57
57
|
* 1. project-local agents.yaml (nearest to `startPath`)
|
|
58
|
-
* 2. ~/.agents
|
|
58
|
+
* 2. ~/.agents/.system/agents.yaml
|
|
59
59
|
* 3. default: `available` (use the pinned default version when healthy,
|
|
60
60
|
* otherwise fall through to a healthy account so a single rate-limited
|
|
61
61
|
* account doesn't block the run).
|
package/dist/lib/routines.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ export interface JobConfig {
|
|
|
32
32
|
config?: Record<string, unknown>;
|
|
33
33
|
version?: string;
|
|
34
34
|
runOnce?: boolean;
|
|
35
|
+
endAt?: string;
|
|
35
36
|
}
|
|
36
37
|
/** Metadata for a single job execution, persisted as JSON in the run directory. */
|
|
37
38
|
export interface RunMeta {
|
|
@@ -45,10 +46,19 @@ export interface RunMeta {
|
|
|
45
46
|
completedAt: string | null;
|
|
46
47
|
exitCode: number | null;
|
|
47
48
|
}
|
|
48
|
-
/**
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
/**
|
|
50
|
+
* List all job configs, scanning project > user routine dirs.
|
|
51
|
+
* Project routines (`<project>/.agents/routines/`) shadow user routines of the
|
|
52
|
+
* same name. Project discovery is opt-in via `cwd`; the daemon (which calls
|
|
53
|
+
* `listJobs()` with no argument) only sees user routines.
|
|
54
|
+
*/
|
|
55
|
+
export declare function listJobs(cwd?: string): JobConfig[];
|
|
56
|
+
/**
|
|
57
|
+
* Read a single job config by name, checking project > user.
|
|
58
|
+
* Project discovery is opt-in via `cwd`; daemon callers pass no argument and
|
|
59
|
+
* only resolve user routines.
|
|
60
|
+
*/
|
|
61
|
+
export declare function readJob(name: string, cwd?: string): JobConfig | null;
|
|
52
62
|
/** Write a job config to disk, omitting fields that match defaults. */
|
|
53
63
|
export declare function writeJob(config: JobConfig): void;
|
|
54
64
|
/** Delete a job config file by name. Returns true if the file existed. */
|
|
@@ -57,6 +67,8 @@ export declare function deleteJob(name: string): boolean;
|
|
|
57
67
|
export declare function setJobEnabled(name: string, enabled: boolean): void;
|
|
58
68
|
/** Validate a partial job config, returning a list of human-readable errors. */
|
|
59
69
|
export declare function validateJob(config: Partial<JobConfig>): string[];
|
|
70
|
+
/** True when a job's endAt has already elapsed. False when endAt is unset or in the future. */
|
|
71
|
+
export declare function isPastEndAt(config: Pick<JobConfig, 'endAt'>, now?: Date): boolean;
|
|
60
72
|
/** Expand built-in and user-defined template variables in a job's prompt string. */
|
|
61
73
|
export declare function resolveJobPrompt(config: JobConfig): string;
|
|
62
74
|
/** Parse a human-readable timeout string (e.g. "10m", "2h", "1h30m", "3d", "1w") into milliseconds.
|