@agentplugins/cli 0.1.0 → 0.2.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.
Files changed (46) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.d.ts +14 -5
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +135 -9
  5. package/dist/cli.js.map +1 -1
  6. package/dist/commands/add.d.ts +11 -0
  7. package/dist/commands/add.d.ts.map +1 -0
  8. package/dist/commands/add.js +123 -0
  9. package/dist/commands/add.js.map +1 -0
  10. package/dist/commands/build.d.ts +26 -0
  11. package/dist/commands/build.d.ts.map +1 -1
  12. package/dist/commands/build.js +81 -45
  13. package/dist/commands/build.js.map +1 -1
  14. package/dist/commands/doctor.d.ts +10 -0
  15. package/dist/commands/doctor.d.ts.map +1 -0
  16. package/dist/commands/doctor.js +62 -0
  17. package/dist/commands/doctor.js.map +1 -0
  18. package/dist/commands/info.d.ts +11 -0
  19. package/dist/commands/info.d.ts.map +1 -0
  20. package/dist/commands/info.js +84 -0
  21. package/dist/commands/info.js.map +1 -0
  22. package/dist/commands/init.d.ts +6 -3
  23. package/dist/commands/init.d.ts.map +1 -1
  24. package/dist/commands/init.js +277 -72
  25. package/dist/commands/init.js.map +1 -1
  26. package/dist/commands/lint.d.ts +13 -0
  27. package/dist/commands/lint.d.ts.map +1 -0
  28. package/dist/commands/lint.js +56 -0
  29. package/dist/commands/lint.js.map +1 -0
  30. package/dist/commands/list.d.ts +10 -0
  31. package/dist/commands/list.d.ts.map +1 -0
  32. package/dist/commands/list.js +47 -0
  33. package/dist/commands/list.js.map +1 -0
  34. package/dist/commands/preview.d.ts +14 -0
  35. package/dist/commands/preview.d.ts.map +1 -0
  36. package/dist/commands/preview.js +110 -0
  37. package/dist/commands/preview.js.map +1 -0
  38. package/dist/commands/remove.d.ts +11 -0
  39. package/dist/commands/remove.d.ts.map +1 -0
  40. package/dist/commands/remove.js +31 -0
  41. package/dist/commands/remove.js.map +1 -0
  42. package/dist/commands/update.d.ts +11 -0
  43. package/dist/commands/update.d.ts.map +1 -0
  44. package/dist/commands/update.js +58 -0
  45. package/dist/commands/update.js.map +1 -0
  46. package/package.json +18 -17
@@ -0,0 +1,10 @@
1
+ /**
2
+ * AgentPlugins Doctor Command
3
+ *
4
+ * Runs diagnostics on the store, detected agents, and symlinks.
5
+ */
6
+ export interface DoctorOptions {
7
+ json?: boolean;
8
+ }
9
+ export declare function doctor(options: DoctorOptions): Promise<void>;
10
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA4DlE"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * AgentPlugins Doctor Command
3
+ *
4
+ * Runs diagnostics on the store, detected agents, and symlinks.
5
+ */
6
+ import chalk from 'chalk';
7
+ import { runDoctor } from '@agentplugins/core';
8
+ export async function doctor(options) {
9
+ const result = runDoctor();
10
+ if (options.json) {
11
+ console.log(JSON.stringify(result, null, 2));
12
+ return;
13
+ }
14
+ console.log(chalk.bold('\n🩺 AgentPlugins Doctor\n'));
15
+ // Store
16
+ console.log(chalk.cyan('Store'));
17
+ console.log(chalk.gray(` Path: ${result.storePath}`));
18
+ console.log(chalk.gray(` Exists: ${result.storeExists ? chalk.green('yes') : chalk.red('no')}`));
19
+ console.log(chalk.gray(` Skills: ${result.skillsCompatPath}`));
20
+ console.log(chalk.gray(` Skills exists: ${result.skillsCompatExists ? chalk.green('yes') : chalk.red('no')}`));
21
+ // Agents
22
+ console.log(chalk.cyan('\nAgents'));
23
+ const detected = result.agents.filter((a) => a.binaryFound || a.skillPathExists);
24
+ if (detected.length === 0) {
25
+ console.log(chalk.yellow(' No agents detected.'));
26
+ }
27
+ for (const agent of result.agents) {
28
+ const detectedHere = agent.binaryFound || agent.skillPathExists;
29
+ const status = detectedHere ? chalk.green('āœ“') : chalk.gray('ā—‹');
30
+ const binStatus = agent.binaryFound ? chalk.green('found') : chalk.gray('not found');
31
+ const pathStatus = agent.skillPathExists ? chalk.green('exists') : chalk.gray('missing');
32
+ console.log(chalk.gray(` ${status} ${agent.displayName.padEnd(22)} binary: ${binStatus} path: ${pathStatus}`));
33
+ }
34
+ // Plugins
35
+ console.log(chalk.cyan(`\nPlugins (${result.plugins.length})`));
36
+ if (result.plugins.length === 0) {
37
+ console.log(chalk.gray(' No plugins installed.'));
38
+ }
39
+ for (const plugin of result.plugins) {
40
+ const linkCount = plugin.symlinks.length;
41
+ const broken = plugin.symlinks.filter((s) => !s.valid).length;
42
+ const status = broken > 0 ? chalk.yellow('⚠') : chalk.green('āœ“');
43
+ console.log(chalk.gray(` ${status} ${plugin.meta.name.padEnd(24)} v${plugin.meta.version} links: ${linkCount}${broken > 0 ? ` (${broken} broken)` : ''}`));
44
+ }
45
+ // Issues
46
+ if (result.issues.length > 0) {
47
+ const errors = result.issues.filter((i) => i.level === 'error');
48
+ console.log(chalk.cyan(`\nIssues (${result.issues.length})`));
49
+ for (const issue of result.issues) {
50
+ const icon = issue.level === 'error' ? chalk.red('āœ—') : issue.level === 'warning' ? chalk.yellow('⚠') : chalk.blue('ℹ');
51
+ console.log(` ${icon} ${issue.message}`);
52
+ }
53
+ if (errors.length > 0) {
54
+ console.log(chalk.red(`\n${errors.length} error(s) found.`));
55
+ }
56
+ }
57
+ else {
58
+ console.log(chalk.green('\nāœ… All checks passed.'));
59
+ }
60
+ console.log();
61
+ }
62
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * AgentPlugins Info Command
3
+ *
4
+ * Shows detailed information about an installed plugin.
5
+ */
6
+ export interface InfoOptions {
7
+ name: string;
8
+ json?: boolean;
9
+ }
10
+ export declare function info(options: InfoOptions): Promise<void>;
11
+ //# sourceMappingURL=info.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"info.d.ts","sourceRoot":"","sources":["../../src/commands/info.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAiF9D"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * AgentPlugins Info Command
3
+ *
4
+ * Shows detailed information about an installed plugin.
5
+ */
6
+ import chalk from 'chalk';
7
+ import { getPluginInfo } from '@agentplugins/core';
8
+ export async function info(options) {
9
+ const plugin = getPluginInfo(options.name);
10
+ if (!plugin) {
11
+ console.error(chalk.red(`Plugin "${options.name}" is not installed.`));
12
+ process.exit(1);
13
+ }
14
+ if (options.json) {
15
+ console.log(JSON.stringify({
16
+ name: plugin.meta.name,
17
+ version: plugin.meta.version,
18
+ source: plugin.meta.source,
19
+ commit: plugin.meta.commit,
20
+ installedAt: plugin.meta.installedAt,
21
+ updatedAt: plugin.meta.updatedAt,
22
+ manifestPath: plugin.meta.manifestPath,
23
+ storePath: plugin.path,
24
+ manifest: plugin.manifest,
25
+ symlinks: plugin.symlinks,
26
+ }, null, 2));
27
+ return;
28
+ }
29
+ const m = plugin.meta;
30
+ console.log(chalk.bold(`\nā„¹ļø ${m.name}\n`));
31
+ console.log(chalk.cyan(' Metadata'));
32
+ console.log(chalk.gray(` Name: ${m.name}`));
33
+ console.log(chalk.gray(` Version: ${m.version}`));
34
+ console.log(chalk.gray(` Source: ${m.source}`));
35
+ console.log(chalk.gray(` Commit: ${m.commit}`));
36
+ console.log(chalk.gray(` Installed: ${m.installedAt}`));
37
+ console.log(chalk.gray(` Updated: ${m.updatedAt}`));
38
+ console.log(chalk.gray(` Manifest: ${m.manifestPath}`));
39
+ console.log(chalk.gray(` Store path: ${plugin.path}`));
40
+ // Manifest details
41
+ if (plugin.manifest) {
42
+ const manifest = plugin.manifest;
43
+ const description = manifest['description'];
44
+ const author = manifest['author'];
45
+ const license = manifest['license'];
46
+ const hooks = manifest['hooks'];
47
+ const skills = manifest['skills'];
48
+ const tools = manifest['tools'];
49
+ console.log(chalk.cyan('\n Manifest'));
50
+ if (description)
51
+ console.log(chalk.gray(` Description: ${description}`));
52
+ if (author) {
53
+ const authorStr = typeof author === 'string' ? author : author?.name || '';
54
+ if (authorStr)
55
+ console.log(chalk.gray(` Author: ${authorStr}`));
56
+ }
57
+ if (license)
58
+ console.log(chalk.gray(` License: ${license}`));
59
+ if (hooks && typeof hooks === 'object') {
60
+ const hookNames = Object.keys(hooks);
61
+ console.log(chalk.gray(` Hooks: ${hookNames.join(', ')}`));
62
+ }
63
+ if (Array.isArray(skills)) {
64
+ console.log(chalk.gray(` Skills: ${skills.length}`));
65
+ }
66
+ if (Array.isArray(tools)) {
67
+ console.log(chalk.gray(` Tools: ${tools.length}`));
68
+ }
69
+ }
70
+ // Symlinks
71
+ if (plugin.symlinks.length > 0) {
72
+ console.log(chalk.cyan('\n Symlinks'));
73
+ for (const s of plugin.symlinks) {
74
+ const status = s.valid ? chalk.green('āœ“') : chalk.red('āœ—');
75
+ console.log(chalk.gray(` ${status} ${s.agentDisplayName.padEnd(20)} ${s.linkPath}`));
76
+ }
77
+ }
78
+ else {
79
+ console.log(chalk.cyan('\n Symlinks'));
80
+ console.log(chalk.gray(' (none — no agent harnesses detected)'));
81
+ }
82
+ console.log();
83
+ }
84
+ //# sourceMappingURL=info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"info.js","sourceRoot":"","sources":["../../src/commands/info.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,14 @@
1
1
  /**
2
2
  * AgentPlugins Init Command
3
3
  *
4
- * Scaffolds a new AgentPlugins plugin project.
4
+ * Scaffolds a new AgentPlugins plugin project interactively via @clack/prompts,
5
+ * or non-interactively when --yes is passed.
5
6
  */
6
7
  export interface InitOptions {
7
- name: string;
8
- targets: string[];
8
+ name?: string;
9
+ template?: string;
10
+ yes: boolean;
11
+ target?: string;
9
12
  }
10
13
  export declare function init(options: InitOptions): Promise<void>;
11
14
  //# sourceMappingURL=init.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAiJ9D"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAmDD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA0B9D"}
@@ -1,75 +1,281 @@
1
1
  /**
2
2
  * AgentPlugins Init Command
3
3
  *
4
- * Scaffolds a new AgentPlugins plugin project.
4
+ * Scaffolds a new AgentPlugins plugin project interactively via @clack/prompts,
5
+ * or non-interactively when --yes is passed.
5
6
  */
6
7
  import { resolve } from 'node:path';
7
8
  import { mkdir, writeFile } from 'node:fs/promises';
8
9
  import chalk from 'chalk';
10
+ import * as p from '@clack/prompts';
11
+ const TARGET_OPTIONS = [
12
+ { value: 'claude', label: 'Claude', hint: 'Anthropic Claude Code' },
13
+ { value: 'codex', label: 'Codex', hint: 'OpenAI Codex' },
14
+ { value: 'copilot', label: 'Copilot', hint: 'GitHub Copilot' },
15
+ { value: 'gemini', label: 'Gemini', hint: 'Google Gemini' },
16
+ { value: 'kimi', label: 'Kimi', hint: 'Moonshot Kimi' },
17
+ { value: 'opencode', label: 'OpenCode', hint: 'OpenCode agent' },
18
+ { value: 'pimono', label: 'Pi Mono', hint: 'Pi Mono agent' },
19
+ ];
20
+ const HOOK_OPTIONS = [
21
+ { value: 'sessionStart', label: 'sessionStart' },
22
+ { value: 'preToolUse', label: 'preToolUse' },
23
+ { value: 'postToolUse', label: 'postToolUse' },
24
+ { value: 'notification', label: 'notification' },
25
+ { value: 'stop', label: 'stop' },
26
+ ];
27
+ const HOOK_NAMES = ['sessionStart', 'preToolUse', 'postToolUse', 'notification', 'stop'];
28
+ const TEMPLATES = ['minimal', 'logger', 'security-guard', 'formatter'];
29
+ const DEFAULTS = {
30
+ name: 'my-plugin',
31
+ version: '0.1.0',
32
+ description: 'An AgentPlugins plugin',
33
+ license: 'MIT',
34
+ targets: ['claude', 'codex'],
35
+ hooks: ['sessionStart', 'preToolUse'],
36
+ template: 'logger',
37
+ };
38
+ const KEBAB_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
9
39
  export async function init(options) {
10
- const { name, targets } = options;
40
+ if (options.template && !TEMPLATES.includes(options.template)) {
41
+ console.error(chalk.red(`Unknown template: ${options.template}`));
42
+ console.error(chalk.gray(`Available templates: ${TEMPLATES.join(', ')}`));
43
+ process.exit(1);
44
+ }
45
+ let answers;
46
+ if (options.yes) {
47
+ answers = getDefaults(options);
48
+ console.log(chalk.bold(`\nšŸ†• Creating AgentPlugins plugin: ${answers.name}\n`));
49
+ await generateFiles(answers);
50
+ console.log(chalk.green('āœ… Plugin scaffolded!\n'));
51
+ }
52
+ else {
53
+ p.intro('AgentPlugins plugin scaffold');
54
+ answers = await runInteractive(options);
55
+ await generateFiles(answers);
56
+ p.outro('Plugin scaffolded!');
57
+ }
58
+ console.log(chalk.gray('Next steps:'));
59
+ console.log(chalk.gray(` cd ${answers.name}`));
60
+ console.log(chalk.gray(' npm install'));
61
+ console.log(chalk.gray(' npm run validate'));
62
+ console.log(chalk.gray(' npm run build\n'));
63
+ }
64
+ // ─── Interactive Flow ─────────────────────────────────────────────────────────
65
+ async function runInteractive(opts) {
66
+ let name;
67
+ if (opts.name) {
68
+ name = toKebabCase(opts.name);
69
+ }
70
+ else {
71
+ const raw = await p.text({
72
+ message: 'Plugin name (kebab-case)',
73
+ placeholder: 'my-plugin',
74
+ defaultValue: DEFAULTS.name,
75
+ validate: (v) => v.length === 0 || !KEBAB_RE.test(v)
76
+ ? 'Use kebab-case (lowercase letters, digits, hyphens)'
77
+ : undefined,
78
+ });
79
+ name = toKebabCase(assertValue(raw));
80
+ }
81
+ const version = assertValue(await p.text({
82
+ message: 'Version',
83
+ initialValue: DEFAULTS.version,
84
+ }));
85
+ const description = assertValue(await p.text({
86
+ message: 'Description',
87
+ placeholder: 'Describe what your plugin does...',
88
+ validate: (v) => v.trim().length < 10 ? 'Description must be at least 10 characters' : undefined,
89
+ }));
90
+ const license = assertValue(await p.text({
91
+ message: 'License',
92
+ initialValue: DEFAULTS.license,
93
+ }));
94
+ let targets;
95
+ if (opts.target) {
96
+ targets = opts.target.split(',').map((t) => t.trim()).filter(Boolean);
97
+ }
98
+ else {
99
+ const picked = assertValue(await p.multiselect({
100
+ message: 'Target platforms',
101
+ options: TARGET_OPTIONS,
102
+ required: false,
103
+ }));
104
+ targets = picked.length > 0 ? picked : [...DEFAULTS.targets];
105
+ }
106
+ const pickedHooks = assertValue(await p.multiselect({
107
+ message: 'Hook coverage',
108
+ options: HOOK_OPTIONS,
109
+ required: false,
110
+ }));
111
+ const hooks = pickedHooks.length > 0 ? pickedHooks : [...DEFAULTS.hooks];
112
+ const includeSkill = assertValue(await p.confirm({ message: 'Include a skill?', initialValue: true }));
113
+ let skillName = '';
114
+ let skillDescription = '';
115
+ if (includeSkill) {
116
+ skillName = assertValue(await p.text({
117
+ message: 'Skill name',
118
+ placeholder: `${name}-skill`,
119
+ defaultValue: `${name}-skill`,
120
+ validate: (v) => (v.length === 0 ? 'Skill name is required' : undefined),
121
+ }));
122
+ skillDescription = assertValue(await p.text({
123
+ message: 'Skill description',
124
+ placeholder: `Describe what the ${name} skill does...`,
125
+ validate: (v) => v.trim().length < 10 ? 'Description must be at least 10 characters' : undefined,
126
+ }));
127
+ }
128
+ const includeMcp = assertValue(await p.confirm({ message: 'Include MCP server config?', initialValue: false }));
129
+ const includeCommands = assertValue(await p.confirm({ message: 'Include custom command?', initialValue: false }));
130
+ return {
131
+ name,
132
+ version,
133
+ description,
134
+ license,
135
+ targets,
136
+ hooks,
137
+ template: opts.template ?? DEFAULTS.template,
138
+ skill: includeSkill,
139
+ skillName,
140
+ skillDescription,
141
+ mcp: includeMcp,
142
+ commands: includeCommands,
143
+ };
144
+ }
145
+ // ─── Defaults (--yes path) ─────────────────────────────────────────────────────
146
+ function getDefaults(opts) {
147
+ const name = toKebabCase(opts.name || DEFAULTS.name);
148
+ const targets = opts.target
149
+ ? opts.target.split(',').map((t) => t.trim()).filter(Boolean)
150
+ : [...DEFAULTS.targets];
151
+ return {
152
+ name,
153
+ version: DEFAULTS.version,
154
+ description: DEFAULTS.description,
155
+ license: DEFAULTS.license,
156
+ targets,
157
+ hooks: [...DEFAULTS.hooks],
158
+ template: opts.template ?? DEFAULTS.template,
159
+ skill: true,
160
+ skillName: `${name}-skill`,
161
+ skillDescription: `Default skill for ${name}`,
162
+ mcp: false,
163
+ commands: false,
164
+ };
165
+ }
166
+ // ─── File Generation ───────────────────────────────────────────────────────────
167
+ async function generateFiles(a) {
11
168
  const cwd = process.cwd();
12
- const pluginDir = resolve(cwd, name);
13
- console.log(chalk.bold(`\nšŸ†• Creating AgentPlugins plugin: ${name}\n`));
14
- // Create directory
169
+ const pluginDir = resolve(cwd, a.name);
15
170
  await mkdir(pluginDir, { recursive: true });
16
- // ─── agentplugins.config.ts ────────────────────────────────────────────────
17
- const configContent = `import { definePlugin } from '@agentplugins/core';
171
+ await writeFile(resolve(pluginDir, 'agentplugins.config.ts'), buildConfigContent(a));
172
+ await writeFile(resolve(pluginDir, 'package.json'), JSON.stringify(buildPackageJson(a), null, 2) + '\n');
173
+ await writeFile(resolve(pluginDir, 'tsconfig.json'), JSON.stringify(buildTsConfig(), null, 2) + '\n');
174
+ await writeFile(resolve(pluginDir, '.gitignore'), `dist/\nnode_modules/\n*.log\n`);
175
+ await writeFile(resolve(pluginDir, 'README.md'), buildReadme(a));
176
+ }
177
+ function buildConfigContent(a) {
178
+ const orderedHooks = HOOK_NAMES.filter((h) => a.hooks.includes(h));
179
+ const hooksBlock = orderedHooks
180
+ .map((h) => buildHookEntry(a.template, h, a.name))
181
+ .join('\n');
182
+ const parts = [];
183
+ parts.push(`import { definePlugin } from '@agentplugins/core';
18
184
 
19
185
  export default definePlugin({
20
- name: '${toKebabCase(name)}',
21
- version: '0.1.0',
22
- description: 'My AgentPlugins plugin — works across multiple AI agent harnesses',
186
+ name: '${toKebabCase(a.name)}',
187
+ version: '${a.version}',
188
+ description: ${JSON.stringify(a.description)},
189
+ license: '${a.license}',
23
190
 
24
191
  // Target platforms to compile for
25
- targets: [${targets.map(t => `'${t}'`).join(', ')}] as const,
26
-
27
- // Plugin hooks
192
+ targets: [${a.targets.map((t) => `'${t}'`).join(', ')}] as const,`);
193
+ if (orderedHooks.length > 0) {
194
+ parts.push(`
195
+ // Plugin hooks (${a.template} template)
28
196
  hooks: {
29
- sessionStart: {
30
- handler: {
31
- type: 'inline',
32
- handler: async (ctx) => {
33
- console.log('[AgentPlugins] Session started:', ctx.sessionId);
34
- return {
35
- additionalContext: '${name} plugin is active. Log all tool usage for audit.',
36
- };
37
- },
38
- },
39
- },
40
- preToolUse: {
41
- handler: {
42
- type: 'inline',
43
- handler: async (ctx) => {
44
- console.log('[AgentPlugins] Tool call:', ctx.toolName, JSON.stringify(ctx.toolInput));
45
- // Return nothing to allow the tool call
46
- },
47
- },
48
- },
49
- },
50
-
197
+ ${hooksBlock}
198
+ },`);
199
+ }
200
+ if (a.skill) {
201
+ const sn = a.skillName || `${a.name}-skill`;
202
+ const sd = a.skillDescription || `Default skill for ${a.name}`;
203
+ parts.push(`
51
204
  // Skills the plugin provides
52
205
  skills: [
53
206
  {
54
- name: '${toKebabCase(name)}-skill',
55
- description: 'Default skill for ${name}',
207
+ name: '${sn}',
208
+ description: ${JSON.stringify(sd)},
56
209
  content: \`---
57
- name: ${toKebabCase(name)}-skill
58
- description: Default skill for ${name}
210
+ name: ${sn}
211
+ description: ${sd}
59
212
  ---
60
213
 
61
- When using this plugin, always log your actions for transparency.
214
+ Guidance for the ${a.name} plugin. Follow these instructions when this skill is active.
62
215
  \`,
63
216
  },
64
- ],
65
- });
66
- `;
67
- await writeFile(resolve(pluginDir, 'agentplugins.config.ts'), configContent);
68
- // ─── package.json ─────────────────────────────────────────────────────────
69
- const packageJson = {
70
- name: toKebabCase(name),
71
- version: '0.1.0',
72
- description: `AgentPlugins plugin — works across ${targets.join(', ')}`,
217
+ ],`);
218
+ }
219
+ if (a.mcp) {
220
+ parts.push(`
221
+ // MCP server configuration
222
+ mcpServers: {
223
+ '${a.name}-mcp': {
224
+ command: 'npx',
225
+ args: ['-y', '${a.name}-mcp-server'],
226
+ },
227
+ },`);
228
+ }
229
+ if (a.commands) {
230
+ parts.push(`
231
+ // Custom commands
232
+ commands: [
233
+ { name: '${a.name}:run', description: 'Run ${a.name}', command: 'node ./dist/run.js' },
234
+ ],`);
235
+ }
236
+ parts.push(`});
237
+ `);
238
+ return parts.join('\n');
239
+ }
240
+ function buildHookEntry(template, hookName, pluginName) {
241
+ return ` ${hookName}: {
242
+ handler: {
243
+ type: 'inline',
244
+ handler: ${buildHookBody(template, hookName, pluginName)},
245
+ },
246
+ },`;
247
+ }
248
+ function buildHookBody(template, hookName, pluginName) {
249
+ switch (template) {
250
+ case 'logger':
251
+ return `async (ctx) => { console.log('[${pluginName}] ${hookName}:', JSON.stringify(ctx, null, 2)); }`;
252
+ case 'security-guard':
253
+ if (hookName === 'preToolUse') {
254
+ return `async (ctx) => {
255
+ const dangerous = ['rm -rf', 'curl', 'wget', 'sh -c', 'chmod 777'];
256
+ const cmd = JSON.stringify(ctx.toolInput || {});
257
+ if (dangerous.some(p => cmd.includes(p))) {
258
+ return { decision: 'block', reason: 'Blocked by security-guard: potentially dangerous command' };
259
+ }
260
+ }`;
261
+ }
262
+ return `async (_ctx) => { /* TODO: implement */ }`;
263
+ case 'formatter':
264
+ if (hookName === 'postToolUse') {
265
+ return `async (ctx) => { /* Transform output */ return { transformed: ctx }; }`;
266
+ }
267
+ return `async (_ctx) => { /* TODO: implement */ }`;
268
+ case 'minimal':
269
+ default:
270
+ return `async (_ctx) => { /* TODO: implement */ }`;
271
+ }
272
+ }
273
+ function buildPackageJson(a) {
274
+ return {
275
+ name: toKebabCase(a.name),
276
+ version: a.version,
277
+ description: a.description,
278
+ license: a.license,
73
279
  type: 'module',
74
280
  private: true,
75
281
  scripts: {
@@ -82,9 +288,9 @@ When using this plugin, always log your actions for transparency.
82
288
  typescript: '^5.5.0',
83
289
  },
84
290
  };
85
- await writeFile(resolve(pluginDir, 'package.json'), JSON.stringify(packageJson, null, 2));
86
- // ─── tsconfig.json ────────────────────────────────────────────────────────
87
- const tsconfig = {
291
+ }
292
+ function buildTsConfig() {
293
+ return {
88
294
  compilerOptions: {
89
295
  target: 'ES2022',
90
296
  module: 'NodeNext',
@@ -96,20 +302,18 @@ When using this plugin, always log your actions for transparency.
96
302
  },
97
303
  include: ['agentplugins.config.ts'],
98
304
  };
99
- await writeFile(resolve(pluginDir, 'tsconfig.json'), JSON.stringify(tsconfig, null, 2));
100
- // ─── .gitignore ───────────────────────────────────────────────────────────
101
- await writeFile(resolve(pluginDir, '.gitignore'), `dist/
102
- node_modules/
103
- *.log
104
- `);
105
- // ─── README.md ────────────────────────────────────────────────────────────
106
- const readme = `# ${name}
305
+ }
306
+ function buildReadme(a) {
307
+ const targets = a.targets;
308
+ return `# ${a.name}
309
+
310
+ ${a.description}
107
311
 
108
- An [AgentPlugins](https://github.com/espetro/agentplugins) plugin that works across multiple AI agent harnesses.
312
+ An [AgentPlugins](https://github.com/sigilco/agentplugins) plugin that works across multiple AI agent harnesses.
109
313
 
110
314
  ## Supported Platforms
111
315
 
112
- ${targets.map(t => `- ${t}`).join('\n')}
316
+ ${targets.map((t) => `- ${t}`).join('\n')}
113
317
 
114
318
  ## Development
115
319
 
@@ -124,25 +328,26 @@ npm run validate
124
328
  npm run build
125
329
 
126
330
  # Build for specific targets
127
- npx agentplugins build --target claude,codex
331
+ npx agentplugins build --target ${targets.join(',')}
128
332
  \`\`\`
129
333
 
130
334
  ## Installation
131
335
 
132
336
  After building, install the appropriate output for your agent harness:
133
337
 
134
- ${targets.map(t => `### ${t}
338
+ ${targets.map((t) => `### ${t}
135
339
  \`\`\`bash
136
- ${getInstallCommand(t, name)}
340
+ ${getInstallCommand(t, a.name)}
137
341
  \`\`\``).join('\n\n')}
138
342
  `;
139
- await writeFile(resolve(pluginDir, 'README.md'), readme);
140
- console.log(chalk.green('āœ… Plugin scaffolded!\n'));
141
- console.log(chalk.gray('Next steps:'));
142
- console.log(chalk.gray(` cd ${name}`));
143
- console.log(chalk.gray(' npm install'));
144
- console.log(chalk.gray(' npm run validate'));
145
- console.log(chalk.gray(' npm run build\n'));
343
+ }
344
+ // ─── Helpers ───────────────────────────────────────────────────────────────────
345
+ function assertValue(value) {
346
+ if (p.isCancel(value)) {
347
+ p.cancel('Cancelled');
348
+ process.exit(0);
349
+ }
350
+ return value;
146
351
  }
147
352
  function toKebabCase(str) {
148
353
  return str