@phnx-labs/agents-cli 1.20.3 → 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.
Files changed (193) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +48 -17
  3. package/dist/commands/cli.js +1 -1
  4. package/dist/commands/cloud.js +1 -1
  5. package/dist/commands/commands.js +2 -0
  6. package/dist/commands/doctor.js +1 -1
  7. package/dist/commands/exec.js +52 -16
  8. package/dist/commands/hooks.js +6 -6
  9. package/dist/commands/import.js +90 -37
  10. package/dist/commands/inspect.d.ts +26 -0
  11. package/dist/commands/inspect.js +590 -0
  12. package/dist/commands/mcp.js +17 -16
  13. package/dist/commands/models.js +1 -1
  14. package/dist/commands/packages.js +6 -4
  15. package/dist/commands/permissions.js +13 -12
  16. package/dist/commands/plugins.d.ts +13 -0
  17. package/dist/commands/plugins.js +100 -11
  18. package/dist/commands/prune.js +3 -2
  19. package/dist/commands/pull.d.ts +12 -5
  20. package/dist/commands/pull.js +26 -422
  21. package/dist/commands/push.d.ts +14 -0
  22. package/dist/commands/push.js +30 -0
  23. package/dist/commands/repo.d.ts +1 -1
  24. package/dist/commands/repo.js +155 -112
  25. package/dist/commands/resource-view.d.ts +2 -0
  26. package/dist/commands/resource-view.js +12 -3
  27. package/dist/commands/routines.js +32 -7
  28. package/dist/commands/rules.js +1 -1
  29. package/dist/commands/sessions.js +1 -0
  30. package/dist/commands/setup.d.ts +3 -3
  31. package/dist/commands/setup.js +15 -15
  32. package/dist/commands/skills.js +6 -5
  33. package/dist/commands/subagents.js +5 -4
  34. package/dist/commands/sync.d.ts +18 -5
  35. package/dist/commands/sync.js +251 -65
  36. package/dist/commands/teams.js +1 -0
  37. package/dist/commands/tmux.d.ts +25 -0
  38. package/dist/commands/tmux.js +415 -0
  39. package/dist/commands/trash.d.ts +2 -2
  40. package/dist/commands/trash.js +1 -1
  41. package/dist/commands/versions.js +2 -2
  42. package/dist/commands/view.js +14 -4
  43. package/dist/commands/workflows.js +4 -3
  44. package/dist/commands/worktree.d.ts +4 -5
  45. package/dist/commands/worktree.js +4 -4
  46. package/dist/index.js +68 -20
  47. package/dist/lib/agents.d.ts +19 -10
  48. package/dist/lib/agents.js +102 -28
  49. package/dist/lib/auto-pull-worker.d.ts +1 -1
  50. package/dist/lib/auto-pull-worker.js +2 -2
  51. package/dist/lib/auto-pull.d.ts +1 -1
  52. package/dist/lib/auto-pull.js +1 -1
  53. package/dist/lib/beta.d.ts +1 -1
  54. package/dist/lib/beta.js +1 -1
  55. package/dist/lib/capabilities.js +2 -0
  56. package/dist/lib/commands.d.ts +28 -1
  57. package/dist/lib/commands.js +125 -20
  58. package/dist/lib/doctor-diff.js +2 -2
  59. package/dist/lib/exec.d.ts +14 -0
  60. package/dist/lib/exec.js +39 -5
  61. package/dist/lib/fuzzy.d.ts +12 -2
  62. package/dist/lib/fuzzy.js +29 -4
  63. package/dist/lib/git.js +8 -1
  64. package/dist/lib/hooks.d.ts +2 -2
  65. package/dist/lib/hooks.js +97 -10
  66. package/dist/lib/import.d.ts +21 -0
  67. package/dist/lib/import.js +55 -2
  68. package/dist/lib/mcp.js +32 -2
  69. package/dist/lib/migrate.d.ts +51 -0
  70. package/dist/lib/migrate.js +227 -1
  71. package/dist/lib/models.js +62 -15
  72. package/dist/lib/permissions.d.ts +36 -2
  73. package/dist/lib/permissions.js +217 -7
  74. package/dist/lib/plugin-marketplace.d.ts +108 -40
  75. package/dist/lib/plugin-marketplace.js +243 -94
  76. package/dist/lib/plugins.d.ts +21 -4
  77. package/dist/lib/plugins.js +130 -49
  78. package/dist/lib/profiles-presets.js +12 -12
  79. package/dist/lib/project-launch.d.ts +65 -0
  80. package/dist/lib/project-launch.js +367 -0
  81. package/dist/lib/pty-client.js +1 -1
  82. package/dist/lib/pty-server.d.ts +1 -1
  83. package/dist/lib/pty-server.js +28 -4
  84. package/dist/lib/refresh.d.ts +26 -0
  85. package/dist/lib/refresh.js +315 -0
  86. package/dist/lib/resource-patterns.d.ts +1 -1
  87. package/dist/lib/resource-patterns.js +1 -1
  88. package/dist/lib/resources/commands.js +2 -2
  89. package/dist/lib/resources/hooks.d.ts +1 -1
  90. package/dist/lib/resources/hooks.js +1 -1
  91. package/dist/lib/resources/mcp.d.ts +1 -1
  92. package/dist/lib/resources/mcp.js +5 -6
  93. package/dist/lib/resources/permissions.js +5 -2
  94. package/dist/lib/resources/rules.js +3 -2
  95. package/dist/lib/resources/skills.js +3 -2
  96. package/dist/lib/resources/types.d.ts +1 -1
  97. package/dist/lib/resources.js +2 -2
  98. package/dist/lib/rotate.d.ts +1 -1
  99. package/dist/lib/rotate.js +1 -1
  100. package/dist/lib/routines.d.ts +16 -4
  101. package/dist/lib/routines.js +67 -17
  102. package/dist/lib/rules/compile.js +22 -10
  103. package/dist/lib/rules/rules.js +3 -3
  104. package/dist/lib/runner.js +16 -3
  105. package/dist/lib/scheduler.js +15 -1
  106. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  107. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  108. package/dist/lib/secrets/Agents CLI.app/Contents/_CodeSignature/CodeResources +9 -1
  109. package/dist/lib/secrets/Agents CLI.app/Contents/embedded.provisionprofile +0 -0
  110. package/dist/lib/secrets/linux.d.ts +44 -9
  111. package/dist/lib/secrets/linux.js +302 -48
  112. package/dist/lib/session/db.js +15 -2
  113. package/dist/lib/session/discover.js +118 -3
  114. package/dist/lib/session/parse.js +3 -0
  115. package/dist/lib/session/types.d.ts +1 -1
  116. package/dist/lib/session/types.js +1 -1
  117. package/dist/lib/shims.d.ts +10 -9
  118. package/dist/lib/shims.js +101 -50
  119. package/dist/lib/skills.d.ts +1 -1
  120. package/dist/lib/skills.js +10 -9
  121. package/dist/lib/staleness/detectors/commands.d.ts +3 -0
  122. package/dist/lib/staleness/detectors/commands.js +46 -0
  123. package/dist/lib/staleness/detectors/hooks.d.ts +3 -0
  124. package/dist/lib/staleness/detectors/hooks.js +44 -0
  125. package/dist/lib/staleness/detectors/mcp.d.ts +3 -0
  126. package/dist/lib/staleness/detectors/mcp.js +31 -0
  127. package/dist/lib/staleness/detectors/permissions.d.ts +3 -0
  128. package/dist/lib/staleness/detectors/permissions.js +201 -0
  129. package/dist/lib/staleness/detectors/plugins.d.ts +8 -0
  130. package/dist/lib/staleness/detectors/plugins.js +23 -0
  131. package/dist/lib/staleness/detectors/rules.d.ts +3 -0
  132. package/dist/lib/staleness/detectors/rules.js +34 -0
  133. package/dist/lib/staleness/detectors/skills.d.ts +3 -0
  134. package/dist/lib/staleness/detectors/skills.js +71 -0
  135. package/dist/lib/staleness/detectors/subagents.d.ts +3 -0
  136. package/dist/lib/staleness/detectors/subagents.js +50 -0
  137. package/dist/lib/staleness/detectors/types.d.ts +22 -0
  138. package/dist/lib/staleness/detectors/types.js +1 -0
  139. package/dist/lib/staleness/detectors/workflows.d.ts +3 -0
  140. package/dist/lib/staleness/detectors/workflows.js +28 -0
  141. package/dist/lib/staleness/registry.d.ts +26 -0
  142. package/dist/lib/staleness/registry.js +123 -0
  143. package/dist/lib/staleness/writers/commands.d.ts +3 -0
  144. package/dist/lib/staleness/writers/commands.js +111 -0
  145. package/dist/lib/staleness/writers/hooks.d.ts +3 -0
  146. package/dist/lib/staleness/writers/hooks.js +47 -0
  147. package/dist/lib/staleness/writers/kinds.d.ts +10 -0
  148. package/dist/lib/staleness/writers/kinds.js +15 -0
  149. package/dist/lib/staleness/writers/lazy-map.d.ts +13 -0
  150. package/dist/lib/staleness/writers/lazy-map.js +19 -0
  151. package/dist/lib/staleness/writers/mcp.d.ts +10 -0
  152. package/dist/lib/staleness/writers/mcp.js +19 -0
  153. package/dist/lib/staleness/writers/permissions.d.ts +13 -0
  154. package/dist/lib/staleness/writers/permissions.js +26 -0
  155. package/dist/lib/staleness/writers/plugins.d.ts +7 -0
  156. package/dist/lib/staleness/writers/plugins.js +31 -0
  157. package/dist/lib/staleness/writers/rules.d.ts +7 -0
  158. package/dist/lib/staleness/writers/rules.js +55 -0
  159. package/dist/lib/staleness/writers/skills.d.ts +3 -0
  160. package/dist/lib/staleness/writers/skills.js +81 -0
  161. package/dist/lib/staleness/writers/sources.d.ts +16 -0
  162. package/dist/lib/staleness/writers/sources.js +72 -0
  163. package/dist/lib/staleness/writers/subagents.d.ts +3 -0
  164. package/dist/lib/staleness/writers/subagents.js +53 -0
  165. package/dist/lib/staleness/writers/types.d.ts +36 -0
  166. package/dist/lib/staleness/writers/types.js +1 -0
  167. package/dist/lib/staleness/writers/workflows.d.ts +7 -0
  168. package/dist/lib/staleness/writers/workflows.js +31 -0
  169. package/dist/lib/state.d.ts +34 -11
  170. package/dist/lib/state.js +58 -13
  171. package/dist/lib/subagents.d.ts +0 -2
  172. package/dist/lib/subagents.js +6 -6
  173. package/dist/lib/teams/agents.js +1 -1
  174. package/dist/lib/teams/parsers.d.ts +1 -1
  175. package/dist/lib/tmux/binary.d.ts +67 -0
  176. package/dist/lib/tmux/binary.js +141 -0
  177. package/dist/lib/tmux/index.d.ts +8 -0
  178. package/dist/lib/tmux/index.js +8 -0
  179. package/dist/lib/tmux/paths.d.ts +17 -0
  180. package/dist/lib/tmux/paths.js +30 -0
  181. package/dist/lib/tmux/session.d.ts +122 -0
  182. package/dist/lib/tmux/session.js +305 -0
  183. package/dist/lib/types.d.ts +58 -7
  184. package/dist/lib/types.js +1 -1
  185. package/dist/lib/usage.js +1 -1
  186. package/dist/lib/versions.d.ts +4 -4
  187. package/dist/lib/versions.js +154 -491
  188. package/dist/lib/workflows.d.ts +2 -4
  189. package/dist/lib/workflows.js +3 -4
  190. package/package.json +7 -7
  191. package/scripts/postinstall.js +16 -63
  192. package/dist/commands/status.d.ts +0 -9
  193. package/dist/commands/status.js +0 -25
@@ -1,435 +1,39 @@
1
1
  /**
2
- * Config pull command.
2
+ * Removed `agents pull` command.
3
3
  *
4
- * Registers the `agents pull` command which clones or updates the
5
- * system ~/.agents-system/ git repo and syncs CLI versions, MCP servers,
6
- * resources, and hooks to installed agent versions.
4
+ * `agents pull` was a god-command bundling git fetch+ff with local
5
+ * materialization (install CLIs, register MCP, sync resources, register hooks,
6
+ * etc.). It is replaced by the explicit split:
7
+ *
8
+ * - `agents repo pull <alias>` — git fetch+ff on system / user / extra
9
+ * - `agents repo refresh [agent]` — re-materialize installed version homes
10
+ * - `agents setup` — first-time bootstrap
11
+ *
12
+ * The command is kept registered so old muscle-memory invocations get a clear
13
+ * redirect instead of an "unknown command" error.
7
14
  */
8
- import chalk from 'chalk';
9
- import ora from 'ora';
10
- import { AGENTS, ALL_AGENT_IDS, HOOKS_CAPABLE_AGENTS, MCP_CAPABLE_AGENTS, getAllCliStates, registerMcpToTargets, isAgentName, resolveAgentName, agentLabel, } from '../lib/agents.js';
11
- import { readManifest, MANIFEST_FILENAME, } from '../lib/manifest.js';
12
- import { getUserAgentsDir, ensureAgentsDir, getEnabledExtraRepos, } from '../lib/state.js';
13
- import { isGitRepo, pullRepo, isSystemRepoOrigin, } from '../lib/git.js';
14
- import * as fs from 'fs';
15
- import * as path from 'path';
16
- import { installVersion, listInstalledVersions, getGlobalDefault, setGlobalDefault, getVersionHomePath, syncResourcesToVersion, getAvailableResources, getActuallySyncedResources, getNewResources, getProjectOnlyResources, hasNewResources, promptNewResourceSelection, promptResourceSelection, resolveConfiguredAgentTargets, } from '../lib/versions.js';
17
- import { listCliStatus, installCli, describeMethod, describeCheck, selectInstallMethod, } from '../lib/cli-resources.js';
18
- import { ensureShimCurrent, isShimsInPath, addShimsToPath, getPathSetupInstructions, switchConfigSymlink, switchHomeFileSymlinks, } from '../lib/shims.js';
19
- import { parseHookManifest, registerHooksToSettings } from '../lib/hooks.js';
20
15
  import { setHelpSections } from '../lib/help.js';
21
- import { select, confirm } from '@inquirer/prompts';
22
- import { isInteractiveTerminal, isPromptCancelled } from './utils.js';
23
- /**
24
- * Old repo layout stored promptcuts under claude/promptcuts.yaml (agent-scoped).
25
- * The new layout is ~/.agents-system/promptcuts.yaml at the repo root the hook
26
- * reads from a fixed path so it survives version upgrades. If the root file
27
- * doesn't exist yet but an agent-scoped one does, hoist the first one found.
28
- */
29
- function migratePromptcutsToRoot(agentsDir) {
30
- const rootPath = path.join(agentsDir, 'promptcuts.yaml');
31
- if (fs.existsSync(rootPath))
32
- return;
33
- const agentDirs = ['claude', 'codex', 'cursor', 'gemini', 'opencode'];
34
- for (const dir of agentDirs) {
35
- const legacyPath = path.join(agentsDir, dir, 'promptcuts.yaml');
36
- if (fs.existsSync(legacyPath)) {
37
- try {
38
- fs.renameSync(legacyPath, rootPath);
39
- console.log(chalk.gray(`Moved ${dir}/promptcuts.yaml → promptcuts.yaml (repo root)`));
40
- return;
41
- }
42
- catch {
43
- // Best-effort migration; hook still works if the user moves it manually.
44
- }
45
- }
46
- }
47
- }
48
- /** Register the `agents pull` command. */
16
+ const REDIRECT = 'agents-cli: "agents pull" was removed.\n' +
17
+ ' Git pull a repo: agents repo pull <alias> (system | user | <extra>)\n' +
18
+ ' Re-materialize: agents repo refresh [agent] (claude | codex | ...)\n' +
19
+ ' First-time setup: agents setup\n\n';
20
+ /** Register the deprecated `agents pull` command as a hard-error redirect. */
49
21
  export function registerPullCommand(program) {
50
22
  const pullCmd = program
51
23
  .command('pull [agent]')
52
- .description('Sync your user repo at ~/.agents/ and refresh installed agent CLIs. (Deprecated — prefer \'agents repo pull\' and \'agents setup\'.)')
53
- .option('-y, --yes', 'Auto-sync all resources without prompting')
54
- .option('--skip-clis', 'Pull config changes but do not install or upgrade agent CLIs');
24
+ .description('Removed. See `agents repo pull` + `agents repo refresh`.')
25
+ .option('-y, --yes', '(no-op)')
26
+ .option('--skip-clis', '(no-op)');
55
27
  setHelpSections(pullCmd, {
56
- examples: `
57
- # First time: clone the system repo into ~/.agents-system/
58
- agents pull
59
-
60
- # Sync only one agent's config
61
- agents pull claude
62
-
63
- # Non-interactive (scripts / CI)
64
- agents pull -y
65
-
66
- # Sync config without touching installed CLI versions
67
- agents pull --skip-clis
68
- `,
69
28
  notes: `
70
- Deprecated. Use:
71
- agents setup first-time setup
72
- agents repo pull force-sync now
73
- agents repo push push your user repo
74
-
75
- What it syncs:
76
- - CLI versions listed in agents.yaml
77
- - Commands, skills, hooks
78
- - MCP server configs
79
- - Memory/rules files
80
- - Permissions groups
29
+ Removed. Equivalents:
30
+ agents repo pull <alias> git pull (system | user | extra)
31
+ agents repo refresh [agent] re-materialize version homes
32
+ agents setup first-time bootstrap
81
33
  `,
82
34
  });
83
- pullCmd.action(async (arg1, options) => {
84
- // Deprecation banner — `agents pull` is on its way out. agents-cli now
85
- // auto-syncs the system repo in the background and surfaces upstream
86
- // changes for user/extra repos as one-line notices. Repo lifecycle is
87
- // managed under `agents repo`. We keep this command functional today
88
- // because `agents setup` still invokes it for first-time setup; once
89
- // setup is refactored to call the bootstrap helpers directly, this
90
- // command will hard-error like `agents memory` does.
91
- if (!options.yes && process.argv[2] === 'pull') {
92
- process.stderr.write('agents-cli: "agents pull" is deprecated.\n' +
93
- ' First-time setup: agents setup\n' +
94
- ' Force a sync now: agents repo pull\n' +
95
- ' Push your repo: agents repo push\n\n');
96
- }
97
- const skipPrompts = options.yes || !isInteractiveTerminal();
98
- let agentFilter;
99
- if (arg1) {
100
- if (isAgentName(arg1)) {
101
- agentFilter = resolveAgentName(arg1);
102
- }
103
- else {
104
- console.log(chalk.red(`Invalid agent: ${arg1}`));
105
- console.log(chalk.gray(`Available: ${ALL_AGENT_IDS.join(', ')}`));
106
- return;
107
- }
108
- }
109
- const agentsDir = getUserAgentsDir();
110
- ensureAgentsDir();
111
- const spinner = ora('Syncing...').start();
112
- try {
113
- let commit = '';
114
- if (isGitRepo(agentsDir)) {
115
- // Don't pull if the remote is the system repo — that's a misconfiguration
116
- if (await isSystemRepoOrigin(agentsDir)) {
117
- spinner.fail('~/.agents/ is pointing at the system repo. Use a personal repo instead.');
118
- console.log(chalk.gray('\nCreate your own repo: agents repo init'));
119
- return;
120
- }
121
- spinner.text = 'Pulling updates...';
122
- const result = await pullRepo(agentsDir);
123
- if (!result.success) {
124
- spinner.fail(`Pull failed: ${result.error}`);
125
- return;
126
- }
127
- commit = result.commit;
128
- spinner.succeed(`Updated to ${commit}`);
129
- }
130
- else {
131
- // ~/.agents/ is not a git repo yet — skip git pull, proceed with local resource sync
132
- spinner.succeed('Using local ~/.agents/ (no remote configured)');
133
- }
134
- // Pull extra DotAgent repos before resource sync so any new skills /
135
- // commands they ship land in the version homes on this same run.
136
- const extraRepos = getEnabledExtraRepos();
137
- if (extraRepos.length > 0) {
138
- console.log(chalk.bold(`\nExtra repos (${extraRepos.length}):\n`));
139
- for (const { alias, dir } of extraRepos) {
140
- const extraSpinner = ora(`Pulling ${alias}...`).start();
141
- const result = await pullRepo(dir);
142
- if (result.success) {
143
- extraSpinner.succeed(`${alias} -> ${result.commit}`);
144
- }
145
- else {
146
- extraSpinner.warn(`${alias}: ${result.error}`);
147
- }
148
- }
149
- }
150
- // One-time migration: promptcuts.yaml moved from agent-scoped
151
- // (e.g. claude/promptcuts.yaml) to repo root. We move it so the
152
- // hook at ~/.agents-system/hooks/ can always find it at a fixed path.
153
- migratePromptcutsToRoot(agentsDir);
154
- // Read manifest for CLI versions and MCP config
155
- const manifest = readManifest(agentsDir);
156
- if (!manifest) {
157
- console.log(chalk.gray(`\nNo ${MANIFEST_FILENAME} found`));
158
- }
159
- // Install/upgrade CLI versions
160
- if (!options.skipClis && manifest?.agents) {
161
- console.log(chalk.bold('\nCLI Versions:\n'));
162
- const cliAgents = Object.keys(manifest.agents);
163
- for (const agentId of cliAgents) {
164
- if (agentFilter && agentId !== agentFilter)
165
- continue;
166
- const agent = AGENTS[agentId];
167
- if (!agent)
168
- continue;
169
- const cliSpinner = ora(`Checking ${agentLabel(agent.id)}...`).start();
170
- const versions = listInstalledVersions(agentId);
171
- const targetVersion = manifest.agents[agentId] || 'latest';
172
- const result = await installVersion(agentId, targetVersion, (msg) => { cliSpinner.text = msg; });
173
- if (result.success) {
174
- const isNew = versions.length === 0;
175
- if (isNew) {
176
- cliSpinner.succeed(`Installed ${agentLabel(agent.id)}@${result.installedVersion}`);
177
- }
178
- else {
179
- cliSpinner.succeed(`${agentLabel(agent.id)}@${result.installedVersion}`);
180
- }
181
- // Repair if deleted and regenerate if its schema is out of date.
182
- ensureShimCurrent(agentId);
183
- }
184
- else {
185
- cliSpinner.warn(`${agentLabel(agent.id)}: ${result.error}`);
186
- }
187
- }
188
- }
189
- // Register MCP servers
190
- if (manifest?.mcp && Object.keys(manifest.mcp).length > 0) {
191
- console.log(chalk.bold('\nMCP Servers:\n'));
192
- for (const [name, config] of Object.entries(manifest.mcp)) {
193
- if (!config.command || config.transport === 'http')
194
- continue;
195
- const scopedAgents = (config.agents ? [...config.agents] : [...MCP_CAPABLE_AGENTS]).filter((id) => !agentFilter || id === agentFilter);
196
- const scopedVersions = config.agentVersions
197
- ? Object.fromEntries(Object.entries(config.agentVersions).filter(([agentId]) => !agentFilter || agentId === agentFilter))
198
- : undefined;
199
- const targets = resolveConfiguredAgentTargets(scopedAgents, scopedVersions, MCP_CAPABLE_AGENTS);
200
- const results = await registerMcpToTargets(targets, name, config.command, config.scope || 'user', config.transport || 'stdio');
201
- for (const result of results) {
202
- if (result.success) {
203
- const label = result.version
204
- ? `${agentLabel(result.agentId)}@${result.version}`
205
- : agentLabel(result.agentId);
206
- console.log(` ${chalk.green('+')} ${name} -> ${label}`);
207
- }
208
- }
209
- }
210
- }
211
- // Sync resources to default version homes only
212
- const cliStates = await getAllCliStates();
213
- const agentsToSync = agentFilter ? [agentFilter] : ALL_AGENT_IDS;
214
- const available = getAvailableResources();
215
- for (const agentId of agentsToSync) {
216
- if (!cliStates[agentId]?.installed && listInstalledVersions(agentId).length === 0)
217
- continue;
218
- const defaultVer = getGlobalDefault(agentId);
219
- if (!defaultVer)
220
- continue;
221
- const actuallySynced = getActuallySyncedResources(agentId, defaultVer);
222
- const newResources = getNewResources(available, actuallySynced, getProjectOnlyResources());
223
- const hasAnySynced = actuallySynced.commands.length > 0 ||
224
- actuallySynced.skills.length > 0 ||
225
- actuallySynced.hooks.length > 0 ||
226
- actuallySynced.memory.length > 0 ||
227
- actuallySynced.mcp.length > 0 ||
228
- actuallySynced.permissions.length > 0 ||
229
- actuallySynced.plugins.length > 0;
230
- try {
231
- let selection;
232
- if (skipPrompts) {
233
- // -y flag: sync all without prompting
234
- if (!hasAnySynced || hasNewResources(newResources, agentId)) {
235
- selection = {
236
- commands: 'all', skills: 'all', hooks: 'all', memory: 'all',
237
- mcp: 'all', permissions: 'all', subagents: 'all', plugins: 'all',
238
- };
239
- }
240
- }
241
- else if (!hasAnySynced) {
242
- // Nothing synced yet - prompt for ALL resources
243
- console.log(chalk.yellow(`\n${agentLabel(agentId)}@${defaultVer} has no synced resources.`));
244
- const userSelection = await promptResourceSelection(agentId);
245
- if (userSelection)
246
- selection = userSelection;
247
- }
248
- else if (hasNewResources(newResources, agentId, defaultVer)) {
249
- // Has synced before, but NEW items available
250
- console.log(chalk.cyan(`\n${agentLabel(agentId)}@${defaultVer}:`));
251
- const userSelection = await promptNewResourceSelection(agentId, newResources, defaultVer);
252
- if (userSelection)
253
- selection = userSelection;
254
- }
255
- if (selection && Object.keys(selection).length > 0) {
256
- const syncResult = syncResourcesToVersion(agentId, defaultVer, selection);
257
- const synced = [];
258
- if (syncResult.commands)
259
- synced.push('commands');
260
- if (syncResult.skills)
261
- synced.push('skills');
262
- if (syncResult.hooks)
263
- synced.push('hooks');
264
- if (syncResult.memory.length > 0)
265
- synced.push('memory');
266
- if (syncResult.permissions)
267
- synced.push('permissions');
268
- if (syncResult.mcp.length > 0)
269
- synced.push('mcp');
270
- if (syncResult.plugins.length > 0)
271
- synced.push('plugins');
272
- if (synced.length > 0) {
273
- console.log(chalk.green(` Synced: ${synced.join(', ')}`));
274
- }
275
- }
276
- }
277
- catch (err) {
278
- if (isPromptCancelled(err)) {
279
- console.log(chalk.gray('Skipped resource selection'));
280
- }
281
- else {
282
- throw err;
283
- }
284
- }
285
- }
286
- // Register hooks as lifecycle events in each agent's config file.
287
- // Claude/codex/gemini all support prompt-time hooks, though only
288
- // claude can replace the prompt — codex/gemini append via
289
- // additionalContext. The hook script detects the caller and emits
290
- // the correct protocol.
291
- const hookManifest = parseHookManifest();
292
- if (Object.keys(hookManifest).length > 0) {
293
- let hookRegistered = 0;
294
- const hookAgents = new Set(HOOKS_CAPABLE_AGENTS);
295
- for (const agentId of agentsToSync) {
296
- if (!hookAgents.has(agentId))
297
- continue;
298
- const versions = listInstalledVersions(agentId);
299
- const defaultVer = getGlobalDefault(agentId);
300
- const targetVersions = defaultVer ? [defaultVer] : versions.slice(-1);
301
- for (const ver of targetVersions) {
302
- const home = getVersionHomePath(agentId, ver);
303
- const result = registerHooksToSettings(agentId, home, hookManifest);
304
- hookRegistered += result.registered.length;
305
- for (const error of result.errors) {
306
- console.log(chalk.yellow(` Hook warning: ${error}`));
307
- }
308
- }
309
- }
310
- if (hookRegistered > 0) {
311
- console.log(chalk.green(`\nRegistered ${hookRegistered} hook lifecycle event(s)`));
312
- }
313
- }
314
- // Auto-add shims to PATH if not already there
315
- if (!isShimsInPath()) {
316
- const pathResult = addShimsToPath();
317
- if (pathResult.success && !pathResult.alreadyPresent) {
318
- console.log(chalk.green(`\nAdded shims to ~/${pathResult.rcFile}`));
319
- console.log(chalk.gray('Restart your shell or run: source ~/' + pathResult.rcFile));
320
- }
321
- else if (!pathResult.success) {
322
- console.log(chalk.yellow('\nCould not auto-add shims to PATH:'));
323
- console.log(chalk.gray(getPathSetupInstructions()));
324
- }
325
- }
326
- // Check for agents without a default version - offer to switch
327
- if (!skipPrompts) {
328
- const agentsNeedingDefault = [];
329
- for (const agentId of agentsToSync) {
330
- const versions = listInstalledVersions(agentId);
331
- if (versions.length > 0 && !getGlobalDefault(agentId)) {
332
- agentsNeedingDefault.push(agentId);
333
- }
334
- }
335
- // Phase 1: Collect all version selections first
336
- const selectedVersions = [];
337
- for (const agentId of agentsNeedingDefault) {
338
- const versions = listInstalledVersions(agentId);
339
- const agent = AGENTS[agentId];
340
- const shouldSwitch = await select({
341
- message: `${agentLabel(agent.id)} has no default version. Set one now?`,
342
- choices: [
343
- { name: 'Yes, pick a version', value: 'pick' },
344
- { name: 'Skip for now', value: 'skip' },
345
- ],
346
- });
347
- if (shouldSwitch === 'pick') {
348
- const selectedVersion = await select({
349
- message: `Select ${agentLabel(agent.id)} version:`,
350
- choices: versions.map((v) => ({ name: v, value: v })),
351
- });
352
- selectedVersions.push({ agentId, version: selectedVersion });
353
- }
354
- }
355
- // Apply migrations for all selected versions
356
- for (const { agentId, version } of selectedVersions) {
357
- const agent = AGENTS[agentId];
358
- setGlobalDefault(agentId, version);
359
- const symlinkResult = await switchConfigSymlink(agentId, version);
360
- if (!symlinkResult.success) {
361
- console.log(chalk.yellow(`Warning: ${symlinkResult.error}`));
362
- }
363
- else if (symlinkResult.backupPath) {
364
- console.log(chalk.gray(`Backed up existing config to: ${symlinkResult.backupPath}`));
365
- }
366
- switchHomeFileSymlinks(agentId, version);
367
- console.log(chalk.green(`Set ${agentLabel(agent.id)}@${version} as default`));
368
- }
369
- }
370
- // Report (and optionally install) any declared CLIs that are missing
371
- // from the host. Skipped under -y so non-interactive pulls don't trigger
372
- // package-manager prompts.
373
- try {
374
- const { statuses, errors } = listCliStatus(process.cwd());
375
- for (const err of errors) {
376
- console.log(chalk.yellow(` CLI manifest parse error: ${err.file}: ${err.reason}`));
377
- }
378
- const missing = statuses.filter((s) => !s.installed);
379
- if (missing.length > 0) {
380
- console.log(chalk.bold('\nDeclared CLIs missing from this host:'));
381
- for (const s of missing) {
382
- const method = selectInstallMethod(s.manifest);
383
- const action = method ? describeMethod(method) : chalk.red('no compatible install method');
384
- console.log(` ${chalk.cyan(s.manifest.name.padEnd(20))} ${chalk.gray(action)}`);
385
- }
386
- console.log('');
387
- if (!skipPrompts) {
388
- const proceed = await confirm({ message: `Install ${missing.length} missing CLI(s) now?`, default: true });
389
- if (proceed) {
390
- for (const s of missing) {
391
- console.log(chalk.bold(`\n→ ${s.manifest.name}`));
392
- const result = installCli(s.manifest);
393
- if (result.error) {
394
- console.log(chalk.red(` ${result.error}`));
395
- continue;
396
- }
397
- if (result.installed) {
398
- console.log(chalk.green(` installed`));
399
- if (s.manifest.postInstall) {
400
- console.log(chalk.gray(s.manifest.postInstall.trim().split('\n').map((l) => ' ' + l).join('\n')));
401
- }
402
- }
403
- else {
404
- console.log(chalk.yellow(` install ran but \`${describeCheck(s.manifest.check)}\` still fails`));
405
- }
406
- }
407
- }
408
- else {
409
- console.log(chalk.gray(`Skipped. Run 'agents cli install' later.`));
410
- }
411
- }
412
- else {
413
- console.log(chalk.gray(`Run 'agents cli install' to install them.`));
414
- }
415
- }
416
- }
417
- catch (err) {
418
- if (!isPromptCancelled(err)) {
419
- console.log(chalk.yellow(`CLI install skipped: ${err.message}`));
420
- }
421
- }
422
- console.log(chalk.green('\nPull complete'));
423
- }
424
- catch (err) {
425
- if (isPromptCancelled(err)) {
426
- spinner.stop();
427
- console.log(chalk.yellow('\nCancelled'));
428
- return;
429
- }
430
- spinner.fail('Failed to sync');
431
- console.error(chalk.red(err.message));
432
- process.exit(1);
433
- }
35
+ pullCmd.action(() => {
36
+ process.stderr.write(REDIRECT);
37
+ process.exit(2);
434
38
  });
435
39
  }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Removed `agents push` command.
3
+ *
4
+ * `agents push` was previously the inverse of the god-command `agents pull` —
5
+ * it pushed local commits in `~/.agents/` upstream. It is replaced by the
6
+ * explicit `agents repo push <alias>` so the target repo is named, matching
7
+ * the post-split `agents repo pull` shape.
8
+ *
9
+ * Kept registered so muscle-memory invocations (including `agents push --help`)
10
+ * land on a clear redirect instead of cascading to the top-level help.
11
+ */
12
+ import type { Command } from 'commander';
13
+ /** Register the deprecated `agents push` command as a hard-error redirect. */
14
+ export declare function registerPushCommand(program: Command): void;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Removed `agents push` command.
3
+ *
4
+ * `agents push` was previously the inverse of the god-command `agents pull` —
5
+ * it pushed local commits in `~/.agents/` upstream. It is replaced by the
6
+ * explicit `agents repo push <alias>` so the target repo is named, matching
7
+ * the post-split `agents repo pull` shape.
8
+ *
9
+ * Kept registered so muscle-memory invocations (including `agents push --help`)
10
+ * land on a clear redirect instead of cascading to the top-level help.
11
+ */
12
+ import { setHelpSections } from '../lib/help.js';
13
+ const REDIRECT = 'agents-cli: "agents push" was removed.\n' +
14
+ ' Git push a repo: agents repo push <alias> (system | user | <extra>)\n\n';
15
+ /** Register the deprecated `agents push` command as a hard-error redirect. */
16
+ export function registerPushCommand(program) {
17
+ const pushCmd = program
18
+ .command('push [alias]')
19
+ .description('Removed. See `agents repo push`.');
20
+ setHelpSections(pushCmd, {
21
+ notes: `
22
+ Removed. Equivalent:
23
+ agents repo push <alias> git push (system | user | extra)
24
+ `,
25
+ });
26
+ pushCmd.action(() => {
27
+ process.stderr.write(REDIRECT);
28
+ process.exit(2);
29
+ });
30
+ }
@@ -2,7 +2,7 @@
2
2
  * Extra DotAgent repo management.
3
3
  *
4
4
  * Registers `agents repo add|init|list|remove|enable|disable` which manage
5
- * additional DotAgent repos alongside the primary ~/.agents-system/ repo so
5
+ * additional DotAgent repos alongside the primary ~/.agents/.system/ repo so
6
6
  * private, work, or team skills can ship separately from public ones.
7
7
  *
8
8
  * Extras are user-level config: managed clones live at ~/.agents-<alias>/ as