@sporesec/arcana 2.2.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 (181) hide show
  1. package/dist/cli.d.ts +3 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +219 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/commands/audit.d.ts +17 -0
  6. package/dist/commands/audit.d.ts.map +1 -0
  7. package/dist/commands/audit.js +157 -0
  8. package/dist/commands/audit.js.map +1 -0
  9. package/dist/commands/audit.test.d.ts +2 -0
  10. package/dist/commands/audit.test.d.ts.map +1 -0
  11. package/dist/commands/audit.test.js +217 -0
  12. package/dist/commands/audit.test.js.map +1 -0
  13. package/dist/commands/clean.d.ts +5 -0
  14. package/dist/commands/clean.d.ts.map +1 -0
  15. package/dist/commands/clean.js +125 -0
  16. package/dist/commands/clean.js.map +1 -0
  17. package/dist/commands/config.d.ts +4 -0
  18. package/dist/commands/config.d.ts.map +1 -0
  19. package/dist/commands/config.js +135 -0
  20. package/dist/commands/config.js.map +1 -0
  21. package/dist/commands/create.d.ts +2 -0
  22. package/dist/commands/create.d.ts.map +1 -0
  23. package/dist/commands/create.js +100 -0
  24. package/dist/commands/create.js.map +1 -0
  25. package/dist/commands/doctor.d.ts +6 -0
  26. package/dist/commands/doctor.d.ts.map +1 -0
  27. package/dist/commands/doctor.js +213 -0
  28. package/dist/commands/doctor.js.map +1 -0
  29. package/dist/commands/info.d.ts +5 -0
  30. package/dist/commands/info.d.ts.map +1 -0
  31. package/dist/commands/info.js +114 -0
  32. package/dist/commands/info.js.map +1 -0
  33. package/dist/commands/init.d.ts +13 -0
  34. package/dist/commands/init.d.ts.map +1 -0
  35. package/dist/commands/init.js +216 -0
  36. package/dist/commands/init.js.map +1 -0
  37. package/dist/commands/install.d.ts +8 -0
  38. package/dist/commands/install.d.ts.map +1 -0
  39. package/dist/commands/install.js +404 -0
  40. package/dist/commands/install.js.map +1 -0
  41. package/dist/commands/list.d.ts +8 -0
  42. package/dist/commands/list.d.ts.map +1 -0
  43. package/dist/commands/list.js +100 -0
  44. package/dist/commands/list.js.map +1 -0
  45. package/dist/commands/providers.d.ts +6 -0
  46. package/dist/commands/providers.d.ts.map +1 -0
  47. package/dist/commands/providers.js +103 -0
  48. package/dist/commands/providers.js.map +1 -0
  49. package/dist/commands/scan.d.ts +5 -0
  50. package/dist/commands/scan.d.ts.map +1 -0
  51. package/dist/commands/scan.js +110 -0
  52. package/dist/commands/scan.js.map +1 -0
  53. package/dist/commands/search.d.ts +6 -0
  54. package/dist/commands/search.d.ts.map +1 -0
  55. package/dist/commands/search.js +58 -0
  56. package/dist/commands/search.js.map +1 -0
  57. package/dist/commands/stats.d.ts +4 -0
  58. package/dist/commands/stats.d.ts.map +1 -0
  59. package/dist/commands/stats.js +143 -0
  60. package/dist/commands/stats.js.map +1 -0
  61. package/dist/commands/uninstall.d.ts +6 -0
  62. package/dist/commands/uninstall.d.ts.map +1 -0
  63. package/dist/commands/uninstall.js +163 -0
  64. package/dist/commands/uninstall.js.map +1 -0
  65. package/dist/commands/update.d.ts +7 -0
  66. package/dist/commands/update.d.ts.map +1 -0
  67. package/dist/commands/update.js +348 -0
  68. package/dist/commands/update.js.map +1 -0
  69. package/dist/commands/validate.d.ts +6 -0
  70. package/dist/commands/validate.d.ts.map +1 -0
  71. package/dist/commands/validate.js +140 -0
  72. package/dist/commands/validate.js.map +1 -0
  73. package/dist/index.d.ts +3 -0
  74. package/dist/index.d.ts.map +1 -0
  75. package/dist/index.js +39 -0
  76. package/dist/index.js.map +1 -0
  77. package/dist/interactive.d.ts +2 -0
  78. package/dist/interactive.d.ts.map +1 -0
  79. package/dist/interactive.js +812 -0
  80. package/dist/interactive.js.map +1 -0
  81. package/dist/providers/arcana.d.ts +5 -0
  82. package/dist/providers/arcana.d.ts.map +1 -0
  83. package/dist/providers/arcana.js +11 -0
  84. package/dist/providers/arcana.js.map +1 -0
  85. package/dist/providers/base.d.ts +11 -0
  86. package/dist/providers/base.d.ts.map +1 -0
  87. package/dist/providers/base.js +10 -0
  88. package/dist/providers/base.js.map +1 -0
  89. package/dist/providers/github.d.ts +25 -0
  90. package/dist/providers/github.d.ts.map +1 -0
  91. package/dist/providers/github.js +146 -0
  92. package/dist/providers/github.js.map +1 -0
  93. package/dist/registry.d.ts +9 -0
  94. package/dist/registry.d.ts.map +1 -0
  95. package/dist/registry.js +71 -0
  96. package/dist/registry.js.map +1 -0
  97. package/dist/types.d.ts +67 -0
  98. package/dist/types.d.ts.map +1 -0
  99. package/dist/types.js +2 -0
  100. package/dist/types.js.map +1 -0
  101. package/dist/utils/atomic.d.ts +2 -0
  102. package/dist/utils/atomic.d.ts.map +1 -0
  103. package/dist/utils/atomic.js +20 -0
  104. package/dist/utils/atomic.js.map +1 -0
  105. package/dist/utils/atomic.test.d.ts +2 -0
  106. package/dist/utils/atomic.test.d.ts.map +1 -0
  107. package/dist/utils/atomic.test.js +31 -0
  108. package/dist/utils/atomic.test.js.map +1 -0
  109. package/dist/utils/cache.d.ts +4 -0
  110. package/dist/utils/cache.d.ts.map +1 -0
  111. package/dist/utils/cache.js +47 -0
  112. package/dist/utils/cache.js.map +1 -0
  113. package/dist/utils/config.d.ts +6 -0
  114. package/dist/utils/config.d.ts.map +1 -0
  115. package/dist/utils/config.js +90 -0
  116. package/dist/utils/config.js.map +1 -0
  117. package/dist/utils/config.test.d.ts +2 -0
  118. package/dist/utils/config.test.d.ts.map +1 -0
  119. package/dist/utils/config.test.js +38 -0
  120. package/dist/utils/config.test.js.map +1 -0
  121. package/dist/utils/errors.d.ts +6 -0
  122. package/dist/utils/errors.d.ts.map +1 -0
  123. package/dist/utils/errors.js +11 -0
  124. package/dist/utils/errors.js.map +1 -0
  125. package/dist/utils/frontmatter.d.ts +12 -0
  126. package/dist/utils/frontmatter.d.ts.map +1 -0
  127. package/dist/utils/frontmatter.js +172 -0
  128. package/dist/utils/frontmatter.js.map +1 -0
  129. package/dist/utils/frontmatter.test.d.ts +2 -0
  130. package/dist/utils/frontmatter.test.d.ts.map +1 -0
  131. package/dist/utils/frontmatter.test.js +152 -0
  132. package/dist/utils/frontmatter.test.js.map +1 -0
  133. package/dist/utils/fs.d.ts +16 -0
  134. package/dist/utils/fs.d.ts.map +1 -0
  135. package/dist/utils/fs.js +118 -0
  136. package/dist/utils/fs.js.map +1 -0
  137. package/dist/utils/fs.test.d.ts +2 -0
  138. package/dist/utils/fs.test.d.ts.map +1 -0
  139. package/dist/utils/fs.test.js +145 -0
  140. package/dist/utils/fs.test.js.map +1 -0
  141. package/dist/utils/help.d.ts +6 -0
  142. package/dist/utils/help.d.ts.map +1 -0
  143. package/dist/utils/help.js +117 -0
  144. package/dist/utils/help.js.map +1 -0
  145. package/dist/utils/help.test.d.ts +2 -0
  146. package/dist/utils/help.test.d.ts.map +1 -0
  147. package/dist/utils/help.test.js +66 -0
  148. package/dist/utils/help.test.js.map +1 -0
  149. package/dist/utils/history.d.ts +10 -0
  150. package/dist/utils/history.d.ts.map +1 -0
  151. package/dist/utils/history.js +58 -0
  152. package/dist/utils/history.js.map +1 -0
  153. package/dist/utils/http.d.ts +17 -0
  154. package/dist/utils/http.d.ts.map +1 -0
  155. package/dist/utils/http.js +165 -0
  156. package/dist/utils/http.js.map +1 -0
  157. package/dist/utils/http.test.d.ts +2 -0
  158. package/dist/utils/http.test.d.ts.map +1 -0
  159. package/dist/utils/http.test.js +55 -0
  160. package/dist/utils/http.test.js.map +1 -0
  161. package/dist/utils/parallel.d.ts +2 -0
  162. package/dist/utils/parallel.d.ts.map +1 -0
  163. package/dist/utils/parallel.js +17 -0
  164. package/dist/utils/parallel.js.map +1 -0
  165. package/dist/utils/scanner.d.ts +27 -0
  166. package/dist/utils/scanner.d.ts.map +1 -0
  167. package/dist/utils/scanner.js +195 -0
  168. package/dist/utils/scanner.js.map +1 -0
  169. package/dist/utils/ui.d.ts +27 -0
  170. package/dist/utils/ui.d.ts.map +1 -0
  171. package/dist/utils/ui.js +99 -0
  172. package/dist/utils/ui.js.map +1 -0
  173. package/dist/utils/ui.test.d.ts +2 -0
  174. package/dist/utils/ui.test.d.ts.map +1 -0
  175. package/dist/utils/ui.test.js +31 -0
  176. package/dist/utils/ui.test.js.map +1 -0
  177. package/dist/utils/validate.d.ts +2 -0
  178. package/dist/utils/validate.d.ts.map +1 -0
  179. package/dist/utils/validate.js +7 -0
  180. package/dist/utils/validate.js.map +1 -0
  181. package/package.json +62 -0
@@ -0,0 +1,216 @@
1
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
2
+ import { join, basename, dirname } from "node:path";
3
+ import * as p from "@clack/prompts";
4
+ import chalk from "chalk";
5
+ import { renderBanner } from "../utils/help.js";
6
+ export function detectProject(cwd) {
7
+ const name = basename(cwd);
8
+ if (existsSync(join(cwd, "go.mod")))
9
+ return { name, type: "Go", lang: "go" };
10
+ if (existsSync(join(cwd, "Cargo.toml")))
11
+ return { name, type: "Rust", lang: "rust" };
12
+ if (existsSync(join(cwd, "requirements.txt")) || existsSync(join(cwd, "pyproject.toml")))
13
+ return { name, type: "Python", lang: "python" };
14
+ if (existsSync(join(cwd, "package.json"))) {
15
+ try {
16
+ const raw = readFileSync(join(cwd, "package.json"), "utf-8");
17
+ const pkg = JSON.parse(raw);
18
+ if (pkg.dependencies?.next || pkg.devDependencies?.next)
19
+ return { name, type: "Next.js", lang: "typescript" };
20
+ if (pkg.dependencies?.react || pkg.devDependencies?.react)
21
+ return { name, type: "React", lang: "typescript" };
22
+ }
23
+ catch { /* ignore */ }
24
+ return { name, type: "Node.js", lang: "typescript" };
25
+ }
26
+ return { name, type: "Unknown", lang: "general" };
27
+ }
28
+ function claudeTemplate(proj) {
29
+ return `# CLAUDE.md - ${proj.name}
30
+
31
+ ## Project
32
+ - **Type:** ${proj.type}
33
+ - **Language:** ${proj.lang}
34
+
35
+ ## Coding Preferences
36
+ - Follow existing patterns in the codebase
37
+ - Handle errors explicitly
38
+ - Use meaningful variable names, no abbreviations
39
+
40
+ ## Build & Test
41
+ <!-- Add build/test commands so Claude can verify changes -->
42
+ <!-- Example: npm test, go test ./..., pytest -->
43
+
44
+ ## Project Structure
45
+ <!-- Describe your project structure here -->
46
+ `;
47
+ }
48
+ function cursorTemplate(proj) {
49
+ return `---
50
+ description: Project conventions for ${proj.name}
51
+ globs:
52
+ ---
53
+
54
+ # ${proj.name} (${proj.type})
55
+
56
+ ## Language
57
+ ${proj.lang}
58
+
59
+ ## Coding Standards
60
+ - Follow existing patterns in the codebase
61
+ - Handle errors explicitly
62
+ - Use meaningful variable names
63
+ `;
64
+ }
65
+ function codexTemplate(proj) {
66
+ return `# AGENTS.md - ${proj.name}
67
+
68
+ ## Project
69
+ Type: ${proj.type} | Language: ${proj.lang}
70
+
71
+ ## Sandbox
72
+ Codex runs in a sandboxed environment with no network access.
73
+ All dependencies must be pre-installed before the session.
74
+
75
+ ## Guidelines
76
+ - Follow existing patterns in the codebase
77
+ - Handle errors explicitly
78
+ - Use meaningful variable names
79
+ `;
80
+ }
81
+ function geminiTemplate(proj) {
82
+ return `# GEMINI.md - ${proj.name}
83
+
84
+ ## Project Context
85
+ This is a ${proj.type} project using ${proj.lang}.
86
+
87
+ ## Project Files
88
+ <!-- List key files and directories so Gemini can navigate the codebase -->
89
+ <!-- Example: src/ - main source, tests/ - test files -->
90
+
91
+ ## Instructions
92
+ - Follow existing patterns in the codebase
93
+ - Handle errors explicitly
94
+ - Use meaningful variable names
95
+ `;
96
+ }
97
+ function antigravityTemplate(proj) {
98
+ return `# Antigravity - ${proj.name}
99
+
100
+ ## Project Context
101
+ This is a ${proj.type} project using ${proj.lang}.
102
+ Antigravity workspace: \`.agent/\` (rules, workflows, skills)
103
+
104
+ ## Project Files
105
+ <!-- List key files and directories so the agent can navigate the codebase -->
106
+ <!-- Example: src/ - main source, tests/ - test files -->
107
+
108
+ ## Instructions
109
+ - Follow existing patterns in the codebase
110
+ - Handle errors explicitly
111
+ - Use meaningful variable names
112
+ `;
113
+ }
114
+ function windsurfTemplate(proj) {
115
+ return `# Windsurf Cascades Rules - ${proj.name}
116
+
117
+ Project: ${proj.name} (${proj.type})
118
+ Language: ${proj.lang}
119
+
120
+ ## Rules
121
+ - Follow existing patterns in the codebase
122
+ - Handle errors explicitly
123
+ - Use meaningful variable names
124
+ - Always explain changes before applying them
125
+ `;
126
+ }
127
+ function aiderTemplate(_proj) {
128
+ return `# Aider Configuration
129
+ model: sonnet
130
+ auto-commits: true
131
+ auto-test: false
132
+ # Add conventions below
133
+ conventions:
134
+ - Follow existing patterns in the codebase
135
+ - Write clean, maintainable code
136
+ - Handle errors explicitly
137
+ `;
138
+ }
139
+ const TOOL_FILES = {
140
+ claude: { path: "CLAUDE.md", template: claudeTemplate, label: "Claude Code" },
141
+ cursor: {
142
+ path: join(".cursor", "rules", "project.mdc"),
143
+ template: cursorTemplate,
144
+ label: "Cursor",
145
+ },
146
+ codex: { path: "AGENTS.md", template: codexTemplate, label: "Codex CLI" },
147
+ gemini: { path: "GEMINI.md", template: geminiTemplate, label: "Gemini CLI" },
148
+ antigravity: { path: "GEMINI.md", template: antigravityTemplate, label: "Antigravity" },
149
+ windsurf: { path: ".windsurfrules", template: windsurfTemplate, label: "Windsurf" },
150
+ aider: { path: ".aider.conf.yml", template: aiderTemplate, label: "Aider" },
151
+ };
152
+ export const SKILL_SUGGESTIONS = {
153
+ "Go": ["golang-pro", "go-linter-configuration", "testing-strategy", "security-review"],
154
+ "Rust": ["rust-best-practices", "testing-strategy", "security-review"],
155
+ "Python": ["python-best-practices", "testing-strategy", "security-review"],
156
+ "Next.js": ["typescript", "typescript-advanced", "frontend-design", "performance-optimization", "security-review"],
157
+ "React": ["typescript", "frontend-design", "frontend-code-review", "testing-strategy"],
158
+ "Node.js": ["typescript", "npm-package", "testing-strategy", "security-review"],
159
+ };
160
+ export const SKILL_SUGGESTIONS_DEFAULT = ["code-reviewer", "security-review", "codebase-dissection", "testing-strategy"];
161
+ export async function initCommand(opts) {
162
+ console.log(renderBanner());
163
+ console.log();
164
+ p.intro(chalk.bold("Initialize arcana"));
165
+ const cwd = process.cwd();
166
+ const proj = detectProject(cwd);
167
+ p.log.step(`Project detected: ${chalk.cyan(proj.name)} (${proj.type})`);
168
+ if (opts.tool && opts.tool !== "all" && !(opts.tool in TOOL_FILES)) {
169
+ const valid = Object.keys(TOOL_FILES).join(", ");
170
+ p.cancel(`Unknown tool: ${opts.tool}. Valid: ${valid}`);
171
+ process.exit(1);
172
+ }
173
+ const tools = opts.tool === "all" || !opts.tool
174
+ ? ["claude", "cursor", "codex", "gemini", "antigravity", "windsurf", "aider"]
175
+ : [opts.tool];
176
+ let created = 0;
177
+ let skipped = 0;
178
+ for (const tool of tools) {
179
+ const entry = TOOL_FILES[tool];
180
+ if (!entry) {
181
+ p.log.warn(`Unknown tool: ${tool}`);
182
+ continue;
183
+ }
184
+ const relPath = typeof entry.path === "function" ? entry.path(cwd) : entry.path;
185
+ const fullPath = join(cwd, relPath);
186
+ if (existsSync(fullPath)) {
187
+ p.log.info(`Skip ${relPath} (already exists)`);
188
+ skipped++;
189
+ continue;
190
+ }
191
+ const content = entry.template(proj);
192
+ try {
193
+ mkdirSync(dirname(fullPath), { recursive: true });
194
+ writeFileSync(fullPath, content, "utf-8");
195
+ }
196
+ catch (err) {
197
+ p.log.warn(`Failed to create ${relPath}: ${err instanceof Error ? err.message : "unknown error"}`);
198
+ continue;
199
+ }
200
+ p.log.success(`Created ${chalk.cyan(relPath)} (${entry.label})`);
201
+ created++;
202
+ }
203
+ if (created > 0) {
204
+ p.log.info(`${created} file${created > 1 ? "s" : ""} created. Edit them to match your project.`);
205
+ }
206
+ else {
207
+ p.log.info("All config files already exist.");
208
+ }
209
+ if (skipped > 0)
210
+ p.log.info(`${skipped} skipped (already exist)`);
211
+ const suggestions = SKILL_SUGGESTIONS[proj.type] || SKILL_SUGGESTIONS_DEFAULT;
212
+ const skillList = suggestions.map((s) => `arcana install ${s}`).join("\n");
213
+ p.note(skillList, "Recommended skills");
214
+ p.outro(`Next: ${chalk.cyan("arcana install <skill>")} or ${chalk.cyan("arcana install --all")}`);
215
+ }
216
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export declare function installCommand(skillNames: string[], opts: {
2
+ provider?: string;
3
+ all?: boolean;
4
+ force?: boolean;
5
+ dryRun?: boolean;
6
+ json?: boolean;
7
+ }): Promise<void>;
8
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"AAiDA,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAAE,EACpB,IAAI,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAC5F,OAAO,CAAC,IAAI,CAAC,CA+Bf"}
@@ -0,0 +1,404 @@
1
+ import * as p from "@clack/prompts";
2
+ import chalk from "chalk";
3
+ import { printErrorWithHint } from "../utils/ui.js";
4
+ import { installSkill, isSkillInstalled, writeSkillMeta, readSkillMeta } from "../utils/fs.js";
5
+ import { getProvider, getProviders } from "../registry.js";
6
+ import { loadConfig } from "../utils/config.js";
7
+ import { renderBanner } from "../utils/help.js";
8
+ import { validateSlug } from "../utils/validate.js";
9
+ import { scanSkillContent } from "../utils/scanner.js";
10
+ /**
11
+ * Scan fetched skill files for security threats before installing.
12
+ * Returns true if install should proceed, false to block.
13
+ */
14
+ function preInstallScan(skillName, files, force) {
15
+ const skillMd = files.find(f => f.path.endsWith("SKILL.md"));
16
+ if (!skillMd)
17
+ return true;
18
+ const issues = scanSkillContent(skillMd.content);
19
+ if (issues.length === 0)
20
+ return true;
21
+ const critical = issues.filter(i => i.level === "critical");
22
+ const high = issues.filter(i => i.level === "high");
23
+ if (critical.length > 0) {
24
+ p.log.error(`Security scan blocked ${chalk.bold(skillName)}:`);
25
+ for (const issue of critical) {
26
+ p.log.error(` [CRIT] ${issue.category}: ${issue.detail} (line ${issue.line})`);
27
+ }
28
+ for (const issue of high) {
29
+ p.log.warn(` [HIGH] ${issue.category}: ${issue.detail} (line ${issue.line})`);
30
+ }
31
+ if (!force) {
32
+ p.log.info(chalk.dim("Use --force to install anyway (not recommended)."));
33
+ return false;
34
+ }
35
+ p.log.warn("Installing despite security issues (--force).");
36
+ }
37
+ else if (high.length > 0) {
38
+ p.log.warn(`Security warnings for ${chalk.bold(skillName)}:`);
39
+ for (const issue of high) {
40
+ p.log.warn(` [HIGH] ${issue.category}: ${issue.detail} (line ${issue.line})`);
41
+ }
42
+ }
43
+ return true;
44
+ }
45
+ export async function installCommand(skillNames, opts) {
46
+ if (opts.json) {
47
+ return installJson(skillNames, opts);
48
+ }
49
+ console.log(renderBanner());
50
+ console.log();
51
+ if (skillNames.length === 0 && !opts.all) {
52
+ p.intro(chalk.bold("Install skill"));
53
+ p.cancel("Specify a skill name or use --all");
54
+ p.log.info("Usage: arcana install <skill-name> [skill2 ...]");
55
+ p.log.info(" arcana install --all");
56
+ process.exit(1);
57
+ }
58
+ const providerName = opts.provider ?? loadConfig().defaultProvider;
59
+ const providers = opts.all ? getProviders() : [getProvider(providerName)];
60
+ if (providers.length === 0) {
61
+ p.cancel("No providers configured. Run: arcana providers --add owner/repo");
62
+ process.exit(1);
63
+ }
64
+ if (opts.all) {
65
+ await installAllInteractive(providers, opts.dryRun, opts.force);
66
+ }
67
+ else if (skillNames.length === 1) {
68
+ await installOneInteractive(skillNames[0], providers[0], opts.dryRun, opts.force);
69
+ }
70
+ else {
71
+ await installMultipleInteractive(skillNames, providers[0], opts.dryRun, opts.force);
72
+ }
73
+ }
74
+ async function installOneInteractive(skillName, provider, dryRun, force) {
75
+ p.intro(chalk.bold("Install skill"));
76
+ try {
77
+ validateSlug(skillName, "skill name");
78
+ }
79
+ catch (err) {
80
+ p.cancel(err instanceof Error ? err.message : "Invalid skill name");
81
+ process.exit(1);
82
+ }
83
+ if (isSkillInstalled(skillName)) {
84
+ if (dryRun) {
85
+ p.log.info(`${skillName} is already installed.`);
86
+ p.outro("Dry run complete.");
87
+ return;
88
+ }
89
+ if (!force) {
90
+ p.cancel(`${skillName} is already installed. Use --force to reinstall.`);
91
+ process.exit(0);
92
+ }
93
+ const existingMeta = readSkillMeta(skillName);
94
+ if (existingMeta?.source && existingMeta.source !== provider.name) {
95
+ p.log.warn(`Overwriting ${skillName} (was from ${existingMeta.source}, now from ${provider.name})`);
96
+ }
97
+ p.log.warn(`${skillName} is already installed. Reinstalling...`);
98
+ }
99
+ if (dryRun) {
100
+ p.log.info(`Would install ${chalk.bold(skillName)} from ${provider.name}`);
101
+ p.outro("Dry run complete.");
102
+ return;
103
+ }
104
+ const spin = p.spinner();
105
+ spin.start(`Fetching ${chalk.bold(skillName)} from ${provider.name}...`);
106
+ try {
107
+ const files = await provider.fetch(skillName);
108
+ spin.stop("Fetched.");
109
+ if (!preInstallScan(skillName, files, force)) {
110
+ process.exit(1);
111
+ }
112
+ const spin2 = p.spinner();
113
+ spin2.start(`Installing ${chalk.bold(skillName)}...`);
114
+ const dir = installSkill(skillName, files);
115
+ const remote = await provider.info(skillName);
116
+ writeSkillMeta(skillName, {
117
+ version: remote?.version ?? "0.0.0",
118
+ installedAt: new Date().toISOString(),
119
+ source: provider.name,
120
+ description: remote?.description,
121
+ fileCount: files.length,
122
+ sizeBytes: files.reduce((s, f) => s + f.content.length, 0),
123
+ });
124
+ const sizeKB = files.reduce((s, f) => s + f.content.length, 0) / 1024;
125
+ spin2.stop(`Installed ${chalk.bold(skillName)} (${files.length} files, ${sizeKB.toFixed(1)} KB)`);
126
+ if (sizeKB > 50) {
127
+ p.log.warn(`Large skill (${sizeKB.toFixed(0)} KB, ~${Math.round(sizeKB * 3)} tokens). May use significant context.`);
128
+ }
129
+ p.log.info(`Location: ${dir}`);
130
+ p.outro(`Next: ${chalk.cyan("arcana validate " + skillName)}`);
131
+ }
132
+ catch (err) {
133
+ p.log.error(`Failed to install ${skillName}`);
134
+ printErrorWithHint(err, true);
135
+ process.exit(1);
136
+ }
137
+ }
138
+ async function installMultipleInteractive(skillNames, provider, dryRun, force) {
139
+ p.intro(chalk.bold(`Install ${skillNames.length} skills`));
140
+ for (const name of skillNames) {
141
+ try {
142
+ validateSlug(name, "skill name");
143
+ }
144
+ catch (err) {
145
+ p.log.error(err instanceof Error ? err.message : `Invalid skill name: ${name}`);
146
+ process.exit(1);
147
+ }
148
+ }
149
+ if (dryRun) {
150
+ const wouldInstall = [];
151
+ const alreadyInstalled = [];
152
+ for (const skillName of skillNames) {
153
+ if (isSkillInstalled(skillName) && !force) {
154
+ alreadyInstalled.push(skillName);
155
+ }
156
+ else {
157
+ wouldInstall.push(skillName);
158
+ }
159
+ }
160
+ if (wouldInstall.length > 0) {
161
+ p.log.info(`Would install: ${wouldInstall.join(", ")}`);
162
+ }
163
+ if (alreadyInstalled.length > 0) {
164
+ p.log.info(`Already installed: ${alreadyInstalled.join(", ")}`);
165
+ }
166
+ p.outro("Dry run complete.");
167
+ return;
168
+ }
169
+ const spin = p.spinner();
170
+ spin.start(`Processing ${skillNames.length} skills...`);
171
+ const installedList = [];
172
+ const skippedList = [];
173
+ const failedList = [];
174
+ for (let i = 0; i < skillNames.length; i++) {
175
+ const skillName = skillNames[i];
176
+ if (isSkillInstalled(skillName) && !force) {
177
+ skippedList.push(skillName);
178
+ continue;
179
+ }
180
+ spin.message(`Installing ${chalk.bold(skillName)} (${i + 1}/${skillNames.length}) from ${provider.name}...`);
181
+ try {
182
+ const files = await provider.fetch(skillName);
183
+ if (!preInstallScan(skillName, files, force)) {
184
+ failedList.push(skillName);
185
+ continue;
186
+ }
187
+ installSkill(skillName, files);
188
+ const remote = await provider.info(skillName);
189
+ writeSkillMeta(skillName, {
190
+ version: remote?.version ?? "0.0.0",
191
+ installedAt: new Date().toISOString(),
192
+ source: provider.name,
193
+ description: remote?.description,
194
+ fileCount: files.length,
195
+ sizeBytes: files.reduce((s, f) => s + f.content.length, 0),
196
+ });
197
+ installedList.push(skillName);
198
+ }
199
+ catch (err) {
200
+ failedList.push(skillName);
201
+ if (err instanceof Error)
202
+ p.log.warn(`Failed to install ${skillName}: ${err.message}`);
203
+ }
204
+ }
205
+ spin.stop(`Done`);
206
+ p.log.info(`${installedList.length} installed${skippedList.length > 0 ? `, ${skippedList.length} skipped (already installed)` : ""}${failedList.length > 0 ? `, ${failedList.length} failed` : ""}`);
207
+ p.outro(`Next: ${chalk.cyan("arcana doctor")}`);
208
+ if (failedList.length > 0)
209
+ process.exit(1);
210
+ }
211
+ async function installAllInteractive(providers, dryRun, force) {
212
+ p.intro(chalk.bold("Install all skills"));
213
+ const spin = p.spinner();
214
+ spin.start("Fetching skill list...");
215
+ if (dryRun) {
216
+ let total = 0;
217
+ for (const provider of providers) {
218
+ try {
219
+ const skills = await provider.list();
220
+ total += skills.length;
221
+ }
222
+ catch (err) {
223
+ if (err instanceof Error)
224
+ p.log.warn(`Failed to list ${provider.name}: ${err.message}`);
225
+ }
226
+ }
227
+ spin.stop(`Would install ${total} skills`);
228
+ p.outro("Dry run complete.");
229
+ return;
230
+ }
231
+ const installedList = [];
232
+ const skippedList = [];
233
+ const failedList = [];
234
+ for (const provider of providers) {
235
+ let skills;
236
+ try {
237
+ skills = await provider.list();
238
+ }
239
+ catch (err) {
240
+ if (err instanceof Error)
241
+ p.log.warn(`Failed to list ${provider.name}: ${err.message}`);
242
+ continue;
243
+ }
244
+ const total = skills.length;
245
+ for (let i = 0; i < total; i++) {
246
+ const skill = skills[i];
247
+ if (isSkillInstalled(skill.name) && !force) {
248
+ skippedList.push(skill.name);
249
+ continue;
250
+ }
251
+ try {
252
+ spin.message(`Installing ${chalk.bold(skill.name)} (${i + 1}/${total}) from ${provider.name}...`);
253
+ const files = await provider.fetch(skill.name);
254
+ if (!preInstallScan(skill.name, files, force)) {
255
+ failedList.push(skill.name);
256
+ continue;
257
+ }
258
+ installSkill(skill.name, files);
259
+ writeSkillMeta(skill.name, {
260
+ version: skill.version,
261
+ installedAt: new Date().toISOString(),
262
+ source: provider.name,
263
+ description: skill.description,
264
+ fileCount: files.length,
265
+ sizeBytes: files.reduce((s, f) => s + f.content.length, 0),
266
+ });
267
+ installedList.push(skill.name);
268
+ }
269
+ catch (err) {
270
+ failedList.push(skill.name);
271
+ if (err instanceof Error)
272
+ p.log.warn(`Failed to install ${skill.name}: ${err.message}`);
273
+ }
274
+ }
275
+ }
276
+ spin.stop(`Installed ${installedList.length} skills${failedList.length > 0 ? `, ${failedList.length} failed` : ""}`);
277
+ if (skippedList.length > 0) {
278
+ p.log.info(`Skipped ${skippedList.length} already installed${force ? "" : " (use --force to reinstall)"}`);
279
+ }
280
+ p.outro(`Next: ${chalk.cyan("arcana doctor")}`);
281
+ if (failedList.length > 0)
282
+ process.exit(1);
283
+ }
284
+ async function installJson(skillNames, opts) {
285
+ if (skillNames.length === 0 && !opts.all) {
286
+ console.log(JSON.stringify({ installed: [], skipped: [], failed: [], error: "No skill specified" }));
287
+ process.exit(1);
288
+ }
289
+ const providerName = opts.provider ?? loadConfig().defaultProvider;
290
+ const providers = opts.all ? getProviders() : [getProvider(providerName)];
291
+ if (opts.all) {
292
+ if (opts.dryRun) {
293
+ const wouldInstall = [];
294
+ const errors = [];
295
+ for (const provider of providers) {
296
+ try {
297
+ const skills = await provider.list();
298
+ wouldInstall.push(...skills.map(s => s.name));
299
+ }
300
+ catch (err) {
301
+ errors.push(`Failed to list ${provider.name}: ${err instanceof Error ? err.message : "unknown error"}`);
302
+ }
303
+ }
304
+ const result = { dryRun: true, wouldInstall };
305
+ if (errors.length > 0)
306
+ result.errors = errors;
307
+ console.log(JSON.stringify(result));
308
+ return;
309
+ }
310
+ const installedList = [];
311
+ const skippedList = [];
312
+ const failedList = [];
313
+ const failedErrors = {};
314
+ const errors = [];
315
+ for (const provider of providers) {
316
+ let skills;
317
+ try {
318
+ skills = await provider.list();
319
+ }
320
+ catch (err) {
321
+ errors.push(`Failed to list ${provider.name}: ${err instanceof Error ? err.message : "unknown error"}`);
322
+ continue;
323
+ }
324
+ for (const skill of skills) {
325
+ if (isSkillInstalled(skill.name) && !opts.force) {
326
+ skippedList.push(skill.name);
327
+ continue;
328
+ }
329
+ try {
330
+ const files = await provider.fetch(skill.name);
331
+ if (!preInstallScan(skill.name, files, opts.force)) {
332
+ failedList.push(skill.name);
333
+ failedErrors[skill.name] = "Blocked by security scan";
334
+ continue;
335
+ }
336
+ installSkill(skill.name, files);
337
+ writeSkillMeta(skill.name, {
338
+ version: skill.version,
339
+ installedAt: new Date().toISOString(),
340
+ source: provider.name,
341
+ description: skill.description,
342
+ fileCount: files.length,
343
+ sizeBytes: files.reduce((s, f) => s + f.content.length, 0),
344
+ });
345
+ installedList.push(skill.name);
346
+ }
347
+ catch (err) {
348
+ failedList.push(skill.name);
349
+ failedErrors[skill.name] = err instanceof Error ? err.message : "unknown";
350
+ }
351
+ }
352
+ }
353
+ const result = { installed: installedList, skipped: skippedList, failed: failedList };
354
+ if (errors.length > 0)
355
+ result.errors = errors;
356
+ if (Object.keys(failedErrors).length > 0)
357
+ result.failedErrors = failedErrors;
358
+ console.log(JSON.stringify(result));
359
+ if (failedList.length > 0)
360
+ process.exit(1);
361
+ }
362
+ else {
363
+ const provider = providers[0];
364
+ if (opts.dryRun) {
365
+ console.log(JSON.stringify({ dryRun: true, wouldInstall: skillNames }));
366
+ return;
367
+ }
368
+ const installedList = [];
369
+ const skippedList = [];
370
+ const failedList = [];
371
+ for (const skillName of skillNames) {
372
+ try {
373
+ validateSlug(skillName, "skill name");
374
+ if (isSkillInstalled(skillName) && !opts.force) {
375
+ skippedList.push(skillName);
376
+ continue;
377
+ }
378
+ const files = await provider.fetch(skillName);
379
+ if (!preInstallScan(skillName, files, opts.force)) {
380
+ failedList.push(skillName);
381
+ continue;
382
+ }
383
+ installSkill(skillName, files);
384
+ const remote = await provider.info(skillName);
385
+ writeSkillMeta(skillName, {
386
+ version: remote?.version ?? "0.0.0",
387
+ installedAt: new Date().toISOString(),
388
+ source: provider.name,
389
+ description: remote?.description,
390
+ fileCount: files.length,
391
+ sizeBytes: files.reduce((s, f) => s + f.content.length, 0),
392
+ });
393
+ installedList.push(skillName);
394
+ }
395
+ catch (err) {
396
+ failedList.push(skillName);
397
+ }
398
+ }
399
+ console.log(JSON.stringify({ installed: installedList, skipped: skippedList, failed: failedList }));
400
+ if (failedList.length > 0)
401
+ process.exit(1);
402
+ }
403
+ }
404
+ //# sourceMappingURL=install.js.map