@michaelhartmayer/agentctl 1.2.1 → 1.2.2
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 +29 -24
- package/dist/effects.js +3 -1
- package/dist/index.js +116 -119
- package/dist/logic/ctl.js +9 -6
- package/dist/logic/index.js +7 -3
- package/package.json +1 -1
package/dist/ctl.js
CHANGED
|
@@ -42,6 +42,18 @@ async function getCappedAncestor(dir, baseDir) {
|
|
|
42
42
|
}
|
|
43
43
|
return null;
|
|
44
44
|
}
|
|
45
|
+
async function getMissingAncestorGroups(args, agentctlDir) {
|
|
46
|
+
const missing = [];
|
|
47
|
+
for (let i = 1; i < args.length; i++) {
|
|
48
|
+
const segments = args.slice(0, i);
|
|
49
|
+
const dir = path_1.default.join(agentctlDir, ...segments);
|
|
50
|
+
const manifestPath = path_1.default.join(dir, 'manifest.json');
|
|
51
|
+
if (!(await fs_extra_1.default.pathExists(manifestPath))) {
|
|
52
|
+
missing.push({ dir, name: segments[segments.length - 1] });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return missing;
|
|
56
|
+
}
|
|
45
57
|
async function getContext(options) {
|
|
46
58
|
const cwd = options.cwd || process.cwd();
|
|
47
59
|
return {
|
|
@@ -54,56 +66,50 @@ async function getContext(options) {
|
|
|
54
66
|
}
|
|
55
67
|
async function scaffold(args, options = {}) {
|
|
56
68
|
const ctx = await getContext(options);
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
const agentctlDir = isGlobal ? rootDir : path_1.default.join(rootDir, '.agentctl');
|
|
69
|
+
const localRoot = ctx.localRoot || ctx.cwd;
|
|
70
|
+
const agentctlDir = path_1.default.join(localRoot, '.agentctl');
|
|
60
71
|
const targetDir = path_1.default.join(agentctlDir, args.join(path_1.default.sep));
|
|
61
72
|
const exists = await fs_extra_1.default.pathExists(targetDir);
|
|
62
|
-
const cappedAncestor =
|
|
63
|
-
const
|
|
73
|
+
const cappedAncestor = await getCappedAncestor(targetDir, agentctlDir);
|
|
74
|
+
const missingAncestorGroups = await getMissingAncestorGroups(args, agentctlDir);
|
|
64
75
|
const { effects } = ctl_1.Logic.planScaffold(args, ctx, {
|
|
65
76
|
exists,
|
|
66
77
|
cappedAncestor: cappedAncestor || undefined,
|
|
67
78
|
type: 'scaffold',
|
|
68
|
-
|
|
69
|
-
isNewLocalRoot
|
|
79
|
+
missingAncestorGroups
|
|
70
80
|
});
|
|
71
81
|
await (0, effects_1.execute)(effects);
|
|
72
82
|
}
|
|
73
83
|
async function alias(args, target, options = {}) {
|
|
74
84
|
const ctx = await getContext(options);
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
const agentctlDir = isGlobal ? rootDir : path_1.default.join(rootDir, '.agentctl');
|
|
85
|
+
const localRoot = ctx.localRoot || ctx.cwd;
|
|
86
|
+
const agentctlDir = path_1.default.join(localRoot, '.agentctl');
|
|
78
87
|
const targetDir = path_1.default.join(agentctlDir, args.join(path_1.default.sep));
|
|
79
88
|
const exists = await fs_extra_1.default.pathExists(targetDir);
|
|
80
|
-
const cappedAncestor =
|
|
81
|
-
const
|
|
89
|
+
const cappedAncestor = await getCappedAncestor(targetDir, agentctlDir);
|
|
90
|
+
const missingAncestorGroups = await getMissingAncestorGroups(args, agentctlDir);
|
|
82
91
|
const { effects } = ctl_1.Logic.planScaffold(args, ctx, {
|
|
83
92
|
exists,
|
|
84
93
|
cappedAncestor: cappedAncestor || undefined,
|
|
85
94
|
type: 'alias',
|
|
86
95
|
target,
|
|
87
|
-
|
|
88
|
-
isNewLocalRoot
|
|
96
|
+
missingAncestorGroups
|
|
89
97
|
});
|
|
90
98
|
await (0, effects_1.execute)(effects);
|
|
91
99
|
}
|
|
92
100
|
async function group(args, options = {}) {
|
|
93
101
|
const ctx = await getContext(options);
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
const agentctlDir = isGlobal ? rootDir : path_1.default.join(rootDir, '.agentctl');
|
|
102
|
+
const localRoot = ctx.localRoot || ctx.cwd;
|
|
103
|
+
const agentctlDir = path_1.default.join(localRoot, '.agentctl');
|
|
97
104
|
const targetDir = path_1.default.join(agentctlDir, args.join(path_1.default.sep));
|
|
98
105
|
const exists = await fs_extra_1.default.pathExists(targetDir);
|
|
99
|
-
const cappedAncestor =
|
|
100
|
-
const
|
|
106
|
+
const cappedAncestor = await getCappedAncestor(targetDir, agentctlDir);
|
|
107
|
+
const missingAncestorGroups = await getMissingAncestorGroups(args, agentctlDir);
|
|
101
108
|
const { effects } = ctl_1.Logic.planScaffold(args, ctx, {
|
|
102
109
|
exists,
|
|
103
110
|
cappedAncestor: cappedAncestor || undefined,
|
|
104
111
|
type: 'group',
|
|
105
|
-
|
|
106
|
-
isNewLocalRoot
|
|
112
|
+
missingAncestorGroups
|
|
107
113
|
});
|
|
108
114
|
await (0, effects_1.execute)(effects);
|
|
109
115
|
}
|
|
@@ -192,14 +198,13 @@ async function installSkill(agent, options = {}) {
|
|
|
192
198
|
}
|
|
193
199
|
async function install(repoUrl, pathArgs, options = {}) {
|
|
194
200
|
const ctx = await getContext(options);
|
|
195
|
-
const isNewLocalRoot = !options.global && !(await fs_extra_1.default.pathExists(path_1.default.join(ctx.cwd, '.agentctl')));
|
|
196
201
|
const installCtx = {
|
|
197
202
|
repoUrl,
|
|
198
203
|
pathParts: pathArgs,
|
|
199
204
|
global: !!options.global,
|
|
200
205
|
allowCollisions: !!options.allowCollisions,
|
|
201
|
-
localRoot:
|
|
202
|
-
isNewLocalRoot,
|
|
206
|
+
localRoot: ctx.localRoot || ctx.cwd,
|
|
207
|
+
isNewLocalRoot: !options.global && !ctx.localRoot,
|
|
203
208
|
globalRoot: ctx.globalRoot,
|
|
204
209
|
osTmpdir: os_1.default.tmpdir()
|
|
205
210
|
};
|
package/dist/effects.js
CHANGED
|
@@ -46,7 +46,9 @@ async function execute(effects) {
|
|
|
46
46
|
break;
|
|
47
47
|
}
|
|
48
48
|
case 'spawn': {
|
|
49
|
-
const child =
|
|
49
|
+
const child = effect.args
|
|
50
|
+
? (0, child_process_1.spawn)(effect.command, effect.args, effect.options)
|
|
51
|
+
: (0, child_process_1.spawn)(effect.command, effect.options);
|
|
50
52
|
if (effect.onExit) {
|
|
51
53
|
child.on('exit', effect.onExit);
|
|
52
54
|
}
|
package/dist/index.js
CHANGED
|
@@ -28,33 +28,33 @@ const ctl = program.command('ctl')
|
|
|
28
28
|
.action((opts, command) => {
|
|
29
29
|
command.help();
|
|
30
30
|
})
|
|
31
|
-
.addHelpText('after', `
|
|
32
|
-
${chalk_1.default.bold('Agentctl Paradigm:')}
|
|
33
|
-
Agentctl acts as a unified control plane allowing both Humans and AI Agents
|
|
34
|
-
to create, discover, and execute local shell commands. By running \`agentctl ctl scaffold <name>\`
|
|
35
|
-
you create a directory in the \`.agentctl\` folder containing a \`manifest.json\`
|
|
36
|
-
and a run script. This dynamically creates a new \`agentctl <name>\` command that
|
|
37
|
-
is easily callable by agents and globally executable on your machine.
|
|
38
|
-
|
|
39
|
-
Commands:
|
|
40
|
-
|
|
41
|
-
${chalk_1.default.bold('Creation')}
|
|
42
|
-
scaffold [path...] create a new command
|
|
43
|
-
alias [args...] create a shell alias
|
|
44
|
-
group [path...] create a namespace group
|
|
45
|
-
|
|
46
|
-
${chalk_1.default.bold('Organize & Scope')}
|
|
47
|
-
rm [options] [path...] delete a command
|
|
48
|
-
mv [options] [src] [dest] rename/move a command
|
|
49
|
-
global [options] [path...] make a command global
|
|
50
|
-
local [options] [path...] make a command local
|
|
51
|
-
|
|
52
|
-
${chalk_1.default.bold('Information')}
|
|
53
|
-
list list all commands
|
|
54
|
-
inspect [path...] inspect command details
|
|
55
|
-
|
|
56
|
-
${chalk_1.default.bold('Integration')}
|
|
57
|
-
install [options] [repoUrl] [pathParts...] install remote command group
|
|
31
|
+
.addHelpText('after', `
|
|
32
|
+
${chalk_1.default.bold('Agentctl Paradigm:')}
|
|
33
|
+
Agentctl acts as a unified control plane allowing both Humans and AI Agents
|
|
34
|
+
to create, discover, and execute local shell commands. By running \`agentctl ctl scaffold <name>\`
|
|
35
|
+
you create a directory in the \`.agentctl\` folder containing a \`manifest.json\`
|
|
36
|
+
and a run script. This dynamically creates a new \`agentctl <name>\` command that
|
|
37
|
+
is easily callable by agents and globally executable on your machine.
|
|
38
|
+
|
|
39
|
+
Commands:
|
|
40
|
+
|
|
41
|
+
${chalk_1.default.bold('Creation')}
|
|
42
|
+
scaffold [path...] create a new command
|
|
43
|
+
alias [args...] create a shell alias
|
|
44
|
+
group [path...] create a namespace group
|
|
45
|
+
|
|
46
|
+
${chalk_1.default.bold('Organize & Scope')}
|
|
47
|
+
rm [options] [path...] delete a command
|
|
48
|
+
mv [options] [src] [dest] rename/move a command
|
|
49
|
+
global [options] [path...] make a command global
|
|
50
|
+
local [options] [path...] make a command local
|
|
51
|
+
|
|
52
|
+
${chalk_1.default.bold('Information')}
|
|
53
|
+
list list all commands
|
|
54
|
+
inspect [path...] inspect command details
|
|
55
|
+
|
|
56
|
+
${chalk_1.default.bold('Integration')}
|
|
57
|
+
install [options] [repoUrl] [pathParts...] install remote command group
|
|
58
58
|
`);
|
|
59
59
|
const withErrorHandling = (fn) => {
|
|
60
60
|
return async (...args) => {
|
|
@@ -76,31 +76,30 @@ const normalizePath = (parts) => parts.flatMap(p => p.split(/[\s/\\:]+/).filter(
|
|
|
76
76
|
ctl.command('scaffold')
|
|
77
77
|
.description('Scaffold a new command directory with a manifest and starter script.')
|
|
78
78
|
.argument('[path...]', 'Hierarchical path for the new command (e.g., "dev start" or "utils/cleanup")')
|
|
79
|
-
.option('-g, --global', 'Create command in global scope')
|
|
80
79
|
.summary('create a new command')
|
|
81
|
-
.addHelpText('after', `
|
|
82
|
-
Additional Info:
|
|
83
|
-
This command creates a folder in your local .agentctl directory.
|
|
84
|
-
Inside this newly created folder, it generates:
|
|
85
|
-
- manifest.json: Metadata config to edit for your command.
|
|
86
|
-
- command.sh/cmd: A starter script to edit for your actual logic.
|
|
87
|
-
|
|
88
|
-
Manifest Schema (manifest.json) to edit:
|
|
89
|
-
{
|
|
90
|
-
"name": "<command_folder_name>",
|
|
91
|
-
"description": "<insert command summary here>",
|
|
92
|
-
"help": "<insert longer usage/help instructions here>",
|
|
93
|
-
"type": "scaffold", // do not change!
|
|
94
|
-
"run": "./command.cmd" // points to the script to execute
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
Note:
|
|
98
|
-
- The "description" is displayed when you view this command in a list.
|
|
99
|
-
- Commands must provide their own help implementation (e.g. by handling --help inside your script).
|
|
100
|
-
|
|
101
|
-
Examples:
|
|
102
|
-
$ agentctl ctl scaffold build:front
|
|
103
|
-
$ agentctl ctl scaffold "build front" # Creates group 'build' and subcommand 'front'
|
|
80
|
+
.addHelpText('after', `
|
|
81
|
+
Additional Info:
|
|
82
|
+
This command creates a folder in your local .agentctl directory.
|
|
83
|
+
Inside this newly created folder, it generates:
|
|
84
|
+
- manifest.json: Metadata config to edit for your command.
|
|
85
|
+
- command.sh/cmd: A starter script to edit for your actual logic.
|
|
86
|
+
|
|
87
|
+
Manifest Schema (manifest.json) to edit:
|
|
88
|
+
{
|
|
89
|
+
"name": "<command_folder_name>",
|
|
90
|
+
"description": "<insert command summary here>",
|
|
91
|
+
"help": "<insert longer usage/help instructions here>",
|
|
92
|
+
"type": "scaffold", // do not change!
|
|
93
|
+
"run": "./command.cmd" // points to the script to execute
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
Note:
|
|
97
|
+
- The "description" is displayed when you view this command in a list.
|
|
98
|
+
- Commands must provide their own help implementation (e.g. by handling --help inside your script).
|
|
99
|
+
|
|
100
|
+
Examples:
|
|
101
|
+
$ agentctl ctl scaffold build:front
|
|
102
|
+
$ agentctl ctl scaffold "build front" # Creates group 'build' and subcommand 'front'
|
|
104
103
|
`)
|
|
105
104
|
.action(withErrorHandling(async (pathParts, opts, command) => {
|
|
106
105
|
const normalized = normalizePath(pathParts);
|
|
@@ -108,17 +107,16 @@ Examples:
|
|
|
108
107
|
command.help();
|
|
109
108
|
return;
|
|
110
109
|
}
|
|
111
|
-
await (0, ctl_1.scaffold)(normalized
|
|
110
|
+
await (0, ctl_1.scaffold)(normalized);
|
|
112
111
|
}));
|
|
113
112
|
ctl.command('alias')
|
|
114
113
|
.description('Create a command that executes a raw shell string.')
|
|
115
114
|
.argument('[args...]', 'Hierarchical path segments followed by the shell command target')
|
|
116
|
-
.option('-g, --global', 'Create alias in global scope')
|
|
117
115
|
.summary('create a shell alias')
|
|
118
|
-
.addHelpText('after', `
|
|
119
|
-
Examples:
|
|
120
|
-
$ agentctl ctl alias dev logs "docker compose logs -f"
|
|
121
|
-
$ agentctl ctl alias list-files "ls -la"
|
|
116
|
+
.addHelpText('after', `
|
|
117
|
+
Examples:
|
|
118
|
+
$ agentctl ctl alias dev logs "docker compose logs -f"
|
|
119
|
+
$ agentctl ctl alias list-files "ls -la"
|
|
122
120
|
`)
|
|
123
121
|
.action(withErrorHandling(async (args, opts, command) => {
|
|
124
122
|
if (!args || args.length < 2) {
|
|
@@ -131,36 +129,35 @@ Examples:
|
|
|
131
129
|
command.help();
|
|
132
130
|
return;
|
|
133
131
|
}
|
|
134
|
-
await (0, ctl_1.alias)(name, target
|
|
132
|
+
await (0, ctl_1.alias)(name, target);
|
|
135
133
|
}));
|
|
136
134
|
ctl.command('group')
|
|
137
135
|
.description('Create a command group (namespace) to organize subcommands.')
|
|
138
136
|
.argument('[path...]', 'Hierarchical path for the group (e.g., "dev" or "cloud/aws")')
|
|
139
|
-
.option('-g, --global', 'Create group in global scope')
|
|
140
137
|
.summary('create a namespace group')
|
|
141
|
-
.addHelpText('after', `
|
|
142
|
-
Additional Info:
|
|
143
|
-
Groups allow you to categorize commands. Running a group command without
|
|
144
|
-
subcommands will list all direct subcommands within that group.
|
|
145
|
-
|
|
146
|
-
This command creates a folder in your local .agentctl directory.
|
|
147
|
-
Inside this newly created folder, it generates a manifest.json.
|
|
148
|
-
|
|
149
|
-
Group Schema (manifest.json) to edit:
|
|
150
|
-
{
|
|
151
|
-
"name": "<group_folder_name>",
|
|
152
|
-
"description": "<insert group summary here>",
|
|
153
|
-
"help": "<insert longer group description/instructions here>",
|
|
154
|
-
"type": "group" // do not change!
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
Note:
|
|
158
|
-
- The "description" is displayed when you view this group in a list.
|
|
159
|
-
- The "help" is displayed when you call this group without a subcommand.
|
|
160
|
-
|
|
161
|
-
Examples:
|
|
162
|
-
$ agentctl ctl group dev
|
|
163
|
-
$ agentctl ctl group "data pipelines" # Creates group 'data' and subgroup 'pipelines'
|
|
138
|
+
.addHelpText('after', `
|
|
139
|
+
Additional Info:
|
|
140
|
+
Groups allow you to categorize commands. Running a group command without
|
|
141
|
+
subcommands will list all direct subcommands within that group.
|
|
142
|
+
|
|
143
|
+
This command creates a folder in your local .agentctl directory.
|
|
144
|
+
Inside this newly created folder, it generates a manifest.json.
|
|
145
|
+
|
|
146
|
+
Group Schema (manifest.json) to edit:
|
|
147
|
+
{
|
|
148
|
+
"name": "<group_folder_name>",
|
|
149
|
+
"description": "<insert group summary here>",
|
|
150
|
+
"help": "<insert longer group description/instructions here>",
|
|
151
|
+
"type": "group" // do not change!
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
Note:
|
|
155
|
+
- The "description" is displayed when you view this group in a list.
|
|
156
|
+
- The "help" is displayed when you call this group without a subcommand.
|
|
157
|
+
|
|
158
|
+
Examples:
|
|
159
|
+
$ agentctl ctl group dev
|
|
160
|
+
$ agentctl ctl group "data pipelines" # Creates group 'data' and subgroup 'pipelines'
|
|
164
161
|
`)
|
|
165
162
|
.action(withErrorHandling(async (parts, opts, command) => {
|
|
166
163
|
const normalized = normalizePath(parts);
|
|
@@ -168,17 +165,17 @@ Examples:
|
|
|
168
165
|
command.help();
|
|
169
166
|
return;
|
|
170
167
|
}
|
|
171
|
-
await (0, ctl_1.group)(normalized
|
|
168
|
+
await (0, ctl_1.group)(normalized);
|
|
172
169
|
}));
|
|
173
170
|
ctl.command('rm')
|
|
174
171
|
.description('Permanently remove a command or group.')
|
|
175
172
|
.argument('[path...]', 'Command path to remove')
|
|
176
173
|
.option('-g, --global', 'Remove from global scope instead of local')
|
|
177
174
|
.summary('delete a command')
|
|
178
|
-
.addHelpText('after', `
|
|
179
|
-
Examples:
|
|
180
|
-
$ agentctl ctl rm dev start
|
|
181
|
-
$ agentctl ctl rm utils--global
|
|
175
|
+
.addHelpText('after', `
|
|
176
|
+
Examples:
|
|
177
|
+
$ agentctl ctl rm dev start
|
|
178
|
+
$ agentctl ctl rm utils--global
|
|
182
179
|
`)
|
|
183
180
|
.action(withErrorHandling(async (parts, opts, command) => {
|
|
184
181
|
const normalized = normalizePath(parts);
|
|
@@ -194,10 +191,10 @@ ctl.command('mv')
|
|
|
194
191
|
.argument('[dest]', 'New path (space-separated or quoted)')
|
|
195
192
|
.option('-g, --global', 'Operate in global scope')
|
|
196
193
|
.summary('rename/move a command')
|
|
197
|
-
.addHelpText('after', `
|
|
198
|
-
Examples:
|
|
199
|
-
$ agentctl ctl mv "dev start" "dev begin"
|
|
200
|
-
$ agentctl ctl mv utils scripts--global
|
|
194
|
+
.addHelpText('after', `
|
|
195
|
+
Examples:
|
|
196
|
+
$ agentctl ctl mv "dev start" "dev begin"
|
|
197
|
+
$ agentctl ctl mv utils scripts--global
|
|
201
198
|
`)
|
|
202
199
|
.action(withErrorHandling(async (src, dest, opts, command) => {
|
|
203
200
|
const normalizedSrc = normalizePath(src ? [src] : []);
|
|
@@ -211,12 +208,12 @@ Examples:
|
|
|
211
208
|
ctl.command('list')
|
|
212
209
|
.description('List all available commands across local and global scopes.')
|
|
213
210
|
.summary('list all commands')
|
|
214
|
-
.addHelpText('after', `
|
|
215
|
-
Output Columns:
|
|
216
|
-
TYPE - scaffold, alias, or group
|
|
217
|
-
SCOPE - local(project - specific) or global(user - wide)
|
|
218
|
-
COMMAND - The path used to invoke the command
|
|
219
|
-
DESCRIPTION - Brief text from the command's manifest
|
|
211
|
+
.addHelpText('after', `
|
|
212
|
+
Output Columns:
|
|
213
|
+
TYPE - scaffold, alias, or group
|
|
214
|
+
SCOPE - local(project - specific) or global(user - wide)
|
|
215
|
+
COMMAND - The path used to invoke the command
|
|
216
|
+
DESCRIPTION - Brief text from the command's manifest
|
|
220
217
|
`)
|
|
221
218
|
.action(withErrorHandling(async () => {
|
|
222
219
|
const items = await (0, ctl_1.list)();
|
|
@@ -231,9 +228,9 @@ ctl.command('inspect')
|
|
|
231
228
|
.description('Show the internal manifest and file system path of a command.')
|
|
232
229
|
.argument('[path...]', 'Command path to inspect')
|
|
233
230
|
.summary('inspect command details')
|
|
234
|
-
.addHelpText('after', `
|
|
235
|
-
Examples:
|
|
236
|
-
$ agentctl ctl inspect dev start
|
|
231
|
+
.addHelpText('after', `
|
|
232
|
+
Examples:
|
|
233
|
+
$ agentctl ctl inspect dev start
|
|
237
234
|
`)
|
|
238
235
|
.action(withErrorHandling(async (parts, opts, command) => {
|
|
239
236
|
const normalized = normalizePath(parts);
|
|
@@ -256,13 +253,13 @@ ctl.command('global')
|
|
|
256
253
|
.option('-m, --move', 'Move the command (delete local after copying)')
|
|
257
254
|
.option('-c, --copy', 'Copy the command (keep local version, default)')
|
|
258
255
|
.summary('make a command global')
|
|
259
|
-
.addHelpText('after', `
|
|
260
|
-
Additional Info:
|
|
261
|
-
Global commands are stored in your home directory and are available in any project.
|
|
262
|
-
|
|
263
|
-
Examples:
|
|
264
|
-
$ agentctl ctl global utils / cleanup
|
|
265
|
-
$ agentctl ctl global dev / deploy--move
|
|
256
|
+
.addHelpText('after', `
|
|
257
|
+
Additional Info:
|
|
258
|
+
Global commands are stored in your home directory and are available in any project.
|
|
259
|
+
|
|
260
|
+
Examples:
|
|
261
|
+
$ agentctl ctl global utils / cleanup
|
|
262
|
+
$ agentctl ctl global dev / deploy--move
|
|
266
263
|
`)
|
|
267
264
|
.action(withErrorHandling(async (parts, opts, command) => {
|
|
268
265
|
const normalized = normalizePath(parts);
|
|
@@ -278,10 +275,10 @@ ctl.command('local')
|
|
|
278
275
|
.option('-m, --move', 'Move the command (delete global after pulling)')
|
|
279
276
|
.option('-c, --copy', 'Copy the command (keep global version, default)')
|
|
280
277
|
.summary('make a command local')
|
|
281
|
-
.addHelpText('after', `
|
|
282
|
-
Examples:
|
|
283
|
-
$ agentctl ctl local utils / shared
|
|
284
|
-
$ agentctl ctl local snippets / js--move
|
|
278
|
+
.addHelpText('after', `
|
|
279
|
+
Examples:
|
|
280
|
+
$ agentctl ctl local utils / shared
|
|
281
|
+
$ agentctl ctl local snippets / js--move
|
|
285
282
|
`)
|
|
286
283
|
.action(withErrorHandling(async (parts, opts, command) => {
|
|
287
284
|
const normalized = normalizePath(parts);
|
|
@@ -298,14 +295,14 @@ ctl.command('install')
|
|
|
298
295
|
.option('-g, --global', 'Install globally instead of locally')
|
|
299
296
|
.option('--allow-collisions', 'Allow overwriting existing commands or merging into groups')
|
|
300
297
|
.summary('install remote command group')
|
|
301
|
-
.addHelpText('after', `
|
|
302
|
-
Additional Info:
|
|
303
|
-
Fetches the.agentctl folder from the remote repository and installs it into
|
|
304
|
-
your local or global agentctl environment.
|
|
305
|
-
|
|
306
|
-
Examples:
|
|
307
|
-
$ agentctl ctl install https://github.com/org/repo-tools
|
|
308
|
-
$ agentctl ctl install https://github.com/org/deploy-scripts deploy --global
|
|
298
|
+
.addHelpText('after', `
|
|
299
|
+
Additional Info:
|
|
300
|
+
Fetches the.agentctl folder from the remote repository and installs it into
|
|
301
|
+
your local or global agentctl environment.
|
|
302
|
+
|
|
303
|
+
Examples:
|
|
304
|
+
$ agentctl ctl install https://github.com/org/repo-tools
|
|
305
|
+
$ agentctl ctl install https://github.com/org/deploy-scripts deploy --global
|
|
309
306
|
`)
|
|
310
307
|
.action(withErrorHandling(async (repoUrl, pathParts, opts, command) => {
|
|
311
308
|
if (!repoUrl) {
|
package/dist/logic/ctl.js
CHANGED
|
@@ -21,15 +21,21 @@ exports.Logic = {
|
|
|
21
21
|
if (options.cappedAncestor) {
|
|
22
22
|
throw new Error(`Cannot nest command under capped command: ${options.cappedAncestor.relPath}`);
|
|
23
23
|
}
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const agentctlDir = isGlobal ? rootDir : path_1.default.join(rootDir, '.agentctl');
|
|
24
|
+
const localRoot = ctx.localRoot || ctx.cwd;
|
|
25
|
+
const agentctlDir = path_1.default.join(localRoot, '.agentctl');
|
|
27
26
|
const cmdPath = args.join(path_1.default.sep);
|
|
28
27
|
const targetDir = path_1.default.join(agentctlDir, cmdPath);
|
|
29
28
|
const name = args[args.length - 1];
|
|
30
29
|
const type = options.type || 'scaffold';
|
|
31
30
|
const isWin = ctx.platform === 'win32';
|
|
32
31
|
const effects = [{ type: 'mkdir', path: targetDir }];
|
|
32
|
+
for (const group of options.missingAncestorGroups || []) {
|
|
33
|
+
effects.push({
|
|
34
|
+
type: 'writeJson',
|
|
35
|
+
path: path_1.default.join(group.dir, 'manifest.json'),
|
|
36
|
+
content: { name: group.name, type: 'group' }
|
|
37
|
+
});
|
|
38
|
+
}
|
|
33
39
|
const manifest = {
|
|
34
40
|
name,
|
|
35
41
|
description: '<insert summary>',
|
|
@@ -54,9 +60,6 @@ exports.Logic = {
|
|
|
54
60
|
const logMsg = type === 'scaffold' ? `Scaffolded command: ${args.join(' ')}` :
|
|
55
61
|
type === 'alias' ? `Aliased command: ${args.join(' ')} -> ${options.target}` :
|
|
56
62
|
`Created group: ${args.join(' ')}`;
|
|
57
|
-
if (options.isNewLocalRoot) {
|
|
58
|
-
effects.unshift({ type: 'log', message: `Initialized new .agentctl folder in ${rootDir}` });
|
|
59
|
-
}
|
|
60
63
|
effects.push({ type: 'log', message: logMsg });
|
|
61
64
|
return { effects };
|
|
62
65
|
},
|
package/dist/logic/index.js
CHANGED
|
@@ -27,13 +27,17 @@ exports.AppLogic = {
|
|
|
27
27
|
runCmd = path_1.default.resolve(cmdDir, runCmd);
|
|
28
28
|
}
|
|
29
29
|
runCmd = runCmd.replace(/{{DIR}}/g, cmdDir);
|
|
30
|
-
const
|
|
30
|
+
const quoteArg = (arg) => /[\s"'\\$`]/.test(arg) ? JSON.stringify(arg) : arg;
|
|
31
|
+
const displayedArgs = remainingArgs.map(quoteArg).join(' ');
|
|
32
|
+
const fullCommand = displayedArgs ? `${runCmd} ${displayedArgs}` : runCmd;
|
|
33
|
+
const isAlias = manifest.type === 'alias';
|
|
31
34
|
effects.push({ type: 'log', message: `[${scope}] Running: ${fullCommand}` }, {
|
|
32
35
|
type: 'spawn',
|
|
33
|
-
command: fullCommand,
|
|
36
|
+
command: isAlias ? fullCommand : runCmd,
|
|
37
|
+
args: isAlias ? undefined : remainingArgs,
|
|
34
38
|
options: {
|
|
35
39
|
cwd: process.cwd(),
|
|
36
|
-
shell:
|
|
40
|
+
shell: isAlias,
|
|
37
41
|
stdio: 'inherit',
|
|
38
42
|
env: { ...process.env, AGENTCTL_SCOPE: scope }
|
|
39
43
|
},
|