@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.
Files changed (102) hide show
  1. package/dist/cli.js +25 -298
  2. package/dist/command-defs.d.ts +28 -0
  3. package/dist/command-defs.js +414 -0
  4. package/dist/commands/audit.js +18 -4
  5. package/dist/commands/clean.d.ts +1 -0
  6. package/dist/commands/clean.js +80 -0
  7. package/dist/commands/compress.d.ts +5 -0
  8. package/dist/commands/compress.js +38 -0
  9. package/dist/commands/config.js +40 -26
  10. package/dist/commands/create.js +2 -0
  11. package/dist/commands/curate.d.ts +39 -0
  12. package/dist/commands/curate.js +222 -0
  13. package/dist/commands/diff.js +2 -0
  14. package/dist/commands/doctor.d.ts +1 -0
  15. package/dist/commands/doctor.js +61 -2
  16. package/dist/commands/import-cmd.js +5 -0
  17. package/dist/commands/index.d.ts +5 -0
  18. package/dist/commands/index.js +107 -0
  19. package/dist/commands/info.js +19 -8
  20. package/dist/commands/init.d.ts +3 -0
  21. package/dist/commands/init.js +71 -0
  22. package/dist/commands/install.js +2 -0
  23. package/dist/commands/list.js +8 -0
  24. package/dist/commands/load.d.ts +10 -0
  25. package/dist/commands/load.js +130 -0
  26. package/dist/commands/lock.js +35 -24
  27. package/dist/commands/mcp.d.ts +4 -0
  28. package/dist/commands/mcp.js +87 -0
  29. package/dist/commands/outdated.js +8 -6
  30. package/dist/commands/providers.js +29 -21
  31. package/dist/commands/recommend.js +11 -3
  32. package/dist/commands/remember.d.ts +12 -0
  33. package/dist/commands/remember.js +111 -0
  34. package/dist/commands/scan.d.ts +2 -0
  35. package/dist/commands/scan.js +46 -8
  36. package/dist/commands/search.js +6 -0
  37. package/dist/commands/uninstall.js +36 -0
  38. package/dist/commands/update.js +27 -0
  39. package/dist/commands/validate.js +8 -0
  40. package/dist/commands/verify.js +2 -0
  41. package/dist/compress/engine.d.ts +21 -0
  42. package/dist/compress/engine.js +106 -0
  43. package/dist/compress/index.d.ts +7 -0
  44. package/dist/compress/index.js +10 -0
  45. package/dist/compress/rules/generic.d.ts +1 -0
  46. package/dist/compress/rules/generic.js +9 -0
  47. package/dist/compress/rules/git.d.ts +1 -0
  48. package/dist/compress/rules/git.js +113 -0
  49. package/dist/compress/rules/npm.d.ts +1 -0
  50. package/dist/compress/rules/npm.js +99 -0
  51. package/dist/compress/rules/test-runner.d.ts +1 -0
  52. package/dist/compress/rules/test-runner.js +103 -0
  53. package/dist/compress/rules/tsc.d.ts +1 -0
  54. package/dist/compress/rules/tsc.js +39 -0
  55. package/dist/compress/tracker.d.ts +16 -0
  56. package/dist/compress/tracker.js +45 -0
  57. package/dist/constants.d.ts +12 -0
  58. package/dist/constants.js +29 -0
  59. package/dist/interactive/helpers.js +1 -0
  60. package/dist/interactive/menu.js +6 -1
  61. package/dist/interactive/optimize-flow.js +4 -4
  62. package/dist/mcp/install.d.ts +10 -0
  63. package/dist/mcp/install.js +109 -0
  64. package/dist/mcp/registry.d.ts +11 -0
  65. package/dist/mcp/registry.js +27 -0
  66. package/dist/providers/anthropics.d.ts +4 -0
  67. package/dist/providers/anthropics.js +10 -0
  68. package/dist/registry.js +4 -0
  69. package/dist/session/trim.d.ts +23 -0
  70. package/dist/session/trim.js +132 -0
  71. package/dist/utils/cache.js +2 -2
  72. package/dist/utils/config.d.ts +2 -0
  73. package/dist/utils/config.js +33 -14
  74. package/dist/utils/help.js +16 -8
  75. package/dist/utils/install-core.js +23 -1
  76. package/dist/utils/memory.d.ts +25 -0
  77. package/dist/utils/memory.js +103 -0
  78. package/dist/utils/project-context.js +4 -0
  79. package/dist/utils/scanner.d.ts +22 -1
  80. package/dist/utils/scanner.js +81 -9
  81. package/dist/utils/sessions.d.ts +2 -0
  82. package/dist/utils/sessions.js +36 -0
  83. package/dist/utils/ui.js +5 -0
  84. package/dist/utils/usage.d.ts +17 -0
  85. package/dist/utils/usage.js +83 -0
  86. package/package.json +42 -7
  87. package/dist/command-registry.d.ts +0 -10
  88. package/dist/command-registry.js +0 -65
  89. package/dist/commands/benchmark.d.ts +0 -4
  90. package/dist/commands/benchmark.js +0 -178
  91. package/dist/commands/compact.d.ts +0 -6
  92. package/dist/commands/compact.js +0 -239
  93. package/dist/commands/optimize.d.ts +0 -3
  94. package/dist/commands/optimize.js +0 -356
  95. package/dist/commands/profile.d.ts +0 -3
  96. package/dist/commands/profile.js +0 -274
  97. package/dist/commands/stats.d.ts +0 -3
  98. package/dist/commands/stats.js +0 -210
  99. package/dist/commands/team.d.ts +0 -3
  100. package/dist/commands/team.js +0 -291
  101. package/dist/interactive.d.ts +0 -1
  102. 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
- // Store default help formatter before overriding
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-registry.js");
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
- program
59
- .command("list")
60
- .description("List available skills")
61
- .option("-p, --provider <name>", "Provider to list from")
62
- .option("-a, --all", "List from all providers")
63
- .option("--installed", "Show only installed skills")
64
- .option("--no-cache", "Bypass skill cache")
65
- .option("-j, --json", "Output as JSON")
66
- .addHelpText("after", "\nExamples:\n arcana list\n arcana list --installed\n arcana list --all --no-cache")
67
- .action(async (opts) => {
68
- const { listCommand } = await import("./commands/list.js");
69
- return listCommand(opts);
70
- });
71
- program
72
- .command("install [skills...]")
73
- .description("Install one or more skills")
74
- .option("-p, --provider <name>", "Provider to install from")
75
- .option("-a, --all", "Install all skills")
76
- .option("-f, --force", "Reinstall even if already installed")
77
- .option("--dry-run", "Show what would be installed without installing")
78
- .option("-j, --json", "Output as JSON")
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;