@sporesec/arcana 3.0.2 → 4.0.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.
- package/dist/cli.js +25 -298
- package/dist/command-defs.d.ts +28 -0
- package/dist/command-defs.js +414 -0
- package/dist/commands/audit.js +18 -4
- package/dist/commands/clean.d.ts +1 -0
- package/dist/commands/clean.js +80 -0
- package/dist/commands/compress.d.ts +5 -0
- package/dist/commands/compress.js +38 -0
- package/dist/commands/config.js +40 -26
- package/dist/commands/create.js +2 -0
- package/dist/commands/curate.d.ts +39 -0
- package/dist/commands/curate.js +222 -0
- package/dist/commands/diff.js +2 -0
- package/dist/commands/doctor.d.ts +1 -0
- package/dist/commands/doctor.js +61 -2
- package/dist/commands/import-cmd.js +5 -0
- package/dist/commands/index.d.ts +5 -0
- package/dist/commands/index.js +107 -0
- package/dist/commands/info.js +19 -8
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.js +71 -0
- package/dist/commands/install.js +2 -0
- package/dist/commands/list.js +8 -0
- package/dist/commands/load.d.ts +10 -0
- package/dist/commands/load.js +130 -0
- package/dist/commands/lock.js +35 -24
- package/dist/commands/mcp.d.ts +4 -0
- package/dist/commands/mcp.js +87 -0
- package/dist/commands/outdated.js +8 -6
- package/dist/commands/providers.js +29 -21
- package/dist/commands/recommend.js +11 -3
- package/dist/commands/remember.d.ts +12 -0
- package/dist/commands/remember.js +111 -0
- package/dist/commands/scan.d.ts +2 -0
- package/dist/commands/scan.js +46 -8
- package/dist/commands/search.js +6 -0
- package/dist/commands/uninstall.js +36 -0
- package/dist/commands/update.js +27 -0
- package/dist/commands/validate.js +8 -0
- package/dist/commands/verify.js +2 -0
- package/dist/compress/engine.d.ts +21 -0
- package/dist/compress/engine.js +106 -0
- package/dist/compress/index.d.ts +7 -0
- package/dist/compress/index.js +10 -0
- package/dist/compress/rules/generic.d.ts +1 -0
- package/dist/compress/rules/generic.js +9 -0
- package/dist/compress/rules/git.d.ts +1 -0
- package/dist/compress/rules/git.js +113 -0
- package/dist/compress/rules/npm.d.ts +1 -0
- package/dist/compress/rules/npm.js +99 -0
- package/dist/compress/rules/test-runner.d.ts +1 -0
- package/dist/compress/rules/test-runner.js +103 -0
- package/dist/compress/rules/tsc.d.ts +1 -0
- package/dist/compress/rules/tsc.js +39 -0
- package/dist/compress/tracker.d.ts +16 -0
- package/dist/compress/tracker.js +45 -0
- package/dist/constants.d.ts +12 -0
- package/dist/constants.js +29 -0
- package/dist/interactive/helpers.js +1 -0
- package/dist/interactive/menu.js +6 -1
- package/dist/interactive/optimize-flow.js +4 -4
- package/dist/mcp/install.d.ts +10 -0
- package/dist/mcp/install.js +109 -0
- package/dist/mcp/registry.d.ts +11 -0
- package/dist/mcp/registry.js +27 -0
- package/dist/providers/anthropics.d.ts +4 -0
- package/dist/providers/anthropics.js +10 -0
- package/dist/registry.js +4 -0
- package/dist/session/trim.d.ts +23 -0
- package/dist/session/trim.js +132 -0
- package/dist/utils/cache.js +2 -2
- package/dist/utils/config.d.ts +2 -0
- package/dist/utils/config.js +33 -14
- package/dist/utils/help.js +16 -8
- package/dist/utils/install-core.js +23 -1
- package/dist/utils/memory.d.ts +25 -0
- package/dist/utils/memory.js +103 -0
- package/dist/utils/project-context.js +4 -0
- package/dist/utils/scanner.d.ts +22 -1
- package/dist/utils/scanner.js +81 -9
- package/dist/utils/sessions.d.ts +2 -0
- package/dist/utils/sessions.js +36 -0
- package/dist/utils/ui.js +5 -0
- package/dist/utils/usage.d.ts +17 -0
- package/dist/utils/usage.js +83 -0
- package/package.json +42 -7
- package/dist/command-registry.d.ts +0 -10
- package/dist/command-registry.js +0 -65
- package/dist/commands/benchmark.d.ts +0 -4
- package/dist/commands/benchmark.js +0 -178
- package/dist/commands/compact.d.ts +0 -6
- package/dist/commands/compact.js +0 -239
- package/dist/commands/optimize.d.ts +0 -3
- package/dist/commands/optimize.js +0 -356
- package/dist/commands/profile.d.ts +0 -3
- package/dist/commands/profile.js +0 -274
- package/dist/commands/stats.d.ts +0 -3
- package/dist/commands/stats.js +0 -210
- package/dist/commands/team.d.ts +0 -3
- package/dist/commands/team.js +0 -291
- package/dist/interactive.d.ts +0 -1
- package/dist/interactive.js +0 -841
package/dist/cli.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
import { ui } from "./utils/ui.js";
|
|
4
|
+
import { COMMANDS } from "./command-defs.js";
|
|
4
5
|
const require = createRequire(import.meta.url);
|
|
5
6
|
const pkg = require("../package.json");
|
|
6
7
|
export function createCli() {
|
|
7
8
|
const program = new Command();
|
|
8
9
|
program.name("arcana").description("Universal AI development CLI").version(pkg.version);
|
|
9
|
-
//
|
|
10
|
+
// Custom help formatter for root command
|
|
10
11
|
const defaultFormatHelp = program.createHelp().formatHelp.bind(program.createHelp());
|
|
11
12
|
program.configureHelp({
|
|
12
13
|
formatHelp: (cmd, helper) => {
|
|
13
14
|
if (cmd.name() === "arcana") {
|
|
14
|
-
// Lazy import to avoid loading help.ts at startup for subcommands
|
|
15
15
|
const { buildCustomHelp } = require("./utils/help.js");
|
|
16
16
|
return buildCustomHelp(pkg.version);
|
|
17
17
|
}
|
|
@@ -29,11 +29,12 @@ export function createCli() {
|
|
|
29
29
|
console.error();
|
|
30
30
|
},
|
|
31
31
|
});
|
|
32
|
+
// Default action: interactive menu or help
|
|
32
33
|
program.argument("[command]", "", "").action(async (cmd) => {
|
|
33
34
|
if (cmd) {
|
|
34
35
|
console.error();
|
|
35
36
|
console.error(ui.error(" Error: ") + `unknown command '${cmd}'`);
|
|
36
|
-
const { findClosestCommand } = await import("./command-
|
|
37
|
+
const { findClosestCommand } = await import("./command-defs.js");
|
|
37
38
|
const match = findClosestCommand(cmd);
|
|
38
39
|
if (match) {
|
|
39
40
|
console.error(ui.dim(` Did you mean '${match}'?`));
|
|
@@ -43,7 +44,6 @@ export function createCli() {
|
|
|
43
44
|
process.exit(1);
|
|
44
45
|
}
|
|
45
46
|
const { isFirstRun, showWelcome, markInitialized, buildCustomHelp } = await import("./utils/help.js");
|
|
46
|
-
// Non-TTY (CI, pipes): print static help
|
|
47
47
|
if (!process.stdout.isTTY) {
|
|
48
48
|
console.log(buildCustomHelp(pkg.version));
|
|
49
49
|
return;
|
|
@@ -55,299 +55,26 @@ export function createCli() {
|
|
|
55
55
|
const { showInteractiveMenu } = await import("./interactive/index.js");
|
|
56
56
|
await showInteractiveMenu(pkg.version);
|
|
57
57
|
});
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
.description(
|
|
61
|
-
.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
.option("--no-check", "Skip conflict detection")
|
|
80
|
-
.addHelpText("after", "\nExamples:\n arcana install code-reviewer\n arcana install skill1 skill2 skill3\n arcana install --all --force")
|
|
81
|
-
.action(async (skills, opts) => {
|
|
82
|
-
const { installCommand } = await import("./commands/install.js");
|
|
83
|
-
return installCommand(skills, opts);
|
|
84
|
-
});
|
|
85
|
-
program
|
|
86
|
-
.command("info <skill>")
|
|
87
|
-
.description("Show skill details")
|
|
88
|
-
.option("-p, --provider <name>", "Provider to search")
|
|
89
|
-
.option("-j, --json", "Output as JSON")
|
|
90
|
-
.action(async (skill, opts) => {
|
|
91
|
-
const { infoCommand } = await import("./commands/info.js");
|
|
92
|
-
return infoCommand(skill, opts);
|
|
93
|
-
});
|
|
94
|
-
program
|
|
95
|
-
.command("search <query>")
|
|
96
|
-
.description("Search for skills across providers")
|
|
97
|
-
.option("-p, --provider <name>", "Limit search to provider")
|
|
98
|
-
.option("--no-cache", "Bypass skill cache")
|
|
99
|
-
.option("-t, --tag <tag>", "Filter by tech stack tag")
|
|
100
|
-
.option("-s, --smart", "Context-aware ranking (uses project detection)")
|
|
101
|
-
.option("-j, --json", "Output as JSON")
|
|
102
|
-
.addHelpText("after", '\nExamples:\n arcana search testing\n arcana search "code review"\n arcana search react --tag typescript\n arcana search api --smart')
|
|
103
|
-
.action(async (query, opts) => {
|
|
104
|
-
const { searchCommand } = await import("./commands/search.js");
|
|
105
|
-
return searchCommand(query, opts);
|
|
106
|
-
});
|
|
107
|
-
program
|
|
108
|
-
.command("providers")
|
|
109
|
-
.description("Manage skill providers")
|
|
110
|
-
.option("--add <owner/repo>", "Add a GitHub provider")
|
|
111
|
-
.option("--remove <name>", "Remove a provider")
|
|
112
|
-
.option("--json", "Output as JSON")
|
|
113
|
-
.action(async (opts) => {
|
|
114
|
-
const { providersCommand } = await import("./commands/providers.js");
|
|
115
|
-
return providersCommand(opts);
|
|
116
|
-
});
|
|
117
|
-
program
|
|
118
|
-
.command("create <name>")
|
|
119
|
-
.description("Create a new skill from template")
|
|
120
|
-
.action(async (name) => {
|
|
121
|
-
const { createCommand } = await import("./commands/create.js");
|
|
122
|
-
return createCommand(name);
|
|
123
|
-
});
|
|
124
|
-
program
|
|
125
|
-
.command("validate [skill]")
|
|
126
|
-
.description("Validate skill structure and metadata")
|
|
127
|
-
.option("-a, --all", "Validate all installed skills")
|
|
128
|
-
.option("-f, --fix", "Auto-fix common issues")
|
|
129
|
-
.option("-j, --json", "Output as JSON")
|
|
130
|
-
.option("--source <dir>", "Validate from source directory instead of install dir")
|
|
131
|
-
.option("--cross", "Run cross-validation (marketplace sync, companions, orphans)")
|
|
132
|
-
.option("--min-score <n>", "Minimum quality score (0-100), fail if any skill scores below", parseInt)
|
|
133
|
-
.action(async (skill, opts) => {
|
|
134
|
-
const { validateCommand } = await import("./commands/validate.js");
|
|
135
|
-
return validateCommand(skill, opts);
|
|
136
|
-
});
|
|
137
|
-
program
|
|
138
|
-
.command("update [skills...]")
|
|
139
|
-
.description("Update installed skills")
|
|
140
|
-
.option("-a, --all", "Update all installed skills")
|
|
141
|
-
.option("-p, --provider <name>", "Update from specific provider")
|
|
142
|
-
.option("-n, --dry-run", "Show what would be updated without updating")
|
|
143
|
-
.option("-j, --json", "Output as JSON")
|
|
144
|
-
.addHelpText("after", "\nExamples:\n arcana update code-reviewer\n arcana update skill1 skill2\n arcana update --all --dry-run")
|
|
145
|
-
.action(async (skills, opts) => {
|
|
146
|
-
const { updateCommand } = await import("./commands/update.js");
|
|
147
|
-
return updateCommand(skills, opts);
|
|
148
|
-
});
|
|
149
|
-
program
|
|
150
|
-
.command("uninstall [skills...]")
|
|
151
|
-
.description("Uninstall one or more skills")
|
|
152
|
-
.option("-y, --yes", "Skip confirmation prompt")
|
|
153
|
-
.option("-j, --json", "Output as JSON")
|
|
154
|
-
.addHelpText("after", "\nExamples:\n arcana uninstall code-reviewer\n arcana uninstall skill1 skill2 --yes")
|
|
155
|
-
.action(async (skills, opts) => {
|
|
156
|
-
const { uninstallCommand } = await import("./commands/uninstall.js");
|
|
157
|
-
return uninstallCommand(skills, opts);
|
|
158
|
-
});
|
|
159
|
-
program
|
|
160
|
-
.command("init")
|
|
161
|
-
.description("Initialize arcana in current project")
|
|
162
|
-
.option("-t, --tool <name>", "Target tool (claude, cursor, codex, gemini, antigravity, windsurf, aider, all)")
|
|
163
|
-
.action(async (opts) => {
|
|
164
|
-
const { initCommand } = await import("./commands/init.js");
|
|
165
|
-
return initCommand(opts);
|
|
166
|
-
});
|
|
167
|
-
program
|
|
168
|
-
.command("doctor")
|
|
169
|
-
.description("Check environment and diagnose issues")
|
|
170
|
-
.option("-j, --json", "Output as JSON")
|
|
171
|
-
.action(async (opts) => {
|
|
172
|
-
const { doctorCommand } = await import("./commands/doctor.js");
|
|
173
|
-
return doctorCommand(opts);
|
|
174
|
-
});
|
|
175
|
-
program
|
|
176
|
-
.command("clean")
|
|
177
|
-
.description("Remove orphaned data, old session logs, and temp files")
|
|
178
|
-
.option("-n, --dry-run", "Show what would be removed without deleting")
|
|
179
|
-
.option("--aggressive", "Delete all session logs regardless of age")
|
|
180
|
-
.option("--keep-days <days>", "Keep main session logs newer than N days (default: 30)", parseInt)
|
|
181
|
-
.option("--json", "Output as JSON")
|
|
182
|
-
.action(async (opts) => {
|
|
183
|
-
const { cleanCommand } = await import("./commands/clean.js");
|
|
184
|
-
return cleanCommand(opts);
|
|
185
|
-
});
|
|
186
|
-
program
|
|
187
|
-
.command("compact")
|
|
188
|
-
.description("Remove agent logs while preserving main session history")
|
|
189
|
-
.option("-n, --dry-run", "Show what would be removed without deleting")
|
|
190
|
-
.option("--prune", "Also prune oversized main sessions (>14d old AND >10 MB)")
|
|
191
|
-
.option("--prune-days <days>", "Override prune age threshold (default: 14)", parseInt)
|
|
192
|
-
.option("-j, --json", "Output as JSON")
|
|
193
|
-
.action(async (opts) => {
|
|
194
|
-
const { compactCommand } = await import("./commands/compact.js");
|
|
195
|
-
return compactCommand(opts);
|
|
196
|
-
});
|
|
197
|
-
program
|
|
198
|
-
.command("stats")
|
|
199
|
-
.description("Show session analytics and token usage")
|
|
200
|
-
.option("-j, --json", "Output as JSON")
|
|
201
|
-
.action(async (opts) => {
|
|
202
|
-
const { statsCommand } = await import("./commands/stats.js");
|
|
203
|
-
return statsCommand(opts);
|
|
204
|
-
});
|
|
205
|
-
program
|
|
206
|
-
.command("config [action] [value]")
|
|
207
|
-
.description("View or modify arcana configuration")
|
|
208
|
-
.option("-j, --json", "Output as JSON")
|
|
209
|
-
.addHelpText("after", "\nExamples:\n arcana config\n arcana config path\n arcana config defaultProvider arcana\n arcana config reset")
|
|
210
|
-
.action(async (action, value, opts) => {
|
|
211
|
-
const { configCommand } = await import("./commands/config.js");
|
|
212
|
-
return configCommand(action, value, opts);
|
|
213
|
-
});
|
|
214
|
-
program
|
|
215
|
-
.command("audit [skill]")
|
|
216
|
-
.description("Audit skill quality (code examples, BAD/GOOD pairs, structure)")
|
|
217
|
-
.option("-a, --all", "Audit all installed skills")
|
|
218
|
-
.option("-j, --json", "Output as JSON")
|
|
219
|
-
.option("--source <dir>", "Audit from source directory instead of install dir")
|
|
220
|
-
.action(async (skill, opts) => {
|
|
221
|
-
const { auditCommand } = await import("./commands/audit.js");
|
|
222
|
-
return auditCommand(skill, opts);
|
|
223
|
-
});
|
|
224
|
-
program
|
|
225
|
-
.command("scan [skill]")
|
|
226
|
-
.description("Scan skills for security threats (prompt injection, malware, credential theft)")
|
|
227
|
-
.option("-a, --all", "Scan all installed skills")
|
|
228
|
-
.option("-j, --json", "Output as JSON")
|
|
229
|
-
.addHelpText("after", "\nExamples:\n arcana scan code-reviewer\n arcana scan --all\n arcana scan --all --json")
|
|
230
|
-
.action(async (skill, opts) => {
|
|
231
|
-
const { scanCommand } = await import("./commands/scan.js");
|
|
232
|
-
return scanCommand(skill, opts);
|
|
233
|
-
});
|
|
234
|
-
program
|
|
235
|
-
.command("optimize")
|
|
236
|
-
.description("Analyze Claude Code setup and suggest token/performance improvements")
|
|
237
|
-
.option("-j, --json", "Output as JSON")
|
|
238
|
-
.action(async (opts) => {
|
|
239
|
-
const { optimizeCommand } = await import("./commands/optimize.js");
|
|
240
|
-
return optimizeCommand(opts);
|
|
241
|
-
});
|
|
242
|
-
// === Security ===
|
|
243
|
-
program
|
|
244
|
-
.command("verify [skill]")
|
|
245
|
-
.description("Verify installed skill integrity against lockfile")
|
|
246
|
-
.option("-a, --all", "Verify all installed skills")
|
|
247
|
-
.option("-j, --json", "Output as JSON")
|
|
248
|
-
.addHelpText("after", "\nExamples:\n arcana verify code-reviewer\n arcana verify --all\n arcana verify --all --json")
|
|
249
|
-
.action(async (skill, opts) => {
|
|
250
|
-
const { verifyCommand } = await import("./commands/verify.js");
|
|
251
|
-
return verifyCommand(skill, opts);
|
|
252
|
-
});
|
|
253
|
-
program
|
|
254
|
-
.command("lock")
|
|
255
|
-
.description("Generate or validate lockfile from installed skills")
|
|
256
|
-
.option("--ci", "Validate lockfile matches installed skills (CI mode)")
|
|
257
|
-
.option("-j, --json", "Output as JSON")
|
|
258
|
-
.addHelpText("after", "\nExamples:\n arcana lock\n arcana lock --ci\n arcana lock --json")
|
|
259
|
-
.action(async (opts) => {
|
|
260
|
-
const { lockCommand } = await import("./commands/lock.js");
|
|
261
|
-
return lockCommand(opts);
|
|
262
|
-
});
|
|
263
|
-
// === Performance & Inspection ===
|
|
264
|
-
program
|
|
265
|
-
.command("benchmark [skill]")
|
|
266
|
-
.description("Measure token cost of installed skills")
|
|
267
|
-
.option("-a, --all", "Benchmark all installed skills")
|
|
268
|
-
.option("-j, --json", "Output as JSON")
|
|
269
|
-
.addHelpText("after", "\nExamples:\n arcana benchmark code-reviewer\n arcana benchmark --all")
|
|
270
|
-
.action(async (skill, opts) => {
|
|
271
|
-
const { benchmarkCommand } = await import("./commands/benchmark.js");
|
|
272
|
-
return benchmarkCommand(skill, opts);
|
|
273
|
-
});
|
|
274
|
-
program
|
|
275
|
-
.command("diff <skill>")
|
|
276
|
-
.description("Show changes between installed and remote skill version")
|
|
277
|
-
.option("-p, --provider <name>", "Provider to compare against")
|
|
278
|
-
.option("-j, --json", "Output as JSON")
|
|
279
|
-
.addHelpText("after", "\nExamples:\n arcana diff code-reviewer\n arcana diff code-reviewer --json")
|
|
280
|
-
.action(async (skill, opts) => {
|
|
281
|
-
const { diffCommand } = await import("./commands/diff.js");
|
|
282
|
-
return diffCommand(skill, opts);
|
|
283
|
-
});
|
|
284
|
-
program
|
|
285
|
-
.command("outdated")
|
|
286
|
-
.description("List skills with newer versions available")
|
|
287
|
-
.option("-p, --provider <name>", "Check against specific provider")
|
|
288
|
-
.option("-j, --json", "Output as JSON")
|
|
289
|
-
.action(async (opts) => {
|
|
290
|
-
const { outdatedCommand } = await import("./commands/outdated.js");
|
|
291
|
-
return outdatedCommand(opts);
|
|
292
|
-
});
|
|
293
|
-
// === Workflow & Team ===
|
|
294
|
-
program
|
|
295
|
-
.command("profile [action] [name] [skills...]")
|
|
296
|
-
.description("Manage skill profiles (named sets of skills)")
|
|
297
|
-
.option("-j, --json", "Output as JSON")
|
|
298
|
-
.addHelpText("after", "\nActions:\n list List all profiles (default)\n create <name> Create a profile\n delete <name> Delete a profile\n show <name> Show skills in a profile\n apply <name> Install all skills from a profile\n\nExamples:\n arcana profile create security scan verify audit\n arcana profile apply security")
|
|
299
|
-
.action(async (action, name, skills, opts) => {
|
|
300
|
-
const { profileCommand } = await import("./commands/profile.js");
|
|
301
|
-
return profileCommand(action, name, skills, opts);
|
|
302
|
-
});
|
|
303
|
-
program
|
|
304
|
-
.command("team [action] [skill]")
|
|
305
|
-
.description("Manage shared team skill configuration")
|
|
306
|
-
.option("-j, --json", "Output as JSON")
|
|
307
|
-
.addHelpText("after", "\nActions:\n init Create .arcana/team.json\n sync Install skills from team config\n add <skill> Add a skill to team config\n remove <skill> Remove a skill from team config\n\nExamples:\n arcana team init\n arcana team add code-reviewer\n arcana team sync")
|
|
308
|
-
.action(async (action, skill, opts) => {
|
|
309
|
-
const { teamCommand } = await import("./commands/team.js");
|
|
310
|
-
return teamCommand(action, skill, opts);
|
|
311
|
-
});
|
|
312
|
-
program
|
|
313
|
-
.command("export")
|
|
314
|
-
.description("Export installed skills as a manifest")
|
|
315
|
-
.option("--sbom", "Export as SPDX-lite software bill of materials")
|
|
316
|
-
.option("-j, --json", "Output as JSON (default)")
|
|
317
|
-
.action(async (opts) => {
|
|
318
|
-
const { exportCommand } = await import("./commands/export-cmd.js");
|
|
319
|
-
return exportCommand(opts);
|
|
320
|
-
});
|
|
321
|
-
program
|
|
322
|
-
.command("import <file>")
|
|
323
|
-
.description("Import and install skills from a manifest file")
|
|
324
|
-
.option("-f, --force", "Reinstall even if already installed")
|
|
325
|
-
.option("-j, --json", "Output as JSON")
|
|
326
|
-
.addHelpText("after", "\nExamples:\n arcana import manifest.json\n arcana import manifest.json --force")
|
|
327
|
-
.action(async (file, opts) => {
|
|
328
|
-
const { importCommand } = await import("./commands/import-cmd.js");
|
|
329
|
-
return importCommand(file, opts);
|
|
330
|
-
});
|
|
331
|
-
program
|
|
332
|
-
.command("completions <shell>")
|
|
333
|
-
.description("Generate shell completion scripts")
|
|
334
|
-
.option("-j, --json", "Output as JSON")
|
|
335
|
-
.addHelpText("after", "\nSupported shells: bash, zsh, fish\n\nExamples:\n arcana completions bash >> ~/.bashrc\n arcana completions zsh >> ~/.zshrc\n arcana completions fish > ~/.config/fish/completions/arcana.fish")
|
|
336
|
-
.action(async (shell, opts) => {
|
|
337
|
-
const { completionsCommand } = await import("./commands/completions.js");
|
|
338
|
-
return completionsCommand(shell, opts);
|
|
339
|
-
});
|
|
340
|
-
// ── Smart Recommendations ──────────────────────────────────────
|
|
341
|
-
program
|
|
342
|
-
.command("recommend")
|
|
343
|
-
.description("Get smart skill recommendations for current project")
|
|
344
|
-
.option("-j, --json", "Output as JSON")
|
|
345
|
-
.option("-l, --limit <n>", "Max results per category", parseInt)
|
|
346
|
-
.option("-p, --provider <name>", "Limit to provider")
|
|
347
|
-
.addHelpText("after", "\nExamples:\n arcana recommend\n arcana recommend --json\n arcana recommend --limit 5")
|
|
348
|
-
.action(async (opts) => {
|
|
349
|
-
const { recommendCommand } = await import("./commands/recommend.js");
|
|
350
|
-
return recommendCommand(opts);
|
|
351
|
-
});
|
|
58
|
+
// Register all commands from definitions
|
|
59
|
+
for (const def of COMMANDS) {
|
|
60
|
+
const cmd = program.command(def.command).description(def.description);
|
|
61
|
+
if (def.allowUnknownOption)
|
|
62
|
+
cmd.allowUnknownOption(true);
|
|
63
|
+
for (const opt of def.options ?? []) {
|
|
64
|
+
if (opt.parseAs === "int") {
|
|
65
|
+
cmd.option(opt.flags, opt.description, parseInt);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
cmd.option(opt.flags, opt.description);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (def.helpText)
|
|
72
|
+
cmd.addHelpText("after", def.helpText);
|
|
73
|
+
cmd.action(async (...args) => {
|
|
74
|
+
const mod = (await import(def.module));
|
|
75
|
+
// Commander passes: [positionalArgs..., opts, Command] — strip Command
|
|
76
|
+
return mod[def.handler](...args.slice(0, -1));
|
|
77
|
+
});
|
|
78
|
+
}
|
|
352
79
|
return program;
|
|
353
80
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface CommandOption {
|
|
2
|
+
flags: string;
|
|
3
|
+
description: string;
|
|
4
|
+
parseAs?: "int";
|
|
5
|
+
}
|
|
6
|
+
export interface CommandDef {
|
|
7
|
+
/** Commander command string, e.g. "install [skills...]" or "info <skill>" */
|
|
8
|
+
command: string;
|
|
9
|
+
description: string;
|
|
10
|
+
group: string;
|
|
11
|
+
options?: CommandOption[];
|
|
12
|
+
helpText?: string;
|
|
13
|
+
/** Module path for lazy import (relative to src/) */
|
|
14
|
+
module: string;
|
|
15
|
+
/** Export name of the handler function */
|
|
16
|
+
handler: string;
|
|
17
|
+
allowUnknownOption?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare const COMMANDS: CommandDef[];
|
|
20
|
+
export declare function getCommandNames(): string[];
|
|
21
|
+
export declare function getGroupedCommands(): Record<string, {
|
|
22
|
+
name: string;
|
|
23
|
+
usage: string;
|
|
24
|
+
description: string;
|
|
25
|
+
group: string;
|
|
26
|
+
}[]>;
|
|
27
|
+
export declare function findClosestCommand(input: string): string | undefined;
|
|
28
|
+
export declare function getCliReference(): string;
|