@michaelhartmayer/agentctl 1.1.4 → 1.2.1

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
@@ -54,40 +54,56 @@ async function getContext(options) {
54
54
  }
55
55
  async function scaffold(args, options = {}) {
56
56
  const ctx = await getContext(options);
57
- const localRoot = ctx.localRoot || ctx.cwd;
58
- const agentctlDir = path_1.default.join(localRoot, '.agentctl');
57
+ const isGlobal = !!options.global;
58
+ const rootDir = isGlobal ? ctx.globalRoot : ctx.cwd;
59
+ const agentctlDir = isGlobal ? rootDir : path_1.default.join(rootDir, '.agentctl');
59
60
  const targetDir = path_1.default.join(agentctlDir, args.join(path_1.default.sep));
60
61
  const exists = await fs_extra_1.default.pathExists(targetDir);
61
- const cappedAncestor = await getCappedAncestor(targetDir, agentctlDir);
62
- const { effects } = ctl_1.Logic.planScaffold(args, ctx, { exists, cappedAncestor: cappedAncestor || undefined, type: 'scaffold' });
62
+ const cappedAncestor = isGlobal ? null : await getCappedAncestor(targetDir, agentctlDir);
63
+ const isNewLocalRoot = !isGlobal && !(await fs_extra_1.default.pathExists(agentctlDir));
64
+ const { effects } = ctl_1.Logic.planScaffold(args, ctx, {
65
+ exists,
66
+ cappedAncestor: cappedAncestor || undefined,
67
+ type: 'scaffold',
68
+ scope: isGlobal ? 'global' : 'local',
69
+ isNewLocalRoot
70
+ });
63
71
  await (0, effects_1.execute)(effects);
64
72
  }
65
73
  async function alias(args, target, options = {}) {
66
74
  const ctx = await getContext(options);
67
- const localRoot = ctx.localRoot || ctx.cwd;
68
- const agentctlDir = path_1.default.join(localRoot, '.agentctl');
75
+ const isGlobal = !!options.global;
76
+ const rootDir = isGlobal ? ctx.globalRoot : ctx.cwd;
77
+ const agentctlDir = isGlobal ? rootDir : path_1.default.join(rootDir, '.agentctl');
69
78
  const targetDir = path_1.default.join(agentctlDir, args.join(path_1.default.sep));
70
79
  const exists = await fs_extra_1.default.pathExists(targetDir);
71
- const cappedAncestor = await getCappedAncestor(targetDir, agentctlDir);
80
+ const cappedAncestor = isGlobal ? null : await getCappedAncestor(targetDir, agentctlDir);
81
+ const isNewLocalRoot = !isGlobal && !(await fs_extra_1.default.pathExists(agentctlDir));
72
82
  const { effects } = ctl_1.Logic.planScaffold(args, ctx, {
73
83
  exists,
74
84
  cappedAncestor: cappedAncestor || undefined,
75
85
  type: 'alias',
76
- target
86
+ target,
87
+ scope: isGlobal ? 'global' : 'local',
88
+ isNewLocalRoot
77
89
  });
78
90
  await (0, effects_1.execute)(effects);
79
91
  }
80
92
  async function group(args, options = {}) {
81
93
  const ctx = await getContext(options);
82
- const localRoot = ctx.localRoot || ctx.cwd;
83
- const agentctlDir = path_1.default.join(localRoot, '.agentctl');
94
+ const isGlobal = !!options.global;
95
+ const rootDir = isGlobal ? ctx.globalRoot : ctx.cwd;
96
+ const agentctlDir = isGlobal ? rootDir : path_1.default.join(rootDir, '.agentctl');
84
97
  const targetDir = path_1.default.join(agentctlDir, args.join(path_1.default.sep));
85
98
  const exists = await fs_extra_1.default.pathExists(targetDir);
86
- const cappedAncestor = await getCappedAncestor(targetDir, agentctlDir);
99
+ const cappedAncestor = isGlobal ? null : await getCappedAncestor(targetDir, agentctlDir);
100
+ const isNewLocalRoot = !isGlobal && !(await fs_extra_1.default.pathExists(agentctlDir));
87
101
  const { effects } = ctl_1.Logic.planScaffold(args, ctx, {
88
102
  exists,
89
103
  cappedAncestor: cappedAncestor || undefined,
90
- type: 'group'
104
+ type: 'group',
105
+ scope: isGlobal ? 'global' : 'local',
106
+ isNewLocalRoot
91
107
  });
92
108
  await (0, effects_1.execute)(effects);
93
109
  }
@@ -176,13 +192,14 @@ async function installSkill(agent, options = {}) {
176
192
  }
177
193
  async function install(repoUrl, pathArgs, options = {}) {
178
194
  const ctx = await getContext(options);
195
+ const isNewLocalRoot = !options.global && !(await fs_extra_1.default.pathExists(path_1.default.join(ctx.cwd, '.agentctl')));
179
196
  const installCtx = {
180
197
  repoUrl,
181
198
  pathParts: pathArgs,
182
199
  global: !!options.global,
183
200
  allowCollisions: !!options.allowCollisions,
184
- localRoot: ctx.localRoot || ctx.cwd,
185
- isNewLocalRoot: !options.global && !ctx.localRoot,
201
+ localRoot: options.global ? ctx.globalRoot : ctx.cwd,
202
+ isNewLocalRoot,
186
203
  globalRoot: ctx.globalRoot,
187
204
  osTmpdir: os_1.default.tmpdir()
188
205
  };
package/dist/index.js CHANGED
@@ -25,6 +25,9 @@ const ctl = program.command('ctl')
25
25
  .description('Agent Controller Management - Create, organize, and manage commands')
26
26
  .addHelpCommand(false)
27
27
  .configureHelp({ visibleCommands: () => [] })
28
+ .action((opts, command) => {
29
+ command.help();
30
+ })
28
31
  .addHelpText('after', `
29
32
  ${chalk_1.default.bold('Agentctl Paradigm:')}
30
33
  Agentctl acts as a unified control plane allowing both Humans and AI Agents
@@ -73,6 +76,7 @@ const normalizePath = (parts) => parts.flatMap(p => p.split(/[\s/\\:]+/).filter(
73
76
  ctl.command('scaffold')
74
77
  .description('Scaffold a new command directory with a manifest and starter script.')
75
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')
76
80
  .summary('create a new command')
77
81
  .addHelpText('after', `
78
82
  Additional Info:
@@ -104,11 +108,12 @@ Examples:
104
108
  command.help();
105
109
  return;
106
110
  }
107
- await (0, ctl_1.scaffold)(normalized);
111
+ await (0, ctl_1.scaffold)(normalized, { global: opts.global });
108
112
  }));
109
113
  ctl.command('alias')
110
114
  .description('Create a command that executes a raw shell string.')
111
115
  .argument('[args...]', 'Hierarchical path segments followed by the shell command target')
116
+ .option('-g, --global', 'Create alias in global scope')
112
117
  .summary('create a shell alias')
113
118
  .addHelpText('after', `
114
119
  Examples:
@@ -126,11 +131,12 @@ Examples:
126
131
  command.help();
127
132
  return;
128
133
  }
129
- await (0, ctl_1.alias)(name, target);
134
+ await (0, ctl_1.alias)(name, target, { global: opts.global });
130
135
  }));
131
136
  ctl.command('group')
132
137
  .description('Create a command group (namespace) to organize subcommands.')
133
138
  .argument('[path...]', 'Hierarchical path for the group (e.g., "dev" or "cloud/aws")')
139
+ .option('-g, --global', 'Create group in global scope')
134
140
  .summary('create a namespace group')
135
141
  .addHelpText('after', `
136
142
  Additional Info:
@@ -162,7 +168,7 @@ Examples:
162
168
  command.help();
163
169
  return;
164
170
  }
165
- await (0, ctl_1.group)(normalized);
171
+ await (0, ctl_1.group)(normalized, { global: opts.global });
166
172
  }));
167
173
  ctl.command('rm')
168
174
  .description('Permanently remove a command or group.')
package/dist/logic/ctl.js CHANGED
@@ -21,8 +21,9 @@ 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 localRoot = ctx.localRoot || ctx.cwd;
25
- const agentctlDir = path_1.default.join(localRoot, '.agentctl');
24
+ const isGlobal = options.scope === 'global';
25
+ const rootDir = isGlobal ? ctx.globalRoot : ctx.cwd;
26
+ const agentctlDir = isGlobal ? rootDir : path_1.default.join(rootDir, '.agentctl');
26
27
  const cmdPath = args.join(path_1.default.sep);
27
28
  const targetDir = path_1.default.join(agentctlDir, cmdPath);
28
29
  const name = args[args.length - 1];
@@ -53,6 +54,9 @@ exports.Logic = {
53
54
  const logMsg = type === 'scaffold' ? `Scaffolded command: ${args.join(' ')}` :
54
55
  type === 'alias' ? `Aliased command: ${args.join(' ')} -> ${options.target}` :
55
56
  `Created group: ${args.join(' ')}`;
57
+ if (options.isNewLocalRoot) {
58
+ effects.unshift({ type: 'log', message: `Initialized new .agentctl folder in ${rootDir}` });
59
+ }
56
60
  effects.push({ type: 'log', message: logMsg });
57
61
  return { effects };
58
62
  },
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public"
5
5
  },
6
6
  "description": "Agent Controller - A unified interface for humans and AI agents",
7
- "version": "1.1.4",
7
+ "version": "1.2.1",
8
8
  "main": "dist/index.js",
9
9
  "bin": {
10
10
  "agentctl": "./dist/index.js"