@sporesec/arcana 2.4.0 → 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 (245) hide show
  1. package/dist/cli.d.ts +0 -1
  2. package/dist/cli.js +120 -9
  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 +0 -1
  10. package/dist/commands/clean.js +19 -8
  11. package/dist/commands/compact.d.ts +2 -1
  12. package/dist/commands/compact.js +74 -14
  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 +64 -23
  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 +26 -33
  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 +0 -1
  38. package/dist/commands/optimize.js +111 -20
  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 +24 -20
  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 +0 -1
  112. package/dist/utils/fs.js +30 -11
  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 +74 -62
  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/compact.d.ts.map +0 -1
  147. package/dist/commands/compact.js.map +0 -1
  148. package/dist/commands/config.d.ts.map +0 -1
  149. package/dist/commands/config.js.map +0 -1
  150. package/dist/commands/create.d.ts.map +0 -1
  151. package/dist/commands/create.js.map +0 -1
  152. package/dist/commands/doctor.d.ts.map +0 -1
  153. package/dist/commands/doctor.js.map +0 -1
  154. package/dist/commands/info.d.ts.map +0 -1
  155. package/dist/commands/info.js.map +0 -1
  156. package/dist/commands/init.d.ts.map +0 -1
  157. package/dist/commands/init.js.map +0 -1
  158. package/dist/commands/install.d.ts.map +0 -1
  159. package/dist/commands/install.js.map +0 -1
  160. package/dist/commands/list.d.ts.map +0 -1
  161. package/dist/commands/list.js.map +0 -1
  162. package/dist/commands/optimize.d.ts.map +0 -1
  163. package/dist/commands/optimize.js.map +0 -1
  164. package/dist/commands/providers.d.ts.map +0 -1
  165. package/dist/commands/providers.js.map +0 -1
  166. package/dist/commands/scan.d.ts.map +0 -1
  167. package/dist/commands/scan.js.map +0 -1
  168. package/dist/commands/search.d.ts.map +0 -1
  169. package/dist/commands/search.js.map +0 -1
  170. package/dist/commands/stats.d.ts.map +0 -1
  171. package/dist/commands/stats.js.map +0 -1
  172. package/dist/commands/uninstall.d.ts.map +0 -1
  173. package/dist/commands/uninstall.js.map +0 -1
  174. package/dist/commands/update.d.ts.map +0 -1
  175. package/dist/commands/update.js.map +0 -1
  176. package/dist/commands/validate.d.ts.map +0 -1
  177. package/dist/commands/validate.js.map +0 -1
  178. package/dist/index.d.ts.map +0 -1
  179. package/dist/index.js.map +0 -1
  180. package/dist/interactive.d.ts.map +0 -1
  181. package/dist/interactive.js.map +0 -1
  182. package/dist/providers/arcana.d.ts.map +0 -1
  183. package/dist/providers/arcana.js.map +0 -1
  184. package/dist/providers/base.d.ts.map +0 -1
  185. package/dist/providers/base.js.map +0 -1
  186. package/dist/providers/github.d.ts.map +0 -1
  187. package/dist/providers/github.js.map +0 -1
  188. package/dist/registry.d.ts.map +0 -1
  189. package/dist/registry.js.map +0 -1
  190. package/dist/types.d.ts.map +0 -1
  191. package/dist/types.js.map +0 -1
  192. package/dist/utils/atomic.d.ts.map +0 -1
  193. package/dist/utils/atomic.js.map +0 -1
  194. package/dist/utils/atomic.test.d.ts +0 -2
  195. package/dist/utils/atomic.test.d.ts.map +0 -1
  196. package/dist/utils/atomic.test.js +0 -31
  197. package/dist/utils/atomic.test.js.map +0 -1
  198. package/dist/utils/cache.d.ts.map +0 -1
  199. package/dist/utils/cache.js.map +0 -1
  200. package/dist/utils/config.d.ts.map +0 -1
  201. package/dist/utils/config.js.map +0 -1
  202. package/dist/utils/config.test.d.ts +0 -2
  203. package/dist/utils/config.test.d.ts.map +0 -1
  204. package/dist/utils/config.test.js +0 -38
  205. package/dist/utils/config.test.js.map +0 -1
  206. package/dist/utils/errors.d.ts.map +0 -1
  207. package/dist/utils/errors.js.map +0 -1
  208. package/dist/utils/frontmatter.d.ts.map +0 -1
  209. package/dist/utils/frontmatter.js.map +0 -1
  210. package/dist/utils/frontmatter.test.d.ts +0 -2
  211. package/dist/utils/frontmatter.test.d.ts.map +0 -1
  212. package/dist/utils/frontmatter.test.js +0 -152
  213. package/dist/utils/frontmatter.test.js.map +0 -1
  214. package/dist/utils/fs.d.ts.map +0 -1
  215. package/dist/utils/fs.js.map +0 -1
  216. package/dist/utils/fs.test.d.ts +0 -2
  217. package/dist/utils/fs.test.d.ts.map +0 -1
  218. package/dist/utils/fs.test.js +0 -145
  219. package/dist/utils/fs.test.js.map +0 -1
  220. package/dist/utils/help.d.ts.map +0 -1
  221. package/dist/utils/help.js.map +0 -1
  222. package/dist/utils/help.test.d.ts +0 -2
  223. package/dist/utils/help.test.d.ts.map +0 -1
  224. package/dist/utils/help.test.js +0 -66
  225. package/dist/utils/help.test.js.map +0 -1
  226. package/dist/utils/history.d.ts.map +0 -1
  227. package/dist/utils/history.js.map +0 -1
  228. package/dist/utils/http.d.ts.map +0 -1
  229. package/dist/utils/http.js.map +0 -1
  230. package/dist/utils/http.test.d.ts +0 -2
  231. package/dist/utils/http.test.d.ts.map +0 -1
  232. package/dist/utils/http.test.js +0 -55
  233. package/dist/utils/http.test.js.map +0 -1
  234. package/dist/utils/parallel.d.ts.map +0 -1
  235. package/dist/utils/parallel.js.map +0 -1
  236. package/dist/utils/scanner.d.ts.map +0 -1
  237. package/dist/utils/scanner.js.map +0 -1
  238. package/dist/utils/ui.d.ts.map +0 -1
  239. package/dist/utils/ui.js.map +0 -1
  240. package/dist/utils/ui.test.d.ts +0 -2
  241. package/dist/utils/ui.test.d.ts.map +0 -1
  242. package/dist/utils/ui.test.js +0 -31
  243. package/dist/utils/ui.test.js.map +0 -1
  244. package/dist/utils/validate.d.ts.map +0 -1
  245. package/dist/utils/validate.js.map +0 -1
@@ -0,0 +1,66 @@
1
+ import * as p from "@clack/prompts";
2
+ import chalk from "chalk";
3
+ import { isSkillInstalled } from "../utils/fs.js";
4
+ import { getProvider } from "../registry.js";
5
+ import { ui } from "../utils/ui.js";
6
+ import { appendHistory } from "../utils/history.js";
7
+ import { handleCancel, truncate } from "./helpers.js";
8
+ import { skillDetailFlow } from "./skill-detail.js";
9
+ export async function searchFlow(allSkills, providerName) {
10
+ while (true) {
11
+ const query = await p.text({
12
+ message: "Search for:",
13
+ placeholder: "e.g. testing, review, golang",
14
+ validate: (v) => (!v || v.trim().length === 0 ? "Enter a search term" : undefined),
15
+ });
16
+ handleCancel(query);
17
+ const provider = getProvider(providerName);
18
+ const s = p.spinner();
19
+ s.start(`Searching "${query}"...`);
20
+ let results;
21
+ try {
22
+ results = await provider.search(query);
23
+ }
24
+ catch (err) {
25
+ s.stop("Search failed");
26
+ if (err instanceof Error)
27
+ p.log.error(ui.dim(err.message));
28
+ return;
29
+ }
30
+ s.stop(`${results.length} result${results.length !== 1 ? "s" : ""}`);
31
+ appendHistory("search", query);
32
+ if (results.length === 0) {
33
+ p.log.info("No skills matched. Try a different query.");
34
+ const again = await p.confirm({ message: "Search again?" });
35
+ handleCancel(again);
36
+ if (!again)
37
+ return;
38
+ continue;
39
+ }
40
+ const nav = await searchResultsPicker(results, allSkills, providerName);
41
+ if (nav === "done")
42
+ return;
43
+ // "search" continues the loop
44
+ }
45
+ }
46
+ async function searchResultsPicker(results, allSkills, providerName) {
47
+ while (true) {
48
+ const options = results.map((skill) => ({
49
+ value: skill.name,
50
+ label: `${skill.name}${isSkillInstalled(skill.name) ? chalk.green(" \u2713") : ""}`,
51
+ hint: truncate(skill.description, 50),
52
+ }));
53
+ const picked = await p.select({
54
+ message: "Pick a skill for details",
55
+ options: [...options, { value: "__search", label: "Search again" }, { value: "__back", label: "Back" }],
56
+ });
57
+ handleCancel(picked);
58
+ if (picked === "__search")
59
+ return "search";
60
+ if (picked === "__back")
61
+ return "done";
62
+ const result = await skillDetailFlow(picked, allSkills, providerName);
63
+ if (result === "menu")
64
+ return "done";
65
+ }
66
+ }
@@ -0,0 +1,2 @@
1
+ import type { SkillInfo } from "../types.js";
2
+ export declare function quickSetup(allSkills: SkillInfo[], providerName: string): Promise<void>;
@@ -0,0 +1,48 @@
1
+ import { existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import * as p from "@clack/prompts";
4
+ import chalk from "chalk";
5
+ import { isSkillInstalled } from "../utils/fs.js";
6
+ import { handleCancel } from "./helpers.js";
7
+ import { doBatchInstall } from "./browse.js";
8
+ export async function quickSetup(allSkills, providerName) {
9
+ const { detectProject, SKILL_SUGGESTIONS, SKILL_SUGGESTIONS_DEFAULT } = await import("../commands/init.js");
10
+ const proj = detectProject(process.cwd());
11
+ p.log.step(`Detected: ${chalk.cyan(proj.name)} (${proj.type})`);
12
+ const suggestions = SKILL_SUGGESTIONS[proj.type] ?? SKILL_SUGGESTIONS_DEFAULT;
13
+ const availableNames = new Set(allSkills.map((s) => s.name));
14
+ const validSuggestions = suggestions.filter((s) => availableNames.has(s));
15
+ if (validSuggestions.length === 0) {
16
+ p.log.info("No specific recommendations for this project type.");
17
+ return;
18
+ }
19
+ const notInstalled = validSuggestions.filter((s) => !isSkillInstalled(s));
20
+ if (notInstalled.length === 0) {
21
+ p.log.success("All recommended skills are already installed.");
22
+ return;
23
+ }
24
+ const options = validSuggestions.map((name) => {
25
+ const installed = isSkillInstalled(name);
26
+ return {
27
+ value: name,
28
+ label: `${name}${installed ? chalk.green(" \u2713 installed") : ""}`,
29
+ hint: installed ? "already installed" : "not installed",
30
+ };
31
+ });
32
+ const selected = await p.multiselect({
33
+ message: `Recommended skills for ${proj.type}`,
34
+ options,
35
+ required: false,
36
+ });
37
+ handleCancel(selected);
38
+ const toInstall = selected.filter((s) => !isSkillInstalled(s));
39
+ if (toInstall.length > 0) {
40
+ await doBatchInstall(toInstall, providerName);
41
+ }
42
+ else if (selected.length > 0) {
43
+ p.log.info("All selected skills are already installed.");
44
+ }
45
+ if (!existsSync(join(process.cwd(), "CLAUDE.md"))) {
46
+ p.log.info(`Tip: Run ${chalk.cyan("arcana init")} to create project config files.`);
47
+ }
48
+ }
@@ -0,0 +1,5 @@
1
+ import type { SkillInfo } from "../types.js";
2
+ declare function doInstall(skillName: string, providerName: string): Promise<boolean>;
3
+ declare function doUninstall(skillName: string): boolean;
4
+ export declare function skillDetailFlow(skillName: string, allSkills: SkillInfo[], providerName: string): Promise<"back" | "menu">;
5
+ export { doInstall, doUninstall };
@@ -0,0 +1,126 @@
1
+ import { existsSync, rmSync } from "node:fs";
2
+ import * as p from "@clack/prompts";
3
+ import chalk from "chalk";
4
+ import { isSkillInstalled, readSkillMeta, getSkillDir } from "../utils/fs.js";
5
+ import { getProvider } from "../registry.js";
6
+ import { appendHistory } from "../utils/history.js";
7
+ import { installOneCore } from "../utils/install-core.js";
8
+ import { removeSymlinksFor } from "../commands/uninstall.js";
9
+ import { ui } from "../utils/ui.js";
10
+ import { handleCancel } from "./helpers.js";
11
+ import { getCategoryFor, getRelatedSkills } from "./categories.js";
12
+ async function doInstall(skillName, providerName) {
13
+ const provider = getProvider(providerName);
14
+ const s = p.spinner();
15
+ s.start(`Installing ${chalk.bold(skillName)}...`);
16
+ try {
17
+ const result = await installOneCore(skillName, provider, {});
18
+ if (!result.success) {
19
+ s.stop(`Failed to install ${skillName}`);
20
+ if (result.error)
21
+ p.log.error(ui.dim(result.error));
22
+ return false;
23
+ }
24
+ s.stop(`Installed ${chalk.bold(skillName)} (${result.files?.length ?? 0} files)`);
25
+ appendHistory("install", skillName);
26
+ return true;
27
+ }
28
+ catch (err) {
29
+ s.stop(`Failed to install ${skillName}`);
30
+ if (err instanceof Error)
31
+ p.log.error(ui.dim(err.message));
32
+ return false;
33
+ }
34
+ }
35
+ function doUninstall(skillName) {
36
+ const skillDir = getSkillDir(skillName);
37
+ if (!existsSync(skillDir))
38
+ return false;
39
+ try {
40
+ rmSync(skillDir, { recursive: true, force: true });
41
+ removeSymlinksFor(skillName);
42
+ appendHistory("uninstall", skillName);
43
+ return true;
44
+ }
45
+ catch {
46
+ return false;
47
+ }
48
+ }
49
+ export async function skillDetailFlow(skillName, allSkills, providerName) {
50
+ const info = allSkills.find((s) => s.name === skillName);
51
+ const installed = isSkillInstalled(skillName);
52
+ const meta = installed ? readSkillMeta(skillName) : null;
53
+ // Build info block
54
+ const lines = [];
55
+ lines.push(`${chalk.bold(skillName)} ${info ? `v${info.version}` : ""}`);
56
+ if (info?.description)
57
+ lines.push(info.description);
58
+ lines.push("");
59
+ if (info?.verified)
60
+ lines.push(`Trust: ${chalk.green("Verified")} (official)`);
61
+ else
62
+ lines.push(`Trust: Community`);
63
+ if (info?.author)
64
+ lines.push(`Author: ${info.author}`);
65
+ if (info?.tags && info.tags.length > 0)
66
+ lines.push(`Tags: ${info.tags.join(", ")}`);
67
+ const category = getCategoryFor(skillName);
68
+ if (category)
69
+ lines.push(`Category: ${category}`);
70
+ if (info?.source)
71
+ lines.push(`Source: ${info.source}`);
72
+ if (info?.companions && info.companions.length > 0) {
73
+ lines.push(`Companions: ${info.companions.join(", ")}`);
74
+ }
75
+ if (info?.conflicts && info.conflicts.length > 0) {
76
+ lines.push(`${chalk.red("Conflicts:")} ${info.conflicts.join(", ")}`);
77
+ }
78
+ if (installed && meta) {
79
+ const date = meta.installedAt ? new Date(meta.installedAt).toLocaleDateString() : "";
80
+ lines.push(`Status: ${chalk.green("installed")} (v${meta.version}${date ? `, ${date}` : ""})`);
81
+ }
82
+ else {
83
+ lines.push(`Status: ${chalk.dim("not installed")}`);
84
+ }
85
+ const related = getRelatedSkills(skillName);
86
+ if (related.length > 0) {
87
+ lines.push(`Related: ${related.join(", ")}`);
88
+ }
89
+ p.note(lines.join("\n"), skillName);
90
+ // Action menu
91
+ const actions = [];
92
+ if (installed) {
93
+ actions.push({ value: "reinstall", label: "Reinstall (overwrite)" });
94
+ actions.push({ value: "uninstall", label: "Uninstall (remove files)" });
95
+ }
96
+ else {
97
+ actions.push({ value: "install", label: "Install this skill" });
98
+ }
99
+ actions.push({ value: "back", label: "Back" });
100
+ const action = await p.select({ message: "Action", options: actions });
101
+ handleCancel(action);
102
+ switch (action) {
103
+ case "install":
104
+ case "reinstall": {
105
+ await doInstall(skillName, providerName);
106
+ return "back";
107
+ }
108
+ case "uninstall": {
109
+ const ok = await p.confirm({ message: `Uninstall ${chalk.bold(skillName)}?` });
110
+ handleCancel(ok);
111
+ if (ok) {
112
+ const success = doUninstall(skillName);
113
+ if (success) {
114
+ p.log.success(`Removed ${chalk.bold(skillName)}`);
115
+ }
116
+ else {
117
+ p.log.error(`Failed to remove ${skillName}`);
118
+ }
119
+ }
120
+ return "back";
121
+ }
122
+ default:
123
+ return "back";
124
+ }
125
+ }
126
+ export { doInstall, doUninstall };
@@ -1,2 +1 @@
1
1
  export declare function showInteractiveMenu(version: string): Promise<void>;
2
- //# sourceMappingURL=interactive.d.ts.map
@@ -18,39 +18,74 @@ const AMBER = chalk.hex("#d4943a");
18
18
  // ---------------------------------------------------------------------------
19
19
  const SKILL_CATEGORIES = {
20
20
  "Code Quality & Review": [
21
- "code-reviewer", "codebase-dissection", "testing-strategy",
22
- "refactoring-patterns", "git-workflow", "pre-production-review",
23
- "frontend-code-review", "dependency-audit", "performance-optimization",
21
+ "code-reviewer",
22
+ "codebase-dissection",
23
+ "testing-strategy",
24
+ "refactoring-patterns",
25
+ "git-workflow",
26
+ "pre-production-review",
27
+ "frontend-code-review",
28
+ "dependency-audit",
29
+ "performance-optimization",
24
30
  ],
25
31
  "Security & Infrastructure": [
26
- "security-review", "local-security", "container-security",
27
- "docker-kubernetes", "ci-cd-pipelines", "ci-cd-automation",
28
- "monitoring-observability", "incident-response",
32
+ "security-review",
33
+ "local-security",
34
+ "container-security",
35
+ "docker-kubernetes",
36
+ "ci-cd-pipelines",
37
+ "ci-cd-automation",
38
+ "monitoring-observability",
39
+ "incident-response",
29
40
  ],
30
41
  "Languages & Frameworks": [
31
- "golang-pro", "go-linter-configuration", "typescript", "typescript-advanced",
32
- "python-best-practices", "rust-best-practices", "frontend-design",
33
- "fullstack-developer", "remotion-best-practices", "npm-package",
42
+ "golang-pro",
43
+ "go-linter-configuration",
44
+ "typescript",
45
+ "typescript-advanced",
46
+ "python-best-practices",
47
+ "rust-best-practices",
48
+ "frontend-design",
49
+ "fullstack-developer",
50
+ "remotion-best-practices",
51
+ "npm-package",
34
52
  ],
35
53
  "API, Data & Docs": [
36
- "api-design", "api-testing", "programming-architecture",
37
- "database-design", "env-config", "cost-optimization",
38
- "docx", "xlsx", "doc-generation", "update-docs",
54
+ "api-design",
55
+ "api-testing",
56
+ "programming-architecture",
57
+ "database-design",
58
+ "env-config",
59
+ "cost-optimization",
60
+ "docx",
61
+ "xlsx",
62
+ "doc-generation",
63
+ "update-docs",
39
64
  ],
40
65
  "Game Design & Production": [
41
- "game-design-theory", "game-engines", "game-programming-languages",
42
- "gameplay-mechanics", "level-design", "game-tools-workflows",
43
- "game-servers", "networking-servers", "synchronization-algorithms",
44
- "monetization-systems", "publishing-platforms", "daw-music",
66
+ "game-design-theory",
67
+ "game-engines",
68
+ "game-programming-languages",
69
+ "gameplay-mechanics",
70
+ "level-design",
71
+ "game-tools-workflows",
72
+ "game-servers",
73
+ "networking-servers",
74
+ "synchronization-algorithms",
75
+ "monetization-systems",
76
+ "publishing-platforms",
77
+ "daw-music",
45
78
  ],
46
79
  "Graphics, Audio & Performance": [
47
- "graphics-rendering", "shader-techniques", "particle-systems",
48
- "audio-systems", "asset-optimization", "optimization-performance",
80
+ "graphics-rendering",
81
+ "shader-techniques",
82
+ "particle-systems",
83
+ "audio-systems",
84
+ "asset-optimization",
85
+ "optimization-performance",
49
86
  "memory-management",
50
87
  ],
51
- "Skill Development": [
52
- "skill-creation-guide", "skill-creator", "find-skills", "project-migration",
53
- ],
88
+ "Skill Development": ["skill-creation-guide", "skill-creator", "find-skills", "project-migration"],
54
89
  };
55
90
  // ---------------------------------------------------------------------------
56
91
  // Helpers
@@ -68,7 +103,7 @@ function countInstalled() {
68
103
  const dir = getInstallDir();
69
104
  if (!existsSync(dir))
70
105
  return 0;
71
- return readdirSync(dir).filter(d => {
106
+ return readdirSync(dir).filter((d) => {
72
107
  try {
73
108
  return statSync(join(dir, d)).isDirectory();
74
109
  }
@@ -91,16 +126,14 @@ function getRelatedSkills(skillName, limit = 3) {
91
126
  const cat = getCategoryFor(skillName);
92
127
  if (!cat)
93
128
  return [];
94
- return (SKILL_CATEGORIES[cat] ?? [])
95
- .filter(s => s !== skillName && !isSkillInstalled(s))
96
- .slice(0, limit);
129
+ return (SKILL_CATEGORIES[cat] ?? []).filter((s) => s !== skillName && !isSkillInstalled(s)).slice(0, limit);
97
130
  }
98
131
  function getInstalledNames() {
99
132
  const dir = getInstallDir();
100
133
  if (!existsSync(dir))
101
134
  return [];
102
135
  return readdirSync(dir)
103
- .filter(d => {
136
+ .filter((d) => {
104
137
  try {
105
138
  return statSync(join(dir, d)).isDirectory();
106
139
  }
@@ -110,7 +143,7 @@ function getInstalledNames() {
110
143
  })
111
144
  .sort();
112
145
  }
113
- function buildMenuOptions(installedCount, availableCount) {
146
+ function buildMenuOptions(installedCount, _availableCount) {
114
147
  const isNew = installedCount === 0;
115
148
  const options = [];
116
149
  if (isNew) {
@@ -211,7 +244,7 @@ function doUninstall(skillName) {
211
244
  // Skill Detail View (central action point)
212
245
  // ---------------------------------------------------------------------------
213
246
  async function skillDetailFlow(skillName, allSkills, providerName) {
214
- const info = allSkills.find(s => s.name === skillName);
247
+ const info = allSkills.find((s) => s.name === skillName);
215
248
  const installed = isSkillInstalled(skillName);
216
249
  const meta = installed ? readSkillMeta(skillName) : null;
217
250
  // Build info block
@@ -277,11 +310,11 @@ async function skillDetailFlow(skillName, allSkills, providerName) {
277
310
  // Browse by Category
278
311
  // ---------------------------------------------------------------------------
279
312
  async function browseByCategory(allSkills, providerName) {
280
- const availableNames = new Set(allSkills.map(s => s.name));
313
+ const availableNames = new Set(allSkills.map((s) => s.name));
281
314
  while (true) {
282
315
  const categoryOptions = Object.entries(SKILL_CATEGORIES).map(([name, skills]) => {
283
- const valid = skills.filter(s => availableNames.has(s));
284
- const installedCount = valid.filter(s => isSkillInstalled(s)).length;
316
+ const valid = skills.filter((s) => availableNames.has(s));
317
+ const installedCount = valid.filter((s) => isSkillInstalled(s)).length;
285
318
  return {
286
319
  value: name,
287
320
  label: name,
@@ -290,10 +323,7 @@ async function browseByCategory(allSkills, providerName) {
290
323
  });
291
324
  const category = await p.select({
292
325
  message: "Browse by category",
293
- options: [
294
- ...categoryOptions,
295
- { value: "__back", label: "Back" },
296
- ],
326
+ options: [...categoryOptions, { value: "__back", label: "Back" }],
297
327
  });
298
328
  handleCancel(category);
299
329
  if (category === "__back")
@@ -302,15 +332,15 @@ async function browseByCategory(allSkills, providerName) {
302
332
  }
303
333
  }
304
334
  async function categorySkillList(categoryName, skillNames, allSkills, providerName) {
305
- const availableNames = new Set(allSkills.map(s => s.name));
306
- const validSkills = skillNames.filter(s => availableNames.has(s));
335
+ const availableNames = new Set(allSkills.map((s) => s.name));
336
+ const validSkills = skillNames.filter((s) => availableNames.has(s));
307
337
  if (validSkills.length === 0) {
308
338
  p.log.warn("No skills found in this category.");
309
339
  return;
310
340
  }
311
341
  while (true) {
312
- const options = validSkills.map(name => {
313
- const info = allSkills.find(s => s.name === name);
342
+ const options = validSkills.map((name) => {
343
+ const info = allSkills.find((s) => s.name === name);
314
344
  const installed = isSkillInstalled(name);
315
345
  return {
316
346
  value: name,
@@ -318,7 +348,7 @@ async function categorySkillList(categoryName, skillNames, allSkills, providerNa
318
348
  hint: truncate(info?.description ?? "", 50),
319
349
  };
320
350
  });
321
- const notInstalled = validSkills.filter(s => !isSkillInstalled(s));
351
+ const notInstalled = validSkills.filter((s) => !isSkillInstalled(s));
322
352
  const extraOptions = [];
323
353
  if (notInstalled.length > 0) {
324
354
  extraOptions.push({
@@ -386,18 +416,14 @@ async function searchFlow(allSkills, providerName) {
386
416
  }
387
417
  async function searchResultsPicker(results, allSkills, providerName) {
388
418
  while (true) {
389
- const options = results.map(skill => ({
419
+ const options = results.map((skill) => ({
390
420
  value: skill.name,
391
421
  label: `${skill.name}${isSkillInstalled(skill.name) ? chalk.green(" \u2713") : ""}`,
392
422
  hint: truncate(skill.description, 50),
393
423
  }));
394
424
  const picked = await p.select({
395
425
  message: "Pick a skill for details",
396
- options: [
397
- ...options,
398
- { value: "__search", label: "Search again" },
399
- { value: "__back", label: "Back" },
400
- ],
426
+ options: [...options, { value: "__search", label: "Search again" }, { value: "__back", label: "Back" }],
401
427
  });
402
428
  handleCancel(picked);
403
429
  if (picked === "__search")
@@ -417,7 +443,7 @@ async function quickSetup(allSkills, providerName) {
417
443
  const proj = detectProject(process.cwd());
418
444
  p.log.step(`Detected: ${chalk.cyan(proj.name)} (${proj.type})`);
419
445
  const suggestions = SKILL_SUGGESTIONS[proj.type] ?? SKILL_SUGGESTIONS_DEFAULT;
420
- const availableNames = new Set(allSkills.map(s => s.name));
446
+ const availableNames = new Set(allSkills.map((s) => s.name));
421
447
  const validSuggestions = suggestions.filter((s) => availableNames.has(s));
422
448
  if (validSuggestions.length === 0) {
423
449
  p.log.info("No specific recommendations for this project type.");
@@ -467,17 +493,17 @@ async function manageInstalled(allSkills, providerName) {
467
493
  const groups = [];
468
494
  const categorized = new Set();
469
495
  for (const [cat, catSkills] of Object.entries(SKILL_CATEGORIES)) {
470
- const installed = catSkills.filter(s => names.includes(s));
496
+ const installed = catSkills.filter((s) => names.includes(s));
471
497
  if (installed.length > 0) {
472
498
  groups.push({ cat, skills: installed });
473
- installed.forEach(s => categorized.add(s));
499
+ installed.forEach((s) => categorized.add(s));
474
500
  }
475
501
  }
476
- const uncategorized = names.filter(s => !categorized.has(s));
502
+ const uncategorized = names.filter((s) => !categorized.has(s));
477
503
  if (uncategorized.length > 0) {
478
504
  groups.push({ cat: "Other", skills: uncategorized });
479
505
  }
480
- const options = groups.map(g => ({
506
+ const options = groups.map((g) => ({
481
507
  value: g.cat,
482
508
  label: g.cat,
483
509
  hint: `${g.skills.length} installed`,
@@ -502,7 +528,7 @@ async function manageInstalled(allSkills, providerName) {
502
528
  await bulkUninstall(names);
503
529
  continue;
504
530
  }
505
- const group = groups.find(g => g.cat === picked);
531
+ const group = groups.find((g) => g.cat === picked);
506
532
  if (group) {
507
533
  await installedCategoryList(group.cat, group.skills, allSkills, providerName);
508
534
  }
@@ -510,12 +536,12 @@ async function manageInstalled(allSkills, providerName) {
510
536
  }
511
537
  async function installedCategoryList(categoryName, installedNames, allSkills, providerName) {
512
538
  while (true) {
513
- const stillInstalled = installedNames.filter(s => isSkillInstalled(s));
539
+ const stillInstalled = installedNames.filter((s) => isSkillInstalled(s));
514
540
  if (stillInstalled.length === 0) {
515
541
  p.log.info("No skills remaining in this category.");
516
542
  return;
517
543
  }
518
- const options = stillInstalled.map(name => {
544
+ const options = stillInstalled.map((name) => {
519
545
  const meta = readSkillMeta(name);
520
546
  const ver = meta ? `v${meta.version}` : "";
521
547
  const date = meta?.installedAt ? new Date(meta.installedAt).toLocaleDateString() : "";
@@ -540,7 +566,7 @@ async function installedCategoryList(categoryName, installedNames, allSkills, pr
540
566
  async function bulkUninstall(installedNames) {
541
567
  const selected = await p.multiselect({
542
568
  message: "Select skills to uninstall",
543
- options: installedNames.map(name => ({ value: name, label: name })),
569
+ options: installedNames.map((name) => ({ value: name, label: name })),
544
570
  required: false,
545
571
  maxItems: 15,
546
572
  });
@@ -583,7 +609,7 @@ async function updateAll(providerName) {
583
609
  p.log.error(ui.dim(err.message));
584
610
  return;
585
611
  }
586
- const remoteMap = new Map(remoteSkills.map(rs => [rs.name, rs]));
612
+ const remoteMap = new Map(remoteSkills.map((rs) => [rs.name, rs]));
587
613
  const updates = [];
588
614
  for (const name of installed) {
589
615
  const remote = remoteMap.get(name);
@@ -642,15 +668,13 @@ async function checkHealth() {
642
668
  const checks = runDoctorChecks();
643
669
  p.log.step(chalk.bold("Environment Health Check"));
644
670
  for (const check of checks) {
645
- const icon = check.status === "pass" ? chalk.green("OK")
646
- : check.status === "warn" ? chalk.yellow("!!")
647
- : chalk.red("XX");
671
+ const icon = check.status === "pass" ? chalk.green("OK") : check.status === "warn" ? chalk.yellow("!!") : chalk.red("XX");
648
672
  p.log.info(`${icon} ${chalk.bold(check.name)}: ${check.message}`);
649
673
  if (check.fix)
650
674
  p.log.info(chalk.dim(` Fix: ${check.fix}`));
651
675
  }
652
- const fails = checks.filter(c => c.status === "fail").length;
653
- const warns = checks.filter(c => c.status === "warn").length;
676
+ const fails = checks.filter((c) => c.status === "fail").length;
677
+ const warns = checks.filter((c) => c.status === "warn").length;
654
678
  if (fails > 0) {
655
679
  p.log.error(`${fails} issue${fails > 1 ? "s" : ""} found`);
656
680
  }
@@ -662,10 +686,10 @@ async function checkHealth() {
662
686
  return;
663
687
  }
664
688
  // Offer fixes once - no loop. User can re-enter health check to verify.
665
- const fixChecks = checks.filter(c => c.fix && c.status !== "pass");
689
+ const fixChecks = checks.filter((c) => c.fix && c.status !== "pass");
666
690
  if (fixChecks.length === 0)
667
691
  return;
668
- const fixOptions = fixChecks.map(c => {
692
+ const fixOptions = fixChecks.map((c) => {
669
693
  const cmd = c.fix.replace(/^Run:\s*/, "");
670
694
  return { value: cmd, label: `Run: ${cmd}`, hint: c.name };
671
695
  });
@@ -677,7 +701,7 @@ async function checkHealth() {
677
701
  if (fixAction !== "__skip") {
678
702
  const cmd = fixAction;
679
703
  const SAFE_PREFIXES = ["arcana ", "git config "];
680
- if (!SAFE_PREFIXES.some(pre => cmd.startsWith(pre))) {
704
+ if (!SAFE_PREFIXES.some((pre) => cmd.startsWith(pre))) {
681
705
  p.log.warn(`Skipped unsafe command: ${cmd}`);
682
706
  }
683
707
  else {
@@ -724,7 +748,7 @@ export async function showInteractiveMenu(version) {
724
748
  const config = loadConfig();
725
749
  const providerName = config.defaultProvider;
726
750
  // Fetch skill list once for the session
727
- let allSkills = [];
751
+ const allSkills = [];
728
752
  let availableCount = 0;
729
753
  try {
730
754
  const providers = getProviders();
@@ -815,4 +839,3 @@ export async function showInteractiveMenu(version) {
815
839
  }
816
840
  }
817
841
  }
818
- //# sourceMappingURL=interactive.js.map
@@ -2,4 +2,3 @@ import { GitHubProvider } from "./github.js";
2
2
  export declare class ArcanaProvider extends GitHubProvider {
3
3
  constructor();
4
4
  }
5
- //# sourceMappingURL=arcana.d.ts.map
@@ -8,4 +8,3 @@ export class ArcanaProvider extends GitHubProvider {
8
8
  });
9
9
  }
10
10
  }
11
- //# sourceMappingURL=arcana.js.map
@@ -8,4 +8,3 @@ export declare abstract class Provider {
8
8
  clearCache(): void;
9
9
  info(skillName: string): Promise<SkillInfo | null>;
10
10
  }
11
- //# sourceMappingURL=base.d.ts.map
@@ -7,4 +7,3 @@ export class Provider {
7
7
  return skills.find((s) => s.name === skillName) ?? null;
8
8
  }
9
9
  }
10
- //# sourceMappingURL=base.js.map
@@ -22,4 +22,3 @@ export declare class GitHubProvider extends Provider {
22
22
  search(query: string): Promise<SkillInfo[]>;
23
23
  clearCache(): void;
24
24
  }
25
- //# sourceMappingURL=github.d.ts.map
@@ -81,6 +81,11 @@ export class GitHubProvider extends Provider {
81
81
  version: p.version,
82
82
  source: this.name,
83
83
  repo: `https://github.com/${this.owner}/${this.repo}`,
84
+ tags: p.tags,
85
+ conflicts: p.conflicts,
86
+ companions: p.companions,
87
+ verified: p.verified,
88
+ author: p.author,
84
89
  }));
85
90
  // Warn about malformed entries
86
91
  const skipped = data.plugins.length - this.cache.length;
@@ -119,7 +124,7 @@ export class GitHubProvider extends Provider {
119
124
  return { path: relativePath, content };
120
125
  }
121
126
  catch (err) {
122
- throw new Error(`Failed to fetch file "${relativePath}" for skill "${skillName}": ${err instanceof Error ? err.message : String(err)}`);
127
+ throw new Error(`Failed to fetch file "${relativePath}" for skill "${skillName}": ${err instanceof Error ? err.message : String(err)}`, { cause: err });
123
128
  }
124
129
  }, 6);
125
130
  return results.filter((r) => r !== null);
@@ -128,7 +133,8 @@ export class GitHubProvider extends Provider {
128
133
  const all = await this.list();
129
134
  const q = query.toLowerCase();
130
135
  const exact = all.filter((s) => s.name.toLowerCase().includes(q) ||
131
- s.description.toLowerCase().includes(q));
136
+ s.description.toLowerCase().includes(q) ||
137
+ s.tags?.some((t) => t.toLowerCase().includes(q)));
132
138
  if (exact.length > 0)
133
139
  return exact;
134
140
  // Fuzzy fallback: match skills where Levenshtein distance to name <= 3
@@ -143,4 +149,3 @@ export class GitHubProvider extends Provider {
143
149
  clearCacheFile(this.cacheKey);
144
150
  }
145
151
  }
146
- //# sourceMappingURL=github.js.map