@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
@@ -0,0 +1,131 @@
1
+ import { readFileSync, existsSync } from "node:fs";
2
+ import { getProvider } from "../registry.js";
3
+ import { installSkill, writeSkillMeta } from "../utils/fs.js";
4
+ import { loadConfig } from "../utils/config.js";
5
+ import { updateLockEntry } from "../utils/integrity.js";
6
+ import { validateSlug } from "../utils/validate.js";
7
+ function parseManifest(raw) {
8
+ const parsed = JSON.parse(raw);
9
+ if (typeof parsed !== "object" || parsed === null || !Array.isArray(parsed.skills)) {
10
+ throw new Error("Invalid manifest: expected object with 'skills' array");
11
+ }
12
+ const obj = parsed;
13
+ const skills = obj.skills.map((entry, i) => {
14
+ if (typeof entry !== "object" || entry === null) {
15
+ throw new Error(`Invalid manifest entry at index ${i}`);
16
+ }
17
+ const e = entry;
18
+ if (typeof e.name !== "string" || e.name.length === 0) {
19
+ throw new Error(`Invalid manifest entry at index ${i}: missing name`);
20
+ }
21
+ return {
22
+ name: e.name,
23
+ version: typeof e.version === "string" ? e.version : undefined,
24
+ source: typeof e.source === "string" ? e.source : undefined,
25
+ description: typeof e.description === "string" ? e.description : undefined,
26
+ };
27
+ });
28
+ return { skills };
29
+ }
30
+ export async function importCommand(file, opts) {
31
+ if (!existsSync(file)) {
32
+ if (opts.json) {
33
+ console.log(JSON.stringify({ error: `File not found: ${file}` }));
34
+ }
35
+ else {
36
+ console.error(`Error: File not found: ${file}`);
37
+ }
38
+ process.exit(1);
39
+ }
40
+ let manifest;
41
+ try {
42
+ const raw = readFileSync(file, "utf-8");
43
+ manifest = parseManifest(raw);
44
+ }
45
+ catch (err) {
46
+ const msg = err instanceof Error ? err.message : "Failed to parse manifest";
47
+ if (opts.json) {
48
+ console.log(JSON.stringify({ error: msg }));
49
+ }
50
+ else {
51
+ console.error(`Error: ${msg}`);
52
+ }
53
+ process.exit(1);
54
+ }
55
+ if (manifest.skills.length === 0) {
56
+ if (opts.json) {
57
+ console.log(JSON.stringify({ installed: [], skipped: [], failed: [], message: "No skills in manifest" }));
58
+ }
59
+ else {
60
+ console.log("No skills found in manifest.");
61
+ }
62
+ return;
63
+ }
64
+ const config = loadConfig();
65
+ const installed = [];
66
+ const skipped = [];
67
+ const failed = [];
68
+ const errors = {};
69
+ for (const entry of manifest.skills) {
70
+ // Validate skill name
71
+ try {
72
+ validateSlug(entry.name, "skill name");
73
+ }
74
+ catch (err) {
75
+ const msg = err instanceof Error ? err.message : "Invalid skill name";
76
+ failed.push(entry.name);
77
+ errors[entry.name] = msg;
78
+ if (!opts.json) {
79
+ console.error(`Skipping ${entry.name}: ${msg}`);
80
+ }
81
+ continue;
82
+ }
83
+ // Check if already installed (skip unless --force)
84
+ const { isSkillInstalled } = await import("../utils/fs.js");
85
+ if (isSkillInstalled(entry.name) && !opts.force) {
86
+ skipped.push(entry.name);
87
+ continue;
88
+ }
89
+ // Fetch and install
90
+ try {
91
+ const providerName = entry.source ?? config.defaultProvider;
92
+ const provider = getProvider(providerName);
93
+ const files = await provider.fetch(entry.name);
94
+ installSkill(entry.name, files);
95
+ const remote = await provider.info(entry.name);
96
+ const version = remote?.version ?? entry.version ?? "0.0.0";
97
+ writeSkillMeta(entry.name, {
98
+ version,
99
+ installedAt: new Date().toISOString(),
100
+ source: provider.name,
101
+ description: remote?.description ?? entry.description,
102
+ fileCount: files.length,
103
+ sizeBytes: files.reduce((s, f) => s + f.content.length, 0),
104
+ });
105
+ updateLockEntry(entry.name, version, provider.name, files);
106
+ installed.push(entry.name);
107
+ if (!opts.json) {
108
+ console.log(`Installed ${entry.name}`);
109
+ }
110
+ }
111
+ catch (err) {
112
+ const msg = err instanceof Error ? err.message : "unknown error";
113
+ failed.push(entry.name);
114
+ errors[entry.name] = msg;
115
+ if (!opts.json) {
116
+ console.error(`Failed to install ${entry.name}: ${msg}`);
117
+ }
118
+ }
119
+ }
120
+ if (opts.json) {
121
+ const result = { installed, skipped, failed };
122
+ if (Object.keys(errors).length > 0)
123
+ result.errors = errors;
124
+ console.log(JSON.stringify(result));
125
+ }
126
+ else {
127
+ console.log(`Import complete: ${installed.length} installed, ${skipped.length} skipped, ${failed.length} failed`);
128
+ }
129
+ if (failed.length > 0)
130
+ process.exit(1);
131
+ }
@@ -2,4 +2,3 @@ export declare function infoCommand(skillName: string, opts: {
2
2
  provider?: string;
3
3
  json?: boolean;
4
4
  }): Promise<void>;
5
- //# sourceMappingURL=info.d.ts.map
@@ -39,7 +39,12 @@ export async function infoCommand(skillName, opts) {
39
39
  installedVersion: meta?.version,
40
40
  source: skill.source,
41
41
  repo: skill.repo,
42
- }
42
+ tags: skill.tags,
43
+ verified: skill.verified,
44
+ author: skill.author,
45
+ companions: skill.companions,
46
+ conflicts: skill.conflicts,
47
+ },
43
48
  }));
44
49
  return;
45
50
  }
@@ -47,11 +52,32 @@ export async function infoCommand(skillName, opts) {
47
52
  if (installed) {
48
53
  const meta = readSkillMeta(skillName);
49
54
  const localVersion = meta?.version ?? "unknown";
50
- console.log(" " + ui.success("Installed") + (localVersion !== skill.version ? ui.warn(` (local: v${localVersion})`) : ""));
55
+ console.log(" " +
56
+ ui.success("Installed") +
57
+ (localVersion !== skill.version ? ui.warn(` (local: v${localVersion})`) : ""));
51
58
  }
52
59
  console.log();
53
60
  console.log(" " + skill.description);
54
61
  console.log();
62
+ if (skill.verified) {
63
+ console.log(" " + ui.success("[Verified]") + " Official skill");
64
+ }
65
+ else {
66
+ console.log(ui.dim(" Community skill"));
67
+ }
68
+ if (skill.author) {
69
+ console.log(ui.dim(` Author: ${skill.author}`));
70
+ }
71
+ if (skill.tags && skill.tags.length > 0) {
72
+ console.log(ui.dim(` Tags: ${skill.tags.join(", ")}`));
73
+ }
74
+ if (skill.companions && skill.companions.length > 0) {
75
+ console.log(ui.dim(` Works with: ${skill.companions.join(", ")}`));
76
+ }
77
+ if (skill.conflicts && skill.conflicts.length > 0) {
78
+ console.log(ui.warn(` Conflicts: ${skill.conflicts.join(", ")}`));
79
+ }
80
+ console.log();
55
81
  console.log(ui.dim(` Source: ${skill.source}`));
56
82
  if (skill.repo) {
57
83
  console.log(ui.dim(` Repo: ${skill.repo}`));
@@ -77,7 +103,7 @@ export async function infoCommand(skillName, opts) {
77
103
  installed: true,
78
104
  source: meta?.source ?? "local",
79
105
  offline: true,
80
- }
106
+ },
81
107
  }));
82
108
  return;
83
109
  }
@@ -111,4 +137,3 @@ export async function infoCommand(skillName, opts) {
111
137
  }
112
138
  process.exit(1);
113
139
  }
114
- //# sourceMappingURL=info.js.map
@@ -10,4 +10,3 @@ export declare function initCommand(opts: {
10
10
  tool?: string;
11
11
  }): Promise<void>;
12
12
  export {};
13
- //# sourceMappingURL=init.d.ts.map
@@ -1,139 +1,122 @@
1
1
  import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
2
- import { join, basename, dirname } from "node:path";
2
+ import { join, dirname } from "node:path";
3
3
  import * as p from "@clack/prompts";
4
4
  import chalk from "chalk";
5
5
  import { renderBanner } from "../utils/help.js";
6
+ import { detectProjectContext } from "../utils/project-context.js";
6
7
  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" };
8
+ const ctx = detectProjectContext(cwd);
9
+ return { name: ctx.name, type: ctx.type, lang: ctx.lang };
27
10
  }
28
11
  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 -->
12
+ return `# CLAUDE.md - ${proj.name}
13
+
14
+ ## Project
15
+ - **Type:** ${proj.type}
16
+ - **Language:** ${proj.lang}
17
+
18
+ ## Coding Preferences
19
+ - Follow existing patterns in the codebase
20
+ - Handle errors explicitly
21
+ - Use meaningful variable names, no abbreviations
22
+
23
+ ## Build & Test
24
+ <!-- Add build/test commands so Claude can verify changes -->
25
+ <!-- Example: npm test, go test ./..., pytest -->
26
+
27
+ ## Project Structure
28
+ <!-- Describe your project structure here -->
46
29
  `;
47
30
  }
48
31
  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
32
+ return `---
33
+ description: Project conventions for ${proj.name}
34
+ globs:
35
+ ---
36
+
37
+ # ${proj.name} (${proj.type})
38
+
39
+ ## Language
40
+ ${proj.lang}
41
+
42
+ ## Coding Standards
43
+ - Follow existing patterns in the codebase
44
+ - Handle errors explicitly
45
+ - Use meaningful variable names
63
46
  `;
64
47
  }
65
48
  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
49
+ return `# AGENTS.md - ${proj.name}
50
+
51
+ ## Project
52
+ Type: ${proj.type} | Language: ${proj.lang}
53
+
54
+ ## Sandbox
55
+ Codex runs in a sandboxed environment with no network access.
56
+ All dependencies must be pre-installed before the session.
57
+
58
+ ## Guidelines
59
+ - Follow existing patterns in the codebase
60
+ - Handle errors explicitly
61
+ - Use meaningful variable names
79
62
  `;
80
63
  }
81
64
  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
65
+ return `# GEMINI.md - ${proj.name}
66
+
67
+ ## Project Context
68
+ This is a ${proj.type} project using ${proj.lang}.
69
+
70
+ ## Project Files
71
+ <!-- List key files and directories so Gemini can navigate the codebase -->
72
+ <!-- Example: src/ - main source, tests/ - test files -->
73
+
74
+ ## Instructions
75
+ - Follow existing patterns in the codebase
76
+ - Handle errors explicitly
77
+ - Use meaningful variable names
95
78
  `;
96
79
  }
97
80
  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
81
+ return `# Antigravity - ${proj.name}
82
+
83
+ ## Project Context
84
+ This is a ${proj.type} project using ${proj.lang}.
85
+ Antigravity workspace: \`.agent/\` (rules, workflows, skills)
86
+
87
+ ## Project Files
88
+ <!-- List key files and directories so the agent 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
112
95
  `;
113
96
  }
114
97
  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
98
+ return `# Windsurf Cascades Rules - ${proj.name}
99
+
100
+ Project: ${proj.name} (${proj.type})
101
+ Language: ${proj.lang}
102
+
103
+ ## Rules
104
+ - Follow existing patterns in the codebase
105
+ - Handle errors explicitly
106
+ - Use meaningful variable names
107
+ - Always explain changes before applying them
125
108
  `;
126
109
  }
127
110
  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
111
+ return `# Aider Configuration
112
+ model: sonnet
113
+ auto-commits: true
114
+ auto-test: false
115
+ # Add conventions below
116
+ conventions:
117
+ - Follow existing patterns in the codebase
118
+ - Write clean, maintainable code
119
+ - Handle errors explicitly
137
120
  `;
138
121
  }
139
122
  const TOOL_FILES = {
@@ -150,14 +133,19 @@ const TOOL_FILES = {
150
133
  aider: { path: ".aider.conf.yml", template: aiderTemplate, label: "Aider" },
151
134
  };
152
135
  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"],
136
+ Go: ["golang-pro", "go-linter-configuration", "testing-strategy", "security-review"],
137
+ Rust: ["rust-best-practices", "testing-strategy", "security-review"],
138
+ Python: ["python-best-practices", "testing-strategy", "security-review"],
156
139
  "Next.js": ["typescript", "typescript-advanced", "frontend-design", "performance-optimization", "security-review"],
157
- "React": ["typescript", "frontend-design", "frontend-code-review", "testing-strategy"],
140
+ React: ["typescript", "frontend-design", "frontend-code-review", "testing-strategy"],
158
141
  "Node.js": ["typescript", "npm-package", "testing-strategy", "security-review"],
159
142
  };
160
- export const SKILL_SUGGESTIONS_DEFAULT = ["code-reviewer", "security-review", "codebase-dissection", "testing-strategy"];
143
+ export const SKILL_SUGGESTIONS_DEFAULT = [
144
+ "code-reviewer",
145
+ "security-review",
146
+ "codebase-dissection",
147
+ "testing-strategy",
148
+ ];
161
149
  export async function initCommand(opts) {
162
150
  console.log(renderBanner());
163
151
  console.log();
@@ -208,9 +196,60 @@ export async function initCommand(opts) {
208
196
  }
209
197
  if (skipped > 0)
210
198
  p.log.info(`${skipped} skipped (already exist)`);
199
+ // Offer to install PreCompact hook for context preservation
200
+ const globalSettings = join(process.env.HOME || process.env.USERPROFILE || "", ".claude", "settings.json");
201
+ let hasPreCompactHook = false;
202
+ if (existsSync(globalSettings)) {
203
+ try {
204
+ const settings = JSON.parse(readFileSync(globalSettings, "utf-8"));
205
+ hasPreCompactHook = Array.isArray(settings?.hooks?.PreCompact) && settings.hooks.PreCompact.length > 0;
206
+ }
207
+ catch {
208
+ /* ignore */
209
+ }
210
+ }
211
+ if (!hasPreCompactHook) {
212
+ const installHook = await p.confirm({
213
+ message: "Install PreCompact hook? (preserves context before auto-compaction)",
214
+ initialValue: true,
215
+ });
216
+ if (p.isCancel(installHook)) {
217
+ p.cancel("Cancelled");
218
+ process.exit(0);
219
+ }
220
+ if (installHook) {
221
+ try {
222
+ let settings = {};
223
+ if (existsSync(globalSettings)) {
224
+ settings = JSON.parse(readFileSync(globalSettings, "utf-8"));
225
+ }
226
+ const hooks = (settings.hooks ?? {});
227
+ hooks.PreCompact = [
228
+ {
229
+ matcher: "",
230
+ hooks: [
231
+ {
232
+ type: "command",
233
+ command: 'bash -c \'PROJ_DIR="$HOME/.claude/projects"; for d in "$PROJ_DIR"/*/memory; do if [ -d "$d" ]; then echo "## Handover $(date +%Y-%m-%d_%H%M)" >> "$d/HANDOVER.md"; echo "Auto-compaction triggered. Review MEMORY.md for preserved context." >> "$d/HANDOVER.md"; echo "" >> "$d/HANDOVER.md"; fi; done\'',
234
+ timeout: 10,
235
+ },
236
+ ],
237
+ },
238
+ ];
239
+ settings.hooks = hooks;
240
+ writeFileSync(globalSettings, JSON.stringify(settings, null, 2) + "\n", "utf-8");
241
+ p.log.success("Installed PreCompact hook in ~/.claude/settings.json");
242
+ }
243
+ catch (err) {
244
+ p.log.warn(`Could not install hook: ${err instanceof Error ? err.message : "unknown"}`);
245
+ }
246
+ }
247
+ }
248
+ else {
249
+ p.log.info("PreCompact hook already installed");
250
+ }
211
251
  const suggestions = SKILL_SUGGESTIONS[proj.type] || SKILL_SUGGESTIONS_DEFAULT;
212
252
  const skillList = suggestions.map((s) => `arcana install ${s}`).join("\n");
213
253
  p.note(skillList, "Recommended skills");
214
254
  p.outro(`Next: ${chalk.cyan("arcana install <skill>")} or ${chalk.cyan("arcana install --all")}`);
215
255
  }
216
- //# sourceMappingURL=init.js.map
@@ -4,5 +4,5 @@ export declare function installCommand(skillNames: string[], opts: {
4
4
  force?: boolean;
5
5
  dryRun?: boolean;
6
6
  json?: boolean;
7
+ noCheck?: boolean;
7
8
  }): Promise<void>;
8
- //# sourceMappingURL=install.d.ts.map