@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
@@ -3,6 +3,7 @@ import { join } from "node:path";
3
3
  import { homedir } from "node:os";
4
4
  import { ui, banner } from "../utils/ui.js";
5
5
  import { getDirSize } from "../utils/fs.js";
6
+ import { PRUNE_DEFAULT_DAYS, PRUNE_SIZE_THRESHOLD_BYTES, PRUNE_KEEP_NEWEST } from "../constants.js";
6
7
  function analyzeProject(projDir, projName) {
7
8
  const now = Date.now();
8
9
  const mainFiles = [];
@@ -40,12 +41,11 @@ function analyzeProject(projDir, projName) {
40
41
  continue;
41
42
  }
42
43
  }
43
- const totalBytes = mainFiles.reduce((s, f) => s + f.sizeBytes, 0)
44
- + agentFiles.reduce((s, f) => s + f.sizeBytes, 0)
45
- + sessionDirs.reduce((s, d) => s + d.sizeBytes, 0);
44
+ const totalBytes = mainFiles.reduce((s, f) => s + f.sizeBytes, 0) +
45
+ agentFiles.reduce((s, f) => s + f.sizeBytes, 0) +
46
+ sessionDirs.reduce((s, d) => s + d.sizeBytes, 0);
46
47
  // Reclaimable: all agent files + all session dirs
47
- const reclaimableBytes = agentFiles.reduce((s, f) => s + f.sizeBytes, 0)
48
- + sessionDirs.reduce((s, d) => s + d.sizeBytes, 0);
48
+ const reclaimableBytes = agentFiles.reduce((s, f) => s + f.sizeBytes, 0) + sessionDirs.reduce((s, d) => s + d.sizeBytes, 0);
49
49
  return { name: projName, mainFiles, agentFiles, sessionDirs, totalBytes, reclaimableBytes };
50
50
  }
51
51
  function formatBytes(bytes) {
@@ -57,6 +57,39 @@ function formatBytes(bytes) {
57
57
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
58
58
  return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
59
59
  }
60
+ /**
61
+ * Prune oversized main session files.
62
+ * Targets files older than pruneDays AND larger than 10 MB.
63
+ * Always keeps the 3 newest sessions per project regardless.
64
+ */
65
+ function pruneMainSessions(analyses, projectsDir, pruneDays, dryRun, json) {
66
+ const pruned = [];
67
+ let reclaimedBytes = 0;
68
+ for (const a of analyses) {
69
+ // Sort main files by age (newest first) to protect the 3 newest
70
+ const sorted = [...a.mainFiles].sort((x, y) => x.daysOld - y.daysOld);
71
+ const candidates = sorted.slice(PRUNE_KEEP_NEWEST); // Skip the 3 newest
72
+ for (const f of candidates) {
73
+ if (f.daysOld > pruneDays && f.sizeBytes > PRUNE_SIZE_THRESHOLD_BYTES) {
74
+ const sizeMB = (f.sizeBytes / (1024 * 1024)).toFixed(1);
75
+ if (!json) {
76
+ console.log(` ${ui.warn("Prune:")} ${f.name} ${ui.dim(`(${sizeMB} MB, ${f.daysOld}d old)`)}`);
77
+ }
78
+ if (!dryRun) {
79
+ try {
80
+ rmSync(join(projectsDir, a.name, f.name), { force: true });
81
+ }
82
+ catch {
83
+ /* skip */
84
+ }
85
+ }
86
+ pruned.push({ project: a.name, file: f.name, sizeMB, daysOld: f.daysOld });
87
+ reclaimedBytes += f.sizeBytes;
88
+ }
89
+ }
90
+ }
91
+ return { pruned, reclaimedBytes };
92
+ }
60
93
  export async function compactCommand(opts) {
61
94
  if (!opts.json)
62
95
  banner();
@@ -89,7 +122,7 @@ export async function compactCommand(opts) {
89
122
  analyses.sort((a, b) => b.totalBytes - a.totalBytes);
90
123
  if (opts.json) {
91
124
  const jsonResult = {
92
- projects: analyses.map(a => ({
125
+ projects: analyses.map((a) => ({
93
126
  name: a.name,
94
127
  totalBytes: a.totalBytes,
95
128
  reclaimableBytes: a.reclaimableBytes,
@@ -99,7 +132,6 @@ export async function compactCommand(opts) {
99
132
  })),
100
133
  totalReclaimed: dryRun ? 0 : analyses.reduce((s, a) => s + a.reclaimableBytes, 0),
101
134
  };
102
- console.log(JSON.stringify(jsonResult, null, 2));
103
135
  if (!dryRun) {
104
136
  for (const a of analyses) {
105
137
  const projDir = join(projectsDir, a.name);
@@ -107,22 +139,36 @@ export async function compactCommand(opts) {
107
139
  try {
108
140
  rmSync(join(projDir, f.name), { force: true });
109
141
  }
110
- catch { /* skip */ }
142
+ catch {
143
+ /* skip */
144
+ }
111
145
  }
112
146
  for (const d of a.sessionDirs) {
113
147
  try {
114
148
  rmSync(join(projDir, d.name), { recursive: true, force: true });
115
149
  }
116
- catch { /* skip */ }
150
+ catch {
151
+ /* skip */
152
+ }
117
153
  }
118
154
  }
119
155
  }
156
+ if (opts.prune) {
157
+ const pruneDays = opts.pruneDays ?? PRUNE_DEFAULT_DAYS;
158
+ const pruneResult = pruneMainSessions(analyses, projectsDir, pruneDays, dryRun, true);
159
+ jsonResult.pruned = pruneResult.pruned;
160
+ jsonResult.prunedBytes = pruneResult.reclaimedBytes;
161
+ if (!dryRun) {
162
+ jsonResult.totalReclaimed = jsonResult.totalReclaimed + pruneResult.reclaimedBytes;
163
+ }
164
+ }
165
+ console.log(JSON.stringify(jsonResult, null, 2));
120
166
  return;
121
167
  }
122
168
  if (!opts.json)
123
169
  console.log(ui.bold(" Session Compaction Report\n"));
124
170
  let totalReclaimed = 0;
125
- const hasWork = analyses.some(a => a.reclaimableBytes > 0);
171
+ const hasWork = analyses.some((a) => a.reclaimableBytes > 0);
126
172
  for (const a of analyses) {
127
173
  if (a.totalBytes < 1024)
128
174
  continue; // Skip tiny projects
@@ -141,7 +187,9 @@ export async function compactCommand(opts) {
141
187
  try {
142
188
  rmSync(join(projDir, f.name), { force: true });
143
189
  }
144
- catch { /* skip */ }
190
+ catch {
191
+ /* skip */
192
+ }
145
193
  }
146
194
  }
147
195
  totalReclaimed += agentSize;
@@ -157,7 +205,9 @@ export async function compactCommand(opts) {
157
205
  try {
158
206
  rmSync(join(projDir, d.name), { recursive: true, force: true });
159
207
  }
160
- catch { /* skip */ }
208
+ catch {
209
+ /* skip */
210
+ }
161
211
  }
162
212
  }
163
213
  totalReclaimed += dirSize;
@@ -165,8 +215,19 @@ export async function compactCommand(opts) {
165
215
  }
166
216
  console.log();
167
217
  }
218
+ // Prune oversized main sessions if requested
219
+ if (opts.prune) {
220
+ const pruneDays = opts.pruneDays ?? PRUNE_DEFAULT_DAYS;
221
+ console.log(ui.bold(` Pruning main sessions (>${pruneDays}d old AND >10 MB, keeping 3 newest per project)\n`));
222
+ const pruneResult = pruneMainSessions(analyses, projectsDir, pruneDays, dryRun, false);
223
+ totalReclaimed += pruneResult.reclaimedBytes;
224
+ if (pruneResult.pruned.length === 0) {
225
+ console.log(ui.dim(" No oversized sessions to prune."));
226
+ }
227
+ console.log();
228
+ }
168
229
  // Summary
169
- if (!hasWork) {
230
+ if (!hasWork && !opts.prune) {
170
231
  console.log(ui.success(" Already compact. No agent logs to remove."));
171
232
  }
172
233
  else {
@@ -176,4 +237,3 @@ export async function compactCommand(opts) {
176
237
  }
177
238
  console.log();
178
239
  }
179
- //# sourceMappingURL=compact.js.map
@@ -0,0 +1,3 @@
1
+ export declare function completionsCommand(shell: string, opts: {
2
+ json?: boolean;
3
+ }): void;
@@ -0,0 +1,104 @@
1
+ const BASH_COMPLETIONS = `# arcana bash completion
2
+ _arcana_completions() {
3
+ local cur="\${COMP_WORDS[COMP_CWORD]}"
4
+ local commands="list install info search providers create validate update uninstall init doctor clean compact stats config audit scan optimize verify lock profile benchmark diff outdated team export import completions"
5
+
6
+ if [ "\${COMP_CWORD}" -eq 1 ]; then
7
+ COMPREPLY=( $(compgen -W "\${commands}" -- "\${cur}") )
8
+ fi
9
+ }
10
+ complete -F _arcana_completions arcana
11
+ `;
12
+ const ZSH_COMPLETIONS = `#compdef arcana
13
+ _arcana() {
14
+ local -a commands
15
+ commands=(
16
+ 'list:List available skills'
17
+ 'install:Install one or more skills'
18
+ 'info:Show skill details'
19
+ 'search:Search for skills'
20
+ 'providers:Manage skill providers'
21
+ 'create:Create a new skill'
22
+ 'validate:Validate skill structure'
23
+ 'update:Update installed skills'
24
+ 'uninstall:Uninstall skills'
25
+ 'init:Initialize arcana in project'
26
+ 'doctor:Check environment'
27
+ 'clean:Remove orphaned data'
28
+ 'compact:Remove agent logs'
29
+ 'stats:Show session analytics'
30
+ 'config:View or modify config'
31
+ 'audit:Audit skill quality'
32
+ 'scan:Scan for security threats'
33
+ 'optimize:Suggest improvements'
34
+ 'verify:Verify skill integrity'
35
+ 'lock:Manage lockfile'
36
+ 'profile:Manage skill profiles'
37
+ 'benchmark:Measure token cost'
38
+ 'diff:Show skill changes'
39
+ 'outdated:List outdated skills'
40
+ 'team:Team skill management'
41
+ 'export:Export skill manifest'
42
+ 'import:Import skills'
43
+ 'completions:Generate shell completions'
44
+ )
45
+ _describe 'command' commands
46
+ }
47
+ _arcana
48
+ `;
49
+ const FISH_COMPLETIONS = `# arcana fish completion
50
+ set -l commands list install info search providers create validate update uninstall init doctor clean compact stats config audit scan optimize verify lock profile benchmark diff outdated team export import completions
51
+ complete -c arcana -f
52
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a list -d "List available skills"
53
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a install -d "Install skills"
54
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a info -d "Show skill details"
55
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a search -d "Search for skills"
56
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a providers -d "Manage providers"
57
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a create -d "Create a skill"
58
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a validate -d "Validate skills"
59
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a update -d "Update skills"
60
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a uninstall -d "Uninstall skills"
61
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a init -d "Initialize arcana"
62
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a doctor -d "Check environment"
63
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a clean -d "Remove orphaned data"
64
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a compact -d "Remove agent logs"
65
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a stats -d "Session analytics"
66
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a config -d "View/modify config"
67
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a audit -d "Audit skill quality"
68
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a scan -d "Security scan"
69
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a optimize -d "Suggest improvements"
70
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a verify -d "Verify integrity"
71
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a lock -d "Manage lockfile"
72
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a profile -d "Skill profiles"
73
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a benchmark -d "Measure token cost"
74
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a diff -d "Show skill changes"
75
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a outdated -d "List outdated skills"
76
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a team -d "Team management"
77
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a export -d "Export manifest"
78
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a import -d "Import skills"
79
+ complete -c arcana -n "not __fish_seen_subcommand_from $commands" -a completions -d "Shell completions"
80
+ `;
81
+ const SHELLS = {
82
+ bash: BASH_COMPLETIONS,
83
+ zsh: ZSH_COMPLETIONS,
84
+ fish: FISH_COMPLETIONS,
85
+ };
86
+ export function completionsCommand(shell, opts) {
87
+ const supported = Object.keys(SHELLS);
88
+ if (!supported.includes(shell)) {
89
+ if (opts.json) {
90
+ console.log(JSON.stringify({ error: `Unsupported shell: ${shell}`, supported }));
91
+ }
92
+ else {
93
+ console.error(`Unsupported shell: ${shell}`);
94
+ console.error(`Supported: ${supported.join(", ")}`);
95
+ }
96
+ process.exit(1);
97
+ }
98
+ if (opts.json) {
99
+ console.log(JSON.stringify({ shell, script: SHELLS[shell] }));
100
+ }
101
+ else {
102
+ console.log(SHELLS[shell]);
103
+ }
104
+ }
@@ -1,4 +1,3 @@
1
1
  export declare function configCommand(action: string | undefined, value: string | undefined, opts?: {
2
2
  json?: boolean;
3
3
  }): Promise<void>;
4
- //# sourceMappingURL=config.d.ts.map
@@ -20,9 +20,15 @@ export async function configCommand(action, value, opts) {
20
20
  const envInstallDir = process.env.ARCANA_INSTALL_DIR;
21
21
  const envProvider = process.env.ARCANA_DEFAULT_PROVIDER;
22
22
  const rows = [
23
- [ui.dim("defaultProvider"), config.defaultProvider + (envProvider ? ` ${ui.warn("(overridden by ARCANA_DEFAULT_PROVIDER)")}` : "")],
24
- [ui.dim("installDir"), config.installDir + (envInstallDir ? ` ${ui.warn("(overridden by ARCANA_INSTALL_DIR)")}` : "")],
25
- [ui.dim("providers"), config.providers.map(p => p.name).join(", ")],
23
+ [
24
+ ui.dim("defaultProvider"),
25
+ config.defaultProvider + (envProvider ? ` ${ui.warn("(overridden by ARCANA_DEFAULT_PROVIDER)")}` : ""),
26
+ ],
27
+ [
28
+ ui.dim("installDir"),
29
+ config.installDir + (envInstallDir ? ` ${ui.warn("(overridden by ARCANA_INSTALL_DIR)")}` : ""),
30
+ ],
31
+ [ui.dim("providers"), config.providers.map((p) => p.name).join(", ")],
26
32
  ];
27
33
  table(rows);
28
34
  console.log();
@@ -58,7 +64,11 @@ export async function configCommand(action, value, opts) {
58
64
  }
59
65
  catch (err) {
60
66
  if (opts?.json) {
61
- console.log(JSON.stringify({ action: "reset", success: false, error: err instanceof Error ? err.message : "Failed to remove config" }));
67
+ console.log(JSON.stringify({
68
+ action: "reset",
69
+ success: false,
70
+ error: err instanceof Error ? err.message : "Failed to remove config",
71
+ }));
62
72
  }
63
73
  else {
64
74
  console.log(ui.error(` Failed to reset config: ${err instanceof Error ? err.message : "unknown error"}`));
@@ -115,7 +125,7 @@ export async function configCommand(action, value, opts) {
115
125
  }
116
126
  }
117
127
  if (key === "defaultProvider") {
118
- const providerNames = config.providers.map(p => p.name);
128
+ const providerNames = config.providers.map((p) => p.name);
119
129
  if (!providerNames.includes(value)) {
120
130
  console.log(ui.error(` Provider '${value}' not configured. Add it first with: arcana providers --add owner/repo`));
121
131
  console.log();
@@ -132,4 +142,3 @@ export async function configCommand(action, value, opts) {
132
142
  console.log();
133
143
  }
134
144
  }
135
- //# sourceMappingURL=config.js.map
@@ -1,2 +1 @@
1
1
  export declare function createCommand(name: string): Promise<void>;
2
- //# sourceMappingURL=create.d.ts.map
@@ -65,6 +65,7 @@ export async function createCommand(name) {
65
65
  return "Description is required";
66
66
  if (val.length < 10)
67
67
  return "Too short (minimum 10 chars)";
68
+ return undefined;
68
69
  },
69
70
  });
70
71
  if (p.isCancel(description)) {
@@ -97,4 +98,3 @@ export async function createCommand(name) {
97
98
  p.log.info("Edit SKILL.md to add your skill instructions.");
98
99
  p.outro(`Next: ${chalk.cyan("arcana validate " + name)}`);
99
100
  }
100
- //# sourceMappingURL=create.js.map
@@ -0,0 +1,4 @@
1
+ export declare function diffCommand(skill: string, opts: {
2
+ provider?: string;
3
+ json?: boolean;
4
+ }): Promise<void>;
@@ -0,0 +1,166 @@
1
+ import { existsSync, readFileSync, readdirSync, lstatSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { getInstallDir, readSkillMeta } from "../utils/fs.js";
4
+ import { getProvider } from "../registry.js";
5
+ import { loadConfig } from "../utils/config.js";
6
+ import { validateSlug } from "../utils/validate.js";
7
+ function readDirRecursive(dir) {
8
+ const results = [];
9
+ const queue = [{ fullDir: dir, relPrefix: "" }];
10
+ while (queue.length > 0) {
11
+ const { fullDir, relPrefix } = queue.pop();
12
+ let entries;
13
+ try {
14
+ entries = readdirSync(fullDir);
15
+ }
16
+ catch {
17
+ continue;
18
+ }
19
+ for (const entry of entries) {
20
+ const fullPath = join(fullDir, entry);
21
+ try {
22
+ const stat = lstatSync(fullPath);
23
+ if (stat.isSymbolicLink())
24
+ continue;
25
+ const relPath = relPrefix ? `${relPrefix}/${entry}` : entry;
26
+ if (stat.isDirectory()) {
27
+ queue.push({ fullDir: fullPath, relPrefix: relPath });
28
+ }
29
+ else {
30
+ results.push({
31
+ path: relPath,
32
+ content: readFileSync(fullPath, "utf-8"),
33
+ });
34
+ }
35
+ }
36
+ catch {
37
+ // skip unreadable entries
38
+ }
39
+ }
40
+ }
41
+ return results;
42
+ }
43
+ function computeLineDiff(localContent, remoteContent) {
44
+ const localLines = localContent.split("\n");
45
+ const remoteLines = remoteContent.split("\n");
46
+ const localSet = new Set(localLines);
47
+ const remoteSet = new Set(remoteLines);
48
+ let linesAdded = 0;
49
+ let linesRemoved = 0;
50
+ for (const line of remoteLines) {
51
+ if (!localSet.has(line)) {
52
+ linesAdded++;
53
+ }
54
+ }
55
+ for (const line of localLines) {
56
+ if (!remoteSet.has(line)) {
57
+ linesRemoved++;
58
+ }
59
+ }
60
+ return { linesAdded, linesRemoved };
61
+ }
62
+ export async function diffCommand(skill, opts) {
63
+ try {
64
+ validateSlug(skill, "skill name");
65
+ }
66
+ catch (err) {
67
+ console.error(err instanceof Error ? err.message : "Invalid skill name");
68
+ process.exit(1);
69
+ }
70
+ const installDir = getInstallDir();
71
+ const skillDir = join(installDir, skill);
72
+ if (!existsSync(skillDir)) {
73
+ console.error(`Skill "${skill}" is not installed.`);
74
+ process.exit(1);
75
+ }
76
+ const providerName = opts.provider ?? loadConfig().defaultProvider;
77
+ const provider = getProvider(providerName);
78
+ let remoteFiles;
79
+ try {
80
+ remoteFiles = await provider.fetch(skill);
81
+ }
82
+ catch (err) {
83
+ console.error(`Failed to fetch remote skill "${skill}": ${err instanceof Error ? err.message : "unknown error"}`);
84
+ process.exit(1);
85
+ }
86
+ const localFiles = readDirRecursive(skillDir);
87
+ const meta = readSkillMeta(skill);
88
+ const localVersion = meta?.version ?? "0.0.0";
89
+ let remoteVersion = "0.0.0";
90
+ try {
91
+ const remoteInfo = await provider.info(skill);
92
+ if (remoteInfo) {
93
+ remoteVersion = remoteInfo.version;
94
+ }
95
+ }
96
+ catch {
97
+ // keep default
98
+ }
99
+ const localMap = new Map();
100
+ for (const file of localFiles) {
101
+ localMap.set(file.path, file.content);
102
+ }
103
+ const remoteMap = new Map();
104
+ for (const file of remoteFiles) {
105
+ remoteMap.set(file.path, file.content);
106
+ }
107
+ const added = [];
108
+ const removed = [];
109
+ const modified = [];
110
+ for (const [path] of remoteMap) {
111
+ if (!localMap.has(path)) {
112
+ added.push(path);
113
+ }
114
+ }
115
+ for (const [path] of localMap) {
116
+ if (!remoteMap.has(path)) {
117
+ removed.push(path);
118
+ }
119
+ }
120
+ for (const [path, remoteContent] of remoteMap) {
121
+ const localContent = localMap.get(path);
122
+ if (localContent !== undefined && localContent !== remoteContent) {
123
+ const { linesAdded, linesRemoved } = computeLineDiff(localContent, remoteContent);
124
+ modified.push({ path, linesAdded, linesRemoved });
125
+ }
126
+ }
127
+ const result = {
128
+ skill,
129
+ localVersion,
130
+ remoteVersion,
131
+ added,
132
+ removed,
133
+ modified,
134
+ };
135
+ if (opts.json) {
136
+ console.log(JSON.stringify(result, null, 2));
137
+ return;
138
+ }
139
+ // Console output
140
+ console.log(`Diff: ${skill}`);
141
+ console.log(` Local version: ${localVersion}`);
142
+ console.log(` Remote version: ${remoteVersion}`);
143
+ console.log();
144
+ if (added.length === 0 && removed.length === 0 && modified.length === 0) {
145
+ console.log(" No differences found.");
146
+ return;
147
+ }
148
+ if (added.length > 0) {
149
+ console.log(` Added (${added.length}):`);
150
+ for (const path of added) {
151
+ console.log(` + ${path}`);
152
+ }
153
+ }
154
+ if (removed.length > 0) {
155
+ console.log(` Removed (${removed.length}):`);
156
+ for (const path of removed) {
157
+ console.log(` - ${path}`);
158
+ }
159
+ }
160
+ if (modified.length > 0) {
161
+ console.log(` Modified (${modified.length}):`);
162
+ for (const entry of modified) {
163
+ console.log(` ~ ${entry.path} (+${entry.linesAdded} / -${entry.linesRemoved})`);
164
+ }
165
+ }
166
+ }
@@ -3,4 +3,3 @@ export declare function runDoctorChecks(): DoctorCheck[];
3
3
  export declare function doctorCommand(opts?: {
4
4
  json?: boolean;
5
5
  }): Promise<void>;
6
- //# sourceMappingURL=doctor.d.ts.map