@michaelhartmayer/agentctl 1.0.2 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ctl.js CHANGED
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
12
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
4
  };
@@ -27,324 +18,298 @@ const path_1 = __importDefault(require("path"));
27
18
  const resolve_1 = require("./resolve");
28
19
  const fs_utils_1 = require("./fs-utils");
29
20
  const manifest_1 = require("./manifest");
30
- function scaffold(args_1) {
31
- return __awaiter(this, arguments, void 0, function* (args, options = {}) {
32
- const { targetDir, name, isWin } = yield prepareCommand(args, options);
33
- const scriptName = isWin ? 'command.cmd' : 'command.sh';
34
- const scriptPath = path_1.default.join(targetDir, scriptName);
35
- const scriptContent = isWin
36
- ? '@echo off\r\nREM Add your command logic here\r\necho Not implemented'
37
- : '#!/usr/bin/env bash\n# Add your command logic here\necho "Not implemented"';
38
- yield fs_extra_1.default.writeFile(scriptPath, scriptContent);
39
- if (!isWin)
40
- yield fs_extra_1.default.chmod(scriptPath, 0o755);
41
- const manifest = {
42
- name,
43
- description: '',
44
- type: 'scaffold',
45
- run: `./${scriptName}`,
46
- };
47
- yield fs_extra_1.default.writeJson(path_1.default.join(targetDir, 'manifest.json'), manifest, { spaces: 2 });
48
- console.log(`Scaffolded command: ${args.join(' ')}`);
49
- });
21
+ async function scaffold(args, options = {}) {
22
+ const { targetDir, name, isWin } = await prepareCommand(args, options);
23
+ const scriptName = isWin ? 'command.cmd' : 'command.sh';
24
+ const scriptPath = path_1.default.join(targetDir, scriptName);
25
+ const scriptContent = isWin
26
+ ? '@echo off\r\nREM Add your command logic here\r\necho Not implemented'
27
+ : '#!/usr/bin/env bash\n# Add your command logic here\necho "Not implemented"';
28
+ await fs_extra_1.default.writeFile(scriptPath, scriptContent);
29
+ if (!isWin)
30
+ await fs_extra_1.default.chmod(scriptPath, 0o755);
31
+ const manifest = {
32
+ name,
33
+ description: '',
34
+ type: 'scaffold',
35
+ run: `./${scriptName}`,
36
+ };
37
+ await fs_extra_1.default.writeJson(path_1.default.join(targetDir, 'manifest.json'), manifest, { spaces: 2 });
38
+ console.log(`Scaffolded command: ${args.join(' ')}`);
50
39
  }
51
- function alias(args_1, target_1) {
52
- return __awaiter(this, arguments, void 0, function* (args, target, options = {}) {
53
- const { targetDir, name } = yield prepareCommand(args, options);
54
- const manifest = {
55
- name,
56
- description: '',
57
- type: 'alias',
58
- run: target,
59
- };
60
- yield fs_extra_1.default.writeJson(path_1.default.join(targetDir, 'manifest.json'), manifest, { spaces: 2 });
61
- console.log(`Aliased command: ${args.join(' ')} -> ${target}`);
62
- });
40
+ async function alias(args, target, options = {}) {
41
+ const { targetDir, name } = await prepareCommand(args, options);
42
+ const manifest = {
43
+ name,
44
+ description: '',
45
+ type: 'alias',
46
+ run: target,
47
+ };
48
+ await fs_extra_1.default.writeJson(path_1.default.join(targetDir, 'manifest.json'), manifest, { spaces: 2 });
49
+ console.log(`Aliased command: ${args.join(' ')} -> ${target}`);
63
50
  }
64
- function group(args_1) {
65
- return __awaiter(this, arguments, void 0, function* (args, options = {}) {
66
- const { targetDir, name } = yield prepareCommand(args, options);
67
- const manifest = {
68
- name,
69
- description: '',
70
- type: 'group',
71
- };
72
- yield fs_extra_1.default.writeJson(path_1.default.join(targetDir, 'manifest.json'), manifest, { spaces: 2 });
73
- console.log(`Created group: ${args.join(' ')}`);
74
- });
51
+ async function group(args, options = {}) {
52
+ const { targetDir, name } = await prepareCommand(args, options);
53
+ const manifest = {
54
+ name,
55
+ description: '',
56
+ type: 'group',
57
+ };
58
+ await fs_extra_1.default.writeJson(path_1.default.join(targetDir, 'manifest.json'), manifest, { spaces: 2 });
59
+ console.log(`Created group: ${args.join(' ')}`);
75
60
  }
76
- function pushGlobal(args_1) {
77
- return __awaiter(this, arguments, void 0, function* (args, options = {}) {
78
- const cwd = options.cwd || process.cwd();
79
- const localRoot = (0, fs_utils_1.findLocalRoot)(cwd);
80
- if (!localRoot)
81
- throw new Error('Not in a local context');
82
- const globalRoot = options.globalDir || (0, fs_utils_1.getGlobalRoot)();
83
- const localAgentctl = path_1.default.join(localRoot, '.agentctl');
84
- const cmdPathStr = args.join(path_1.default.sep);
85
- const srcDir = path_1.default.join(localAgentctl, cmdPathStr);
86
- if (!(yield fs_extra_1.default.pathExists(srcDir))) {
87
- throw new Error(`Local command ${args.join(' ')} not found`);
88
- }
89
- const destDir = path_1.default.join(globalRoot, cmdPathStr);
90
- if (yield fs_extra_1.default.pathExists(destDir)) {
91
- throw new Error(`Global command ${args.join(' ')} already exists`);
92
- }
93
- yield fs_extra_1.default.ensureDir(path_1.default.dirname(destDir));
94
- if (options.move) {
95
- yield fs_extra_1.default.move(srcDir, destDir);
96
- console.log(`Moved ${args.join(' ')} to global scope`);
97
- }
98
- else {
99
- yield fs_extra_1.default.copy(srcDir, destDir);
100
- console.log(`Copied ${args.join(' ')} to global scope`);
101
- }
102
- });
61
+ async function pushGlobal(args, options = {}) {
62
+ const cwd = options.cwd || process.cwd();
63
+ const localRoot = (0, fs_utils_1.findLocalRoot)(cwd);
64
+ if (!localRoot)
65
+ throw new Error('Not in a local context');
66
+ const globalRoot = options.globalDir || (0, fs_utils_1.getGlobalRoot)();
67
+ const localAgentctl = path_1.default.join(localRoot, '.agentctl');
68
+ const cmdPathStr = args.join(path_1.default.sep);
69
+ const srcDir = path_1.default.join(localAgentctl, cmdPathStr);
70
+ if (!await fs_extra_1.default.pathExists(srcDir)) {
71
+ throw new Error(`Local command ${args.join(' ')} not found`);
72
+ }
73
+ const destDir = path_1.default.join(globalRoot, cmdPathStr);
74
+ if (await fs_extra_1.default.pathExists(destDir)) {
75
+ throw new Error(`Global command ${args.join(' ')} already exists`);
76
+ }
77
+ await fs_extra_1.default.ensureDir(path_1.default.dirname(destDir));
78
+ if (options.move) {
79
+ await fs_extra_1.default.move(srcDir, destDir);
80
+ console.log(`Moved ${args.join(' ')} to global scope`);
81
+ }
82
+ else {
83
+ await fs_extra_1.default.copy(srcDir, destDir);
84
+ console.log(`Copied ${args.join(' ')} to global scope`);
85
+ }
103
86
  }
104
- function pullLocal(args_1) {
105
- return __awaiter(this, arguments, void 0, function* (args, options = {}) {
106
- const cwd = options.cwd || process.cwd();
107
- const localRoot = (0, fs_utils_1.findLocalRoot)(cwd);
108
- if (!localRoot)
109
- throw new Error('Not in a local context');
110
- const globalRoot = options.globalDir || (0, fs_utils_1.getGlobalRoot)();
111
- const cmdPathStr = args.join(path_1.default.sep);
112
- const srcDir = path_1.default.join(globalRoot, cmdPathStr);
113
- if (!(yield fs_extra_1.default.pathExists(srcDir))) {
114
- throw new Error(`Global command ${args.join(' ')} not found`);
115
- }
116
- const localAgentctl = path_1.default.join(localRoot, '.agentctl');
117
- const destDir = path_1.default.join(localAgentctl, cmdPathStr);
118
- if (yield fs_extra_1.default.pathExists(destDir)) {
119
- throw new Error(`Local command ${args.join(' ')} already exists`);
120
- }
121
- yield fs_extra_1.default.ensureDir(path_1.default.dirname(destDir));
122
- if (options.move) {
123
- yield fs_extra_1.default.move(srcDir, destDir);
124
- console.log(`Moved ${args.join(' ')} to local scope`);
125
- }
126
- else {
127
- yield fs_extra_1.default.copy(srcDir, destDir);
128
- console.log(`Copied ${args.join(' ')} to local scope`);
129
- }
130
- });
87
+ async function pullLocal(args, options = {}) {
88
+ const cwd = options.cwd || process.cwd();
89
+ const localRoot = (0, fs_utils_1.findLocalRoot)(cwd);
90
+ if (!localRoot)
91
+ throw new Error('Not in a local context');
92
+ const globalRoot = options.globalDir || (0, fs_utils_1.getGlobalRoot)();
93
+ const cmdPathStr = args.join(path_1.default.sep);
94
+ const srcDir = path_1.default.join(globalRoot, cmdPathStr);
95
+ if (!await fs_extra_1.default.pathExists(srcDir)) {
96
+ throw new Error(`Global command ${args.join(' ')} not found`);
97
+ }
98
+ const localAgentctl = path_1.default.join(localRoot, '.agentctl');
99
+ const destDir = path_1.default.join(localAgentctl, cmdPathStr);
100
+ if (await fs_extra_1.default.pathExists(destDir)) {
101
+ throw new Error(`Local command ${args.join(' ')} already exists`);
102
+ }
103
+ await fs_extra_1.default.ensureDir(path_1.default.dirname(destDir));
104
+ if (options.move) {
105
+ await fs_extra_1.default.move(srcDir, destDir);
106
+ console.log(`Moved ${args.join(' ')} to local scope`);
107
+ }
108
+ else {
109
+ await fs_extra_1.default.copy(srcDir, destDir);
110
+ console.log(`Copied ${args.join(' ')} to local scope`);
111
+ }
131
112
  }
132
113
  const skills_1 = require("./skills");
133
- function installSkill(agent_1) {
134
- return __awaiter(this, arguments, void 0, function* (agent, options = {}) {
135
- const cwd = options.cwd || process.cwd();
136
- if (!skills_1.SUPPORTED_AGENTS.includes(agent)) {
137
- throw new Error(`Agent '${agent}' not supported. Supported agents: ${skills_1.SUPPORTED_AGENTS.join(', ')}`);
138
- }
139
- let targetDir;
140
- if (agent === 'cursor') {
141
- targetDir = path_1.default.join(cwd, '.cursor', 'skills');
114
+ async function installSkill(agent, options = {}) {
115
+ const cwd = options.cwd || process.cwd();
116
+ if (!skills_1.SUPPORTED_AGENTS.includes(agent)) {
117
+ throw new Error(`Agent '${agent}' not supported. Supported agents: ${skills_1.SUPPORTED_AGENTS.join(', ')}`);
118
+ }
119
+ let targetDir;
120
+ if (agent === 'cursor') {
121
+ targetDir = path_1.default.join(cwd, '.cursor', 'skills');
122
+ }
123
+ else if (agent === 'antigravity') {
124
+ if (options.global) {
125
+ const globalRoot = options.antigravityGlobalDir || (0, fs_utils_1.getAntigravityGlobalRoot)();
126
+ targetDir = path_1.default.join(globalRoot, 'skills', 'agentctl');
142
127
  }
143
- else if (agent === 'antigravity') {
144
- if (options.global) {
145
- const globalRoot = options.antigravityGlobalDir || (0, fs_utils_1.getAntigravityGlobalRoot)();
146
- targetDir = path_1.default.join(globalRoot, 'skills', 'agentctl');
147
- }
148
- else {
149
- targetDir = path_1.default.join(cwd, '.agent', 'skills', 'agentctl');
150
- }
151
- }
152
- else if (agent === 'agentsmd') {
153
- targetDir = path_1.default.join(cwd, '.agents', 'skills', 'agentctl');
128
+ else {
129
+ targetDir = path_1.default.join(cwd, '.agent', 'skills', 'agentctl');
154
130
  }
155
- else if (agent === 'gemini') {
156
- if (options.global) {
157
- const globalRoot = options.geminiGlobalDir || path_1.default.join(process.env.HOME || process.env.USERPROFILE, '.gemini');
158
- targetDir = path_1.default.join(globalRoot, 'skills', 'agentctl');
159
- }
160
- else {
161
- targetDir = path_1.default.join(cwd, '.gemini', 'skills', 'agentctl');
162
- }
131
+ }
132
+ else if (agent === 'agentsmd') {
133
+ targetDir = path_1.default.join(cwd, '.agents', 'skills', 'agentctl');
134
+ }
135
+ else if (agent === 'gemini') {
136
+ if (options.global) {
137
+ const globalRoot = options.geminiGlobalDir || path_1.default.join(process.env.HOME || process.env.USERPROFILE, '.gemini');
138
+ targetDir = path_1.default.join(globalRoot, 'skills', 'agentctl');
163
139
  }
164
140
  else {
165
- throw new Error(`Agent logic for '${agent}' not implemented.`);
141
+ targetDir = path_1.default.join(cwd, '.gemini', 'skills', 'agentctl');
166
142
  }
167
- const p = yield (0, skills_1.copySkill)(targetDir, agent);
168
- console.log(`Installed skill for ${agent} at ${p}`);
169
- });
143
+ }
144
+ else {
145
+ throw new Error(`Agent logic for '${agent}' not implemented.`);
146
+ }
147
+ const p = await (0, skills_1.copySkill)(targetDir, agent);
148
+ console.log(`Installed skill for ${agent} at ${p}`);
170
149
  }
171
- function rm(args_1) {
172
- return __awaiter(this, arguments, void 0, function* (args, options = {}) {
173
- const resolved = yield (0, resolve_1.resolveCommand)(args, options);
174
- if (!resolved) {
175
- throw new Error(`Command ${args.join(' ')} not found${options.global ? ' in global scope' : ''}`);
176
- }
177
- const targetDir = path_1.default.dirname(resolved.manifestPath);
178
- yield fs_extra_1.default.remove(targetDir);
179
- console.log(`Removed ${resolved.scope} command: ${args.join(' ')}`);
180
- });
150
+ async function rm(args, options = {}) {
151
+ const resolved = await (0, resolve_1.resolveCommand)(args, options);
152
+ if (!resolved) {
153
+ throw new Error(`Command ${args.join(' ')} not found${options.global ? ' in global scope' : ''}`);
154
+ }
155
+ const targetDir = path_1.default.dirname(resolved.manifestPath);
156
+ await fs_extra_1.default.remove(targetDir);
157
+ console.log(`Removed ${resolved.scope} command: ${args.join(' ')}`);
181
158
  }
182
- function mv(srcArgs_1, destArgs_1) {
183
- return __awaiter(this, arguments, void 0, function* (srcArgs, destArgs, options = {}) {
184
- const resolved = yield (0, resolve_1.resolveCommand)(srcArgs, options);
185
- if (!resolved) {
186
- throw new Error(`Command ${srcArgs.join(' ')} not found`);
187
- }
188
- const srcDir = path_1.default.dirname(resolved.manifestPath);
189
- const rootDir = resolved.scope === 'local'
190
- ? (0, fs_utils_1.findLocalRoot)(options.cwd || process.cwd())
191
- : (options.globalDir || (0, fs_utils_1.getGlobalRoot)());
192
- if (!rootDir)
193
- throw new Error('Cannot determine root for move');
194
- const agentctlDir = resolved.scope === 'local' ? path_1.default.join(rootDir, '.agentctl') : rootDir;
195
- // For global, rootDir IS the agentctl dir (config dir). Local has .agentctl subdir.
196
- const destPathStr = destArgs.join(path_1.default.sep);
197
- const destDir = path_1.default.join(agentctlDir, destPathStr);
198
- if (yield fs_extra_1.default.pathExists(destDir)) {
199
- throw new Error(`Destination ${destArgs.join(' ')} already exists`);
200
- }
201
- // Check parent validity (nesting under capped)
202
- let current = path_1.default.dirname(destDir);
203
- while (current.length >= agentctlDir.length && !isSamePath(current, path_1.default.dirname(agentctlDir))) {
204
- if (yield isCapped(current)) {
205
- const relPath = path_1.default.relative(agentctlDir, current); // relative to base
206
- throw new Error(`Cannot nest command under capped command: ${relPath}`);
207
- }
208
- current = path_1.default.dirname(current);
209
- }
210
- yield fs_extra_1.default.move(srcDir, destDir);
211
- // Update manifest name
212
- const manifestPath = path_1.default.join(destDir, 'manifest.json');
213
- if (yield fs_extra_1.default.pathExists(manifestPath)) {
214
- const manifest = yield fs_extra_1.default.readJson(manifestPath);
215
- manifest.name = destArgs[destArgs.length - 1];
216
- yield fs_extra_1.default.writeJson(manifestPath, manifest, { spaces: 2 });
159
+ async function mv(srcArgs, destArgs, options = {}) {
160
+ const resolved = await (0, resolve_1.resolveCommand)(srcArgs, options);
161
+ if (!resolved) {
162
+ throw new Error(`Command ${srcArgs.join(' ')} not found`);
163
+ }
164
+ const srcDir = path_1.default.dirname(resolved.manifestPath);
165
+ const rootDir = resolved.scope === 'local'
166
+ ? (0, fs_utils_1.findLocalRoot)(options.cwd || process.cwd())
167
+ : (options.globalDir || (0, fs_utils_1.getGlobalRoot)());
168
+ if (!rootDir)
169
+ throw new Error('Cannot determine root for move');
170
+ const agentctlDir = resolved.scope === 'local' ? path_1.default.join(rootDir, '.agentctl') : rootDir;
171
+ // For global, rootDir IS the agentctl dir (config dir). Local has .agentctl subdir.
172
+ const destPathStr = destArgs.join(path_1.default.sep);
173
+ const destDir = path_1.default.join(agentctlDir, destPathStr);
174
+ if (await fs_extra_1.default.pathExists(destDir)) {
175
+ throw new Error(`Destination ${destArgs.join(' ')} already exists`);
176
+ }
177
+ // Check parent validity (nesting under capped)
178
+ let current = path_1.default.dirname(destDir);
179
+ while (current.length >= agentctlDir.length && !isSamePath(current, path_1.default.dirname(agentctlDir))) {
180
+ if (await isCapped(current)) {
181
+ const relPath = path_1.default.relative(agentctlDir, current); // relative to base
182
+ throw new Error(`Cannot nest command under capped command: ${relPath}`);
217
183
  }
218
- console.log(`Moved ${srcArgs.join(' ')} to ${destArgs.join(' ')}`);
219
- });
184
+ current = path_1.default.dirname(current);
185
+ }
186
+ await fs_extra_1.default.move(srcDir, destDir);
187
+ // Update manifest name
188
+ const manifestPath = path_1.default.join(destDir, 'manifest.json');
189
+ if (await fs_extra_1.default.pathExists(manifestPath)) {
190
+ const manifest = await fs_extra_1.default.readJson(manifestPath);
191
+ manifest.name = destArgs[destArgs.length - 1];
192
+ await fs_extra_1.default.writeJson(manifestPath, manifest, { spaces: 2 });
193
+ }
194
+ console.log(`Moved ${srcArgs.join(' ')} to ${destArgs.join(' ')}`);
220
195
  }
221
- function inspect(args_1) {
222
- return __awaiter(this, arguments, void 0, function* (args, options = {}) {
223
- const resolved = yield (0, resolve_1.resolveCommand)(args, options);
224
- if (!resolved) {
225
- return null;
226
- }
227
- return {
228
- manifest: resolved.manifest,
229
- resolvedPath: resolved.manifestPath,
230
- scope: resolved.scope
231
- };
232
- });
196
+ async function inspect(args, options = {}) {
197
+ const resolved = await (0, resolve_1.resolveCommand)(args, options);
198
+ if (!resolved) {
199
+ return null;
200
+ }
201
+ return {
202
+ manifest: resolved.manifest,
203
+ resolvedPath: resolved.manifestPath,
204
+ scope: resolved.scope
205
+ };
233
206
  }
234
- function list() {
235
- return __awaiter(this, arguments, void 0, function* (options = {}) {
236
- const cwd = options.cwd || process.cwd();
237
- const localRoot = (0, fs_utils_1.findLocalRoot)(cwd);
238
- const globalRoot = options.globalDir || (0, fs_utils_1.getGlobalRoot)();
239
- const commands = new Map();
240
- function walk(dir, prefix, scope) {
241
- return __awaiter(this, void 0, void 0, function* () {
242
- if (!(yield fs_extra_1.default.pathExists(dir)))
243
- return;
244
- const files = yield fs_extra_1.default.readdir(dir);
245
- for (const file of files) {
246
- const filePath = path_1.default.join(dir, file);
247
- let stats;
248
- try {
249
- stats = yield fs_extra_1.default.stat(filePath);
250
- }
251
- catch (_a) {
252
- continue;
253
- }
254
- if (!stats.isDirectory())
255
- continue;
256
- const cmdPathParts = [...prefix, file];
257
- const cmdPath = cmdPathParts.join(' ');
258
- let manifest = null;
259
- const mPath = path_1.default.join(filePath, 'manifest.json');
260
- if (yield fs_extra_1.default.pathExists(mPath)) {
261
- manifest = yield (0, manifest_1.readManifest)(mPath);
262
- }
263
- let type = 'group';
264
- if (manifest) {
265
- if ((0, manifest_1.isCappedManifest)(manifest)) {
266
- type = manifest.type || 'scaffold';
267
- }
268
- else if (manifest.type) {
269
- type = manifest.type;
270
- }
271
- }
272
- const item = {
273
- path: cmdPath,
274
- type,
275
- scope,
276
- description: (manifest === null || manifest === void 0 ? void 0 : manifest.description) || ''
277
- };
278
- if (!commands.has(cmdPath)) {
279
- commands.set(cmdPath, item);
280
- const effectiveManifest = manifest || { name: file, type: 'group' };
281
- if (!(0, manifest_1.isCappedManifest)(effectiveManifest)) {
282
- yield walk(filePath, cmdPathParts, scope);
283
- }
284
- }
285
- else {
286
- const existing = commands.get(cmdPath);
287
- if (existing && existing.scope === 'local') {
288
- if (existing.type === 'group' && type === 'group') {
289
- yield walk(filePath, cmdPathParts, scope);
290
- }
291
- }
207
+ async function list(options = {}) {
208
+ const cwd = options.cwd || process.cwd();
209
+ const localRoot = (0, fs_utils_1.findLocalRoot)(cwd);
210
+ const globalRoot = options.globalDir || (0, fs_utils_1.getGlobalRoot)();
211
+ const commands = new Map();
212
+ async function walk(dir, prefix, scope) {
213
+ if (!await fs_extra_1.default.pathExists(dir))
214
+ return;
215
+ const files = await fs_extra_1.default.readdir(dir);
216
+ for (const file of files) {
217
+ const filePath = path_1.default.join(dir, file);
218
+ let stats;
219
+ try {
220
+ stats = await fs_extra_1.default.stat(filePath);
221
+ }
222
+ catch {
223
+ continue;
224
+ }
225
+ if (!stats.isDirectory())
226
+ continue;
227
+ const cmdPathParts = [...prefix, file];
228
+ const cmdPath = cmdPathParts.join(' ');
229
+ let manifest = null;
230
+ const mPath = path_1.default.join(filePath, 'manifest.json');
231
+ if (await fs_extra_1.default.pathExists(mPath)) {
232
+ manifest = await (0, manifest_1.readManifest)(mPath);
233
+ }
234
+ let type = 'group';
235
+ if (manifest) {
236
+ if ((0, manifest_1.isCappedManifest)(manifest)) {
237
+ type = manifest.type || 'scaffold';
238
+ }
239
+ else if (manifest.type) {
240
+ type = manifest.type;
241
+ }
242
+ }
243
+ const item = {
244
+ path: cmdPath,
245
+ type,
246
+ scope,
247
+ description: manifest?.description || ''
248
+ };
249
+ if (!commands.has(cmdPath)) {
250
+ commands.set(cmdPath, item);
251
+ const effectiveManifest = manifest || { name: file, type: 'group' };
252
+ if (!(0, manifest_1.isCappedManifest)(effectiveManifest)) {
253
+ await walk(filePath, cmdPathParts, scope);
254
+ }
255
+ }
256
+ else {
257
+ const existing = commands.get(cmdPath);
258
+ if (existing && existing.scope === 'local') {
259
+ if (existing.type === 'group' && type === 'group') {
260
+ await walk(filePath, cmdPathParts, scope);
292
261
  }
293
262
  }
294
- });
295
- }
296
- if (localRoot) {
297
- yield walk(path_1.default.join(localRoot, '.agentctl'), [], 'local');
263
+ }
298
264
  }
299
- yield walk(globalRoot, [], 'global');
300
- return Array.from(commands.values());
301
- });
265
+ }
266
+ if (localRoot) {
267
+ await walk(path_1.default.join(localRoot, '.agentctl'), [], 'local');
268
+ }
269
+ await walk(globalRoot, [], 'global');
270
+ return Array.from(commands.values());
302
271
  }
303
272
  // Helpers
304
- function prepareCommand(args_1) {
305
- return __awaiter(this, arguments, void 0, function* (args, options = {}) {
306
- const cwd = options.cwd || process.cwd();
307
- const rootDir = cwd;
308
- const agentctlDir = path_1.default.join(rootDir, '.agentctl');
309
- if (args.length === 0)
310
- throw new Error('No command path provided');
311
- const cmdPath = args.join(path_1.default.sep);
312
- const targetDir = path_1.default.join(agentctlDir, cmdPath);
313
- if (yield fs_extra_1.default.pathExists(targetDir)) {
314
- throw new Error(`Command ${args.join(' ')} already exists`);
273
+ async function prepareCommand(args, options = {}) {
274
+ const cwd = options.cwd || process.cwd();
275
+ const rootDir = cwd;
276
+ const agentctlDir = path_1.default.join(rootDir, '.agentctl');
277
+ if (args.length === 0)
278
+ throw new Error('No command path provided');
279
+ const cmdPath = args.join(path_1.default.sep);
280
+ const targetDir = path_1.default.join(agentctlDir, cmdPath);
281
+ if (await fs_extra_1.default.pathExists(targetDir)) {
282
+ throw new Error(`Command ${args.join(' ')} already exists`);
283
+ }
284
+ let current = path_1.default.dirname(targetDir);
285
+ while (current.length >= agentctlDir.length && !isSamePath(current, path_1.default.dirname(agentctlDir))) {
286
+ if (await isCapped(current)) {
287
+ const relPath = path_1.default.relative(agentctlDir, current); // This uses cwd for resolution if agentctlDir is cwd resolved
288
+ // Need to verify relative works predictably
289
+ // agentctlDir comes from path.join(cwd, '.agentctl').
290
+ throw new Error(`Cannot nest command under capped command: ${relPath}`);
315
291
  }
316
- let current = path_1.default.dirname(targetDir);
317
- while (current.length >= agentctlDir.length && !isSamePath(current, path_1.default.dirname(agentctlDir))) {
318
- if (yield isCapped(current)) {
319
- const relPath = path_1.default.relative(agentctlDir, current); // This uses cwd for resolution if agentctlDir is cwd resolved
320
- // Need to verify relative works predictably
321
- // agentctlDir comes from path.join(cwd, '.agentctl').
322
- throw new Error(`Cannot nest command under capped command: ${relPath}`);
323
- }
324
- current = path_1.default.dirname(current);
325
- }
326
- yield fs_extra_1.default.ensureDir(targetDir);
327
- return {
328
- targetDir,
329
- name: args[args.length - 1],
330
- isWin: process.platform === 'win32'
331
- };
332
- });
292
+ current = path_1.default.dirname(current);
293
+ }
294
+ await fs_extra_1.default.ensureDir(targetDir);
295
+ return {
296
+ targetDir,
297
+ name: args[args.length - 1],
298
+ isWin: process.platform === 'win32'
299
+ };
333
300
  }
334
- function isCapped(dir) {
335
- return __awaiter(this, void 0, void 0, function* () {
336
- const manifestPath = path_1.default.join(dir, 'manifest.json');
337
- if (yield fs_extra_1.default.pathExists(manifestPath)) {
338
- try {
339
- const m = yield fs_extra_1.default.readJson(manifestPath);
340
- return (0, manifest_1.isCappedManifest)(m);
341
- }
342
- catch (_a) {
343
- return false;
344
- }
301
+ async function isCapped(dir) {
302
+ const manifestPath = path_1.default.join(dir, 'manifest.json');
303
+ if (await fs_extra_1.default.pathExists(manifestPath)) {
304
+ try {
305
+ const m = await fs_extra_1.default.readJson(manifestPath);
306
+ return (0, manifest_1.isCappedManifest)(m);
307
+ }
308
+ catch {
309
+ return false;
345
310
  }
346
- return false;
347
- });
311
+ }
312
+ return false;
348
313
  }
349
314
  function isSamePath(p1, p2) {
350
315
  return path_1.default.relative(p1, p2) === '';