@sporesec/arcana 2.3.1 → 3.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 (241) hide show
  1. package/dist/cli.d.ts +0 -1
  2. package/dist/cli.js +140 -10
  3. package/dist/command-registry.d.ts +10 -0
  4. package/dist/command-registry.js +65 -0
  5. package/dist/commands/audit.d.ts +0 -1
  6. package/dist/commands/audit.js +16 -6
  7. package/dist/commands/benchmark.d.ts +4 -0
  8. package/dist/commands/benchmark.js +178 -0
  9. package/dist/commands/clean.d.ts +2 -1
  10. package/dist/commands/clean.js +198 -47
  11. package/dist/commands/compact.d.ts +6 -0
  12. package/dist/commands/compact.js +239 -0
  13. package/dist/commands/completions.d.ts +3 -0
  14. package/dist/commands/completions.js +104 -0
  15. package/dist/commands/config.d.ts +0 -1
  16. package/dist/commands/config.js +15 -6
  17. package/dist/commands/create.d.ts +0 -1
  18. package/dist/commands/create.js +1 -1
  19. package/dist/commands/diff.d.ts +4 -0
  20. package/dist/commands/diff.js +166 -0
  21. package/dist/commands/doctor.d.ts +0 -1
  22. package/dist/commands/doctor.js +153 -24
  23. package/dist/commands/export-cmd.d.ts +4 -0
  24. package/dist/commands/export-cmd.js +66 -0
  25. package/dist/commands/import-cmd.d.ts +4 -0
  26. package/dist/commands/import-cmd.js +131 -0
  27. package/dist/commands/info.d.ts +0 -1
  28. package/dist/commands/info.js +29 -4
  29. package/dist/commands/init.d.ts +0 -1
  30. package/dist/commands/init.js +156 -117
  31. package/dist/commands/install.d.ts +1 -1
  32. package/dist/commands/install.js +118 -205
  33. package/dist/commands/list.d.ts +0 -1
  34. package/dist/commands/list.js +12 -4
  35. package/dist/commands/lock.d.ts +4 -0
  36. package/dist/commands/lock.js +171 -0
  37. package/dist/commands/optimize.d.ts +3 -0
  38. package/dist/commands/optimize.js +356 -0
  39. package/dist/commands/outdated.d.ts +4 -0
  40. package/dist/commands/outdated.js +159 -0
  41. package/dist/commands/profile.d.ts +3 -0
  42. package/dist/commands/profile.js +274 -0
  43. package/dist/commands/providers.d.ts +0 -1
  44. package/dist/commands/providers.js +1 -4
  45. package/dist/commands/recommend.d.ts +5 -0
  46. package/dist/commands/recommend.js +96 -0
  47. package/dist/commands/scan.d.ts +0 -1
  48. package/dist/commands/scan.js +13 -7
  49. package/dist/commands/search.d.ts +2 -1
  50. package/dist/commands/search.js +32 -9
  51. package/dist/commands/stats.d.ts +0 -1
  52. package/dist/commands/stats.js +83 -16
  53. package/dist/commands/team.d.ts +3 -0
  54. package/dist/commands/team.js +291 -0
  55. package/dist/commands/uninstall.d.ts +0 -1
  56. package/dist/commands/uninstall.js +18 -4
  57. package/dist/commands/update.d.ts +0 -1
  58. package/dist/commands/update.js +155 -155
  59. package/dist/commands/validate.d.ts +0 -1
  60. package/dist/commands/validate.js +14 -6
  61. package/dist/commands/verify.d.ts +4 -0
  62. package/dist/commands/verify.js +116 -0
  63. package/dist/constants.d.ts +10 -0
  64. package/dist/constants.js +13 -0
  65. package/dist/index.d.ts +0 -1
  66. package/dist/index.js +0 -1
  67. package/dist/interactive/browse.d.ts +4 -0
  68. package/dist/interactive/browse.js +103 -0
  69. package/dist/interactive/categories.d.ts +4 -0
  70. package/dist/interactive/categories.js +87 -0
  71. package/dist/interactive/health.d.ts +1 -0
  72. package/dist/interactive/health.js +57 -0
  73. package/dist/interactive/helpers.d.ts +11 -0
  74. package/dist/interactive/helpers.js +66 -0
  75. package/dist/interactive/index.d.ts +1 -0
  76. package/dist/interactive/index.js +1 -0
  77. package/dist/interactive/manage.d.ts +2 -0
  78. package/dist/interactive/manage.js +187 -0
  79. package/dist/interactive/menu.d.ts +1 -0
  80. package/dist/interactive/menu.js +107 -0
  81. package/dist/interactive/search.d.ts +2 -0
  82. package/dist/interactive/search.js +66 -0
  83. package/dist/interactive/setup.d.ts +2 -0
  84. package/dist/interactive/setup.js +48 -0
  85. package/dist/interactive/skill-detail.d.ts +5 -0
  86. package/dist/interactive/skill-detail.js +126 -0
  87. package/dist/interactive.d.ts +0 -1
  88. package/dist/interactive.js +89 -66
  89. package/dist/providers/arcana.d.ts +0 -1
  90. package/dist/providers/arcana.js +0 -1
  91. package/dist/providers/base.d.ts +0 -1
  92. package/dist/providers/base.js +0 -1
  93. package/dist/providers/github.d.ts +0 -1
  94. package/dist/providers/github.js +8 -3
  95. package/dist/registry.d.ts +0 -1
  96. package/dist/registry.js +1 -4
  97. package/dist/types.d.ts +10 -1
  98. package/dist/types.js +0 -1
  99. package/dist/utils/atomic.d.ts +0 -1
  100. package/dist/utils/atomic.js +3 -2
  101. package/dist/utils/cache.d.ts +0 -1
  102. package/dist/utils/cache.js +3 -2
  103. package/dist/utils/config.d.ts +2 -1
  104. package/dist/utils/config.js +30 -5
  105. package/dist/utils/conflict-check.d.ts +8 -0
  106. package/dist/utils/conflict-check.js +72 -0
  107. package/dist/utils/errors.d.ts +0 -1
  108. package/dist/utils/errors.js +0 -1
  109. package/dist/utils/frontmatter.d.ts +0 -1
  110. package/dist/utils/frontmatter.js +37 -10
  111. package/dist/utils/fs.d.ts +19 -1
  112. package/dist/utils/fs.js +105 -8
  113. package/dist/utils/help.d.ts +0 -1
  114. package/dist/utils/help.js +15 -28
  115. package/dist/utils/history.d.ts +0 -1
  116. package/dist/utils/history.js +0 -1
  117. package/dist/utils/http.d.ts +0 -1
  118. package/dist/utils/http.js +14 -5
  119. package/dist/utils/install-core.d.ts +48 -0
  120. package/dist/utils/install-core.js +108 -0
  121. package/dist/utils/integrity.d.ts +17 -0
  122. package/dist/utils/integrity.js +84 -0
  123. package/dist/utils/parallel.d.ts +0 -1
  124. package/dist/utils/parallel.js +0 -1
  125. package/dist/utils/project-context.d.ts +19 -0
  126. package/dist/utils/project-context.js +283 -0
  127. package/dist/utils/scanner.d.ts +0 -1
  128. package/dist/utils/scanner.js +138 -10
  129. package/dist/utils/scoring.d.ts +10 -0
  130. package/dist/utils/scoring.js +84 -0
  131. package/dist/utils/ui.d.ts +0 -1
  132. package/dist/utils/ui.js +11 -4
  133. package/dist/utils/validate.d.ts +0 -1
  134. package/dist/utils/validate.js +4 -1
  135. package/package.json +19 -7
  136. package/dist/cli.d.ts.map +0 -1
  137. package/dist/cli.js.map +0 -1
  138. package/dist/commands/audit.d.ts.map +0 -1
  139. package/dist/commands/audit.js.map +0 -1
  140. package/dist/commands/audit.test.d.ts +0 -2
  141. package/dist/commands/audit.test.d.ts.map +0 -1
  142. package/dist/commands/audit.test.js +0 -217
  143. package/dist/commands/audit.test.js.map +0 -1
  144. package/dist/commands/clean.d.ts.map +0 -1
  145. package/dist/commands/clean.js.map +0 -1
  146. package/dist/commands/config.d.ts.map +0 -1
  147. package/dist/commands/config.js.map +0 -1
  148. package/dist/commands/create.d.ts.map +0 -1
  149. package/dist/commands/create.js.map +0 -1
  150. package/dist/commands/doctor.d.ts.map +0 -1
  151. package/dist/commands/doctor.js.map +0 -1
  152. package/dist/commands/info.d.ts.map +0 -1
  153. package/dist/commands/info.js.map +0 -1
  154. package/dist/commands/init.d.ts.map +0 -1
  155. package/dist/commands/init.js.map +0 -1
  156. package/dist/commands/install.d.ts.map +0 -1
  157. package/dist/commands/install.js.map +0 -1
  158. package/dist/commands/list.d.ts.map +0 -1
  159. package/dist/commands/list.js.map +0 -1
  160. package/dist/commands/providers.d.ts.map +0 -1
  161. package/dist/commands/providers.js.map +0 -1
  162. package/dist/commands/scan.d.ts.map +0 -1
  163. package/dist/commands/scan.js.map +0 -1
  164. package/dist/commands/search.d.ts.map +0 -1
  165. package/dist/commands/search.js.map +0 -1
  166. package/dist/commands/stats.d.ts.map +0 -1
  167. package/dist/commands/stats.js.map +0 -1
  168. package/dist/commands/uninstall.d.ts.map +0 -1
  169. package/dist/commands/uninstall.js.map +0 -1
  170. package/dist/commands/update.d.ts.map +0 -1
  171. package/dist/commands/update.js.map +0 -1
  172. package/dist/commands/validate.d.ts.map +0 -1
  173. package/dist/commands/validate.js.map +0 -1
  174. package/dist/index.d.ts.map +0 -1
  175. package/dist/index.js.map +0 -1
  176. package/dist/interactive.d.ts.map +0 -1
  177. package/dist/interactive.js.map +0 -1
  178. package/dist/providers/arcana.d.ts.map +0 -1
  179. package/dist/providers/arcana.js.map +0 -1
  180. package/dist/providers/base.d.ts.map +0 -1
  181. package/dist/providers/base.js.map +0 -1
  182. package/dist/providers/github.d.ts.map +0 -1
  183. package/dist/providers/github.js.map +0 -1
  184. package/dist/registry.d.ts.map +0 -1
  185. package/dist/registry.js.map +0 -1
  186. package/dist/types.d.ts.map +0 -1
  187. package/dist/types.js.map +0 -1
  188. package/dist/utils/atomic.d.ts.map +0 -1
  189. package/dist/utils/atomic.js.map +0 -1
  190. package/dist/utils/atomic.test.d.ts +0 -2
  191. package/dist/utils/atomic.test.d.ts.map +0 -1
  192. package/dist/utils/atomic.test.js +0 -31
  193. package/dist/utils/atomic.test.js.map +0 -1
  194. package/dist/utils/cache.d.ts.map +0 -1
  195. package/dist/utils/cache.js.map +0 -1
  196. package/dist/utils/config.d.ts.map +0 -1
  197. package/dist/utils/config.js.map +0 -1
  198. package/dist/utils/config.test.d.ts +0 -2
  199. package/dist/utils/config.test.d.ts.map +0 -1
  200. package/dist/utils/config.test.js +0 -38
  201. package/dist/utils/config.test.js.map +0 -1
  202. package/dist/utils/errors.d.ts.map +0 -1
  203. package/dist/utils/errors.js.map +0 -1
  204. package/dist/utils/frontmatter.d.ts.map +0 -1
  205. package/dist/utils/frontmatter.js.map +0 -1
  206. package/dist/utils/frontmatter.test.d.ts +0 -2
  207. package/dist/utils/frontmatter.test.d.ts.map +0 -1
  208. package/dist/utils/frontmatter.test.js +0 -152
  209. package/dist/utils/frontmatter.test.js.map +0 -1
  210. package/dist/utils/fs.d.ts.map +0 -1
  211. package/dist/utils/fs.js.map +0 -1
  212. package/dist/utils/fs.test.d.ts +0 -2
  213. package/dist/utils/fs.test.d.ts.map +0 -1
  214. package/dist/utils/fs.test.js +0 -145
  215. package/dist/utils/fs.test.js.map +0 -1
  216. package/dist/utils/help.d.ts.map +0 -1
  217. package/dist/utils/help.js.map +0 -1
  218. package/dist/utils/help.test.d.ts +0 -2
  219. package/dist/utils/help.test.d.ts.map +0 -1
  220. package/dist/utils/help.test.js +0 -66
  221. package/dist/utils/help.test.js.map +0 -1
  222. package/dist/utils/history.d.ts.map +0 -1
  223. package/dist/utils/history.js.map +0 -1
  224. package/dist/utils/http.d.ts.map +0 -1
  225. package/dist/utils/http.js.map +0 -1
  226. package/dist/utils/http.test.d.ts +0 -2
  227. package/dist/utils/http.test.d.ts.map +0 -1
  228. package/dist/utils/http.test.js +0 -55
  229. package/dist/utils/http.test.js.map +0 -1
  230. package/dist/utils/parallel.d.ts.map +0 -1
  231. package/dist/utils/parallel.js.map +0 -1
  232. package/dist/utils/scanner.d.ts.map +0 -1
  233. package/dist/utils/scanner.js.map +0 -1
  234. package/dist/utils/ui.d.ts.map +0 -1
  235. package/dist/utils/ui.js.map +0 -1
  236. package/dist/utils/ui.test.d.ts +0 -2
  237. package/dist/utils/ui.test.d.ts.map +0 -1
  238. package/dist/utils/ui.test.js +0 -31
  239. package/dist/utils/ui.test.js.map +0 -1
  240. package/dist/utils/validate.d.ts.map +0 -1
  241. package/dist/utils/validate.js.map +0 -1
package/dist/cli.d.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  import { Command } from "commander";
2
2
  export declare function createCli(): Command;
3
- //# sourceMappingURL=cli.d.ts.map
package/dist/cli.js CHANGED
@@ -5,10 +5,7 @@ const require = createRequire(import.meta.url);
5
5
  const pkg = require("../package.json");
6
6
  export function createCli() {
7
7
  const program = new Command();
8
- program
9
- .name("arcana")
10
- .description("Universal AI development CLI")
11
- .version(pkg.version);
8
+ program.name("arcana").description("Universal AI development CLI").version(pkg.version);
12
9
  // Store default help formatter before overriding
13
10
  const defaultFormatHelp = program.createHelp().formatHelp.bind(program.createHelp());
14
11
  program.configureHelp({
@@ -36,8 +33,8 @@ export function createCli() {
36
33
  if (cmd) {
37
34
  console.error();
38
35
  console.error(ui.error(" Error: ") + `unknown command '${cmd}'`);
39
- const commands = ["list", "install", "info", "search", "providers", "create", "validate", "update", "uninstall", "init", "doctor", "clean", "stats", "config", "audit", "scan"];
40
- const match = commands.find(c => c.startsWith(cmd.slice(0, 3)));
36
+ const { findClosestCommand } = await import("./command-registry.js");
37
+ const match = findClosestCommand(cmd);
41
38
  if (match) {
42
39
  console.error(ui.dim(` Did you mean '${match}'?`));
43
40
  }
@@ -55,7 +52,7 @@ export function createCli() {
55
52
  showWelcome(pkg.version);
56
53
  markInitialized();
57
54
  }
58
- const { showInteractiveMenu } = await import("./interactive.js");
55
+ const { showInteractiveMenu } = await import("./interactive/index.js");
59
56
  await showInteractiveMenu(pkg.version);
60
57
  });
61
58
  program
@@ -79,6 +76,7 @@ export function createCli() {
79
76
  .option("-f, --force", "Reinstall even if already installed")
80
77
  .option("--dry-run", "Show what would be installed without installing")
81
78
  .option("-j, --json", "Output as JSON")
79
+ .option("--no-check", "Skip conflict detection")
82
80
  .addHelpText("after", "\nExamples:\n arcana install code-reviewer\n arcana install skill1 skill2 skill3\n arcana install --all --force")
83
81
  .action(async (skills, opts) => {
84
82
  const { installCommand } = await import("./commands/install.js");
@@ -98,8 +96,10 @@ export function createCli() {
98
96
  .description("Search for skills across providers")
99
97
  .option("-p, --provider <name>", "Limit search to provider")
100
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
101
  .option("-j, --json", "Output as JSON")
102
- .addHelpText("after", "\nExamples:\n arcana search testing\n arcana search \"code review\"")
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
103
  .action(async (query, opts) => {
104
104
  const { searchCommand } = await import("./commands/search.js");
105
105
  return searchCommand(query, opts);
@@ -171,13 +171,26 @@ export function createCli() {
171
171
  });
172
172
  program
173
173
  .command("clean")
174
- .description("Remove orphaned data and temp files")
174
+ .description("Remove orphaned data, old session logs, and temp files")
175
175
  .option("-n, --dry-run", "Show what would be removed without deleting")
176
+ .option("--aggressive", "Delete all session logs regardless of age")
177
+ .option("--keep-days <days>", "Keep main session logs newer than N days (default: 30)", parseInt)
176
178
  .option("--json", "Output as JSON")
177
179
  .action(async (opts) => {
178
180
  const { cleanCommand } = await import("./commands/clean.js");
179
181
  return cleanCommand(opts);
180
182
  });
183
+ program
184
+ .command("compact")
185
+ .description("Remove agent logs while preserving main session history")
186
+ .option("-n, --dry-run", "Show what would be removed without deleting")
187
+ .option("--prune", "Also prune oversized main sessions (>14d old AND >10 MB)")
188
+ .option("--prune-days <days>", "Override prune age threshold (default: 14)", parseInt)
189
+ .option("-j, --json", "Output as JSON")
190
+ .action(async (opts) => {
191
+ const { compactCommand } = await import("./commands/compact.js");
192
+ return compactCommand(opts);
193
+ });
181
194
  program
182
195
  .command("stats")
183
196
  .description("Show session analytics and token usage")
@@ -214,6 +227,123 @@ export function createCli() {
214
227
  const { scanCommand } = await import("./commands/scan.js");
215
228
  return scanCommand(skill, opts);
216
229
  });
230
+ program
231
+ .command("optimize")
232
+ .description("Analyze Claude Code setup and suggest token/performance improvements")
233
+ .option("-j, --json", "Output as JSON")
234
+ .action(async (opts) => {
235
+ const { optimizeCommand } = await import("./commands/optimize.js");
236
+ return optimizeCommand(opts);
237
+ });
238
+ // === Security ===
239
+ program
240
+ .command("verify [skill]")
241
+ .description("Verify installed skill integrity against lockfile")
242
+ .option("-a, --all", "Verify all installed skills")
243
+ .option("-j, --json", "Output as JSON")
244
+ .addHelpText("after", "\nExamples:\n arcana verify code-reviewer\n arcana verify --all\n arcana verify --all --json")
245
+ .action(async (skill, opts) => {
246
+ const { verifyCommand } = await import("./commands/verify.js");
247
+ return verifyCommand(skill, opts);
248
+ });
249
+ program
250
+ .command("lock")
251
+ .description("Generate or validate lockfile from installed skills")
252
+ .option("--ci", "Validate lockfile matches installed skills (CI mode)")
253
+ .option("-j, --json", "Output as JSON")
254
+ .addHelpText("after", "\nExamples:\n arcana lock\n arcana lock --ci\n arcana lock --json")
255
+ .action(async (opts) => {
256
+ const { lockCommand } = await import("./commands/lock.js");
257
+ return lockCommand(opts);
258
+ });
259
+ // === Performance & Inspection ===
260
+ program
261
+ .command("benchmark [skill]")
262
+ .description("Measure token cost of installed skills")
263
+ .option("-a, --all", "Benchmark all installed skills")
264
+ .option("-j, --json", "Output as JSON")
265
+ .addHelpText("after", "\nExamples:\n arcana benchmark code-reviewer\n arcana benchmark --all")
266
+ .action(async (skill, opts) => {
267
+ const { benchmarkCommand } = await import("./commands/benchmark.js");
268
+ return benchmarkCommand(skill, opts);
269
+ });
270
+ program
271
+ .command("diff <skill>")
272
+ .description("Show changes between installed and remote skill version")
273
+ .option("-p, --provider <name>", "Provider to compare against")
274
+ .option("-j, --json", "Output as JSON")
275
+ .addHelpText("after", "\nExamples:\n arcana diff code-reviewer\n arcana diff code-reviewer --json")
276
+ .action(async (skill, opts) => {
277
+ const { diffCommand } = await import("./commands/diff.js");
278
+ return diffCommand(skill, opts);
279
+ });
280
+ program
281
+ .command("outdated")
282
+ .description("List skills with newer versions available")
283
+ .option("-p, --provider <name>", "Check against specific provider")
284
+ .option("-j, --json", "Output as JSON")
285
+ .action(async (opts) => {
286
+ const { outdatedCommand } = await import("./commands/outdated.js");
287
+ return outdatedCommand(opts);
288
+ });
289
+ // === Workflow & Team ===
290
+ program
291
+ .command("profile [action] [name] [skills...]")
292
+ .description("Manage skill profiles (named sets of skills)")
293
+ .option("-j, --json", "Output as JSON")
294
+ .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")
295
+ .action(async (action, name, skills, opts) => {
296
+ const { profileCommand } = await import("./commands/profile.js");
297
+ return profileCommand(action, name, skills, opts);
298
+ });
299
+ program
300
+ .command("team [action] [skill]")
301
+ .description("Manage shared team skill configuration")
302
+ .option("-j, --json", "Output as JSON")
303
+ .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")
304
+ .action(async (action, skill, opts) => {
305
+ const { teamCommand } = await import("./commands/team.js");
306
+ return teamCommand(action, skill, opts);
307
+ });
308
+ program
309
+ .command("export")
310
+ .description("Export installed skills as a manifest")
311
+ .option("--sbom", "Export as SPDX-lite software bill of materials")
312
+ .option("-j, --json", "Output as JSON (default)")
313
+ .action(async (opts) => {
314
+ const { exportCommand } = await import("./commands/export-cmd.js");
315
+ return exportCommand(opts);
316
+ });
317
+ program
318
+ .command("import <file>")
319
+ .description("Import and install skills from a manifest file")
320
+ .option("-f, --force", "Reinstall even if already installed")
321
+ .option("-j, --json", "Output as JSON")
322
+ .addHelpText("after", "\nExamples:\n arcana import manifest.json\n arcana import manifest.json --force")
323
+ .action(async (file, opts) => {
324
+ const { importCommand } = await import("./commands/import-cmd.js");
325
+ return importCommand(file, opts);
326
+ });
327
+ program
328
+ .command("completions <shell>")
329
+ .description("Generate shell completion scripts")
330
+ .option("-j, --json", "Output as JSON")
331
+ .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")
332
+ .action(async (shell, opts) => {
333
+ const { completionsCommand } = await import("./commands/completions.js");
334
+ return completionsCommand(shell, opts);
335
+ });
336
+ // ── Smart Recommendations ──────────────────────────────────────
337
+ program
338
+ .command("recommend")
339
+ .description("Get smart skill recommendations for current project")
340
+ .option("-j, --json", "Output as JSON")
341
+ .option("-l, --limit <n>", "Max results per category", parseInt)
342
+ .option("-p, --provider <name>", "Limit to provider")
343
+ .addHelpText("after", "\nExamples:\n arcana recommend\n arcana recommend --json\n arcana recommend --limit 5")
344
+ .action(async (opts) => {
345
+ const { recommendCommand } = await import("./commands/recommend.js");
346
+ return recommendCommand(opts);
347
+ });
217
348
  return program;
218
349
  }
219
- //# sourceMappingURL=cli.js.map
@@ -0,0 +1,10 @@
1
+ export interface CommandEntry {
2
+ name: string;
3
+ usage: string;
4
+ description: string;
5
+ group: string;
6
+ }
7
+ export declare function getCommandNames(): string[];
8
+ export declare function getGroupedCommands(): Record<string, CommandEntry[]>;
9
+ export declare function findClosestCommand(input: string): string | undefined;
10
+ export declare function getCliReference(): string;
@@ -0,0 +1,65 @@
1
+ const COMMANDS = [
2
+ // Getting Started
3
+ { name: "init", usage: "init", description: "Initialize arcana in current project", group: "GETTING STARTED" },
4
+ { name: "doctor", usage: "doctor", description: "Check environment and diagnose issues", group: "GETTING STARTED" },
5
+ // Skills
6
+ { name: "list", usage: "list", description: "List available skills", group: "SKILLS" },
7
+ { name: "search", usage: "search <query>", description: "Search across providers", group: "SKILLS" },
8
+ { name: "info", usage: "info <skill>", description: "Show skill details", group: "SKILLS" },
9
+ { name: "install", usage: "install [skills...]", description: "Install one or more skills", group: "SKILLS" },
10
+ { name: "update", usage: "update [skills...]", description: "Update installed skills", group: "SKILLS" },
11
+ { name: "uninstall", usage: "uninstall [skills...]", description: "Remove one or more skills", group: "SKILLS" },
12
+ { name: "recommend", usage: "recommend", description: "Smart skill recommendations", group: "SKILLS" },
13
+ // Development
14
+ { name: "create", usage: "create <name>", description: "Create a new skill from template", group: "DEVELOPMENT" },
15
+ { name: "validate", usage: "validate [skill]", description: "Validate skill structure", group: "DEVELOPMENT" },
16
+ { name: "audit", usage: "audit [skill]", description: "Audit skill quality", group: "DEVELOPMENT" },
17
+ // Security
18
+ { name: "scan", usage: "scan [skill]", description: "Scan skills for security threats", group: "SECURITY" },
19
+ { name: "verify", usage: "verify [skill]", description: "Verify skill integrity", group: "SECURITY" },
20
+ { name: "lock", usage: "lock", description: "Generate or validate lockfile", group: "SECURITY" },
21
+ // Inspection
22
+ { name: "benchmark", usage: "benchmark [skill]", description: "Measure token cost", group: "INSPECTION" },
23
+ { name: "diff", usage: "diff <skill>", description: "Show installed vs remote changes", group: "INSPECTION" },
24
+ { name: "outdated", usage: "outdated", description: "List skills with newer versions", group: "INSPECTION" },
25
+ // Configuration
26
+ {
27
+ name: "config",
28
+ usage: "config [key] [val]",
29
+ description: "View or modify configuration",
30
+ group: "CONFIGURATION",
31
+ },
32
+ { name: "providers", usage: "providers", description: "Manage skill providers", group: "CONFIGURATION" },
33
+ { name: "clean", usage: "clean", description: "Remove orphaned data", group: "CONFIGURATION" },
34
+ { name: "compact", usage: "compact", description: "Remove agent logs", group: "CONFIGURATION" },
35
+ { name: "stats", usage: "stats", description: "Show session analytics", group: "CONFIGURATION" },
36
+ {
37
+ name: "optimize",
38
+ usage: "optimize",
39
+ description: "Suggest token/performance improvements",
40
+ group: "CONFIGURATION",
41
+ },
42
+ // Team & Workflow
43
+ { name: "profile", usage: "profile [action]", description: "Manage skill profiles", group: "WORKFLOW" },
44
+ { name: "team", usage: "team [action]", description: "Shared team skill config", group: "WORKFLOW" },
45
+ { name: "export", usage: "export", description: "Export installed skills manifest", group: "WORKFLOW" },
46
+ { name: "import", usage: "import <file>", description: "Import skills from manifest", group: "WORKFLOW" },
47
+ { name: "completions", usage: "completions <shell>", description: "Generate shell completions", group: "WORKFLOW" },
48
+ ];
49
+ export function getCommandNames() {
50
+ return COMMANDS.map((c) => c.name);
51
+ }
52
+ export function getGroupedCommands() {
53
+ const groups = {};
54
+ for (const cmd of COMMANDS) {
55
+ (groups[cmd.group] ??= []).push(cmd);
56
+ }
57
+ return groups;
58
+ }
59
+ export function findClosestCommand(input) {
60
+ const prefix = input.slice(0, 3).toLowerCase();
61
+ return COMMANDS.find((c) => c.name.startsWith(prefix))?.name;
62
+ }
63
+ export function getCliReference() {
64
+ return COMMANDS.map((c) => `arcana ${c.usage}`).join("\n");
65
+ }
@@ -14,4 +14,3 @@ export declare function auditCommand(skill: string | undefined, opts: {
14
14
  json?: boolean;
15
15
  }): Promise<void>;
16
16
  export {};
17
- //# sourceMappingURL=audit.d.ts.map
@@ -53,7 +53,11 @@ export function auditSkill(skillDir, skillName) {
53
53
  // 6. Not a capabilities list (detects pattern of many "- " lines with no code between them)
54
54
  const bulletLines = (body.match(/^- /gm) || []).length;
55
55
  const isCapabilityList = bulletLines > 20 && codeBlockCount < 3;
56
- checks.push({ name: "Not a capabilities list", passed: !isCapabilityList, detail: isCapabilityList ? `${bulletLines} bullets, ${Math.floor(codeBlockCount)} code blocks` : undefined });
56
+ checks.push({
57
+ name: "Not a capabilities list",
58
+ passed: !isCapabilityList,
59
+ detail: isCapabilityList ? `${bulletLines} bullets, ${Math.floor(codeBlockCount)} code blocks` : undefined,
60
+ });
57
61
  if (!isCapabilityList)
58
62
  score += 15;
59
63
  // 7. Reasonable length (50-500 lines)
@@ -65,7 +69,11 @@ export function auditSkill(skillDir, skillName) {
65
69
  const hasScripts = existsSync(join(skillDir, "scripts"));
66
70
  const hasRefs = existsSync(join(skillDir, "references")) || existsSync(join(skillDir, "rules"));
67
71
  const hasExtras = hasScripts || hasRefs;
68
- checks.push({ name: "Has scripts/ or references/", passed: hasExtras, detail: hasExtras ? [hasScripts && "scripts", hasRefs && "references"].filter(Boolean).join(", ") : "none" });
72
+ checks.push({
73
+ name: "Has scripts/ or references/",
74
+ passed: hasExtras,
75
+ detail: hasExtras ? [hasScripts && "scripts", hasRefs && "references"].filter(Boolean).join(", ") : "none",
76
+ });
69
77
  if (hasExtras)
70
78
  score += 10;
71
79
  // Rating
@@ -129,9 +137,12 @@ export async function auditCommand(skill, opts) {
129
137
  const counts = { PERFECT: 0, STRONG: 0, ADEQUATE: 0, WEAK: 0 };
130
138
  for (const r of results) {
131
139
  counts[r.rating]++;
132
- const ratingColor = r.rating === "PERFECT" ? ui.success
133
- : r.rating === "STRONG" ? ui.cyan
134
- : r.rating === "ADEQUATE" ? ui.warn
140
+ const ratingColor = r.rating === "PERFECT"
141
+ ? ui.success
142
+ : r.rating === "STRONG"
143
+ ? ui.cyan
144
+ : r.rating === "ADEQUATE"
145
+ ? ui.warn
135
146
  : ui.error;
136
147
  console.log(` ${ratingColor(`[${r.rating}]`)} ${ui.bold(r.skill)} ${ui.dim(`(${r.score}/100)`)}`);
137
148
  for (const check of r.checks) {
@@ -154,4 +165,3 @@ export async function auditCommand(skill, opts) {
154
165
  console.log(` ${parts.join(ui.dim(" | "))}`);
155
166
  console.log();
156
167
  }
157
- //# sourceMappingURL=audit.js.map
@@ -0,0 +1,4 @@
1
+ export declare function benchmarkCommand(skill: string | undefined, opts: {
2
+ all?: boolean;
3
+ json?: boolean;
4
+ }): Promise<void>;
@@ -0,0 +1,178 @@
1
+ import { readdirSync, statSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { getInstallDir, readSkillMeta, getDirSize } from "../utils/fs.js";
4
+ import { CONTEXT_WINDOW_TOKENS } from "../constants.js";
5
+ function collectFiles(dir, prefix) {
6
+ const entries = [];
7
+ for (const entry of readdirSync(dir)) {
8
+ const fullPath = join(dir, entry);
9
+ const stat = statSync(fullPath);
10
+ if (stat.isDirectory()) {
11
+ entries.push(...collectFiles(fullPath, prefix ? `${prefix}/${entry}` : entry));
12
+ }
13
+ else {
14
+ entries.push({ path: prefix ? `${prefix}/${entry}` : entry, sizeBytes: stat.size });
15
+ }
16
+ }
17
+ return entries;
18
+ }
19
+ function benchmarkSkill(skillName) {
20
+ const installDir = getInstallDir();
21
+ const skillDir = join(installDir, skillName);
22
+ try {
23
+ statSync(skillDir);
24
+ }
25
+ catch {
26
+ return null;
27
+ }
28
+ const files = collectFiles(skillDir, "");
29
+ const totalBytes = getDirSize(skillDir);
30
+ const estimatedTokens = Math.round(totalBytes / 4);
31
+ const contextPercent = (estimatedTokens / CONTEXT_WINDOW_TOKENS) * 100;
32
+ return {
33
+ name: skillName,
34
+ fileCount: files.length,
35
+ totalBytes,
36
+ estimatedTokens,
37
+ contextPercent,
38
+ files,
39
+ };
40
+ }
41
+ function formatKB(bytes) {
42
+ return (bytes / 1024).toFixed(1) + " KB";
43
+ }
44
+ function formatTokens(tokens) {
45
+ if (tokens >= 1_000_000)
46
+ return (tokens / 1_000_000).toFixed(1) + "M";
47
+ if (tokens >= 1_000)
48
+ return (tokens / 1_000).toFixed(1) + "k";
49
+ return String(tokens);
50
+ }
51
+ export async function benchmarkCommand(skill, opts) {
52
+ const installDir = getInstallDir();
53
+ if (skill) {
54
+ return benchmarkSingle(skill, opts.json);
55
+ }
56
+ if (opts.all) {
57
+ return benchmarkAll(installDir, opts.json);
58
+ }
59
+ console.error("Specify a skill name or use --all to benchmark all installed skills.");
60
+ console.error("Usage: arcana benchmark <skill-name>");
61
+ console.error(" arcana benchmark --all");
62
+ process.exit(1);
63
+ }
64
+ function benchmarkSingle(skillName, json) {
65
+ const result = benchmarkSkill(skillName);
66
+ if (!result) {
67
+ if (json) {
68
+ console.log(JSON.stringify({ error: `Skill "${skillName}" not found` }));
69
+ }
70
+ else {
71
+ console.error(`Skill "${skillName}" is not installed.`);
72
+ }
73
+ process.exit(1);
74
+ }
75
+ const meta = readSkillMeta(skillName);
76
+ if (json) {
77
+ console.log(JSON.stringify({
78
+ name: result.name,
79
+ version: meta?.version ?? "unknown",
80
+ fileCount: result.fileCount,
81
+ totalBytes: result.totalBytes,
82
+ estimatedTokens: result.estimatedTokens,
83
+ contextPercent: Math.round(result.contextPercent * 100) / 100,
84
+ files: result.files.map((f) => ({
85
+ path: f.path,
86
+ sizeBytes: f.sizeBytes,
87
+ estimatedTokens: Math.round(f.sizeBytes / 4),
88
+ })),
89
+ }));
90
+ return;
91
+ }
92
+ console.log();
93
+ console.log(` Benchmark: ${skillName}${meta?.version ? ` v${meta.version}` : ""}`);
94
+ console.log();
95
+ console.log(` Files: ${result.fileCount}`);
96
+ console.log(` Total size: ${formatKB(result.totalBytes)}`);
97
+ console.log(` Est. tokens: ${formatTokens(result.estimatedTokens)}`);
98
+ console.log(` Context usage: ${result.contextPercent.toFixed(2)}% of ${(CONTEXT_WINDOW_TOKENS / 1000).toFixed(0)}k window`);
99
+ console.log();
100
+ console.log(" File breakdown:");
101
+ console.log();
102
+ const sorted = [...result.files].sort((a, b) => b.sizeBytes - a.sizeBytes);
103
+ const maxPathLen = Math.min(Math.max(...sorted.map((f) => f.path.length)), 50);
104
+ for (const file of sorted) {
105
+ const displayPath = file.path.length > 50 ? file.path.slice(0, 47) + "..." : file.path;
106
+ const tokens = Math.round(file.sizeBytes / 4);
107
+ console.log(` ${displayPath.padEnd(maxPathLen + 2)} ${formatKB(file.sizeBytes).padStart(10)} ~${formatTokens(tokens).padStart(6)} tokens`);
108
+ }
109
+ console.log();
110
+ }
111
+ function benchmarkAll(installDir, json) {
112
+ let dirs;
113
+ try {
114
+ dirs = readdirSync(installDir).filter((d) => {
115
+ try {
116
+ return statSync(join(installDir, d)).isDirectory();
117
+ }
118
+ catch {
119
+ return false;
120
+ }
121
+ });
122
+ }
123
+ catch {
124
+ dirs = [];
125
+ }
126
+ if (dirs.length === 0) {
127
+ if (json) {
128
+ console.log(JSON.stringify({ skills: [], totalTokens: 0, totalBytes: 0 }));
129
+ }
130
+ else {
131
+ console.log("No skills installed.");
132
+ }
133
+ return;
134
+ }
135
+ const results = [];
136
+ for (const dir of dirs) {
137
+ const result = benchmarkSkill(dir);
138
+ if (result)
139
+ results.push(result);
140
+ }
141
+ results.sort((a, b) => b.estimatedTokens - a.estimatedTokens);
142
+ const totalBytes = results.reduce((sum, r) => sum + r.totalBytes, 0);
143
+ const totalTokens = results.reduce((sum, r) => sum + r.estimatedTokens, 0);
144
+ const totalContextPercent = (totalTokens / CONTEXT_WINDOW_TOKENS) * 100;
145
+ if (json) {
146
+ console.log(JSON.stringify({
147
+ skills: results.map((r) => ({
148
+ name: r.name,
149
+ fileCount: r.fileCount,
150
+ totalBytes: r.totalBytes,
151
+ estimatedTokens: r.estimatedTokens,
152
+ contextPercent: Math.round(r.contextPercent * 100) / 100,
153
+ })),
154
+ totalBytes,
155
+ totalTokens,
156
+ totalContextPercent: Math.round(totalContextPercent * 100) / 100,
157
+ }));
158
+ return;
159
+ }
160
+ console.log();
161
+ console.log(` Benchmark: ${results.length} installed skill(s)`);
162
+ console.log();
163
+ const maxNameLen = Math.min(Math.max(...results.map((r) => r.name.length)), 30);
164
+ console.log(` ${"Skill".padEnd(maxNameLen + 2)} ${"Files".padStart(5)} ${"Size".padStart(10)} ${"Tokens".padStart(8)} ${"Context %".padStart(9)}`);
165
+ console.log(` ${"-".repeat(maxNameLen + 2)} ${"-".repeat(5)} ${"-".repeat(10)} ${"-".repeat(8)} ${"-".repeat(9)}`);
166
+ for (const r of results) {
167
+ const displayName = r.name.length > 30 ? r.name.slice(0, 27) + "..." : r.name;
168
+ console.log(` ${displayName.padEnd(maxNameLen + 2)} ${String(r.fileCount).padStart(5)} ${formatKB(r.totalBytes).padStart(10)} ${formatTokens(r.estimatedTokens).padStart(8)} ${r.contextPercent.toFixed(2).padStart(8)}%`);
169
+ }
170
+ console.log(` ${"-".repeat(maxNameLen + 2)} ${"-".repeat(5)} ${"-".repeat(10)} ${"-".repeat(8)} ${"-".repeat(9)}`);
171
+ console.log(` ${"TOTAL".padEnd(maxNameLen + 2)} ${String(results.reduce((s, r) => s + r.fileCount, 0)).padStart(5)} ${formatKB(totalBytes).padStart(10)} ${formatTokens(totalTokens).padStart(8)} ${totalContextPercent.toFixed(2).padStart(8)}%`);
172
+ console.log();
173
+ if (totalContextPercent > 50) {
174
+ console.log(` Warning: installed skills consume ${totalContextPercent.toFixed(1)}% of context window.`);
175
+ console.log(" Consider removing unused skills with: arcana uninstall <skill>");
176
+ console.log();
177
+ }
178
+ }
@@ -1,5 +1,6 @@
1
1
  export declare function cleanCommand(opts: {
2
2
  dryRun?: boolean;
3
+ aggressive?: boolean;
4
+ keepDays?: number;
3
5
  json?: boolean;
4
6
  }): Promise<void>;
5
- //# sourceMappingURL=clean.d.ts.map