@michaelhartmayer/agentctl 1.0.3 → 1.1.3
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 +217 -308
- package/dist/effects.js +61 -0
- package/dist/fs-utils.js +26 -19
- package/dist/index.js +256 -232
- package/dist/logic/ctl.js +172 -0
- package/dist/logic/index.js +64 -0
- package/dist/logic/install.js +57 -0
- package/dist/logic/manifest.js +8 -0
- package/dist/logic/resolve.js +73 -0
- package/dist/logic/skills.js +20 -0
- package/dist/logic/utils.js +31 -0
- package/dist/manifest.js +23 -18
- package/dist/resolve.js +52 -109
- package/dist/skills.js +16 -39
- package/package.json +1 -1
- package/dist/package.json +0 -60
- package/dist/src/ctl.js +0 -316
- package/dist/src/fs-utils.js +0 -35
- package/dist/src/index.js +0 -305
- package/dist/src/manifest.js +0 -19
- package/dist/src/resolve.js +0 -112
- package/dist/src/skills.js +0 -39
package/dist/fs-utils.js
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
17
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
18
|
};
|
|
@@ -6,30 +20,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
20
|
exports.getGlobalRoot = getGlobalRoot;
|
|
7
21
|
exports.getAntigravityGlobalRoot = getAntigravityGlobalRoot;
|
|
8
22
|
exports.findLocalRoot = findLocalRoot;
|
|
9
|
-
const path_1 = __importDefault(require("path"));
|
|
10
23
|
const os_1 = __importDefault(require("os"));
|
|
11
24
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
25
|
+
const utils_1 = require("./logic/utils");
|
|
26
|
+
__exportStar(require("./logic/utils"), exports);
|
|
27
|
+
function getRealContext() {
|
|
28
|
+
return {
|
|
29
|
+
platform: process.platform,
|
|
30
|
+
env: process.env,
|
|
31
|
+
homedir: process.env.HOME || process.env.USERPROFILE || os_1.default.homedir()
|
|
32
|
+
};
|
|
33
|
+
}
|
|
12
34
|
function getGlobalRoot() {
|
|
13
|
-
|
|
14
|
-
return path_1.default.join(process.env.APPDATA || path_1.default.join(os_1.default.homedir(), 'AppData', 'Roaming'), 'agentctl');
|
|
15
|
-
}
|
|
16
|
-
return path_1.default.join(os_1.default.homedir(), '.config', 'agentctl');
|
|
35
|
+
return utils_1.UtilsLogic.getGlobalRoot(getRealContext());
|
|
17
36
|
}
|
|
18
37
|
function getAntigravityGlobalRoot() {
|
|
19
|
-
return
|
|
38
|
+
return utils_1.UtilsLogic.getAntigravityGlobalRoot(getRealContext());
|
|
20
39
|
}
|
|
21
40
|
function findLocalRoot(cwd = process.cwd()) {
|
|
22
|
-
|
|
23
|
-
const root = path_1.default.parse(current).root;
|
|
24
|
-
// Safety break and root check
|
|
25
|
-
// Using for(;;) to avoid no-constant-condition
|
|
26
|
-
for (;;) {
|
|
27
|
-
if (fs_extra_1.default.existsSync(path_1.default.join(current, '.agentctl'))) {
|
|
28
|
-
return current;
|
|
29
|
-
}
|
|
30
|
-
if (current === root) {
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
current = path_1.default.dirname(current);
|
|
34
|
-
}
|
|
41
|
+
return utils_1.UtilsLogic.findLocalRoot(cwd, fs_extra_1.default.existsSync);
|
|
35
42
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,147 +1,31 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
4
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
7
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
8
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
9
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
|
-
});
|
|
11
|
-
};
|
|
12
3
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
13
4
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
14
5
|
};
|
|
15
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
7
|
const commander_1 = require("commander");
|
|
17
|
-
const
|
|
18
|
-
require("fs-extra");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
19
9
|
const ctl_1 = require("./ctl");
|
|
20
10
|
const resolve_1 = require("./resolve");
|
|
21
|
-
const
|
|
22
|
-
const
|
|
11
|
+
const effects_1 = require("./effects");
|
|
12
|
+
const index_1 = require("./logic/index");
|
|
13
|
+
const fs_1 = __importDefault(require("fs"));
|
|
14
|
+
const path_1 = __importDefault(require("path"));
|
|
15
|
+
const pkgPath = path_1.default.join(__dirname, '../package.json');
|
|
16
|
+
const pkg = JSON.parse(fs_1.default.readFileSync(pkgPath, 'utf8'));
|
|
23
17
|
const program = new commander_1.Command();
|
|
24
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
25
|
-
const pkg = require('../package.json');
|
|
26
18
|
program
|
|
27
19
|
.name('agentctl')
|
|
28
20
|
.description('Agent Controller CLI - Unified control plane for humans and agents')
|
|
29
|
-
.version(pkg.version)
|
|
30
|
-
|
|
31
|
-
.helpOption(false) // Disable default help to allow pass-through
|
|
32
|
-
.argument('[command...]', 'Command to run')
|
|
33
|
-
.action((args, _options, _command) => __awaiter(void 0, void 0, void 0, function* () {
|
|
34
|
-
// If no args, check for help flag or just show help
|
|
35
|
-
if (!args || args.length === 0) {
|
|
36
|
-
// If they passed --help or -h, show help. If no args at all, show help.
|
|
37
|
-
// Since we ate options, we check raw args or just treat empty args as help.
|
|
38
|
-
// command.opts() won't have help if we disabled it?
|
|
39
|
-
// Actually, if we disable helpOption, --help becomes an unknown option or arg.
|
|
40
|
-
// Let's check process.argv for -h or --help if args is empty?
|
|
41
|
-
// "agentctl --help" -> args=[], options might contain help if we didn't disable it?
|
|
42
|
-
// With helpOption(false), --help is just a flag in argv.
|
|
43
|
-
// If args is empty and we see help flag, show help.
|
|
44
|
-
if (process.argv.includes('--help') || process.argv.includes('-h') || process.argv.length <= 2) {
|
|
45
|
-
program.help();
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
// If args are present, we try to resolve.
|
|
50
|
-
// BUT, "agentctl --help" will result in args being empty if it's parsed as option?
|
|
51
|
-
// Wait, if helpOption(false), then --help is an unknown option.
|
|
52
|
-
// If allowUnknownOption is true, it might not be in 'args' if it looks like a flag.
|
|
53
|
-
// Let's rely on resolveCommand. passed args are variadic.
|
|
54
|
-
// However, "agentctl dev --help" -> args=["dev", "--help"]?
|
|
55
|
-
// My repro says yes: [ 'dev-tools', 'gh', '--help' ].
|
|
56
|
-
// So for "agentctl --help", args might be ["--help"].
|
|
57
|
-
if (args.length === 1 && (args[0] === '--help' || args[0] === '-h')) {
|
|
58
|
-
program.help();
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
// Bypass for ctl subcommand if it slipped through (shouldn't if registered)
|
|
62
|
-
if (args[0] === 'ctl')
|
|
63
|
-
return;
|
|
64
|
-
try {
|
|
65
|
-
// resolveCommand needs to handle flags in args if they are part of the path?
|
|
66
|
-
// No, flags usually come after. resolveCommand stops at first non-matching path part?
|
|
67
|
-
// resolveCommand logic: iterates args.
|
|
68
|
-
// "dev-tools gh --help" -> path "dev-tools gh", remaining "--help"
|
|
69
|
-
const result = yield (0, resolve_1.resolveCommand)(args);
|
|
70
|
-
if (!result) {
|
|
71
|
-
// If not found, and they asked for help, show root help?
|
|
72
|
-
// Or if they just typed a wrong command.
|
|
73
|
-
if (args.includes('--help') || args.includes('-h')) {
|
|
74
|
-
// Try to show help for the partial command?
|
|
75
|
-
// For now, just show root list/help or error.
|
|
76
|
-
// If it's "agentctl dev --help" and "dev" is a group, resolveCommand SHOULD return the group.
|
|
77
|
-
}
|
|
78
|
-
console.error(chalk_1.default.red(`Command '${args.join(' ')}' not found.`));
|
|
79
|
-
console.log(`Run ${chalk_1.default.cyan('agentctl list')} to see available commands.`);
|
|
80
|
-
process.exit(1);
|
|
81
|
-
}
|
|
82
|
-
const { manifest, args: remainingArgs, scope } = result;
|
|
83
|
-
if (manifest.run) {
|
|
84
|
-
// ... run logic ...
|
|
85
|
-
// remainingArgs should contain --help if it was passed.
|
|
86
|
-
const cmdDir = path_1.default.dirname(result.manifestPath);
|
|
87
|
-
let runCmd = manifest.run;
|
|
88
|
-
// Resolve relative path
|
|
89
|
-
if (runCmd.startsWith('./') || runCmd.startsWith('.\\')) {
|
|
90
|
-
runCmd = path_1.default.resolve(cmdDir, runCmd);
|
|
91
|
-
}
|
|
92
|
-
// Interpolate {{DIR}}
|
|
93
|
-
runCmd = runCmd.replace(/{{DIR}}/g, cmdDir);
|
|
94
|
-
const fullCommand = `${runCmd} ${remainingArgs.join(' ')}`;
|
|
95
|
-
console.log(chalk_1.default.dim(`[${scope}] Running: ${fullCommand}`));
|
|
96
|
-
const child = (0, child_process_1.spawn)(fullCommand, {
|
|
97
|
-
cwd: process.cwd(), // Execute in CWD as discussed
|
|
98
|
-
shell: true,
|
|
99
|
-
stdio: 'inherit',
|
|
100
|
-
env: Object.assign(Object.assign({}, process.env), { AGENTCTL_SCOPE: scope })
|
|
101
|
-
});
|
|
102
|
-
child.on('exit', (code) => {
|
|
103
|
-
process.exit(code || 0);
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
// Group
|
|
108
|
-
console.log(chalk_1.default.blue(chalk_1.default.bold(`${manifest.name}`)));
|
|
109
|
-
console.log(manifest.description || 'No description');
|
|
110
|
-
console.log('\nSubcommands:');
|
|
111
|
-
const all = yield (0, ctl_1.list)();
|
|
112
|
-
const prefix = result.cmdPath + ' ';
|
|
113
|
-
// Filter logic roughly for direct children
|
|
114
|
-
const depth = result.cmdPath.split(' ').length;
|
|
115
|
-
const children = all.filter(c => c.path.startsWith(prefix) && c.path !== result.cmdPath);
|
|
116
|
-
const direct = children.filter(c => c.path.split(' ').length === depth + 1);
|
|
117
|
-
if (direct.length === 0 && children.length === 0) {
|
|
118
|
-
console.log(chalk_1.default.dim(' (No subcommands found)'));
|
|
119
|
-
}
|
|
120
|
-
for (const child of direct) {
|
|
121
|
-
console.log(` ${child.path.split(' ').pop()}\t${chalk_1.default.dim(child.description)}`);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
catch (e) {
|
|
126
|
-
if (e instanceof Error) {
|
|
127
|
-
console.error(chalk_1.default.red(e.message));
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
console.error(chalk_1.default.red('An unknown error occurred'));
|
|
131
|
-
}
|
|
132
|
-
process.exit(1);
|
|
133
|
-
}
|
|
134
|
-
}));
|
|
21
|
+
.version(pkg.version);
|
|
22
|
+
// --- Subcommand: ctl ---
|
|
135
23
|
const ctl = program.command('ctl')
|
|
136
|
-
.description('Agent Controller Management - Create,
|
|
137
|
-
// --- Lifecycle Commands ---
|
|
138
|
-
// We'll stick to flat list but with good descriptions.
|
|
139
|
-
// Helper for consistent error handling
|
|
140
|
-
// Helper for consistent error handling
|
|
24
|
+
.description('Agent Controller Management - Create, organize, and manage commands');
|
|
141
25
|
const withErrorHandling = (fn) => {
|
|
142
|
-
return (...args) =>
|
|
26
|
+
return async (...args) => {
|
|
143
27
|
try {
|
|
144
|
-
|
|
28
|
+
await fn(...args);
|
|
145
29
|
}
|
|
146
30
|
catch (e) {
|
|
147
31
|
if (e instanceof Error) {
|
|
@@ -152,164 +36,304 @@ const withErrorHandling = (fn) => {
|
|
|
152
36
|
}
|
|
153
37
|
process.exit(1);
|
|
154
38
|
}
|
|
155
|
-
}
|
|
39
|
+
};
|
|
156
40
|
};
|
|
157
41
|
ctl.command('scaffold')
|
|
158
|
-
.description('
|
|
159
|
-
.argument('
|
|
42
|
+
.description('Scaffold a new command directory with a manifest and starter script.')
|
|
43
|
+
.argument('[path...]', 'Hierarchical path for the new command (e.g., "dev start" or "utils/cleanup")')
|
|
44
|
+
.summary('create a new command')
|
|
160
45
|
.addHelpText('after', `
|
|
46
|
+
Additional Info:
|
|
47
|
+
This command creates a folder in your local .agentctl directory.
|
|
48
|
+
Inside, it generates:
|
|
49
|
+
- manifest.json: Metadata about the command.
|
|
50
|
+
- command.sh/cmd: A starter script for your logic.
|
|
51
|
+
|
|
161
52
|
Examples:
|
|
162
|
-
$ agentctl ctl scaffold
|
|
163
|
-
$ agentctl ctl scaffold
|
|
53
|
+
$ agentctl ctl scaffold build front
|
|
54
|
+
$ agentctl ctl scaffold utils/backup
|
|
164
55
|
`)
|
|
165
|
-
.action(withErrorHandling((pathParts
|
|
166
|
-
|
|
167
|
-
|
|
56
|
+
.action(withErrorHandling(async (pathParts, opts, command) => {
|
|
57
|
+
if (!pathParts || pathParts.length === 0) {
|
|
58
|
+
command.help();
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
await (0, ctl_1.scaffold)(pathParts);
|
|
62
|
+
}));
|
|
168
63
|
ctl.command('alias')
|
|
169
|
-
.description('Create a
|
|
170
|
-
.argument('
|
|
171
|
-
.
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
64
|
+
.description('Create a command that executes a raw shell string.')
|
|
65
|
+
.argument('[args...]', 'Hierarchical path segments followed by the shell command target')
|
|
66
|
+
.summary('create a shell alias')
|
|
67
|
+
.addHelpText('after', `
|
|
68
|
+
Examples:
|
|
69
|
+
$ agentctl ctl alias dev logs "docker compose logs -f"
|
|
70
|
+
$ agentctl ctl alias list-files "ls -la"
|
|
71
|
+
`)
|
|
72
|
+
.action(withErrorHandling(async (args, opts, command) => {
|
|
73
|
+
if (!args || args.length < 2) {
|
|
74
|
+
command.help();
|
|
75
|
+
return;
|
|
175
76
|
}
|
|
176
77
|
const target = args.pop();
|
|
177
78
|
const name = args;
|
|
178
|
-
|
|
179
|
-
}))
|
|
180
|
-
.addHelpText('after', `
|
|
181
|
-
Examples:
|
|
182
|
-
$ agentctl ctl alias tools gh "gh"
|
|
183
|
-
$ agentctl ctl alias dev build "npm run build"
|
|
184
|
-
`);
|
|
79
|
+
await (0, ctl_1.alias)(name, target);
|
|
80
|
+
}));
|
|
185
81
|
ctl.command('group')
|
|
186
|
-
.description('Create a
|
|
187
|
-
.argument('
|
|
82
|
+
.description('Create a command group (namespace) to organize subcommands.')
|
|
83
|
+
.argument('[path...]', 'Hierarchical path for the group (e.g., "dev" or "cloud/aws")')
|
|
84
|
+
.summary('create a namespace group')
|
|
188
85
|
.addHelpText('after', `
|
|
86
|
+
Additional Info:
|
|
87
|
+
Groups allow you to categorize commands. Running a group command without
|
|
88
|
+
subcommands will list all direct subcommands within that group.
|
|
89
|
+
|
|
189
90
|
Examples:
|
|
190
91
|
$ agentctl ctl group dev
|
|
191
|
-
$ agentctl ctl group
|
|
92
|
+
$ agentctl ctl group data/pipelines
|
|
192
93
|
`)
|
|
193
|
-
.action(withErrorHandling((parts
|
|
194
|
-
|
|
195
|
-
|
|
94
|
+
.action(withErrorHandling(async (parts, opts, command) => {
|
|
95
|
+
if (!parts || parts.length === 0) {
|
|
96
|
+
command.help();
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
await (0, ctl_1.group)(parts);
|
|
100
|
+
}));
|
|
196
101
|
ctl.command('rm')
|
|
197
|
-
.description('
|
|
198
|
-
.argument('
|
|
199
|
-
.option('--global', 'Remove from global scope')
|
|
102
|
+
.description('Permanently remove a command or group.')
|
|
103
|
+
.argument('[path...]', 'Command path to remove')
|
|
104
|
+
.option('-g, --global', 'Remove from global scope instead of local')
|
|
105
|
+
.summary('delete a command')
|
|
200
106
|
.addHelpText('after', `
|
|
201
107
|
Examples:
|
|
202
108
|
$ agentctl ctl rm dev start
|
|
203
|
-
$ agentctl ctl rm
|
|
109
|
+
$ agentctl ctl rm utils --global
|
|
204
110
|
`)
|
|
205
|
-
.action(withErrorHandling((parts, opts) =>
|
|
206
|
-
|
|
207
|
-
|
|
111
|
+
.action(withErrorHandling(async (parts, opts, command) => {
|
|
112
|
+
if (!parts || parts.length === 0) {
|
|
113
|
+
command.help();
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
await (0, ctl_1.rm)(parts, { global: opts.global });
|
|
117
|
+
}));
|
|
208
118
|
ctl.command('mv')
|
|
209
|
-
.description('Move a command
|
|
210
|
-
.argument('
|
|
211
|
-
.argument('
|
|
212
|
-
.option('--global', '
|
|
119
|
+
.description('Move or rename a command/group within its current scope.')
|
|
120
|
+
.argument('[src]', 'Current path (space-separated or quoted)')
|
|
121
|
+
.argument('[dest]', 'New path (space-separated or quoted)')
|
|
122
|
+
.option('-g, --global', 'Operate in global scope')
|
|
123
|
+
.summary('rename/move a command')
|
|
213
124
|
.addHelpText('after', `
|
|
214
125
|
Examples:
|
|
215
|
-
$ agentctl ctl mv "dev start" "dev
|
|
216
|
-
$ agentctl ctl mv
|
|
126
|
+
$ agentctl ctl mv "dev start" "dev begin"
|
|
127
|
+
$ agentctl ctl mv utils scripts --global
|
|
217
128
|
`)
|
|
218
|
-
.action(withErrorHandling((src, dest, opts) =>
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
129
|
+
.action(withErrorHandling(async (src, dest, opts, command) => {
|
|
130
|
+
if (!src || !dest) {
|
|
131
|
+
command.help();
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
await (0, ctl_1.mv)(src.split(' '), dest.split(' '), { global: opts.global });
|
|
135
|
+
}));
|
|
222
136
|
ctl.command('list')
|
|
223
|
-
.description('List all available commands across local and global scopes')
|
|
224
|
-
.
|
|
225
|
-
|
|
226
|
-
|
|
137
|
+
.description('List all available commands across local and global scopes.')
|
|
138
|
+
.summary('list all commands')
|
|
139
|
+
.addHelpText('after', `
|
|
140
|
+
Output Columns:
|
|
141
|
+
TYPE - scaffold, alias, or group
|
|
142
|
+
SCOPE - local (project-specific) or global (user-wide)
|
|
143
|
+
COMMAND - The path used to invoke the command
|
|
144
|
+
DESCRIPTION - Brief text from the command's manifest
|
|
145
|
+
`)
|
|
146
|
+
.action(withErrorHandling(async () => {
|
|
147
|
+
const items = await (0, ctl_1.list)();
|
|
148
|
+
console.log(chalk_1.default.bold('TYPE SCOPE COMMAND DESCRIPTION'));
|
|
227
149
|
for (const item of items) {
|
|
228
|
-
|
|
150
|
+
const typePipe = item.type.padEnd(9);
|
|
151
|
+
const scopePipe = item.scope === 'local' ? chalk_1.default.cyan(item.scope.padEnd(9)) : chalk_1.default.magenta(item.scope.padEnd(9));
|
|
152
|
+
console.log(`${typePipe} ${scopePipe} ${chalk_1.default.yellow(item.path.padEnd(19))} ${item.description}`);
|
|
229
153
|
}
|
|
230
|
-
}))
|
|
154
|
+
}));
|
|
231
155
|
ctl.command('inspect')
|
|
232
|
-
.description('
|
|
233
|
-
.argument('
|
|
234
|
-
.
|
|
235
|
-
|
|
156
|
+
.description('Show the internal manifest and file system path of a command.')
|
|
157
|
+
.argument('[path...]', 'Command path to inspect')
|
|
158
|
+
.summary('inspect command details')
|
|
159
|
+
.addHelpText('after', `
|
|
160
|
+
Examples:
|
|
161
|
+
$ agentctl ctl inspect dev start
|
|
162
|
+
`)
|
|
163
|
+
.action(withErrorHandling(async (parts, opts, command) => {
|
|
164
|
+
if (!parts || parts.length === 0) {
|
|
165
|
+
command.help();
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const info = await (0, ctl_1.inspect)(parts);
|
|
236
169
|
if (info) {
|
|
237
170
|
console.log(JSON.stringify(info, null, 2));
|
|
238
171
|
}
|
|
239
172
|
else {
|
|
240
|
-
console.error('Command not found');
|
|
173
|
+
console.error(chalk_1.default.red('Command not found'));
|
|
241
174
|
process.exit(1);
|
|
242
175
|
}
|
|
243
|
-
}))
|
|
244
|
-
// --- Scoping ---
|
|
176
|
+
}));
|
|
245
177
|
ctl.command('global')
|
|
246
|
-
.description('
|
|
247
|
-
.argument('
|
|
248
|
-
.option('--move', 'Move
|
|
249
|
-
.option('--copy', 'Copy (default)')
|
|
178
|
+
.description('Promote a local command to the global scope.')
|
|
179
|
+
.argument('[path...]', 'Local command path to promote')
|
|
180
|
+
.option('-m, --move', 'Move the command (delete local after copying)')
|
|
181
|
+
.option('-c, --copy', 'Copy the command (keep local version, default)')
|
|
182
|
+
.summary('make a command global')
|
|
250
183
|
.addHelpText('after', `
|
|
184
|
+
Additional Info:
|
|
185
|
+
Global commands are stored in your home directory and are available in any project.
|
|
186
|
+
|
|
251
187
|
Examples:
|
|
252
|
-
$ agentctl ctl global
|
|
253
|
-
$ agentctl ctl global
|
|
188
|
+
$ agentctl ctl global utils/cleanup
|
|
189
|
+
$ agentctl ctl global dev/deploy --move
|
|
254
190
|
`)
|
|
255
|
-
.action(withErrorHandling((parts, opts) =>
|
|
256
|
-
|
|
257
|
-
|
|
191
|
+
.action(withErrorHandling(async (parts, opts, command) => {
|
|
192
|
+
if (!parts || parts.length === 0) {
|
|
193
|
+
command.help();
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
await (0, ctl_1.pushGlobal)(parts, { move: opts.move, copy: opts.copy || !opts.move });
|
|
197
|
+
}));
|
|
258
198
|
ctl.command('local')
|
|
259
|
-
.description('Pull a global command
|
|
260
|
-
.argument('
|
|
261
|
-
.option('--move', 'Move
|
|
262
|
-
.option('--copy', 'Copy (default)')
|
|
199
|
+
.description('Pull a global command into the current local project.')
|
|
200
|
+
.argument('[path...]', 'Global command path to pull')
|
|
201
|
+
.option('-m, --move', 'Move the command (delete global after pulling)')
|
|
202
|
+
.option('-c, --copy', 'Copy the command (keep global version, default)')
|
|
203
|
+
.summary('make a command local')
|
|
263
204
|
.addHelpText('after', `
|
|
264
205
|
Examples:
|
|
265
|
-
$ agentctl ctl local
|
|
206
|
+
$ agentctl ctl local utils/shared
|
|
207
|
+
$ agentctl ctl local snippets/js --move
|
|
266
208
|
`)
|
|
267
|
-
.action(withErrorHandling((parts, opts) =>
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
ctl.
|
|
275
|
-
.
|
|
209
|
+
.action(withErrorHandling(async (parts, opts, command) => {
|
|
210
|
+
if (!parts || parts.length === 0) {
|
|
211
|
+
command.help();
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
await (0, ctl_1.pullLocal)(parts, { move: opts.move, copy: opts.copy || !opts.move });
|
|
215
|
+
}));
|
|
216
|
+
ctl.command('install-skill')
|
|
217
|
+
.description('Configure a supported AI agent (like Cursor or Gemini) to natively use Agentctl.')
|
|
218
|
+
.argument('[agent]', 'Agent name (cursor, antigravity, agentsmd, gemini)')
|
|
219
|
+
.option('-g, --global', 'Install globally for the agent (if supported)')
|
|
220
|
+
.summary('configure AI agent integration')
|
|
276
221
|
.addHelpText('after', `
|
|
222
|
+
Supported Agents:
|
|
223
|
+
- cursor (Installs to .cursor/skills)
|
|
224
|
+
- antigravity (Installs to .agent/skills or ~/.gemini/antigravity)
|
|
225
|
+
- agentsmd (Installs to .agents/skills)
|
|
226
|
+
- gemini (Installs to .gemini/skills or ~/.gemini/skills)
|
|
227
|
+
|
|
277
228
|
Examples:
|
|
278
|
-
$ agentctl ctl
|
|
279
|
-
$ agentctl ctl
|
|
280
|
-
$ agentctl ctl --install-skill gemini
|
|
229
|
+
$ agentctl ctl install-skill cursor
|
|
230
|
+
$ agentctl ctl install-skill antigravity --global
|
|
281
231
|
`)
|
|
282
|
-
.action(withErrorHandling((
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
232
|
+
.action(withErrorHandling(async (agent, opts, command) => {
|
|
233
|
+
if (!agent) {
|
|
234
|
+
command.help();
|
|
235
|
+
return;
|
|
286
236
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
237
|
+
await (0, ctl_1.installSkill)(agent, { global: opts.global });
|
|
238
|
+
}));
|
|
239
|
+
ctl.command('install')
|
|
240
|
+
.description('Install a command group from a remote Git repository.')
|
|
241
|
+
.argument('[repoUrl]', 'URL of the remote Git repository containing an .agentctl folder')
|
|
242
|
+
.argument('[pathParts...]', 'Optional local namespace/group to install into')
|
|
243
|
+
.option('-g, --global', 'Install globally instead of locally')
|
|
244
|
+
.option('--allow-collisions', 'Allow overwriting existing commands or merging into groups')
|
|
245
|
+
.summary('install remote command group')
|
|
246
|
+
.addHelpText('after', `
|
|
247
|
+
Additional Info:
|
|
248
|
+
Fetches the .agentctl folder from the remote repository and installs it into
|
|
249
|
+
your local or global agentctl environment.
|
|
250
|
+
|
|
251
|
+
Examples:
|
|
252
|
+
$ agentctl ctl install https://github.com/org/repo-tools
|
|
253
|
+
$ agentctl ctl install https://github.com/org/deploy-scripts deploy --global
|
|
254
|
+
`)
|
|
255
|
+
.action(withErrorHandling(async (repoUrl, pathParts, opts, command) => {
|
|
256
|
+
if (!repoUrl) {
|
|
257
|
+
command.help();
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
await (0, ctl_1.install)(repoUrl, pathParts, { global: opts.global, allowCollisions: opts.allowCollisions });
|
|
261
|
+
}));
|
|
262
|
+
// --- Dynamic Command Logic ---
|
|
263
|
+
async function handleDynamicCommand(args) {
|
|
264
|
+
try {
|
|
265
|
+
const result = await (0, resolve_1.resolveCommand)(args);
|
|
266
|
+
if (!result) {
|
|
267
|
+
const effects = index_1.AppLogic.planApp(args, null);
|
|
268
|
+
await (0, effects_1.execute)(effects.map(e => e.type === 'log' ? { ...e, message: chalk_1.default.red(e.message) } : e));
|
|
269
|
+
process.exit(1);
|
|
270
|
+
}
|
|
271
|
+
if (result.manifest.run) {
|
|
272
|
+
const effects = index_1.AppLogic.planApp(args, result);
|
|
273
|
+
await (0, effects_1.execute)(effects);
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
const all = await (0, ctl_1.list)();
|
|
277
|
+
const effects = index_1.AppLogic.planGroupList(result.manifest, result.cmdPath, all);
|
|
278
|
+
await (0, effects_1.execute)(effects.map(e => {
|
|
279
|
+
if (e.type === 'log') {
|
|
280
|
+
if (e.message === result.manifest.name)
|
|
281
|
+
return { ...e, message: chalk_1.default.blue(chalk_1.default.bold(e.message)) };
|
|
282
|
+
if (e.message === '\nSubcommands:')
|
|
283
|
+
return e;
|
|
284
|
+
if (e.message.startsWith(' '))
|
|
285
|
+
return e;
|
|
286
|
+
if (e.message === 'No description')
|
|
287
|
+
return { ...e, message: chalk_1.default.dim(e.message) };
|
|
288
|
+
}
|
|
289
|
+
return e;
|
|
290
|
+
}));
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
catch (e) {
|
|
294
|
+
if (e instanceof Error) {
|
|
295
|
+
console.error(chalk_1.default.red(e.message));
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
console.error(chalk_1.default.red('An unknown error occurred'));
|
|
291
299
|
}
|
|
300
|
+
process.exit(1);
|
|
292
301
|
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
//
|
|
296
|
-
(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
302
|
+
}
|
|
303
|
+
(async () => {
|
|
304
|
+
// Add help text for user commands dynamically
|
|
297
305
|
try {
|
|
298
|
-
const allCommands =
|
|
299
|
-
const topLevel = allCommands.filter(c => !c.path.includes(' '));
|
|
306
|
+
const allCommands = await (0, ctl_1.list)();
|
|
307
|
+
const topLevel = allCommands.filter(c => !c.path.includes(' '));
|
|
300
308
|
if (topLevel.length > 0) {
|
|
301
309
|
const lines = [''];
|
|
302
|
-
lines.push('User Commands:');
|
|
310
|
+
lines.push(chalk_1.default.bold('User Commands:'));
|
|
303
311
|
for (const cmd of topLevel) {
|
|
304
|
-
|
|
305
|
-
lines.push(` ${cmd.path.padEnd(27)}${cmd.description}`);
|
|
312
|
+
lines.push(` ${chalk_1.default.yellow(cmd.path.padEnd(27))}${cmd.description}`);
|
|
306
313
|
}
|
|
307
314
|
lines.push('');
|
|
308
315
|
program.addHelpText('after', lines.join('\n'));
|
|
309
316
|
}
|
|
310
317
|
}
|
|
311
|
-
catch
|
|
312
|
-
// Ignore errors during help generation
|
|
318
|
+
catch {
|
|
319
|
+
// Ignore errors during help generation
|
|
320
|
+
}
|
|
321
|
+
// Process arguments
|
|
322
|
+
const args = process.argv.slice(2);
|
|
323
|
+
// If no args, show help
|
|
324
|
+
if (args.length === 0) {
|
|
325
|
+
program.help();
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
// Special case: if it starts with 'ctl', or is '--help', '--version', '-h', etc.,
|
|
329
|
+
// let commander handle it natively.
|
|
330
|
+
const firstArg = args[0];
|
|
331
|
+
const isStandardCommand = ['ctl', '--help', '-h', '--version', '-V'].includes(firstArg) || firstArg.startsWith('-');
|
|
332
|
+
if (isStandardCommand) {
|
|
333
|
+
program.parse(process.argv);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
// It's a dynamic command
|
|
337
|
+
await handleDynamicCommand(args);
|
|
313
338
|
}
|
|
314
|
-
|
|
315
|
-
}))();
|
|
339
|
+
})();
|