@arthai/agents 1.0.3 → 1.0.5
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/README.md +22 -0
- package/VERSION +1 -1
- package/bin/cli.js +146 -21
- package/dist/plugins/canvas/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/compass/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/counsel/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/cruise/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/forge/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/prime/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/prism/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/scalpel/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/sentinel/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/shield/.claude-plugin/plugin.json +1 -1
- package/dist/plugins/spark/.claude-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/skills/publish/SKILL.md +3 -0
package/README.md
CHANGED
|
@@ -90,6 +90,28 @@ After installing, use skills in Claude Code:
|
|
|
90
90
|
/restart # restart local dev servers
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
+
## Uninstall
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npx @arthai/agents uninstall forge .
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Remove everything:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
rm -rf .claude/skills .claude/agents .claude/hooks
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Note: hooks merged into `.claude/settings.json` need to be removed manually.
|
|
106
|
+
|
|
107
|
+
## Troubleshooting
|
|
108
|
+
|
|
109
|
+
| Problem | Fix |
|
|
110
|
+
|---------|-----|
|
|
111
|
+
| Skills not showing | Restart Claude Code in the project |
|
|
112
|
+
| `/planning` says unknown skill | Verify files exist: `ls .claude/skills/planning/SKILL.md` |
|
|
113
|
+
| Install says "not found in dist/" | Update: `npx @arthai/agents@latest install forge .` |
|
|
114
|
+
|
|
93
115
|
## Also available as Claude Code plugin
|
|
94
116
|
|
|
95
117
|
```
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.5
|
package/bin/cli.js
CHANGED
|
@@ -26,6 +26,10 @@ switch (command) {
|
|
|
26
26
|
case 'info':
|
|
27
27
|
handleInfo(args[1]);
|
|
28
28
|
break;
|
|
29
|
+
case 'uninstall':
|
|
30
|
+
case 'remove':
|
|
31
|
+
handleUninstall(args.slice(1));
|
|
32
|
+
break;
|
|
29
33
|
case 'legacy':
|
|
30
34
|
handleLegacy(args.slice(1));
|
|
31
35
|
break;
|
|
@@ -94,7 +98,13 @@ function handleInstall(rawArgs) {
|
|
|
94
98
|
process.exit(1);
|
|
95
99
|
}
|
|
96
100
|
|
|
97
|
-
const
|
|
101
|
+
const claudeDir = path.join(targetDir, '.claude');
|
|
102
|
+
const skillsDir = path.join(claudeDir, 'skills');
|
|
103
|
+
const agentsDir = path.join(claudeDir, 'agents');
|
|
104
|
+
|
|
105
|
+
let totalCommands = 0;
|
|
106
|
+
let totalAgents = 0;
|
|
107
|
+
let totalHooks = 0;
|
|
98
108
|
|
|
99
109
|
for (const name of resolved) {
|
|
100
110
|
// Defense-in-depth: verify the resolved path stays inside PLUGINS_DIR
|
|
@@ -107,11 +117,13 @@ function handleInstall(rawArgs) {
|
|
|
107
117
|
console.error(`Plugin '${name}' not found in dist/plugins/. Run compiler.sh first.`);
|
|
108
118
|
process.exit(1);
|
|
109
119
|
}
|
|
110
|
-
|
|
111
|
-
|
|
120
|
+
const counts = installBundle(pluginDir, claudeDir, skillsDir, agentsDir, name);
|
|
121
|
+
totalCommands += counts.commands;
|
|
122
|
+
totalAgents += counts.agents;
|
|
123
|
+
totalHooks += counts.hooks;
|
|
112
124
|
}
|
|
113
125
|
|
|
114
|
-
console.log(`\nDone. ${resolved.length}
|
|
126
|
+
console.log(`\nDone. ${resolved.length} bundle(s) installed: ${totalCommands} skills, ${totalAgents} agents, ${totalHooks} hooks`);
|
|
115
127
|
}
|
|
116
128
|
|
|
117
129
|
// ── list ──────────────────────────────────────────────────────────────────────
|
|
@@ -199,6 +211,71 @@ function handleLegacy(legacyArgs) {
|
|
|
199
211
|
process.exit(result.status || 0);
|
|
200
212
|
}
|
|
201
213
|
|
|
214
|
+
// ── uninstall ────────────────────────────────────────────────────────────────
|
|
215
|
+
|
|
216
|
+
function handleUninstall(rawArgs) {
|
|
217
|
+
if (rawArgs.length === 0) {
|
|
218
|
+
console.error('Usage: arthai uninstall <bundle> [bundle...] [target-path]');
|
|
219
|
+
process.exit(1);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const targetDir = looksLikePath(rawArgs[rawArgs.length - 1])
|
|
223
|
+
? rawArgs.pop()
|
|
224
|
+
: process.cwd();
|
|
225
|
+
|
|
226
|
+
const bundleNames = rawArgs.filter(a => isValidBundleName(a));
|
|
227
|
+
if (bundleNames.length === 0) {
|
|
228
|
+
console.error('No valid bundle names provided.');
|
|
229
|
+
process.exit(1);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const claudeDir = path.join(targetDir, '.claude');
|
|
233
|
+
const skillsDir = path.join(claudeDir, 'skills');
|
|
234
|
+
const agentsDir = path.join(claudeDir, 'agents');
|
|
235
|
+
|
|
236
|
+
for (const name of bundleNames) {
|
|
237
|
+
const pluginDir = path.resolve(PLUGINS_DIR, name);
|
|
238
|
+
if (!fs.existsSync(pluginDir)) {
|
|
239
|
+
console.error(`Bundle '${name}' not found in dist/plugins/.`);
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
let removed = 0;
|
|
244
|
+
|
|
245
|
+
// Remove skills that came from this bundle's commands/
|
|
246
|
+
const commandsDir = path.join(pluginDir, 'commands');
|
|
247
|
+
if (fs.existsSync(commandsDir)) {
|
|
248
|
+
for (const file of fs.readdirSync(commandsDir)) {
|
|
249
|
+
if (!file.endsWith('.md')) continue;
|
|
250
|
+
const skillName = file.replace('.md', '');
|
|
251
|
+
const skillPath = path.join(skillsDir, skillName);
|
|
252
|
+
if (fs.existsSync(skillPath)) {
|
|
253
|
+
fs.rmSync(skillPath, { recursive: true });
|
|
254
|
+
removed++;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Remove agents that came from this bundle
|
|
260
|
+
const srcAgents = path.join(pluginDir, 'agents');
|
|
261
|
+
if (fs.existsSync(srcAgents)) {
|
|
262
|
+
for (const file of fs.readdirSync(srcAgents)) {
|
|
263
|
+
if (!file.endsWith('.md')) continue;
|
|
264
|
+
const agentPath = path.join(agentsDir, file);
|
|
265
|
+
if (fs.existsSync(agentPath)) {
|
|
266
|
+
fs.unlinkSync(agentPath);
|
|
267
|
+
removed++;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
console.log(` Removed ${name}: ${removed} files`);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
console.log('\nNote: hooks in .claude/settings.json were not removed — edit manually if needed.');
|
|
276
|
+
console.log('Done.');
|
|
277
|
+
}
|
|
278
|
+
|
|
202
279
|
// ── helpers ───────────────────────────────────────────────────────────────────
|
|
203
280
|
|
|
204
281
|
// Validate bundle names: only lowercase alphanumeric and hyphens, max 64 chars.
|
|
@@ -257,28 +334,76 @@ function resolveDependencies(names) {
|
|
|
257
334
|
return resolved;
|
|
258
335
|
}
|
|
259
336
|
|
|
260
|
-
function
|
|
261
|
-
const
|
|
337
|
+
function installBundle(pluginDir, claudeDir, skillsDir, agentsDir, name) {
|
|
338
|
+
const counts = { commands: 0, agents: 0, hooks: 0 };
|
|
339
|
+
|
|
340
|
+
// 1. Copy commands/ → .claude/skills/<name>/SKILL.md (each .md becomes a skill dir)
|
|
341
|
+
const commandsDir = path.join(pluginDir, 'commands');
|
|
342
|
+
if (fs.existsSync(commandsDir)) {
|
|
343
|
+
for (const file of fs.readdirSync(commandsDir)) {
|
|
344
|
+
if (!file.endsWith('.md')) continue;
|
|
345
|
+
const skillName = file.replace('.md', '');
|
|
346
|
+
const destDir = path.join(skillsDir, skillName);
|
|
347
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
348
|
+
fs.copyFileSync(path.join(commandsDir, file), path.join(destDir, 'SKILL.md'));
|
|
349
|
+
counts.commands++;
|
|
350
|
+
}
|
|
351
|
+
console.log(` ${name}: ${counts.commands} skills → ${skillsDir}`);
|
|
352
|
+
}
|
|
262
353
|
|
|
263
|
-
//
|
|
264
|
-
|
|
265
|
-
|
|
354
|
+
// 2. Copy agents/ → .claude/agents/
|
|
355
|
+
const srcAgents = path.join(pluginDir, 'agents');
|
|
356
|
+
if (fs.existsSync(srcAgents)) {
|
|
357
|
+
fs.mkdirSync(agentsDir, { recursive: true });
|
|
358
|
+
for (const file of fs.readdirSync(srcAgents)) {
|
|
359
|
+
if (!file.endsWith('.md')) continue;
|
|
360
|
+
fs.copyFileSync(path.join(srcAgents, file), path.join(agentsDir, file));
|
|
361
|
+
counts.agents++;
|
|
362
|
+
}
|
|
363
|
+
console.log(` ${name}: ${counts.agents} agents → ${agentsDir}`);
|
|
266
364
|
}
|
|
267
|
-
fs.mkdirSync(dest, { recursive: true });
|
|
268
365
|
|
|
269
|
-
//
|
|
270
|
-
|
|
366
|
+
// 3. Merge hooks into .claude/settings.json
|
|
367
|
+
const hooksJson = path.join(pluginDir, 'hooks', 'hooks.json');
|
|
368
|
+
if (fs.existsSync(hooksJson)) {
|
|
369
|
+
const pluginHooks = JSON.parse(fs.readFileSync(hooksJson, 'utf8'));
|
|
370
|
+
const settingsPath = path.join(claudeDir, 'settings.json');
|
|
371
|
+
let settings = {};
|
|
372
|
+
if (fs.existsSync(settingsPath)) {
|
|
373
|
+
try { settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); } catch (e) { settings = {}; }
|
|
374
|
+
}
|
|
375
|
+
if (!settings.hooks) settings.hooks = {};
|
|
376
|
+
|
|
377
|
+
// Copy hook scripts to .claude/hooks/
|
|
378
|
+
const hooksDir = path.join(claudeDir, 'hooks');
|
|
379
|
+
fs.mkdirSync(hooksDir, { recursive: true });
|
|
380
|
+
const srcHooksDir = path.join(pluginDir, 'hooks');
|
|
381
|
+
for (const file of fs.readdirSync(srcHooksDir)) {
|
|
382
|
+
if (!file.endsWith('.sh')) continue;
|
|
383
|
+
const dest = path.join(hooksDir, file);
|
|
384
|
+
fs.copyFileSync(path.join(srcHooksDir, file), dest);
|
|
385
|
+
fs.chmodSync(dest, 0o755);
|
|
386
|
+
}
|
|
271
387
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
388
|
+
// Merge hook entries (rewrite CLAUDE_PLUGIN_ROOT to project hooks path)
|
|
389
|
+
const hookData = pluginHooks.hooks || pluginHooks;
|
|
390
|
+
for (const [event, entries] of Object.entries(hookData)) {
|
|
391
|
+
if (!settings.hooks[event]) settings.hooks[event] = [];
|
|
392
|
+
for (const entry of entries) {
|
|
393
|
+
// Rewrite command paths from ${CLAUDE_PLUGIN_ROOT} to $CLAUDE_PROJECT_DIR/.claude
|
|
394
|
+
const rewritten = JSON.parse(
|
|
395
|
+
JSON.stringify(entry).replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g, '$CLAUDE_PROJECT_DIR/.claude')
|
|
396
|
+
);
|
|
397
|
+
settings.hooks[event].push(rewritten);
|
|
398
|
+
counts.hooks++;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
403
|
+
console.log(` ${name}: ${counts.hooks} hook entries merged into settings.json`);
|
|
278
404
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
405
|
+
|
|
406
|
+
return counts;
|
|
282
407
|
}
|
|
283
408
|
|
|
284
409
|
function copyDirRecursive(src, dest) {
|
package/package.json
CHANGED
package/skills/publish/SKILL.md
CHANGED
|
@@ -216,3 +216,6 @@ Tell the user to test in Claude Code:
|
|
|
216
216
|
| `marketplace.json not found` | File at repo root instead of `.claude-plugin/` | Move to `.claude-plugin/marketplace.json` |
|
|
217
217
|
| `E403 cannot publish over previous version` | VERSION not bumped | Derive from git tag, not VERSION file |
|
|
218
218
|
| `Plugin directory not found at path` | `source` path in marketplace.json is wrong | Must be `./plugins/<name>` relative to marketplace root |
|
|
219
|
+
| Version defaults to 1.0.0 | `actions/checkout` uses shallow clone, tags not fetched | Add `fetch-depth: 0` and `fetch-tags: true` to checkout step |
|
|
220
|
+
| Skills not showing in Claude Code | Skills in `skills/` not `commands/` | User-invocable skills must be in `commands/` as flat .md files |
|
|
221
|
+
| npx install doesn't register | Files in `.claude/plugins/` not discovered | npx should copy to `.claude/skills/` + `.claude/agents/`, not `.claude/plugins/` |
|