@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
@@ -10,8 +10,9 @@ import ora from 'ora';
10
10
  import * as fs from 'fs';
11
11
  import * as path from 'path';
12
12
  import { agentLabel } from '../lib/agents.js';
13
+ import { capableAgents } from '../lib/capabilities.js';
13
14
  import { cloneRepo } from '../lib/git.js';
14
- import { discoverSubagentsFromRepo, installSubagentCentrally, listInstalledSubagents, getInstalledSubagent, listSubagentsForAgent, SUBAGENT_CAPABLE_AGENTS, iterSubagentsCapableVersions, removeSubagentFromVersion, } from '../lib/subagents.js';
15
+ import { discoverSubagentsFromRepo, installSubagentCentrally, listInstalledSubagents, getInstalledSubagent, listSubagentsForAgent, iterSubagentsCapableVersions, removeSubagentFromVersion, } from '../lib/subagents.js';
15
16
  import { listInstalledVersions, syncResourcesToVersion, getGlobalDefault, getVersionHomePath, promptAgentVersionSelection, } from '../lib/versions.js';
16
17
  import { getSubagentsDir, recordVersionResources } from '../lib/state.js';
17
18
  import { requireDestructiveArg, promptRemovalTargets, parseCommaSeparatedList, resolveAgentTargetsAutoInstalling, } from './utils.js';
@@ -182,7 +183,7 @@ Examples:
182
183
  let selectedAgents;
183
184
  let versionSelections;
184
185
  if (agentsArg) {
185
- const result = await resolveAgentTargetsAutoInstalling(agentsArg, SUBAGENT_CAPABLE_AGENTS, { yes: options.yes });
186
+ const result = await resolveAgentTargetsAutoInstalling(agentsArg, capableAgents('subagents'), { yes: options.yes });
186
187
  if (!result) {
187
188
  console.log(chalk.gray('Cancelled.'));
188
189
  return;
@@ -191,7 +192,7 @@ Examples:
191
192
  versionSelections = result.versionSelections;
192
193
  }
193
194
  else {
194
- const result = await promptAgentVersionSelection(SUBAGENT_CAPABLE_AGENTS, {
195
+ const result = await promptAgentVersionSelection(capableAgents('subagents'), {
195
196
  skipPrompts: options.yes,
196
197
  });
197
198
  selectedAgents = result.selectedAgents;
@@ -307,7 +308,7 @@ Examples:
307
308
  /** Every (agent, version) that supports subagents and is installed. */
308
309
  function iterSubagentCapableVersions() {
309
310
  const out = [];
310
- for (const agent of SUBAGENT_CAPABLE_AGENTS) {
311
+ for (const agent of capableAgents('subagents')) {
311
312
  for (const version of listInstalledVersions(agent)) {
312
313
  out.push({ agent, version, home: getVersionHomePath(agent, version) });
313
314
  }
@@ -1,10 +1,23 @@
1
1
  /**
2
- * Internal resource sync command.
2
+ * `agents sync` — synchronize central resources into an installed agent version.
3
3
  *
4
- * Registers the hidden `agents sync` command invoked by shims to
5
- * synchronize resources (commands, skills, hooks, memory, MCP, etc.)
6
- * into a specific agent version home before launch.
4
+ * Forms:
5
+ * agents sync claude # uses default/sole installed version
6
+ * agents sync claude@2.1.142 # explicit version
7
+ * agents sync claude@latest # newest installed
8
+ * agents sync --agent claude --agent-version 2.1.142 # legacy form, still supported
9
+ *
10
+ * In a TTY the command previews available/new resources and lets the user
11
+ * select what to sync (same prompts shown after `agents add`). Pass
12
+ * --yes for non-interactive auto-sync, --force to re-sync when nothing
13
+ * has changed, --quiet for total silence.
14
+ *
15
+ * Hot path:
16
+ * --launch is the shim entry point. It skips version-home reconciliation
17
+ * and runs only the cheap project-scoped work (rules compile, workspace
18
+ * resource mirror, per-scope plugin marketplaces). Filesystem-only,
19
+ * sub-50ms steady state. Keep changes here surgical.
7
20
  */
8
21
  import { Command } from 'commander';
9
- /** Register the hidden `agents sync` command. */
22
+ /** Register the `agents sync` command. */
10
23
  export declare function registerSyncCommand(program: Command): void;
@@ -1,88 +1,274 @@
1
1
  /**
2
- * Internal resource sync command.
2
+ * `agents sync` — synchronize central resources into an installed agent version.
3
3
  *
4
- * Registers the hidden `agents sync` command invoked by shims to
5
- * synchronize resources (commands, skills, hooks, memory, MCP, etc.)
6
- * into a specific agent version home before launch.
4
+ * Forms:
5
+ * agents sync claude # uses default/sole installed version
6
+ * agents sync claude@2.1.142 # explicit version
7
+ * agents sync claude@latest # newest installed
8
+ * agents sync --agent claude --agent-version 2.1.142 # legacy form, still supported
9
+ *
10
+ * In a TTY the command previews available/new resources and lets the user
11
+ * select what to sync (same prompts shown after `agents add`). Pass
12
+ * --yes for non-interactive auto-sync, --force to re-sync when nothing
13
+ * has changed, --quiet for total silence.
14
+ *
15
+ * Hot path:
16
+ * --launch is the shim entry point. It skips version-home reconciliation
17
+ * and runs only the cheap project-scoped work (rules compile, workspace
18
+ * resource mirror, per-scope plugin marketplaces). Filesystem-only,
19
+ * sub-50ms steady state. Keep changes here surgical.
7
20
  */
8
21
  import * as path from 'path';
9
22
  import chalk from 'chalk';
10
- import { AGENTS } from '../lib/agents.js';
11
- import { isVersionInstalled, syncResourcesToVersion } from '../lib/versions.js';
23
+ import { agentLabel, resolveAgentName } from '../lib/agents.js';
24
+ import { isVersionInstalled, syncResourcesToVersion, parseAgentSpec, resolveVersion, listInstalledVersions, getAvailableResources, getActuallySyncedResources, getProjectOnlyResources, getNewResources, hasNewResources, promptResourceSelection, promptNewResourceSelection, } from '../lib/versions.js';
12
25
  import { compileRulesForProject } from '../lib/rules/compile.js';
13
- /** Register the hidden `agents sync` command. */
26
+ import { runLaunchSync } from '../lib/project-launch.js';
27
+ import { isInteractiveTerminal, isPromptCancelled } from './utils.js';
28
+ /** Register the `agents sync` command. */
14
29
  export function registerSyncCommand(program) {
15
30
  program
16
- .command('sync', { hidden: true })
17
- .description('Internal: sync resources to a version home. Called by shims, not directly by users.')
18
- .requiredOption('--agent <agent>', 'Agent identifier (claude, codex, gemini, cursor, opencode, openclaw)')
19
- .requiredOption('--agent-version <version>', 'Installed version to sync resources into')
31
+ .command('sync [agentSpec]')
32
+ .summary('Sync resources into an installed agent version')
33
+ .description('Sync resources (commands, skills, hooks, rules, MCPs, plugins, etc.) into an installed agent version. Previews what will change and lets you pick.\n\n[agentSpec] is the agent name with an optional @version, e.g. "claude" or "claude@2.1.142". Omit the version to sync into the active (or sole installed) one.')
34
+ .option('--agent <agent>', 'Agent identifier (legacy form; prefer the positional spec)')
35
+ .option('--agent-version <version>', 'Version to sync into (legacy form; prefer "agent@version")')
20
36
  .option('--project-dir <path>', 'Path to project-level .agents/ directory containing project-scoped resources')
21
37
  .option('--cwd <path>', 'Working directory for discovering project manifest and resources')
38
+ .option('--launch', 'Hot-path mode (shim only): skip version-home reconciliation, run project-scoped compile + workspace mirror + plugin marketplaces', false)
39
+ .option('-y, --yes', 'Skip the interactive preview and auto-sync all detected resources', false)
40
+ .option('--force', 'Re-sync even if no changes are detected since the last sync', false)
22
41
  .option('--quiet', 'Suppress all output (exit code indicates success)', false)
23
- .action((opts) => {
24
- const agentId = opts.agent;
25
- const version = opts.agentVersion;
26
- const projectDir = opts.projectDir;
27
- const cwd = opts.cwd;
28
- const quiet = !!opts.quiet;
29
- if (!AGENTS[agentId]) {
30
- if (!quiet) {
31
- console.error(chalk.red(`Unknown agent '${agentId}'`));
32
- }
42
+ .action(async (agentSpec, opts) => {
43
+ await runSync(agentSpec, opts);
44
+ });
45
+ }
46
+ async function runSync(agentSpec, opts) {
47
+ const quiet = !!opts.quiet;
48
+ const errLog = (msg) => { if (!quiet)
49
+ console.error(msg); };
50
+ const outLog = (msg) => { if (!quiet)
51
+ console.log(msg); };
52
+ // ---------- 1. Resolve agent + version ----------
53
+ let agentId;
54
+ let version;
55
+ if (agentSpec) {
56
+ const parsed = parseAgentSpec(agentSpec);
57
+ if (!parsed) {
58
+ errLog(chalk.red(`Invalid agent spec '${agentSpec}'.`));
59
+ errLog(chalk.gray('Examples: claude, claude@2.1.142, codex@latest'));
33
60
  process.exitCode = 1;
34
61
  return;
35
62
  }
36
- if (!isVersionInstalled(agentId, version)) {
37
- if (!quiet) {
38
- console.error(chalk.red(`${AGENTS[agentId].name}@${version} is not installed`));
39
- }
63
+ agentId = parsed.agent;
64
+ if (parsed.version !== 'latest')
65
+ version = parsed.version;
66
+ }
67
+ if (opts.agent) {
68
+ const resolved = resolveAgentName(opts.agent);
69
+ if (!resolved) {
70
+ errLog(chalk.red(`Unknown agent '${opts.agent}'.`));
40
71
  process.exitCode = 1;
41
72
  return;
42
73
  }
43
- const result = syncResourcesToVersion(agentId, version, undefined, { projectDir, cwd });
44
- // Compile project-scope rules into the workspace itself so each agent's
45
- // native loader picks up cwd/<INSTRUCTIONS_FILE>. projectDir is the
46
- // .agents/ directory; the workspace root is its parent.
47
- let projectCompile = null;
48
- if (projectDir) {
49
- const projectRoot = path.dirname(projectDir);
50
- projectCompile = compileRulesForProject(projectRoot);
51
- }
52
- if (quiet) {
53
- return;
74
+ agentId = resolved;
75
+ }
76
+ if (opts.agentVersion) {
77
+ version = opts.agentVersion;
78
+ }
79
+ if (!agentId) {
80
+ errLog(chalk.red('Usage: agents sync <agent>[@version]'));
81
+ errLog(chalk.gray(' agents sync claude'));
82
+ errLog(chalk.gray(' agents sync claude@2.1.142'));
83
+ process.exitCode = 1;
84
+ return;
85
+ }
86
+ // ---------- 2. Resolve version (project pin → global default → sole installed) ----------
87
+ if (!version) {
88
+ version = resolveVersion(agentId, process.cwd()) || undefined;
89
+ if (!version) {
90
+ const installed = listInstalledVersions(agentId);
91
+ if (installed.length === 1) {
92
+ version = installed[0];
93
+ }
94
+ else if (installed.length === 0) {
95
+ errLog(chalk.red(`No ${agentLabel(agentId)} versions installed.`));
96
+ errLog(chalk.gray(`Install one: agents add ${agentId}@latest`));
97
+ process.exitCode = 1;
98
+ return;
99
+ }
100
+ else {
101
+ errLog(chalk.red(`No default ${agentLabel(agentId)} version pinned. Specify one:`));
102
+ for (const v of installed) {
103
+ errLog(chalk.gray(` agents sync ${agentId}@${v}`));
104
+ }
105
+ process.exitCode = 1;
106
+ return;
107
+ }
54
108
  }
55
- const synced = [];
56
- if (result.commands)
57
- synced.push('commands');
58
- if (result.skills)
59
- synced.push('skills');
60
- if (result.hooks)
61
- synced.push('hooks');
62
- if (result.memory.length > 0)
63
- synced.push('memory');
64
- if (result.permissions)
65
- synced.push('permissions');
66
- if (result.mcp.length > 0)
67
- synced.push('mcp');
68
- if (result.subagents.length > 0)
69
- synced.push('subagents');
70
- if (result.plugins.length > 0)
71
- synced.push('plugins');
72
- if (synced.length > 0) {
73
- console.log(chalk.green(`Synced ${synced.join(', ')} to ${agentId}@${version}`));
109
+ }
110
+ if (!isVersionInstalled(agentId, version)) {
111
+ errLog(chalk.red(`${agentLabel(agentId)}@${version} is not installed.`));
112
+ const installed = listInstalledVersions(agentId);
113
+ if (installed.length > 0) {
114
+ errLog(chalk.gray(`Installed: ${installed.join(', ')}`));
74
115
  }
75
- else {
76
- console.log(chalk.gray('No resources to sync'));
116
+ errLog(chalk.gray(`Install it: agents add ${agentId}@${version}`));
117
+ process.exitCode = 1;
118
+ return;
119
+ }
120
+ const projectDir = opts.projectDir;
121
+ const cwd = opts.cwd || process.cwd();
122
+ // ---------- 3. --launch mode bypasses everything below ----------
123
+ if (opts.launch) {
124
+ runLaunchMode(agentId, version, cwd, quiet);
125
+ return;
126
+ }
127
+ // ---------- 4. Decide selection (interactive preview vs auto) ----------
128
+ const force = !!opts.force;
129
+ const yes = !!opts.yes;
130
+ const interactive = !quiet && !yes && isInteractiveTerminal();
131
+ let selection;
132
+ if (interactive) {
133
+ const available = getAvailableResources(cwd);
134
+ const actuallySynced = getActuallySyncedResources(agentId, version, { cwd });
135
+ const projectOnly = getProjectOnlyResources(cwd);
136
+ const newResources = getNewResources(available, actuallySynced, projectOnly);
137
+ const hasAnySynced = anyResources(actuallySynced);
138
+ try {
139
+ if (!hasAnySynced) {
140
+ outLog(chalk.cyan(`Syncing to ${agentLabel(agentId)}@${version}.`));
141
+ const userSelection = await promptResourceSelection(agentId);
142
+ if (!userSelection || Object.keys(userSelection).length === 0) {
143
+ outLog(chalk.gray('Nothing selected. No changes made.'));
144
+ return;
145
+ }
146
+ selection = userSelection;
147
+ }
148
+ else if (hasNewResources(newResources, agentId, version)) {
149
+ const userSelection = await promptNewResourceSelection(agentId, newResources, version);
150
+ if (!userSelection || Object.keys(userSelection).length === 0) {
151
+ outLog(chalk.gray('Nothing selected. No changes made.'));
152
+ return;
153
+ }
154
+ selection = userSelection;
155
+ }
156
+ else if (!force) {
157
+ outLog(chalk.gray(`${agentLabel(agentId)}@${version} is already in sync.`));
158
+ outLog(chalk.gray('Run with --force to re-sync, or --yes to bypass this check.'));
159
+ return;
160
+ }
161
+ // else: --force on a fully-synced version → selection stays undefined,
162
+ // syncResourcesToVersion falls through to its pattern-based full sync.
77
163
  }
78
- if (projectCompile?.compiled) {
79
- const linkInfo = projectCompile.symlinks.length > 0
80
- ? ` (+ ${projectCompile.symlinks.join(', ')})`
81
- : '';
82
- console.log(chalk.gray(`Compiled project rules → ${projectCompile.agentsPath}${linkInfo}`));
164
+ catch (e) {
165
+ if (isPromptCancelled(e)) {
166
+ outLog(chalk.gray('Cancelled. No changes made.'));
167
+ return;
168
+ }
169
+ throw e;
83
170
  }
84
- if (projectCompile && projectCompile.skippedClobber.length > 0) {
85
- console.log(chalk.yellow(`Skipped (user-authored, not overwritten): ${projectCompile.skippedClobber.join(', ')}`));
171
+ }
172
+ // ---------- 5. Run sync ----------
173
+ const result = syncResourcesToVersion(agentId, version, selection, { projectDir, cwd, force });
174
+ // Compile project-scope rules into the workspace itself so each agent's
175
+ // native loader picks up cwd/<INSTRUCTIONS_FILE>. projectDir is the
176
+ // .agents/ directory; the workspace root is its parent.
177
+ let projectCompile = null;
178
+ if (projectDir) {
179
+ const projectRoot = path.dirname(projectDir);
180
+ projectCompile = compileRulesForProject(projectRoot);
181
+ }
182
+ if (quiet)
183
+ return;
184
+ // ---------- 6. Detailed output ----------
185
+ printSyncDetail(result, agentId, version, cwd);
186
+ if (projectCompile?.compiled) {
187
+ const linkInfo = projectCompile.symlinks.length > 0
188
+ ? ` (+ ${projectCompile.symlinks.join(', ')})`
189
+ : '';
190
+ console.log(chalk.gray(`Compiled project rules → ${projectCompile.agentsPath}${linkInfo}`));
191
+ }
192
+ if (projectCompile && projectCompile.skippedClobber.length > 0) {
193
+ console.log(chalk.yellow(`Skipped (user-authored, not overwritten): ${projectCompile.skippedClobber.join(', ')}`));
194
+ }
195
+ }
196
+ function anyResources(r) {
197
+ return r.commands.length + r.skills.length + r.hooks.length + r.memory.length +
198
+ r.mcp.length + r.permissions.length + r.subagents.length +
199
+ r.plugins.length + r.workflows.length > 0;
200
+ }
201
+ /** Format the post-sync detail output: per-kind count + a name preview. */
202
+ function printSyncDetail(result, agent, version, cwd) {
203
+ // Booleans in SyncResult (commands, skills, hooks, permissions) carry no
204
+ // name list. Re-derive ground truth from the version home so the user
205
+ // sees what's actually present after the sync.
206
+ const synced = getActuallySyncedResources(agent, version, { cwd });
207
+ const lines = [];
208
+ if (result.commands)
209
+ lines.push({ kind: 'commands', items: synced.commands });
210
+ if (result.skills)
211
+ lines.push({ kind: 'skills', items: synced.skills });
212
+ if (result.hooks)
213
+ lines.push({ kind: 'hooks', items: synced.hooks });
214
+ if (result.memory.length > 0)
215
+ lines.push({ kind: 'memory', items: result.memory });
216
+ if (result.permissions)
217
+ lines.push({ kind: 'permissions', items: synced.permissions });
218
+ if (result.mcp.length > 0)
219
+ lines.push({ kind: 'mcp', items: result.mcp });
220
+ if (result.subagents.length > 0)
221
+ lines.push({ kind: 'subagents', items: result.subagents });
222
+ if (result.plugins.length > 0)
223
+ lines.push({ kind: 'plugins', items: result.plugins });
224
+ if (result.workflows.length > 0)
225
+ lines.push({ kind: 'workflows', items: result.workflows });
226
+ if (lines.length === 0) {
227
+ console.log(chalk.gray(`Already in sync — ${agentLabel(agent)}@${version}`));
228
+ return;
229
+ }
230
+ console.log(chalk.green(`Synced to ${agentLabel(agent)}@${version}:`));
231
+ const kindWidth = Math.max(...lines.map(l => l.kind.length));
232
+ const PREVIEW = 5;
233
+ for (const { kind, items } of lines) {
234
+ const padded = kind.padEnd(kindWidth);
235
+ const sorted = [...items].sort((a, b) => a.localeCompare(b));
236
+ const preview = sorted.slice(0, PREVIEW).join(', ');
237
+ const more = sorted.length > PREVIEW ? chalk.gray(`, +${sorted.length - PREVIEW} more`) : '';
238
+ const count = chalk.cyan(`(${sorted.length})`.padStart(5));
239
+ console.log(` ${chalk.bold(padded)} ${count} ${chalk.gray(preview)}${more}`);
240
+ }
241
+ }
242
+ function runLaunchMode(agent, version, cwd, quiet) {
243
+ let result;
244
+ try {
245
+ result = runLaunchSync({ agent, version, cwd });
246
+ }
247
+ catch (err) {
248
+ if (!quiet) {
249
+ console.error(chalk.yellow(`agents: launch sync skipped (${err.message})`));
86
250
  }
87
- });
251
+ return;
252
+ }
253
+ if (quiet)
254
+ return;
255
+ const bits = [];
256
+ if (result.rulesCompiled)
257
+ bits.push('rules');
258
+ if (result.workspaceLinks > 0)
259
+ bits.push(`${result.workspaceLinks} workspace link(s)`);
260
+ const mpCount = Object.keys(result.marketplaces).length;
261
+ if (mpCount > 0) {
262
+ const pluginCount = Object.values(result.marketplaces).reduce((acc, names) => acc + names.length, 0);
263
+ bits.push(`${pluginCount} plugin(s) across ${mpCount} marketplace(s)`);
264
+ }
265
+ if (bits.length === 0) {
266
+ console.log(chalk.gray('No project resources to compile'));
267
+ }
268
+ else {
269
+ console.log(chalk.green(`Launch sync: ${bits.join(', ')}`));
270
+ }
271
+ if (result.workspaceSkipped.length > 0) {
272
+ console.log(chalk.yellow(`Skipped (user-owned, not overwritten): ${result.workspaceSkipped.join(', ')}`));
273
+ }
88
274
  }
@@ -24,6 +24,7 @@ const AGENT_NAMES = {
24
24
  opencode: 'OpenCode',
25
25
  grok: 'Grok',
26
26
  antigravity: 'Antigravity',
27
+ kimi: 'Kimi',
27
28
  };
28
29
  const VALID_AGENTS = Object.keys(AGENT_NAMES);
29
30
  // 'full' kept as historical alias for 'skip'; normalized to 'skip' downstream.
@@ -0,0 +1,25 @@
1
+ /**
2
+ * `agents tmux` — terminal multiplexer integration.
3
+ *
4
+ * Why this exists: the swarmify VS Code extension was hand-rolling tmux
5
+ * commands with brittle shell escaping (`extension/src/vscode/tmux.ts`).
6
+ * Lifting the orchestration into the CLI gives one source of truth that the
7
+ * extension, raw shells, `agents teams`, routines, and the Swarm MCP can all
8
+ * call into.
9
+ *
10
+ * Surface mirrors `agents pty`:
11
+ * agents tmux check
12
+ * agents tmux new <name> [--cmd ...] [--cwd DIR] [--replace] [--attach-existing] [--source S]
13
+ * agents tmux attach <name>
14
+ * agents tmux list [--json]
15
+ * agents tmux has <name>
16
+ * agents tmux split <name> <h|v> [--cmd ...] [--cwd DIR]
17
+ * agents tmux send <name>[:pane] <keys> [--no-enter] [--raw]
18
+ * agents tmux capture <name>[:pane] [--lines N] [--ansi]
19
+ * agents tmux info <name> [--json]
20
+ * agents tmux kill <name>
21
+ * agents tmux kill-all [--yes]
22
+ */
23
+ import type { Command } from 'commander';
24
+ /** Register the `agents tmux` command tree. */
25
+ export declare function registerTmuxCommands(program: Command): void;