@swarmify/agents-cli 1.10.2 → 1.10.4

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 (140) hide show
  1. package/README.md +66 -28
  2. package/dist/commands/__tests__/sessions.test.d.ts +2 -0
  3. package/dist/commands/__tests__/sessions.test.d.ts.map +1 -0
  4. package/dist/commands/__tests__/sessions.test.js +170 -0
  5. package/dist/commands/__tests__/sessions.test.js.map +1 -0
  6. package/dist/commands/commands.d.ts.map +1 -1
  7. package/dist/commands/commands.js +74 -56
  8. package/dist/commands/commands.js.map +1 -1
  9. package/dist/commands/daemon.js +1 -1
  10. package/dist/commands/daemon.js.map +1 -1
  11. package/dist/commands/exec.js +6 -6
  12. package/dist/commands/exec.js.map +1 -1
  13. package/dist/commands/hooks.d.ts.map +1 -1
  14. package/dist/commands/hooks.js +67 -49
  15. package/dist/commands/hooks.js.map +1 -1
  16. package/dist/commands/mcp.d.ts.map +1 -1
  17. package/dist/commands/mcp.js +29 -18
  18. package/dist/commands/mcp.js.map +1 -1
  19. package/dist/commands/packages.d.ts.map +1 -1
  20. package/dist/commands/packages.js +3 -3
  21. package/dist/commands/packages.js.map +1 -1
  22. package/dist/commands/permissions.d.ts.map +1 -1
  23. package/dist/commands/permissions.js +71 -48
  24. package/dist/commands/permissions.js.map +1 -1
  25. package/dist/commands/plugins.js +8 -8
  26. package/dist/commands/plugins.js.map +1 -1
  27. package/dist/commands/pty.d.ts +20 -0
  28. package/dist/commands/pty.d.ts.map +1 -0
  29. package/dist/commands/pty.js +280 -0
  30. package/dist/commands/pty.js.map +1 -0
  31. package/dist/commands/pull.d.ts.map +1 -1
  32. package/dist/commands/pull.js +15 -14
  33. package/dist/commands/pull.js.map +1 -1
  34. package/dist/commands/push.d.ts.map +1 -1
  35. package/dist/commands/push.js +2 -2
  36. package/dist/commands/push.js.map +1 -1
  37. package/dist/commands/routines.d.ts.map +1 -1
  38. package/dist/commands/routines.js +14 -10
  39. package/dist/commands/routines.js.map +1 -1
  40. package/dist/commands/rules.d.ts.map +1 -1
  41. package/dist/commands/rules.js +65 -50
  42. package/dist/commands/rules.js.map +1 -1
  43. package/dist/commands/sessions.d.ts.map +1 -1
  44. package/dist/commands/sessions.js +222 -21
  45. package/dist/commands/sessions.js.map +1 -1
  46. package/dist/commands/sessions.test.d.ts +2 -0
  47. package/dist/commands/sessions.test.d.ts.map +1 -0
  48. package/dist/commands/sessions.test.js +53 -0
  49. package/dist/commands/sessions.test.js.map +1 -0
  50. package/dist/commands/skills.d.ts.map +1 -1
  51. package/dist/commands/skills.js +70 -46
  52. package/dist/commands/skills.js.map +1 -1
  53. package/dist/commands/subagents.d.ts.map +1 -1
  54. package/dist/commands/subagents.js +10 -4
  55. package/dist/commands/subagents.js.map +1 -1
  56. package/dist/commands/utils.d.ts +16 -0
  57. package/dist/commands/utils.d.ts.map +1 -1
  58. package/dist/commands/utils.js +48 -0
  59. package/dist/commands/utils.js.map +1 -1
  60. package/dist/commands/versions.d.ts.map +1 -1
  61. package/dist/commands/versions.js +144 -43
  62. package/dist/commands/versions.js.map +1 -1
  63. package/dist/commands/view.d.ts.map +1 -1
  64. package/dist/commands/view.js +137 -44
  65. package/dist/commands/view.js.map +1 -1
  66. package/dist/index.js +65 -42
  67. package/dist/index.js.map +1 -1
  68. package/dist/lib/agents.d.ts +5 -0
  69. package/dist/lib/agents.d.ts.map +1 -1
  70. package/dist/lib/agents.js +57 -7
  71. package/dist/lib/agents.js.map +1 -1
  72. package/dist/lib/daemon.d.ts.map +1 -1
  73. package/dist/lib/daemon.js +15 -7
  74. package/dist/lib/daemon.js.map +1 -1
  75. package/dist/lib/exec.d.ts.map +1 -1
  76. package/dist/lib/exec.js +8 -1
  77. package/dist/lib/exec.js.map +1 -1
  78. package/dist/lib/git.d.ts.map +1 -1
  79. package/dist/lib/git.js +11 -1
  80. package/dist/lib/git.js.map +1 -1
  81. package/dist/lib/permissions.js +1 -1
  82. package/dist/lib/pty-client.d.ts +22 -0
  83. package/dist/lib/pty-client.d.ts.map +1 -0
  84. package/dist/lib/pty-client.js +181 -0
  85. package/dist/lib/pty-client.js.map +1 -0
  86. package/dist/lib/pty-server.d.ts +16 -0
  87. package/dist/lib/pty-server.d.ts.map +1 -0
  88. package/dist/lib/pty-server.js +422 -0
  89. package/dist/lib/pty-server.js.map +1 -0
  90. package/dist/lib/runner.d.ts.map +1 -1
  91. package/dist/lib/runner.js +13 -9
  92. package/dist/lib/runner.js.map +1 -1
  93. package/dist/lib/sandbox.js +1 -1
  94. package/dist/lib/sandbox.js.map +1 -1
  95. package/dist/lib/session/discover.d.ts +18 -0
  96. package/dist/lib/session/discover.d.ts.map +1 -1
  97. package/dist/lib/session/discover.js +134 -32
  98. package/dist/lib/session/discover.js.map +1 -1
  99. package/dist/lib/session/parse.d.ts +9 -0
  100. package/dist/lib/session/parse.d.ts.map +1 -1
  101. package/dist/lib/session/parse.js +129 -0
  102. package/dist/lib/session/parse.js.map +1 -1
  103. package/dist/lib/session/types.d.ts +1 -1
  104. package/dist/lib/session/types.d.ts.map +1 -1
  105. package/dist/lib/session/types.js +1 -1
  106. package/dist/lib/session/types.js.map +1 -1
  107. package/dist/lib/shims.d.ts.map +1 -1
  108. package/dist/lib/shims.js +6 -1
  109. package/dist/lib/shims.js.map +1 -1
  110. package/dist/lib/state.d.ts +0 -1
  111. package/dist/lib/state.d.ts.map +1 -1
  112. package/dist/lib/state.js +3 -9
  113. package/dist/lib/state.js.map +1 -1
  114. package/dist/lib/types.d.ts +2 -5
  115. package/dist/lib/types.d.ts.map +1 -1
  116. package/dist/lib/types.js.map +1 -1
  117. package/dist/lib/usage.d.ts +29 -0
  118. package/dist/lib/usage.d.ts.map +1 -0
  119. package/dist/lib/usage.js +416 -0
  120. package/dist/lib/usage.js.map +1 -0
  121. package/dist/lib/versions.d.ts.map +1 -1
  122. package/dist/lib/versions.js +19 -8
  123. package/dist/lib/versions.js.map +1 -1
  124. package/package.json +3 -1
  125. package/dist/commands/cron.d.ts +0 -3
  126. package/dist/commands/cron.d.ts.map +0 -1
  127. package/dist/commands/cron.js +0 -457
  128. package/dist/commands/cron.js.map +0 -1
  129. package/dist/lib/cron.d.ts +0 -70
  130. package/dist/lib/cron.d.ts.map +0 -1
  131. package/dist/lib/cron.js +0 -325
  132. package/dist/lib/cron.js.map +0 -1
  133. package/dist/lib/drive-server.d.ts +0 -9
  134. package/dist/lib/drive-server.d.ts.map +0 -1
  135. package/dist/lib/drive-server.js +0 -217
  136. package/dist/lib/drive-server.js.map +0 -1
  137. package/dist/lib/drives.d.ts +0 -34
  138. package/dist/lib/drives.d.ts.map +0 -1
  139. package/dist/lib/drives.js +0 -267
  140. package/dist/lib/drives.js.map +0 -1
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # agents
2
2
 
3
- **One CLI for all your AI coding agents.**
3
+ **The package manager and runtime for AI coding agents.**
4
+
5
+ Install versions. Install skills. Run any agent through one interface. Build pipelines across Claude, Codex, Gemini, Cursor, OpenCode, and more.
4
6
 
5
7
  ```bash
6
8
  npm install -g @swarmify/agents-cli
@@ -8,23 +10,75 @@ npm install -g @swarmify/agents-cli
8
10
 
9
11
  Also available as `ag` -- all commands work with both `agents` and `ag`.
10
12
 
11
- ## The Problem
13
+ ---
14
+
15
+ ## Run any agent. Same interface.
16
+
17
+ ```bash
18
+ agents exec claude "Find all auth vulnerabilities in src/"
19
+ agents exec codex "Fix the issues Claude found"
20
+ agents exec gemini "Write tests for the fixed code"
21
+ ```
12
22
 
13
- You use Claude, Codex, Gemini, Cursor. Each has its own config location, MCP registration, command format, and version management. New machine? Redo everything. Teammate wants your setup? Good luck.
23
+ Each agent resolves to the project-pinned version, with the right skills, MCP servers, and permissions already synced. No setup between steps -- just run.
14
24
 
15
- ## The Solution
25
+ This makes agent pipelines possible. Chain agents by strength, swap one for another, script them in CI -- the interface stays the same:
16
26
 
17
27
  ```bash
18
- agents pull gh:yourname/.agents # One command. Every agent configured.
28
+ # Friday night code review
29
+ agents exec claude "Review all PRs merged this week, summarize risks" \
30
+ | agents exec codex "Write regression tests for the top 3 risks"
31
+
32
+ # Same pipeline, different project -- different agent versions, same commands
33
+ cd ../other-project
34
+ agents exec claude "Review all PRs merged this week, summarize risks"
35
+ # ^ resolves to claude@2.0.0 here instead of claude@2.1.89
19
36
  ```
20
37
 
21
- Your MCP servers, commands, skills, rules, hooks, and permissions -- synced to Claude, Codex, Gemini, Cursor, and OpenCode in one step.
38
+ Supports plan (read-only) and edit modes, effort levels that map to the right model per agent, and JSON output for scripting.
22
39
 
23
40
  ---
24
41
 
25
- ## What You Can Do
42
+ ## Non-interactive usage
43
+
44
+ Other coding agents usually run in non-TTY shells. `agents` now supports that mode directly:
45
+
46
+ ```bash
47
+ agents add codex@latest --yes
48
+ agents use claude@2.1.79 --yes
49
+ agents commands add --names review-pr,debug --agents codex
50
+ agents skills add --names agents-cli --agents claude
51
+ agents sessions view <session-id>
52
+ agents routines view <job-name>
53
+ ```
54
+
55
+ Rules for automation:
56
+
57
+ - Pass explicit names or IDs instead of relying on pickers.
58
+ - Use `--yes` when a command would otherwise ask for default sync or confirmation choices.
59
+ - Use `--names` with `commands`, `skills`, `hooks`, `rules`, and `permissions` to install from central storage without a checkbox prompt.
60
+ - Long `view` commands print directly in non-interactive shells instead of opening `less`.
61
+
62
+ If a command still needs a human-only picker, it now exits with a plain-text hint that shows the matching non-interactive form.
63
+
64
+ ---
65
+
66
+ ## Pin agent versions per project
67
+
68
+ ```bash
69
+ agents add claude@2.0.0 # Install specific version
70
+ agents use claude@2.0.0 -p # Pin to this project
71
+ ```
26
72
 
27
- ### Manage skills across all agents
73
+ Like `.nvmrc` for Node -- different projects use different agent versions. A shim system reads `.agents-version` and routes to the right binary automatically. No other tool does this for AI agents.
74
+
75
+ When you switch versions, configs are backed up and resources are re-synced. Each version gets its own isolated home directory with the right skills, commands, and permissions already in place.
76
+
77
+ ---
78
+
79
+ ## Install skills, MCP servers, and commands once -- every agent gets them
80
+
81
+ ### Skills
28
82
 
29
83
  Skills are reusable knowledge packs -- rules, patterns, and expertise that make your agents better at specific tasks. Install once, available everywhere.
30
84
 
@@ -68,16 +122,6 @@ agents commands view review-pr # View command content
68
122
 
69
123
  Commands are markdown files with a description. The CLI handles format conversion automatically -- markdown for Claude/Gemini/Cursor, TOML for Codex.
70
124
 
71
- ### Version-lock agents per project
72
-
73
- ```bash
74
- agents add claude@2.0.0 # Install specific version
75
- agents use claude@2.0.0 -p # Pin to this project
76
- agents list # Show installed versions
77
- ```
78
-
79
- Like `nvm` for Node -- different projects can use different agent versions. A shim system reads your project config and routes to the right version automatically.
80
-
81
125
  ### Sync your entire setup
82
126
 
83
127
  ```bash
@@ -107,16 +151,6 @@ agents routines logs daily-digest # Check execution logs
107
151
 
108
152
  Jobs run sandboxed -- agents only see directories and tools you explicitly allow.
109
153
 
110
- ### Run any agent with a unified interface
111
-
112
- ```bash
113
- agents exec claude "Find all TODO comments in src/"
114
- agents exec codex -m edit "Add error handling to auth.ts"
115
- agents exec gemini -e detailed "Analyze this architecture"
116
- ```
117
-
118
- Same interface, every agent. Supports plan (read-only) and edit modes, effort levels that map to the right model per agent, and JSON output for scripting.
119
-
120
154
  ### Manage rules/instructions, hooks, and permissions
121
155
 
122
156
  Each agent has its own instruction file format -- Claude uses `CLAUDE.md`, Codex uses `AGENTS.md`, Cursor uses `.cursorrules`. The CLI manages all of them under one command.
@@ -230,6 +264,10 @@ Add rule files in a `rules/` subdirectory -- each rule is a markdown file with s
230
264
  | OpenCode | yes | yes | yes | yes | AGENTS.md | yes | yes | -- |
231
265
  | OpenClaw | yes | yes | -- | yes | workspace/AGENTS.md | yes | -- | -- |
232
266
 
267
+ ## How It Compares
268
+
269
+ See [docs/04-landscape.md](docs/04-landscape.md) for a detailed comparison with other tools in the ecosystem -- Rivet, Agentloom, mise, skills.sh, cass, Microsoft APM, and more.
270
+
233
271
  ## License
234
272
 
235
273
  MIT
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=sessions.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.test.d.ts","sourceRoot":"","sources":["../../../src/commands/__tests__/sessions.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,170 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import * as fs from 'fs';
3
+ import * as os from 'os';
4
+ import * as path from 'path';
5
+ import { spawnSync } from 'child_process';
6
+ const repoRoot = process.cwd();
7
+ const cliEntry = path.join(repoRoot, 'src', 'index.ts');
8
+ const tsxBin = path.join(repoRoot, 'node_modules', '.bin', 'tsx');
9
+ function writeUpdateCache(tempHome) {
10
+ const packageJson = JSON.parse(fs.readFileSync(path.join(repoRoot, 'package.json'), 'utf-8'));
11
+ fs.mkdirSync(path.join(tempHome, '.agents'), { recursive: true });
12
+ fs.writeFileSync(path.join(tempHome, '.agents', '.update-check'), JSON.stringify({ lastCheck: Date.now(), latestVersion: packageJson.version }), 'utf-8');
13
+ }
14
+ function writeClaudeSession(tempHome, projectKey, sessionId, cwd, content, timestamp) {
15
+ fs.mkdirSync(cwd, { recursive: true });
16
+ const sessionsDir = path.join(tempHome, '.claude', 'projects', projectKey);
17
+ fs.mkdirSync(sessionsDir, { recursive: true });
18
+ fs.writeFileSync(path.join(sessionsDir, `${sessionId}.jsonl`), JSON.stringify({
19
+ type: 'user',
20
+ timestamp,
21
+ cwd,
22
+ sessionId,
23
+ version: '2.1.110',
24
+ gitBranch: 'main',
25
+ message: { role: 'user', content },
26
+ }) + '\n', 'utf-8');
27
+ }
28
+ function runAgents(args, cwd, home) {
29
+ return spawnSync(tsxBin, [cliEntry, ...args], {
30
+ cwd,
31
+ env: { ...process.env, HOME: home },
32
+ encoding: 'utf-8',
33
+ });
34
+ }
35
+ function outputOf(result) {
36
+ return `${result.stdout}${result.stderr}`;
37
+ }
38
+ describe('agents sessions', () => {
39
+ it('lists only sessions from the current directory by default and shows all with --all', () => {
40
+ const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), 'agents-sessions-list-'));
41
+ try {
42
+ writeUpdateCache(tempHome);
43
+ const swarmifyDir = path.join(tempHome, 'work', 'swarmify');
44
+ const agentsCliDir = path.join(tempHome, 'work', 'agents-cli');
45
+ const swarmifySessionId = '11111111-1111-4111-8111-111111111111';
46
+ const agentsCliSessionId = '22222222-2222-4222-8222-222222222222';
47
+ writeClaudeSession(tempHome, 'swarmify-test', swarmifySessionId, swarmifyDir, 'Inspect the swarmify session list', '2026-04-17T19:35:30.000Z');
48
+ writeClaudeSession(tempHome, 'agents-cli-test', agentsCliSessionId, agentsCliDir, 'Inspect the agents-cli session list', '2026-04-17T19:36:30.000Z');
49
+ const localResult = runAgents(['sessions'], swarmifyDir, tempHome);
50
+ expect(localResult.status).toBe(0);
51
+ const localOutput = outputOf(localResult);
52
+ expect(localOutput).toContain(swarmifySessionId.slice(0, 8));
53
+ expect(localOutput).not.toContain(agentsCliSessionId.slice(0, 8));
54
+ const allResult = runAgents(['sessions', '--all'], swarmifyDir, tempHome);
55
+ expect(allResult.status).toBe(0);
56
+ const allOutput = outputOf(allResult);
57
+ expect(allOutput).toContain(swarmifySessionId.slice(0, 8));
58
+ expect(allOutput).toContain(agentsCliSessionId.slice(0, 8));
59
+ }
60
+ finally {
61
+ fs.rmSync(tempHome, { recursive: true, force: true });
62
+ }
63
+ });
64
+ });
65
+ describe('agents sessions view', () => {
66
+ it('resolves explicit IDs across directories even when the default listing is scoped to cwd', () => {
67
+ const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), 'agents-sessions-view-global-'));
68
+ try {
69
+ writeUpdateCache(tempHome);
70
+ const swarmifyDir = path.join(tempHome, 'work', 'swarmify');
71
+ const agentsCliDir = path.join(tempHome, 'work', 'agents-cli');
72
+ const siblingSessionId = '33333333-3333-4333-8333-333333333333';
73
+ writeClaudeSession(tempHome, 'swarmify-test', '44444444-4444-4444-8444-444444444444', swarmifyDir, 'Inspect the swarmify session list', '2026-04-17T19:35:30.000Z');
74
+ writeClaudeSession(tempHome, 'agents-cli-test', siblingSessionId, agentsCliDir, 'Review sibling repo state', '2026-04-17T19:36:30.000Z');
75
+ const result = runAgents(['sessions', 'view', siblingSessionId, '--transcript'], swarmifyDir, tempHome);
76
+ expect(result.status).toBe(0);
77
+ const output = outputOf(result);
78
+ expect(output).toContain('Review sibling repo state');
79
+ expect(output).not.toContain(`No session found matching: ${siblingSessionId}`);
80
+ }
81
+ finally {
82
+ fs.rmSync(tempHome, { recursive: true, force: true });
83
+ }
84
+ });
85
+ it('resolves Claude /resume history IDs to the resumed transcript', () => {
86
+ const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), 'agents-sessions-view-'));
87
+ try {
88
+ writeUpdateCache(tempHome);
89
+ const projectRoot = path.join(tempHome, 'work', 'swarmify');
90
+ const transcriptCwd = path.join(projectRoot, 'extension');
91
+ const transcriptId = '92267176-d991-45c2-a8e5-e851e30a203b';
92
+ const historyOnlyId = 'f6a6cd2d-2138-41c4-b653-d2881ce9cdd3';
93
+ fs.mkdirSync(path.join(tempHome, '.claude', 'projects', 'swarmify-test'), { recursive: true });
94
+ fs.writeFileSync(path.join(tempHome, '.claude', 'history.jsonl'), JSON.stringify({
95
+ display: '/resume',
96
+ timestamp: Date.parse('2026-04-17T19:30:00.000Z'),
97
+ project: projectRoot,
98
+ sessionId: historyOnlyId,
99
+ }) + '\n', 'utf-8');
100
+ fs.mkdirSync(transcriptCwd, { recursive: true });
101
+ fs.writeFileSync(path.join(tempHome, '.claude', 'projects', 'swarmify-test', `${transcriptId}.jsonl`), [
102
+ JSON.stringify({
103
+ type: 'user',
104
+ timestamp: '2026-04-17T19:00:00.000Z',
105
+ cwd: transcriptCwd,
106
+ sessionId: transcriptId,
107
+ version: '2.1.110',
108
+ gitBranch: 'main',
109
+ message: { role: 'user', content: 'Earlier context' },
110
+ }),
111
+ JSON.stringify({
112
+ type: 'assistant',
113
+ timestamp: '2026-04-17T19:00:05.000Z',
114
+ cwd: transcriptCwd,
115
+ sessionId: transcriptId,
116
+ version: '2.1.110',
117
+ gitBranch: 'main',
118
+ message: {
119
+ role: 'assistant',
120
+ content: [{ type: 'text', text: 'Earlier reply' }],
121
+ },
122
+ }),
123
+ JSON.stringify({
124
+ type: 'attachment',
125
+ timestamp: '2026-04-17T19:30:30.000Z',
126
+ cwd: transcriptCwd,
127
+ sessionId: transcriptId,
128
+ version: '2.1.110',
129
+ gitBranch: 'main',
130
+ attachment: {
131
+ type: 'hook_success',
132
+ hookName: 'SessionStart:resume',
133
+ hookEvent: 'SessionStart',
134
+ },
135
+ }),
136
+ JSON.stringify({
137
+ type: 'user',
138
+ timestamp: '2026-04-17T19:30:45.000Z',
139
+ cwd: transcriptCwd,
140
+ sessionId: transcriptId,
141
+ version: '2.1.110',
142
+ gitBranch: 'main',
143
+ message: { role: 'user', content: 'Continue from where we left off' },
144
+ }),
145
+ JSON.stringify({
146
+ type: 'assistant',
147
+ timestamp: '2026-04-17T19:31:00.000Z',
148
+ cwd: transcriptCwd,
149
+ sessionId: transcriptId,
150
+ version: '2.1.110',
151
+ gitBranch: 'main',
152
+ message: {
153
+ role: 'assistant',
154
+ content: [{ type: 'text', text: 'Loaded resumed transcript' }],
155
+ },
156
+ }),
157
+ ].join('\n') + '\n', 'utf-8');
158
+ const result = runAgents(['sessions', 'view', historyOnlyId, '--transcript'], repoRoot, tempHome);
159
+ expect(result.status).toBe(0);
160
+ const output = outputOf(result);
161
+ expect(output).toContain(`Resolved Claude history entry ${historyOnlyId} to transcript ${transcriptId}.`);
162
+ expect(output).toContain('Loaded resumed transcript');
163
+ expect(output).not.toContain(`No transcript session found matching: ${historyOnlyId}`);
164
+ }
165
+ finally {
166
+ fs.rmSync(tempHome, { recursive: true, force: true });
167
+ }
168
+ });
169
+ });
170
+ //# sourceMappingURL=sessions.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.test.js","sourceRoot":"","sources":["../../../src/commands/__tests__/sessions.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/commands/commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoCzC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAgd/D"}
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/commands/commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA4CzC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAoe/D"}
@@ -4,12 +4,12 @@ import * as fs from 'fs';
4
4
  import * as os from 'os';
5
5
  import * as path from 'path';
6
6
  import { checkbox } from '@inquirer/prompts';
7
- import { AGENTS, ALL_AGENT_IDS, resolveAgentName, formatAgentError, } from '../lib/agents.js';
7
+ import { AGENTS, ALL_AGENT_IDS, resolveAgentName, formatAgentError, agentLabel, } from '../lib/agents.js';
8
8
  import { cloneRepo } from '../lib/git.js';
9
9
  import { discoverCommands, resolveCommandSource, installCommandCentrally, uninstallCommand, listCentralCommands, listInstalledCommandsWithScope, getCommandInfo, } from '../lib/commands.js';
10
10
  import { listInstalledVersions, getGlobalDefault, syncResourcesToVersion, promptAgentVersionSelection, getVersionHomePath, } from '../lib/versions.js';
11
11
  import { recordVersionResources } from '../lib/state.js';
12
- import { isPromptCancelled, formatPath } from './utils.js';
12
+ import { isPromptCancelled, formatPath, isInteractiveTerminal, parseCommaSeparatedList, printWithPager, requireInteractiveSelection, } from './utils.js';
13
13
  export function registerCommandsCommands(program) {
14
14
  const commandsCmd = program
15
15
  .command('commands')
@@ -45,10 +45,10 @@ export function registerCommandsCommands(program) {
45
45
  const defaultLabel = isDefault ? ' default' : '';
46
46
  const versionStr = chalk.gray(` (${version}${defaultLabel})`);
47
47
  if (commands.length === 0) {
48
- console.log(` ${chalk.bold(agent.name)}${versionStr}: ${chalk.gray('none')}`);
48
+ console.log(` ${chalk.bold(agentLabel(agent.id))}${versionStr}: ${chalk.gray('none')}`);
49
49
  }
50
50
  else {
51
- console.log(` ${chalk.bold(agent.name)}${versionStr}:`);
51
+ console.log(` ${chalk.bold(agentLabel(agent.id))}${versionStr}:`);
52
52
  const userCommands = commands.filter((c) => c.scope === 'user');
53
53
  const projectCommands = commands.filter((c) => c.scope === 'project');
54
54
  if (userCommands.length > 0 && (options.scope === 'all' || options.scope === 'user')) {
@@ -74,13 +74,13 @@ export function registerCommandsCommands(program) {
74
74
  const defaultVer = getGlobalDefault(agentId);
75
75
  if (installedVersions.length === 0) {
76
76
  // Not version-managed, show from effective home
77
- console.log(chalk.bold(`Installed Commands for ${agent.name}\n`));
77
+ console.log(chalk.bold(`Installed Commands for ${agentLabel(agent.id)}\n`));
78
78
  const commands = listInstalledCommandsWithScope(agentId, cwd).filter((c) => options.scope === 'all' || c.scope === options.scope);
79
79
  if (commands.length === 0) {
80
- console.log(` ${chalk.bold(agent.name)}: ${chalk.gray('none')}`);
80
+ console.log(` ${chalk.bold(agentLabel(agent.id))}: ${chalk.gray('none')}`);
81
81
  }
82
82
  else {
83
- console.log(` ${chalk.bold(agent.name)}:`);
83
+ console.log(` ${chalk.bold(agentLabel(agent.id))}:`);
84
84
  const userCommands = commands.filter((c) => c.scope === 'user');
85
85
  if (userCommands.length > 0) {
86
86
  console.log(` ${chalk.gray('User:')}`);
@@ -91,18 +91,18 @@ export function registerCommandsCommands(program) {
91
91
  }
92
92
  return;
93
93
  }
94
- console.log(chalk.bold(`Installed Commands for ${agent.name}\n`));
94
+ console.log(chalk.bold(`Installed Commands for ${agentLabel(agent.id)}\n`));
95
95
  let versionsToShow;
96
96
  if (requestedVersion === 'default') {
97
97
  if (!defaultVer) {
98
- console.log(chalk.yellow(` No default version set for ${agent.name}. Run: agents use ${agentId}@<version>`));
98
+ console.log(chalk.yellow(` No default version set for ${agentLabel(agent.id)}. Run: agents use ${agentId}@<version>`));
99
99
  return;
100
100
  }
101
101
  versionsToShow = [defaultVer];
102
102
  }
103
103
  else if (requestedVersion) {
104
104
  if (!installedVersions.includes(requestedVersion)) {
105
- console.log(chalk.red(` Version ${requestedVersion} not installed for ${agent.name}.`));
105
+ console.log(chalk.red(` Version ${requestedVersion} not installed for ${agentLabel(agent.id)}.`));
106
106
  console.log(chalk.gray(` Installed versions: ${installedVersions.join(', ')}`));
107
107
  return;
108
108
  }
@@ -137,10 +137,10 @@ export function registerCommandsCommands(program) {
137
137
  // Version managed but no default
138
138
  const commands = listInstalledCommandsWithScope(aid, cwd).filter((c) => options.scope === 'all' || c.scope === options.scope);
139
139
  if (commands.length === 0) {
140
- console.log(` ${chalk.bold(agent.name)}: ${chalk.gray('none')}`);
140
+ console.log(` ${chalk.bold(agentLabel(aid))}: ${chalk.gray('none')}`);
141
141
  }
142
142
  else {
143
- console.log(` ${chalk.bold(agent.name)}:`);
143
+ console.log(` ${chalk.bold(agentLabel(aid))}:`);
144
144
  const userCommands = commands.filter((c) => c.scope === 'user');
145
145
  if (userCommands.length > 0) {
146
146
  console.log(` ${chalk.gray('User:')}`);
@@ -157,6 +157,7 @@ export function registerCommandsCommands(program) {
157
157
  .command('add [source]')
158
158
  .description('Install commands from a repo or local path')
159
159
  .option('-a, --agents <list>', 'Comma-separated agents to install to')
160
+ .option('--names <list>', 'Comma-separated command names from ~/.agents/commands/')
160
161
  .option('-y, --yes', 'Skip prompts and use defaults')
161
162
  .action(async (source, options) => {
162
163
  try {
@@ -171,35 +172,54 @@ export function registerCommandsCommands(program) {
171
172
  console.log(chalk.cyan(' agents commands add gh:user/repo'));
172
173
  return;
173
174
  }
174
- // Build choices with descriptions
175
- const choices = centralCommands.map((name) => {
176
- const cmdPath = path.join(os.homedir(), '.agents', 'commands', `${name}.md`);
177
- let description = '';
178
- if (fs.existsSync(cmdPath)) {
179
- const content = fs.readFileSync(cmdPath, 'utf-8');
180
- const match = content.match(/description:\s*(.+)/i) || content.match(/description\s*=\s*"([^"]+)"/);
181
- if (match)
182
- description = match[1].trim();
175
+ const requestedNames = parseCommaSeparatedList(options.names);
176
+ let selectedNames;
177
+ if (requestedNames.length > 0) {
178
+ const missing = requestedNames.filter((name) => !centralCommands.includes(name));
179
+ if (missing.length > 0) {
180
+ console.log(chalk.red(`Unknown command(s): ${missing.join(', ')}`));
181
+ console.log(chalk.gray(`Available: ${centralCommands.join(', ')}`));
182
+ process.exit(1);
183
183
  }
184
- return {
185
- value: name,
186
- name: description ? `${name} ${chalk.gray(description.slice(0, 50))}` : name,
187
- };
188
- });
189
- const selected = await checkbox({
190
- message: 'Select commands to install',
191
- choices: [
192
- { value: '__all__', name: chalk.bold('Select All') },
193
- ...choices,
194
- ],
195
- });
196
- if (selected.length === 0) {
197
- console.log(chalk.gray('No commands selected.'));
198
- return;
184
+ selectedNames = requestedNames;
185
+ }
186
+ else {
187
+ if (!isInteractiveTerminal()) {
188
+ requireInteractiveSelection('Selecting commands from ~/.agents/commands/', [
189
+ 'agents commands add --names README,debug --agents codex',
190
+ 'agents commands add gh:user/repo --agents codex',
191
+ ]);
192
+ }
193
+ // Build choices with descriptions
194
+ const choices = centralCommands.map((name) => {
195
+ const cmdPath = path.join(os.homedir(), '.agents', 'commands', `${name}.md`);
196
+ let description = '';
197
+ if (fs.existsSync(cmdPath)) {
198
+ const content = fs.readFileSync(cmdPath, 'utf-8');
199
+ const match = content.match(/description:\s*(.+)/i) || content.match(/description\s*=\s*"([^"]+)"/);
200
+ if (match)
201
+ description = match[1].trim();
202
+ }
203
+ return {
204
+ value: name,
205
+ name: description ? `${name} ${chalk.gray(description.slice(0, 50))}` : name,
206
+ };
207
+ });
208
+ const selected = await checkbox({
209
+ message: 'Select commands to install',
210
+ choices: [
211
+ { value: '__all__', name: chalk.bold('Select All') },
212
+ ...choices,
213
+ ],
214
+ });
215
+ if (selected.length === 0) {
216
+ console.log(chalk.gray('No commands selected.'));
217
+ return;
218
+ }
219
+ selectedNames = selected.includes('__all__')
220
+ ? centralCommands
221
+ : selected.filter((s) => s !== '__all__');
199
222
  }
200
- const selectedNames = selected.includes('__all__')
201
- ? centralCommands
202
- : selected.filter((s) => s !== '__all__');
203
223
  commands = selectedNames.map((name) => ({ name, description: '' }));
204
224
  fromCentral = true;
205
225
  }
@@ -269,7 +289,9 @@ export function registerCommandsCommands(program) {
269
289
  }
270
290
  }
271
291
  else {
272
- const result = await promptAgentVersionSelection(ALL_AGENT_IDS, { skipPrompts: options.yes });
292
+ const result = await promptAgentVersionSelection(ALL_AGENT_IDS, {
293
+ skipPrompts: options.yes || !isInteractiveTerminal(),
294
+ });
273
295
  selectedAgents = result.selectedAgents;
274
296
  versionSelections = result.versionSelections;
275
297
  }
@@ -322,6 +344,11 @@ export function registerCommandsCommands(program) {
322
344
  console.log(chalk.yellow('No commands installed.'));
323
345
  return;
324
346
  }
347
+ if (!isInteractiveTerminal()) {
348
+ requireInteractiveSelection('Selecting commands to remove', [
349
+ 'agents commands remove README',
350
+ ]);
351
+ }
325
352
  try {
326
353
  const selected = await checkbox({
327
354
  message: 'Select commands to remove',
@@ -351,7 +378,7 @@ export function registerCommandsCommands(program) {
351
378
  let removed = 0;
352
379
  for (const agentId of agents) {
353
380
  if (uninstallCommand(agentId, cmdName)) {
354
- console.log(` ${chalk.red('-')} ${AGENTS[agentId].name}: ${cmdName}`);
381
+ console.log(` ${chalk.red('-')} ${agentLabel(agentId)}: ${cmdName}`);
355
382
  removed++;
356
383
  }
357
384
  }
@@ -371,6 +398,11 @@ export function registerCommandsCommands(program) {
371
398
  console.log(chalk.yellow('No commands installed'));
372
399
  return;
373
400
  }
401
+ if (!isInteractiveTerminal()) {
402
+ requireInteractiveSelection('Selecting a command to view', [
403
+ 'agents commands view README',
404
+ ]);
405
+ }
374
406
  try {
375
407
  const { select } = await import('@inquirer/prompts');
376
408
  name = await select({
@@ -405,21 +437,7 @@ export function registerCommandsCommands(program) {
405
437
  if (command.content) {
406
438
  const rendered = renderMarkdown(command.content);
407
439
  const contentLines = command.content.split('\n');
408
- // Pipe through less for scrolling if content is large
409
- if (contentLines.length > 40) {
410
- const { spawnSync } = await import('child_process');
411
- const less = spawnSync('less', ['-R'], {
412
- input: rendered,
413
- stdio: ['pipe', 'inherit', 'inherit'],
414
- });
415
- // Fallback to direct output if less fails
416
- if (less.status !== 0) {
417
- console.log(rendered);
418
- }
419
- }
420
- else {
421
- console.log(rendered);
422
- }
440
+ printWithPager(rendered, contentLines.length);
423
441
  }
424
442
  });
425
443
  }