superskill 0.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 (301) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/LICENSE +21 -0
  3. package/README.md +235 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +1158 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/brainstorm.d.ts +9 -0
  8. package/dist/commands/brainstorm.js +37 -0
  9. package/dist/commands/brainstorm.js.map +1 -0
  10. package/dist/commands/brainstorm.test.d.ts +1 -0
  11. package/dist/commands/brainstorm.test.js +110 -0
  12. package/dist/commands/brainstorm.test.js.map +1 -0
  13. package/dist/commands/context.d.ts +18 -0
  14. package/dist/commands/context.js +88 -0
  15. package/dist/commands/context.js.map +1 -0
  16. package/dist/commands/context.test.d.ts +1 -0
  17. package/dist/commands/context.test.js +230 -0
  18. package/dist/commands/context.test.js.map +1 -0
  19. package/dist/commands/decide.d.ts +12 -0
  20. package/dist/commands/decide.js +40 -0
  21. package/dist/commands/decide.js.map +1 -0
  22. package/dist/commands/decide.test.d.ts +1 -0
  23. package/dist/commands/decide.test.js +109 -0
  24. package/dist/commands/decide.test.js.map +1 -0
  25. package/dist/commands/graph.d.ts +15 -0
  26. package/dist/commands/graph.js +89 -0
  27. package/dist/commands/graph.js.map +1 -0
  28. package/dist/commands/graph.test.d.ts +1 -0
  29. package/dist/commands/graph.test.js +215 -0
  30. package/dist/commands/graph.test.js.map +1 -0
  31. package/dist/commands/init.d.ts +11 -0
  32. package/dist/commands/init.js +257 -0
  33. package/dist/commands/init.js.map +1 -0
  34. package/dist/commands/learn.d.ts +25 -0
  35. package/dist/commands/learn.js +92 -0
  36. package/dist/commands/learn.js.map +1 -0
  37. package/dist/commands/learn.test.d.ts +1 -0
  38. package/dist/commands/learn.test.js +241 -0
  39. package/dist/commands/learn.test.js.map +1 -0
  40. package/dist/commands/prune.d.ts +58 -0
  41. package/dist/commands/prune.js +246 -0
  42. package/dist/commands/prune.js.map +1 -0
  43. package/dist/commands/read.d.ts +8 -0
  44. package/dist/commands/read.js +7 -0
  45. package/dist/commands/read.js.map +1 -0
  46. package/dist/commands/read.test.d.ts +1 -0
  47. package/dist/commands/read.test.js +48 -0
  48. package/dist/commands/read.test.js.map +1 -0
  49. package/dist/commands/resume.d.ts +20 -0
  50. package/dist/commands/resume.js +141 -0
  51. package/dist/commands/resume.js.map +1 -0
  52. package/dist/commands/resume.test.d.ts +1 -0
  53. package/dist/commands/resume.test.js +243 -0
  54. package/dist/commands/resume.test.js.map +1 -0
  55. package/dist/commands/search.d.ts +8 -0
  56. package/dist/commands/search.js +25 -0
  57. package/dist/commands/search.js.map +1 -0
  58. package/dist/commands/search.test.d.ts +1 -0
  59. package/dist/commands/search.test.js +61 -0
  60. package/dist/commands/search.test.js.map +1 -0
  61. package/dist/commands/session.d.ts +22 -0
  62. package/dist/commands/session.js +79 -0
  63. package/dist/commands/session.js.map +1 -0
  64. package/dist/commands/session.test.d.ts +1 -0
  65. package/dist/commands/session.test.js +231 -0
  66. package/dist/commands/session.test.js.map +1 -0
  67. package/dist/commands/skill/catalog.d.ts +39 -0
  68. package/dist/commands/skill/catalog.js +260 -0
  69. package/dist/commands/skill/catalog.js.map +1 -0
  70. package/dist/commands/skill/index.d.ts +55 -0
  71. package/dist/commands/skill/index.js +82 -0
  72. package/dist/commands/skill/index.js.map +1 -0
  73. package/dist/commands/skill/index.test.d.ts +1 -0
  74. package/dist/commands/skill/index.test.js +137 -0
  75. package/dist/commands/skill/index.test.js.map +1 -0
  76. package/dist/commands/skill/install.d.ts +14 -0
  77. package/dist/commands/skill/install.js +108 -0
  78. package/dist/commands/skill/install.js.map +1 -0
  79. package/dist/commands/skill/install.test.d.ts +1 -0
  80. package/dist/commands/skill/install.test.js +225 -0
  81. package/dist/commands/skill/install.test.js.map +1 -0
  82. package/dist/commands/skill/list.d.ts +6 -0
  83. package/dist/commands/skill/list.js +5 -0
  84. package/dist/commands/skill/list.js.map +1 -0
  85. package/dist/commands/skill/list.test.d.ts +1 -0
  86. package/dist/commands/skill/list.test.js +101 -0
  87. package/dist/commands/skill/list.test.js.map +1 -0
  88. package/dist/commands/skill/marketplace.d.ts +121 -0
  89. package/dist/commands/skill/marketplace.js +548 -0
  90. package/dist/commands/skill/marketplace.js.map +1 -0
  91. package/dist/commands/skill/schema.d.ts +27 -0
  92. package/dist/commands/skill/schema.js +55 -0
  93. package/dist/commands/skill/schema.js.map +1 -0
  94. package/dist/commands/skill/schema.test.d.ts +1 -0
  95. package/dist/commands/skill/schema.test.js +142 -0
  96. package/dist/commands/skill/schema.test.js.map +1 -0
  97. package/dist/commands/skill/validate.d.ts +10 -0
  98. package/dist/commands/skill/validate.js +40 -0
  99. package/dist/commands/skill/validate.js.map +1 -0
  100. package/dist/commands/skill/validate.test.d.ts +1 -0
  101. package/dist/commands/skill/validate.test.js +171 -0
  102. package/dist/commands/skill/validate.test.js.map +1 -0
  103. package/dist/commands/task.d.ts +34 -0
  104. package/dist/commands/task.js +160 -0
  105. package/dist/commands/task.js.map +1 -0
  106. package/dist/commands/task.test.d.ts +1 -0
  107. package/dist/commands/task.test.js +395 -0
  108. package/dist/commands/task.test.js.map +1 -0
  109. package/dist/commands/todo.d.ts +15 -0
  110. package/dist/commands/todo.js +99 -0
  111. package/dist/commands/todo.js.map +1 -0
  112. package/dist/commands/todo.test.d.ts +1 -0
  113. package/dist/commands/todo.test.js +324 -0
  114. package/dist/commands/todo.test.js.map +1 -0
  115. package/dist/commands/write.d.ts +12 -0
  116. package/dist/commands/write.js +40 -0
  117. package/dist/commands/write.js.map +1 -0
  118. package/dist/commands/write.test.d.ts +1 -0
  119. package/dist/commands/write.test.js +79 -0
  120. package/dist/commands/write.test.js.map +1 -0
  121. package/dist/config.d.ts +15 -0
  122. package/dist/config.js +49 -0
  123. package/dist/config.js.map +1 -0
  124. package/dist/config.test.d.ts +1 -0
  125. package/dist/config.test.js +147 -0
  126. package/dist/config.test.js.map +1 -0
  127. package/dist/core/executor.d.ts +11 -0
  128. package/dist/core/executor.js +42 -0
  129. package/dist/core/executor.js.map +1 -0
  130. package/dist/core/executor.test.d.ts +1 -0
  131. package/dist/core/executor.test.js +206 -0
  132. package/dist/core/executor.test.js.map +1 -0
  133. package/dist/core/middleware/error-handler.d.ts +2 -0
  134. package/dist/core/middleware/error-handler.js +29 -0
  135. package/dist/core/middleware/error-handler.js.map +1 -0
  136. package/dist/core/middleware/index.d.ts +2 -0
  137. package/dist/core/middleware/index.js +3 -0
  138. package/dist/core/middleware/index.js.map +1 -0
  139. package/dist/core/middleware/logging.d.ts +2 -0
  140. package/dist/core/middleware/logging.js +18 -0
  141. package/dist/core/middleware/logging.js.map +1 -0
  142. package/dist/core/registry.d.ts +12 -0
  143. package/dist/core/registry.js +552 -0
  144. package/dist/core/registry.js.map +1 -0
  145. package/dist/core/registry.test.d.ts +1 -0
  146. package/dist/core/registry.test.js +213 -0
  147. package/dist/core/registry.test.js.map +1 -0
  148. package/dist/core/types.d.ts +38 -0
  149. package/dist/core/types.js +2 -0
  150. package/dist/core/types.js.map +1 -0
  151. package/dist/integration/coordination.test.d.ts +1 -0
  152. package/dist/integration/coordination.test.js +286 -0
  153. package/dist/integration/coordination.test.js.map +1 -0
  154. package/dist/integration/project-artifacts.test.d.ts +1 -0
  155. package/dist/integration/project-artifacts.test.js +275 -0
  156. package/dist/integration/project-artifacts.test.js.map +1 -0
  157. package/dist/integration/registry-graph.test.d.ts +1 -0
  158. package/dist/integration/registry-graph.test.js +157 -0
  159. package/dist/integration/registry-graph.test.js.map +1 -0
  160. package/dist/integration/vault-lifecycle.test.d.ts +1 -0
  161. package/dist/integration/vault-lifecycle.test.js +183 -0
  162. package/dist/integration/vault-lifecycle.test.js.map +1 -0
  163. package/dist/lib/auto-number.d.ts +10 -0
  164. package/dist/lib/auto-number.js +33 -0
  165. package/dist/lib/auto-number.js.map +1 -0
  166. package/dist/lib/auto-number.test.d.ts +1 -0
  167. package/dist/lib/auto-number.test.js +88 -0
  168. package/dist/lib/auto-number.test.js.map +1 -0
  169. package/dist/lib/auto-profile.d.ts +11 -0
  170. package/dist/lib/auto-profile.js +123 -0
  171. package/dist/lib/auto-profile.js.map +1 -0
  172. package/dist/lib/auto-profile.test.d.ts +1 -0
  173. package/dist/lib/auto-profile.test.js +227 -0
  174. package/dist/lib/auto-profile.test.js.map +1 -0
  175. package/dist/lib/escape-regex.d.ts +4 -0
  176. package/dist/lib/escape-regex.js +8 -0
  177. package/dist/lib/escape-regex.js.map +1 -0
  178. package/dist/lib/escape-regex.test.d.ts +1 -0
  179. package/dist/lib/escape-regex.test.js +27 -0
  180. package/dist/lib/escape-regex.test.js.map +1 -0
  181. package/dist/lib/frontmatter.d.ts +34 -0
  182. package/dist/lib/frontmatter.js +75 -0
  183. package/dist/lib/frontmatter.js.map +1 -0
  184. package/dist/lib/frontmatter.test.d.ts +1 -0
  185. package/dist/lib/frontmatter.test.js +192 -0
  186. package/dist/lib/frontmatter.test.js.map +1 -0
  187. package/dist/lib/project-detector.d.ts +12 -0
  188. package/dist/lib/project-detector.js +124 -0
  189. package/dist/lib/project-detector.js.map +1 -0
  190. package/dist/lib/project-detector.test.d.ts +1 -0
  191. package/dist/lib/project-detector.test.js +117 -0
  192. package/dist/lib/project-detector.test.js.map +1 -0
  193. package/dist/lib/safe-external-path.d.ts +10 -0
  194. package/dist/lib/safe-external-path.js +47 -0
  195. package/dist/lib/safe-external-path.js.map +1 -0
  196. package/dist/lib/safe-external-path.test.d.ts +1 -0
  197. package/dist/lib/safe-external-path.test.js +99 -0
  198. package/dist/lib/safe-external-path.test.js.map +1 -0
  199. package/dist/lib/search-engine.d.ts +19 -0
  200. package/dist/lib/search-engine.js +164 -0
  201. package/dist/lib/search-engine.js.map +1 -0
  202. package/dist/lib/search-engine.test.d.ts +1 -0
  203. package/dist/lib/search-engine.test.js +120 -0
  204. package/dist/lib/search-engine.test.js.map +1 -0
  205. package/dist/lib/session-registry.d.ts +59 -0
  206. package/dist/lib/session-registry.js +231 -0
  207. package/dist/lib/session-registry.js.map +1 -0
  208. package/dist/lib/session-registry.test.d.ts +1 -0
  209. package/dist/lib/session-registry.test.js +199 -0
  210. package/dist/lib/session-registry.test.js.map +1 -0
  211. package/dist/lib/skill-registry.d.ts +13 -0
  212. package/dist/lib/skill-registry.js +77 -0
  213. package/dist/lib/skill-registry.js.map +1 -0
  214. package/dist/lib/stack-detector.d.ts +7 -0
  215. package/dist/lib/stack-detector.js +184 -0
  216. package/dist/lib/stack-detector.js.map +1 -0
  217. package/dist/lib/stack-detector.test.d.ts +1 -0
  218. package/dist/lib/stack-detector.test.js +110 -0
  219. package/dist/lib/stack-detector.test.js.map +1 -0
  220. package/dist/lib/token-estimator.d.ts +19 -0
  221. package/dist/lib/token-estimator.js +59 -0
  222. package/dist/lib/token-estimator.js.map +1 -0
  223. package/dist/lib/token-estimator.test.d.ts +1 -0
  224. package/dist/lib/token-estimator.test.js +65 -0
  225. package/dist/lib/token-estimator.test.js.map +1 -0
  226. package/dist/lib/tool-detector.d.ts +8 -0
  227. package/dist/lib/tool-detector.js +76 -0
  228. package/dist/lib/tool-detector.js.map +1 -0
  229. package/dist/lib/tool-detector.test.d.ts +1 -0
  230. package/dist/lib/tool-detector.test.js +170 -0
  231. package/dist/lib/tool-detector.test.js.map +1 -0
  232. package/dist/lib/vault-fs.d.ts +39 -0
  233. package/dist/lib/vault-fs.js +184 -0
  234. package/dist/lib/vault-fs.js.map +1 -0
  235. package/dist/lib/vault-fs.test.d.ts +1 -0
  236. package/dist/lib/vault-fs.test.js +210 -0
  237. package/dist/lib/vault-fs.test.js.map +1 -0
  238. package/dist/mcp-server.d.ts +2 -0
  239. package/dist/mcp-server.js +387 -0
  240. package/dist/mcp-server.js.map +1 -0
  241. package/dist/setup/clients.d.ts +2 -0
  242. package/dist/setup/clients.js +109 -0
  243. package/dist/setup/clients.js.map +1 -0
  244. package/dist/setup/configure.d.ts +6 -0
  245. package/dist/setup/configure.js +126 -0
  246. package/dist/setup/configure.js.map +1 -0
  247. package/dist/setup/configure.test.d.ts +1 -0
  248. package/dist/setup/configure.test.js +112 -0
  249. package/dist/setup/configure.test.js.map +1 -0
  250. package/dist/setup/detect.d.ts +3 -0
  251. package/dist/setup/detect.js +24 -0
  252. package/dist/setup/detect.js.map +1 -0
  253. package/dist/setup/detect.test.d.ts +1 -0
  254. package/dist/setup/detect.test.js +44 -0
  255. package/dist/setup/detect.test.js.map +1 -0
  256. package/dist/setup/index.d.ts +2 -0
  257. package/dist/setup/index.js +147 -0
  258. package/dist/setup/index.js.map +1 -0
  259. package/dist/setup/instructions.d.ts +4 -0
  260. package/dist/setup/instructions.js +62 -0
  261. package/dist/setup/instructions.js.map +1 -0
  262. package/dist/setup/instructions.test.d.ts +1 -0
  263. package/dist/setup/instructions.test.js +84 -0
  264. package/dist/setup/instructions.test.js.map +1 -0
  265. package/dist/setup/json-config.d.ts +10 -0
  266. package/dist/setup/json-config.js +43 -0
  267. package/dist/setup/json-config.js.map +1 -0
  268. package/dist/setup/json-config.test.d.ts +1 -0
  269. package/dist/setup/json-config.test.js +92 -0
  270. package/dist/setup/json-config.test.js.map +1 -0
  271. package/dist/setup/postinstall.d.ts +2 -0
  272. package/dist/setup/postinstall.js +22 -0
  273. package/dist/setup/postinstall.js.map +1 -0
  274. package/dist/setup/preuninstall.d.ts +2 -0
  275. package/dist/setup/preuninstall.js +12 -0
  276. package/dist/setup/preuninstall.js.map +1 -0
  277. package/dist/setup/setup-integration.test.d.ts +1 -0
  278. package/dist/setup/setup-integration.test.js +72 -0
  279. package/dist/setup/setup-integration.test.js.map +1 -0
  280. package/dist/setup/teardown.d.ts +5 -0
  281. package/dist/setup/teardown.js +94 -0
  282. package/dist/setup/teardown.js.map +1 -0
  283. package/dist/setup/teardown.test.d.ts +1 -0
  284. package/dist/setup/teardown.test.js +105 -0
  285. package/dist/setup/teardown.test.js.map +1 -0
  286. package/dist/setup/toml-config.d.ts +5 -0
  287. package/dist/setup/toml-config.js +26 -0
  288. package/dist/setup/toml-config.js.map +1 -0
  289. package/dist/setup/toml-config.test.d.ts +1 -0
  290. package/dist/setup/toml-config.test.js +49 -0
  291. package/dist/setup/toml-config.test.js.map +1 -0
  292. package/dist/setup/types.d.ts +52 -0
  293. package/dist/setup/types.js +23 -0
  294. package/dist/setup/types.js.map +1 -0
  295. package/dist/test-helpers.d.ts +20 -0
  296. package/dist/test-helpers.js +47 -0
  297. package/dist/test-helpers.js.map +1 -0
  298. package/dist/test-helpers.test.d.ts +1 -0
  299. package/dist/test-helpers.test.js +90 -0
  300. package/dist/test-helpers.test.js.map +1 -0
  301. package/package.json +74 -0
package/dist/cli.js ADDED
@@ -0,0 +1,1158 @@
1
+ #!/usr/bin/env node
2
+ // SPDX-License-Identifier: AGPL-3.0-or-later OR Commercial
3
+ import { Command } from "commander";
4
+ import { loadConfig } from "./config.js";
5
+ import { VaultFS } from "./lib/vault-fs.js";
6
+ import { SessionRegistryManager } from "./lib/session-registry.js";
7
+ import { readCommand, listCommand } from "./commands/read.js";
8
+ import { writeCommand } from "./commands/write.js";
9
+ import { searchCommand } from "./commands/search.js";
10
+ import { contextCommand } from "./commands/context.js";
11
+ import { decideCommand } from "./commands/decide.js";
12
+ import { todoCommand } from "./commands/todo.js";
13
+ import { brainstormCommand } from "./commands/brainstorm.js";
14
+ import { sessionCommand } from "./commands/session.js";
15
+ import { graphRelatedCommand, graphCrossProjectCommand } from "./commands/graph.js";
16
+ import { initCommand } from "./commands/init.js";
17
+ import { taskCommand } from "./commands/task.js";
18
+ import { learnCommand } from "./commands/learn.js";
19
+ import { pruneCommand, statsCommand, deprecateCommand } from "./commands/prune.js";
20
+ import { resumeCommand, formatResumeContext } from "./commands/resume.js";
21
+ import { registerSetupCommands } from "./setup/index.js";
22
+ import { skillCommand } from "./commands/skill/index.js";
23
+ import { generateManifest, loadSkillContent, activateSkills } from "./commands/skill/marketplace.js";
24
+ import { autoDetect, getRelevantDomains } from "./lib/auto-profile.js";
25
+ let _config = null;
26
+ let _vaultFs = null;
27
+ let _sessionRegistry = null;
28
+ function getConfig() {
29
+ if (!_config)
30
+ _config = loadConfig();
31
+ return _config;
32
+ }
33
+ function getVaultFs() {
34
+ if (!_vaultFs)
35
+ _vaultFs = new VaultFS(getConfig().vaultPath);
36
+ return _vaultFs;
37
+ }
38
+ function getSessionRegistry() {
39
+ if (!_sessionRegistry)
40
+ _sessionRegistry = new SessionRegistryManager(getConfig().vaultPath, getConfig().sessionTtlHours);
41
+ return _sessionRegistry;
42
+ }
43
+ const noopLog = {
44
+ debug() { },
45
+ info() { },
46
+ warn() { },
47
+ error() { },
48
+ };
49
+ function createCtx() {
50
+ return {
51
+ vaultFs: getVaultFs(),
52
+ vaultPath: getConfig().vaultPath,
53
+ sessionRegistry: getSessionRegistry(),
54
+ config: getConfig(),
55
+ log: noopLog,
56
+ };
57
+ }
58
+ import { createRequire } from "module";
59
+ const require = createRequire(import.meta.url);
60
+ const { version } = require("../package.json");
61
+ const program = new Command();
62
+ program
63
+ .name("superskill")
64
+ .description("Universal agentic knowledge base + context optimizer + skill marketplace for AI tools")
65
+ .version(version);
66
+ // ── read ──────────────────────────────────────────────
67
+ program
68
+ .command("read <path>")
69
+ .description("Read a vault note")
70
+ .action(async (path) => {
71
+ try {
72
+ const content = await readCommand({ path }, createCtx());
73
+ process.stdout.write(content);
74
+ }
75
+ catch (e) {
76
+ const msg = e instanceof Error ? e.message : String(e);
77
+ console.error(`Error: ${msg}`);
78
+ process.exit(1);
79
+ }
80
+ });
81
+ // ── list ──────────────────────────────────────────────
82
+ program
83
+ .command("list <path>")
84
+ .description("List vault directory")
85
+ .option("-d, --depth <number>", "Listing depth", "1")
86
+ .action(async (path, opts) => {
87
+ try {
88
+ const depth = parseInt(opts.depth, 10);
89
+ if (Number.isNaN(depth) || depth < 1) {
90
+ throw new Error("--depth must be a positive integer");
91
+ }
92
+ const entries = await listCommand({ path, depth }, createCtx());
93
+ for (const entry of entries) {
94
+ console.log(entry);
95
+ }
96
+ }
97
+ catch (e) {
98
+ const msg = e instanceof Error ? e.message : String(e);
99
+ console.error(`Error: ${msg}`);
100
+ process.exit(1);
101
+ }
102
+ });
103
+ // ── write ─────────────────────────────────────────────
104
+ program
105
+ .command("write <path>")
106
+ .description("Write/create a vault note")
107
+ .requiredOption("-c, --content <text>", "Note content")
108
+ .option("-m, --mode <mode>", "Write mode: overwrite|append|prepend", "append")
109
+ .option("-f, --frontmatter <json>", "Frontmatter as JSON")
110
+ .action(async (path, opts) => {
111
+ try {
112
+ const validModes = ["overwrite", "append", "prepend"];
113
+ if (!validModes.includes(opts.mode)) {
114
+ throw new Error(`--mode must be one of: ${validModes.join(", ")}`);
115
+ }
116
+ let fm;
117
+ if (opts.frontmatter) {
118
+ try {
119
+ fm = JSON.parse(opts.frontmatter);
120
+ }
121
+ catch {
122
+ throw new Error(`Invalid JSON in --frontmatter: ${opts.frontmatter}`);
123
+ }
124
+ }
125
+ const result = await writeCommand({
126
+ path,
127
+ content: opts.content,
128
+ mode: opts.mode,
129
+ frontmatter: fm,
130
+ }, createCtx());
131
+ console.log(JSON.stringify(result));
132
+ }
133
+ catch (e) {
134
+ const msg = e instanceof Error ? e.message : String(e);
135
+ console.error(`Error: ${msg}`);
136
+ process.exit(1);
137
+ }
138
+ });
139
+ // ── append ────────────────────────────────────────────
140
+ program
141
+ .command("append <path>")
142
+ .description("Append to an existing vault note")
143
+ .requiredOption("-c, --content <text>", "Content to append")
144
+ .action(async (path, opts) => {
145
+ try {
146
+ const result = await writeCommand({ path, content: opts.content, mode: "append" }, createCtx());
147
+ console.log(JSON.stringify(result));
148
+ }
149
+ catch (e) {
150
+ const msg = e instanceof Error ? e.message : String(e);
151
+ console.error(`Error: ${msg}`);
152
+ process.exit(1);
153
+ }
154
+ });
155
+ // ── search ────────────────────────────────────────────
156
+ program
157
+ .command("search <query>")
158
+ .description("Search the vault")
159
+ .option("-p, --project <slug>", "Restrict to project")
160
+ .option("-l, --limit <number>", "Max results", "10")
161
+ .option("-s, --structured", "Structured frontmatter search")
162
+ .action(async (query, opts) => {
163
+ try {
164
+ const limit = parseInt(opts.limit, 10);
165
+ if (Number.isNaN(limit) || limit < 1) {
166
+ throw new Error("--limit must be a positive integer");
167
+ }
168
+ const results = await searchCommand({
169
+ query,
170
+ project: opts.project,
171
+ limit,
172
+ structured: opts.structured,
173
+ }, createCtx());
174
+ console.log(JSON.stringify(results, null, 2));
175
+ }
176
+ catch (e) {
177
+ const msg = e instanceof Error ? e.message : String(e);
178
+ console.error(`Error: ${msg}`);
179
+ process.exit(1);
180
+ }
181
+ });
182
+ // ── context ───────────────────────────────────────────
183
+ program
184
+ .command("context")
185
+ .description("Get project context (auto-detects from cwd)")
186
+ .option("-p, --project <slug>", "Project slug")
187
+ .option("-d, --detail <level>", "Detail level: summary|full", "summary")
188
+ .action(async (opts) => {
189
+ try {
190
+ const validDetails = ["summary", "full"];
191
+ if (!validDetails.includes(opts.detail)) {
192
+ throw new Error(`--detail must be one of: ${validDetails.join(", ")}`);
193
+ }
194
+ const result = await contextCommand({
195
+ project: opts.project,
196
+ detailLevel: opts.detail,
197
+ }, createCtx());
198
+ console.log(result.context_md);
199
+ }
200
+ catch (e) {
201
+ const msg = e instanceof Error ? e.message : String(e);
202
+ console.error(`Error: ${msg}`);
203
+ process.exit(1);
204
+ }
205
+ });
206
+ // ── init ──────────────────────────────────────────────
207
+ program
208
+ .command("init <project-path>")
209
+ .description("Scan a git repo and generate draft context.md")
210
+ .option("-s, --slug <name>", "Project slug (default: directory name)")
211
+ .action(async (projectPath, opts) => {
212
+ try {
213
+ const result = await initCommand(projectPath, opts.slug);
214
+ process.stdout.write(result.draft_context_md);
215
+ }
216
+ catch (e) {
217
+ const msg = e instanceof Error ? e.message : String(e);
218
+ console.error(`Error: ${msg}`);
219
+ process.exit(1);
220
+ }
221
+ });
222
+ // ── decide ────────────────────────────────────────────
223
+ program
224
+ .command("decide")
225
+ .description("Log an architecture decision record")
226
+ .requiredOption("-t, --title <text>", "Decision title")
227
+ .requiredOption("--decision <text>", "What was decided")
228
+ .option("--context <text>", "Why this decision was needed", "")
229
+ .option("--alternatives <text>", "Alternatives considered")
230
+ .option("--consequences <text>", "Known trade-offs")
231
+ .option("-p, --project <slug>", "Project slug")
232
+ .action(async (opts) => {
233
+ try {
234
+ const result = await decideCommand({
235
+ title: opts.title,
236
+ context: opts.context,
237
+ decision: opts.decision,
238
+ alternatives: opts.alternatives,
239
+ consequences: opts.consequences,
240
+ project: opts.project,
241
+ }, createCtx());
242
+ console.log(JSON.stringify(result));
243
+ }
244
+ catch (e) {
245
+ const msg = e instanceof Error ? e.message : String(e);
246
+ console.error(`Error: ${msg}`);
247
+ process.exit(1);
248
+ }
249
+ });
250
+ // ── todo (deprecated — use task) ─────────────────────
251
+ const todoCmd = program
252
+ .command("todo")
253
+ .description("[Deprecated — use 'task' instead] Manage project todos");
254
+ todoCmd
255
+ .command("list")
256
+ .description("List active todos")
257
+ .option("-p, --project <slug>", "Project slug")
258
+ .option("-b, --blockers-only", "Only show high-priority blockers")
259
+ .action(async (opts) => {
260
+ try {
261
+ const result = await todoCommand({
262
+ action: "list",
263
+ project: opts.project,
264
+ blockersOnly: opts.blockersOnly,
265
+ }, createCtx());
266
+ for (const todo of result.todos) {
267
+ const marker = todo.completed ? "[x]" : "[ ]";
268
+ const priority = todo.priority === "high" ? "P0" : todo.priority === "low" ? "P2" : "P1";
269
+ console.log(`${marker} [${priority}] ${todo.text}`);
270
+ }
271
+ }
272
+ catch (e) {
273
+ const msg = e instanceof Error ? e.message : String(e);
274
+ console.error(`Error: ${msg}`);
275
+ process.exit(1);
276
+ }
277
+ });
278
+ todoCmd
279
+ .command("add <text>")
280
+ .description("Add a todo")
281
+ .option("-p, --project <slug>", "Project slug")
282
+ .option("--priority <level>", "Priority: high|medium|low", "medium")
283
+ .action(async (text, opts) => {
284
+ try {
285
+ const validTodoPriorities = ["high", "medium", "low"];
286
+ if (!validTodoPriorities.includes(opts.priority)) {
287
+ throw new Error(`--priority must be one of: ${validTodoPriorities.join(", ")}`);
288
+ }
289
+ await todoCommand({
290
+ action: "add",
291
+ item: text,
292
+ priority: opts.priority,
293
+ project: opts.project,
294
+ }, createCtx());
295
+ console.log(`Added: ${text}`);
296
+ }
297
+ catch (e) {
298
+ const msg = e instanceof Error ? e.message : String(e);
299
+ console.error(`Error: ${msg}`);
300
+ process.exit(1);
301
+ }
302
+ });
303
+ todoCmd
304
+ .command("complete <text>")
305
+ .description("Complete a todo")
306
+ .option("-p, --project <slug>", "Project slug")
307
+ .action(async (text, opts) => {
308
+ try {
309
+ await todoCommand({
310
+ action: "complete",
311
+ item: text,
312
+ project: opts.project,
313
+ }, createCtx());
314
+ console.log(`Completed: ${text}`);
315
+ }
316
+ catch (e) {
317
+ const msg = e instanceof Error ? e.message : String(e);
318
+ console.error(`Error: ${msg}`);
319
+ process.exit(1);
320
+ }
321
+ });
322
+ // ── task ──────────────────────────────────────────────
323
+ const taskCmd = program
324
+ .command("task")
325
+ .description("Manage project tasks (kanban board)");
326
+ taskCmd
327
+ .command("list")
328
+ .description("List tasks")
329
+ .option("-p, --project <slug>", "Project slug")
330
+ .option("-s, --status <status>", "Filter by status")
331
+ .option("--priority <level>", "Filter by priority")
332
+ .option("--assigned-to <tool>", "Filter by assignee")
333
+ .action(async (opts) => {
334
+ try {
335
+ const validPriorities = ["p0", "p1", "p2"];
336
+ const validStatuses = ["backlog", "in-progress", "blocked", "done", "cancelled"];
337
+ if (opts.priority && !validPriorities.includes(opts.priority)) {
338
+ throw new Error(`--priority must be one of: ${validPriorities.join(", ")}`);
339
+ }
340
+ if (opts.status && !validStatuses.includes(opts.status)) {
341
+ throw new Error(`--status must be one of: ${validStatuses.join(", ")}`);
342
+ }
343
+ const result = await taskCommand({
344
+ action: "list",
345
+ project: opts.project,
346
+ status: opts.status,
347
+ priority: opts.priority,
348
+ assignedTo: opts.assignedTo,
349
+ }, createCtx());
350
+ if (!result.tasks?.length) {
351
+ console.log("No tasks found.");
352
+ return;
353
+ }
354
+ for (const t of result.tasks) {
355
+ const blocked = t.blocked_by.length > 0 ? " [BLOCKED]" : "";
356
+ console.log(`[${t.id}] [${t.priority}] [${t.status}]${blocked} ${t.title}`);
357
+ }
358
+ }
359
+ catch (e) {
360
+ const msg = e instanceof Error ? e.message : String(e);
361
+ console.error(`Error: ${msg}`);
362
+ process.exit(1);
363
+ }
364
+ });
365
+ taskCmd
366
+ .command("add <title>")
367
+ .description("Add a task")
368
+ .option("-p, --project <slug>", "Project slug")
369
+ .option("--priority <level>", "Priority: p0|p1|p2", "p1")
370
+ .option("--blocked-by <ids...>", "Task IDs that block this task")
371
+ .option("--assigned-to <tool>", "Assignee: claude-code|opencode|codex|human")
372
+ .option("--tags <tags>", "Comma-separated tags")
373
+ .action(async (title, opts) => {
374
+ try {
375
+ const validPriorities = ["p0", "p1", "p2"];
376
+ if (!validPriorities.includes(opts.priority)) {
377
+ throw new Error(`--priority must be one of: ${validPriorities.join(", ")}`);
378
+ }
379
+ const tags = opts.tags ? opts.tags.split(",").map((t) => t.trim()) : undefined;
380
+ const result = await taskCommand({
381
+ action: "add",
382
+ title,
383
+ project: opts.project,
384
+ priority: opts.priority,
385
+ blockedBy: opts.blockedBy,
386
+ assignedTo: opts.assignedTo,
387
+ tags,
388
+ }, createCtx());
389
+ console.log(JSON.stringify({ task_id: result.task_id, path: result.path }));
390
+ }
391
+ catch (e) {
392
+ const msg = e instanceof Error ? e.message : String(e);
393
+ console.error(`Error: ${msg}`);
394
+ process.exit(1);
395
+ }
396
+ });
397
+ taskCmd
398
+ .command("update <task-id>")
399
+ .description("Update a task")
400
+ .option("-p, --project <slug>", "Project slug")
401
+ .option("-s, --status <status>", "New status")
402
+ .option("--priority <level>", "New priority")
403
+ .option("--blocked-by <ids...>", "New blocked-by list")
404
+ .option("--assigned-to <tool>", "New assignee")
405
+ .option("-t, --title <text>", "New title")
406
+ .action(async (taskId, opts) => {
407
+ try {
408
+ const validPriorities = ["p0", "p1", "p2"];
409
+ const validStatuses = ["backlog", "in-progress", "blocked", "done", "cancelled"];
410
+ if (opts.priority && !validPriorities.includes(opts.priority)) {
411
+ throw new Error(`--priority must be one of: ${validPriorities.join(", ")}`);
412
+ }
413
+ if (opts.status && !validStatuses.includes(opts.status)) {
414
+ throw new Error(`--status must be one of: ${validStatuses.join(", ")}`);
415
+ }
416
+ const result = await taskCommand({
417
+ action: "update",
418
+ taskId,
419
+ project: opts.project,
420
+ status: opts.status,
421
+ priority: opts.priority,
422
+ blockedBy: opts.blockedBy,
423
+ assignedTo: opts.assignedTo,
424
+ title: opts.title,
425
+ }, createCtx());
426
+ console.log(JSON.stringify({ task_id: result.task_id, updated_fields: result.updated_fields }));
427
+ }
428
+ catch (e) {
429
+ const msg = e instanceof Error ? e.message : String(e);
430
+ console.error(`Error: ${msg}`);
431
+ process.exit(1);
432
+ }
433
+ });
434
+ taskCmd
435
+ .command("board")
436
+ .description("Show task board (kanban view)")
437
+ .option("-p, --project <slug>", "Project slug")
438
+ .action(async (opts) => {
439
+ try {
440
+ const result = await taskCommand({
441
+ action: "board",
442
+ project: opts.project,
443
+ }, createCtx());
444
+ if (!result.board)
445
+ return;
446
+ for (const [status, tasks] of Object.entries(result.board)) {
447
+ if (tasks.length === 0)
448
+ continue;
449
+ console.log(`\n=== ${status.toUpperCase()} (${tasks.length}) ===`);
450
+ for (const t of tasks) {
451
+ const blocked = t.blocked_by.length > 0 ? " [BLOCKED]" : "";
452
+ const assignee = t.assigned_to ? ` @${t.assigned_to}` : "";
453
+ console.log(` [${t.id}] [${t.priority}]${blocked}${assignee} ${t.title}`);
454
+ }
455
+ }
456
+ }
457
+ catch (e) {
458
+ const msg = e instanceof Error ? e.message : String(e);
459
+ console.error(`Error: ${msg}`);
460
+ process.exit(1);
461
+ }
462
+ });
463
+ // ── learn ─────────────────────────────────────────────
464
+ const learnCmd = program
465
+ .command("learn")
466
+ .description("Capture and query learnings");
467
+ learnCmd
468
+ .command("add")
469
+ .description("Capture a learning")
470
+ .requiredOption("-t, --title <text>", "Learning title")
471
+ .requiredOption("-d, --discovery <text>", "What was discovered")
472
+ .option("-p, --project <slug>", "Project slug")
473
+ .option("--tags <tags>", "Comma-separated tags")
474
+ .option("--confidence <level>", "Confidence: high|medium|low", "medium")
475
+ .option("--source <tool>", "Source tool")
476
+ .action(async (opts) => {
477
+ try {
478
+ const validConfidences = ["high", "medium", "low"];
479
+ if (!validConfidences.includes(opts.confidence)) {
480
+ throw new Error(`--confidence must be one of: ${validConfidences.join(", ")}`);
481
+ }
482
+ const tags = opts.tags ? opts.tags.split(",").map((t) => t.trim()) : undefined;
483
+ const result = await learnCommand({
484
+ action: "add",
485
+ title: opts.title,
486
+ discovery: opts.discovery,
487
+ project: opts.project,
488
+ tags,
489
+ confidence: opts.confidence,
490
+ source: opts.source,
491
+ }, createCtx());
492
+ console.log(JSON.stringify({ learning_id: result.learning_id, path: result.path }));
493
+ }
494
+ catch (e) {
495
+ const msg = e instanceof Error ? e.message : String(e);
496
+ console.error(`Error: ${msg}`);
497
+ process.exit(1);
498
+ }
499
+ });
500
+ learnCmd
501
+ .command("list")
502
+ .description("List learnings")
503
+ .option("-p, --project <slug>", "Project slug")
504
+ .option("--tag <tag>", "Filter by tag")
505
+ .action(async (opts) => {
506
+ try {
507
+ const result = await learnCommand({
508
+ action: "list",
509
+ project: opts.project,
510
+ tag: opts.tag,
511
+ }, createCtx());
512
+ if (!result.learnings?.length) {
513
+ console.log(JSON.stringify({ learnings: [] }));
514
+ return;
515
+ }
516
+ if (process.stdout.isTTY) {
517
+ for (const l of result.learnings) {
518
+ const tagStr = l.tags.length > 0 ? ` (${l.tags.join(", ")})` : "";
519
+ console.log(`[${l.id}] [${l.confidence}] ${l.title}${tagStr} — ${l.created}`);
520
+ }
521
+ }
522
+ else {
523
+ console.log(JSON.stringify({ learnings: result.learnings }));
524
+ }
525
+ }
526
+ catch (e) {
527
+ const msg = e instanceof Error ? e.message : String(e);
528
+ console.error(`Error: ${msg}`);
529
+ process.exit(1);
530
+ }
531
+ });
532
+ // ── brainstorm ────────────────────────────────────────
533
+ program
534
+ .command("brainstorm <topic>")
535
+ .description("Start or continue a brainstorm")
536
+ .requiredOption("-c, --content <text>", "Brainstorm content to add")
537
+ .option("-p, --project <slug>", "Project slug")
538
+ .action(async (topic, opts) => {
539
+ try {
540
+ const result = await brainstormCommand({
541
+ topic,
542
+ content: opts.content,
543
+ project: opts.project,
544
+ }, createCtx());
545
+ console.log(JSON.stringify(result));
546
+ }
547
+ catch (e) {
548
+ const msg = e instanceof Error ? e.message : String(e);
549
+ console.error(`Error: ${msg}`);
550
+ process.exit(1);
551
+ }
552
+ });
553
+ // ── session ───────────────────────────────────────────
554
+ const sessionCmd = program
555
+ .command("session")
556
+ .description("Manage agent sessions (swarming coordination)");
557
+ sessionCmd
558
+ .command("register")
559
+ .description("Register a new agent session")
560
+ .requiredOption("--tool <name>", "Tool name: claude-code|opencode|codex")
561
+ .option("-p, --project <slug>", "Project being worked on")
562
+ .option("--task <summary>", "Task summary")
563
+ .option("--files <paths...>", "Files being touched")
564
+ .action(async (opts) => {
565
+ try {
566
+ const result = await sessionCommand({
567
+ action: "register",
568
+ tool: opts.tool,
569
+ project: opts.project,
570
+ taskSummary: opts.task,
571
+ filesTouched: opts.files,
572
+ }, createCtx());
573
+ console.log(JSON.stringify(result, null, 2));
574
+ }
575
+ catch (e) {
576
+ const msg = e instanceof Error ? e.message : String(e);
577
+ console.error(`Error: ${msg}`);
578
+ process.exit(1);
579
+ }
580
+ });
581
+ sessionCmd
582
+ .command("heartbeat <session-id>")
583
+ .description("Update session heartbeat")
584
+ .action(async (sessionId) => {
585
+ try {
586
+ await sessionCommand({ action: "heartbeat", sessionId }, createCtx());
587
+ console.log("Heartbeat updated");
588
+ }
589
+ catch (e) {
590
+ const msg = e instanceof Error ? e.message : String(e);
591
+ console.error(`Error: ${msg}`);
592
+ process.exit(1);
593
+ }
594
+ });
595
+ sessionCmd
596
+ .command("complete <session-id>")
597
+ .description("Mark session as completed")
598
+ .option("--summary <text>", "Session summary")
599
+ .option("--outcome <text>", "Session outcome")
600
+ .option("--files <paths...>", "Files touched during session")
601
+ .option("--tasks <ids...>", "Task IDs completed")
602
+ .option("-p, --project <slug>", "Project slug")
603
+ .action(async (sessionId, opts) => {
604
+ try {
605
+ const result = await sessionCommand({
606
+ action: "complete",
607
+ sessionId,
608
+ taskSummary: opts.summary,
609
+ outcome: opts.outcome,
610
+ filesTouched: opts.files,
611
+ tasksCompleted: opts.tasks,
612
+ project: opts.project,
613
+ }, createCtx());
614
+ console.log("Session completed");
615
+ if (result.session_note_path) {
616
+ console.log(`Session note: ${result.session_note_path}`);
617
+ }
618
+ }
619
+ catch (e) {
620
+ const msg = e instanceof Error ? e.message : String(e);
621
+ console.error(`Error: ${msg}`);
622
+ process.exit(1);
623
+ }
624
+ });
625
+ sessionCmd
626
+ .command("list")
627
+ .description("List active sessions")
628
+ .action(async () => {
629
+ try {
630
+ const result = await sessionCommand({ action: "list_active" }, createCtx());
631
+ if (!result.active_sessions?.length) {
632
+ console.log("No active sessions");
633
+ return;
634
+ }
635
+ for (const s of result.active_sessions) {
636
+ console.log(`[${s.tool}] ${s.project ?? "unknown"}: ${s.task_summary ?? "no task"} (${s.id})`);
637
+ }
638
+ }
639
+ catch (e) {
640
+ const msg = e instanceof Error ? e.message : String(e);
641
+ console.error(`Error: ${msg}`);
642
+ process.exit(1);
643
+ }
644
+ });
645
+ // ── graph ─────────────────────────────────────────────
646
+ const graphCmd = program
647
+ .command("graph")
648
+ .description("Knowledge graph traversal");
649
+ graphCmd
650
+ .command("related <path>")
651
+ .description("Get backlinks and outgoing links for a note")
652
+ .option("--hops <number>", "Traversal depth", "1")
653
+ .action(async (path, opts) => {
654
+ try {
655
+ const hops = parseInt(opts.hops, 10);
656
+ if (Number.isNaN(hops) || hops < 1) {
657
+ throw new Error("--hops must be a positive integer");
658
+ }
659
+ const result = await graphRelatedCommand({ path, hops }, createCtx());
660
+ console.log(JSON.stringify(result, null, 2));
661
+ }
662
+ catch (e) {
663
+ const msg = e instanceof Error ? e.message : String(e);
664
+ console.error(`Error: ${msg}`);
665
+ process.exit(1);
666
+ }
667
+ });
668
+ graphCmd
669
+ .command("cross-project <query>")
670
+ .description("Search across all projects")
671
+ .option("-l, --limit <number>", "Max results", "20")
672
+ .action(async (query, opts) => {
673
+ try {
674
+ const limit = parseInt(opts.limit, 10);
675
+ if (Number.isNaN(limit) || limit < 1) {
676
+ throw new Error("--limit must be a positive integer");
677
+ }
678
+ const grouped = await graphCrossProjectCommand({ query, limit }, createCtx());
679
+ for (const [project, results] of Object.entries(grouped)) {
680
+ console.log(`\n${project} (${results.length} matches):`);
681
+ for (const r of results) {
682
+ console.log(` ${r.path}: ${r.snippet.slice(0, 100)}`);
683
+ }
684
+ }
685
+ }
686
+ catch (e) {
687
+ const msg = e instanceof Error ? e.message : String(e);
688
+ console.error(`Error: ${msg}`);
689
+ process.exit(1);
690
+ }
691
+ });
692
+ // ── prune ─────────────────────────────────────────────
693
+ program
694
+ .command("prune")
695
+ .description("Archive or delete stale vault content")
696
+ .option("-p, --project <slug>", "Project slug")
697
+ .option("-a, --all", "Prune all projects")
698
+ .option("-m, --mode <mode>", "Mode: dry-run|archive|delete", "dry-run")
699
+ .option("--sessions <days>", "Session retention in days", "30")
700
+ .option("--done-tasks <days>", "Done task retention in days", "30")
701
+ .option("--todos <days>", "Completed todo retention in days (0=keep)", "0")
702
+ .action(async (opts) => {
703
+ try {
704
+ const validModes = ["dry-run", "archive", "delete"];
705
+ if (!validModes.includes(opts.mode)) {
706
+ throw new Error(`--mode must be one of: ${validModes.join(", ")}`);
707
+ }
708
+ const policy = {
709
+ sessions: parseInt(opts.sessions, 10) || 30,
710
+ doneTasks: parseInt(opts.doneTasks, 10) || 30,
711
+ todos: parseInt(opts.todos, 10) || 0,
712
+ };
713
+ const results = await pruneCommand({
714
+ project: opts.project,
715
+ mode: opts.mode,
716
+ policy,
717
+ all: opts.all,
718
+ }, createCtx());
719
+ for (const r of results) {
720
+ console.log(`\n=== ${r.project} ===`);
721
+ console.log(` Scanned: ${r.stats.sessions_scanned} sessions, ${r.stats.tasks_scanned} tasks`);
722
+ if (r.archived.length > 0) {
723
+ console.log(` ${opts.mode === "dry-run" ? "Would archive" : "Archived"}: ${r.archived.length} items`);
724
+ for (const a of r.archived)
725
+ console.log(` ${a.from} → ${a.to}`);
726
+ }
727
+ if (r.deleted.length > 0) {
728
+ console.log(` ${opts.mode === "dry-run" ? "Would delete" : "Deleted"}: ${r.deleted.length} items`);
729
+ for (const d of r.deleted)
730
+ console.log(` ${d}`);
731
+ }
732
+ if (r.archived.length === 0 && r.deleted.length === 0) {
733
+ console.log(" Nothing to prune.");
734
+ }
735
+ }
736
+ }
737
+ catch (e) {
738
+ const msg = e instanceof Error ? e.message : String(e);
739
+ console.error(`Error: ${msg}`);
740
+ process.exit(1);
741
+ }
742
+ });
743
+ // ── stats ─────────────────────────────────────────────
744
+ program
745
+ .command("stats")
746
+ .description("Show vault content statistics for a project")
747
+ .option("-p, --project <slug>", "Project slug")
748
+ .action(async (opts) => {
749
+ try {
750
+ const result = await statsCommand({ project: opts.project }, createCtx());
751
+ console.log(`\n=== ${result.project} ===`);
752
+ console.log(` Sessions: ${result.sessions}`);
753
+ console.log(` Tasks: ${result.tasks.total} (backlog: ${result.tasks.backlog}, in-progress: ${result.tasks.inProgress}, done: ${result.tasks.done}, cancelled: ${result.tasks.cancelled})`);
754
+ console.log(` Learnings: ${result.learnings}`);
755
+ console.log(` ADRs: ${result.adrs}`);
756
+ console.log(` Brainstorms: ${result.brainstorms}`);
757
+ console.log(` Total files: ${result.totalFiles}`);
758
+ }
759
+ catch (e) {
760
+ const msg = e instanceof Error ? e.message : String(e);
761
+ console.error(`Error: ${msg}`);
762
+ process.exit(1);
763
+ }
764
+ });
765
+ // ── deprecate ─────────────────────────────────────────
766
+ program
767
+ .command("deprecate <path>")
768
+ .description("Mark a vault item as deprecated")
769
+ .option("-r, --reason <text>", "Reason for deprecation")
770
+ .action(async (path, opts) => {
771
+ try {
772
+ const result = await deprecateCommand({ path, reason: opts.reason }, createCtx());
773
+ console.log(`Deprecated: ${result.path} (status: ${result.status})`);
774
+ }
775
+ catch (e) {
776
+ const msg = e instanceof Error ? e.message : String(e);
777
+ console.error(`Error: ${msg}`);
778
+ process.exit(1);
779
+ }
780
+ });
781
+ // ── resume ────────────────────────────────────────────
782
+ program
783
+ .command("resume")
784
+ .description("Get resume context for continuing work — shows recent sessions, interrupted work, next steps")
785
+ .option("-p, --project <slug>", "Project slug")
786
+ .option("-l, --limit <number>", "Number of recent sessions to show", "5")
787
+ .option("--json", "Output as JSON instead of markdown")
788
+ .action(async (opts) => {
789
+ try {
790
+ const limit = parseInt(opts.limit, 10);
791
+ if (Number.isNaN(limit) || limit < 1) {
792
+ throw new Error("--limit must be a positive integer");
793
+ }
794
+ const result = await resumeCommand({ project: opts.project, limit }, createCtx());
795
+ if (opts.json) {
796
+ console.log(JSON.stringify(result, null, 2));
797
+ }
798
+ else {
799
+ console.log(formatResumeContext(result));
800
+ }
801
+ }
802
+ catch (e) {
803
+ const msg = e instanceof Error ? e.message : String(e);
804
+ console.error(`Error: ${msg}`);
805
+ process.exit(1);
806
+ }
807
+ });
808
+ // ── skill ────────────────────────────────────────────
809
+ const skillCmd = program
810
+ .command("skill")
811
+ .description("Install and manage AI skills from git repos, local files, or URLs");
812
+ skillCmd
813
+ .command("install <source>")
814
+ .description("Install a skill from a file path or URL")
815
+ .option("-f, --force", "Overwrite if already installed")
816
+ .action(async (source, opts) => {
817
+ try {
818
+ const result = await skillCommand(getVaultFs(), getConfig().vaultPath, {
819
+ action: "install",
820
+ source,
821
+ force: opts.force,
822
+ });
823
+ if (result.action === "install" && result.result.success) {
824
+ console.log(`Installed: ${result.result.skill.name} (v${result.result.skill.version})`);
825
+ }
826
+ else if (result.action === "install") {
827
+ console.error(`Error: ${result.result.error}`);
828
+ process.exit(1);
829
+ }
830
+ }
831
+ catch (e) {
832
+ const msg = e instanceof Error ? e.message : String(e);
833
+ console.error(`Error: ${msg}`);
834
+ process.exit(1);
835
+ }
836
+ });
837
+ skillCmd
838
+ .command("list")
839
+ .description("List installed skills")
840
+ .action(async () => {
841
+ try {
842
+ const result = await skillCommand(getVaultFs(), getConfig().vaultPath, {
843
+ action: "list",
844
+ });
845
+ if (result.action === "list") {
846
+ if (result.result.skills.length === 0) {
847
+ console.log("No skills installed.");
848
+ return;
849
+ }
850
+ for (const sk of result.result.skills) {
851
+ const status = sk.status === "deprecated" ? " [DEPRECATED]" : "";
852
+ const autoUpdate = sk.auto_update ? " [auto-update]" : "";
853
+ console.log(` ${sk.name} v${sk.version}${status}${autoUpdate} — installed ${sk.installed_at.slice(0, 10)}`);
854
+ }
855
+ }
856
+ }
857
+ catch (e) {
858
+ const msg = e instanceof Error ? e.message : String(e);
859
+ console.error(`Error: ${msg}`);
860
+ process.exit(1);
861
+ }
862
+ });
863
+ skillCmd
864
+ .command("validate <path>")
865
+ .description("Validate a skill file")
866
+ .action(async (skillPath) => {
867
+ try {
868
+ const result = await skillCommand(getVaultFs(), getConfig().vaultPath, {
869
+ action: "validate",
870
+ skillPath,
871
+ });
872
+ if (result.action === "validate") {
873
+ if (result.result.valid) {
874
+ console.log(`Valid skill: ${result.result.frontmatter.name}`);
875
+ }
876
+ else {
877
+ console.error("Invalid skill:");
878
+ for (const err of result.result.errors) {
879
+ console.error(` - ${err}`);
880
+ }
881
+ process.exit(1);
882
+ }
883
+ }
884
+ }
885
+ catch (e) {
886
+ const msg = e instanceof Error ? e.message : String(e);
887
+ console.error(`Error: ${msg}`);
888
+ process.exit(1);
889
+ }
890
+ });
891
+ skillCmd
892
+ .command("delete <name>")
893
+ .description("Remove an installed skill")
894
+ .action(async (skillName) => {
895
+ try {
896
+ const result = await skillCommand(getVaultFs(), getConfig().vaultPath, {
897
+ action: "delete",
898
+ skillName,
899
+ });
900
+ if (result.action === "delete" && result.result.success) {
901
+ console.log(`Deleted: ${skillName}`);
902
+ }
903
+ else if (result.action === "delete") {
904
+ console.error(`Error: ${result.result.error}`);
905
+ process.exit(1);
906
+ }
907
+ }
908
+ catch (e) {
909
+ const msg = e instanceof Error ? e.message : String(e);
910
+ console.error(`Error: ${msg}`);
911
+ process.exit(1);
912
+ }
913
+ });
914
+ // ── skill marketplace ────────────────────────────────
915
+ skillCmd
916
+ .command("catalog")
917
+ .description("Browse the skill catalog across all repos")
918
+ .option("-d, --domain <id>", "Filter by domain (e.g. tdd, security, planning)")
919
+ .option("-r, --repo <name>", "Filter by repo (ecc, superpowers, gstack, etc.)")
920
+ .option("-s, --search <text>", "Text search")
921
+ .action(async (opts) => {
922
+ try {
923
+ const result = await skillCommand(getVaultFs(), getConfig().vaultPath, {
924
+ action: "catalog",
925
+ domain: opts.domain,
926
+ repo: opts.repo,
927
+ search: opts.search,
928
+ });
929
+ if (result.action === "catalog") {
930
+ const { total, repos, domains, skills } = result.result;
931
+ console.log(`\n Catalog: ${total} skills across ${repos.length} repos\n`);
932
+ console.log(" Repos:");
933
+ for (const r of repos)
934
+ console.log(` ${r.repo}: ${r.count} skills`);
935
+ console.log("\n Domains:");
936
+ for (const d of domains)
937
+ console.log(` ${d.id} (${d.name}): ${d.skill_count} skills`);
938
+ console.log("\n Skills:");
939
+ for (const s of skills) {
940
+ console.log(` [${s.repo}] ${s.id} — ${s.description}`);
941
+ }
942
+ }
943
+ }
944
+ catch (e) {
945
+ const msg = e instanceof Error ? e.message : String(e);
946
+ console.error(`Error: ${msg}`);
947
+ process.exit(1);
948
+ }
949
+ });
950
+ skillCmd
951
+ .command("collisions")
952
+ .description("Show collision matrix — domains where multiple repos compete")
953
+ .action(async () => {
954
+ try {
955
+ const result = await skillCommand(getVaultFs(), getConfig().vaultPath, {
956
+ action: "collisions",
957
+ });
958
+ if (result.action === "collisions") {
959
+ const { collisions, total_collision_domains, total_affected_skills } = result.result;
960
+ console.log(`\n Collisions: ${total_collision_domains} domains, ${total_affected_skills} skills affected\n`);
961
+ for (const c of collisions) {
962
+ console.log(` ${c.domain_name} (${c.domain_id}):`);
963
+ for (const s of c.skills) {
964
+ console.log(` [${s.repo}] ${s.id} — ${s.description}`);
965
+ }
966
+ console.log();
967
+ }
968
+ }
969
+ }
970
+ catch (e) {
971
+ const msg = e instanceof Error ? e.message : String(e);
972
+ console.error(`Error: ${msg}`);
973
+ process.exit(1);
974
+ }
975
+ });
976
+ skillCmd
977
+ .command("resolve")
978
+ .description("Resolve collisions using a profile — shows what gets picked")
979
+ .option("-p, --profile <name>", "Profile: ecc-first, superpowers-first, minimal", "ecc-first")
980
+ .action(async (opts) => {
981
+ try {
982
+ const result = await skillCommand(getVaultFs(), getConfig().vaultPath, {
983
+ action: "resolve",
984
+ profile: opts.profile,
985
+ });
986
+ if (result.action === "resolve") {
987
+ const r = result.result;
988
+ if (!r.success) {
989
+ console.error(`Error: ${r.error}`);
990
+ process.exit(1);
991
+ }
992
+ console.log(`\n Profile: ${r.profile_name}`);
993
+ console.log(` Active skills: ${r.active_skills.length}\n`);
994
+ console.log(" Collision resolutions:");
995
+ for (const res of r.resolutions) {
996
+ console.log(` ${res.domain}: ${res.chosen} (over: ${res.alternatives.join(", ") || "none"})`);
997
+ }
998
+ console.log(`\n Total active: ${r.active_skills.length} skills`);
999
+ }
1000
+ }
1001
+ catch (e) {
1002
+ const msg = e instanceof Error ? e.message : String(e);
1003
+ console.error(`Error: ${msg}`);
1004
+ process.exit(1);
1005
+ }
1006
+ });
1007
+ skillCmd
1008
+ .command("generate")
1009
+ .description("Generate layered super-skill files (core / extended / reference)")
1010
+ .option("-p, --profile <name>", "Profile: ecc-first, superpowers-first, minimal (default: auto-detected)")
1011
+ .option("--auto", "Auto-detect profile and size based on project stack and AI tool (default when --profile is omitted)")
1012
+ .option("--all-domains", "Load all skill domains regardless of detected project stack")
1013
+ .option("--collisions-only", "Only include collision winners, skip non-colliding skills")
1014
+ .option("--pipe", "Output content to stdout instead of writing files")
1015
+ .option("--layer <layer>", "Layer to pipe: core|extended|reference|all (default: core)", "core")
1016
+ .action(async (opts) => {
1017
+ const validLayers = ["core", "extended", "reference", "all"];
1018
+ if (!validLayers.includes(opts.layer)) {
1019
+ process.stderr.write(`Error: --layer must be one of: ${validLayers.join(", ")}\n`);
1020
+ process.exit(1);
1021
+ }
1022
+ try {
1023
+ let resolvedProfile;
1024
+ let relevantDomains;
1025
+ // Auto-detect when no explicit profile is given
1026
+ if (!opts.profile) {
1027
+ const autoConfig = await autoDetect(process.cwd());
1028
+ resolvedProfile = autoConfig.profile;
1029
+ // Apply domain filtering unless --all-domains is set
1030
+ if (!opts.allDomains) {
1031
+ relevantDomains = getRelevantDomains(autoConfig.detectedStack);
1032
+ }
1033
+ if (!opts.pipe) {
1034
+ process.stderr.write(`Auto-detected: ${autoConfig.detectedStack.primary}${autoConfig.detectedStack.frameworks.length ? " + " + autoConfig.detectedStack.frameworks.join(", ") : ""} project on ${autoConfig.detectedTool.tool}\n` +
1035
+ `Profile: ${autoConfig.profile} | Size: ${autoConfig.size}\n`);
1036
+ }
1037
+ }
1038
+ else {
1039
+ resolvedProfile = opts.profile;
1040
+ }
1041
+ const result = await skillCommand(getVaultFs(), getConfig().vaultPath, {
1042
+ action: "generate",
1043
+ profile: resolvedProfile,
1044
+ includeNonColliding: !opts.collisionsOnly,
1045
+ pipe: opts.pipe,
1046
+ pipeLayer: opts.layer,
1047
+ relevantDomains,
1048
+ });
1049
+ if (result.action === "generate") {
1050
+ const r = result.result;
1051
+ if (!r.success) {
1052
+ process.stderr.write(`Error: ${r.error}\n`);
1053
+ process.exit(1);
1054
+ }
1055
+ if (opts.pipe) {
1056
+ // Raw content to stdout; any status/errors to stderr
1057
+ if (r.pipe_content !== undefined) {
1058
+ process.stdout.write(r.pipe_content);
1059
+ }
1060
+ if (r.fetch_errors && r.fetch_errors.length > 0) {
1061
+ process.stderr.write(`\nFetch errors (${r.fetch_errors.length}):\n`);
1062
+ for (const err of r.fetch_errors)
1063
+ process.stderr.write(` - ${err}\n`);
1064
+ }
1065
+ return;
1066
+ }
1067
+ // Normal mode — 3-layer summary
1068
+ const layers = r.layers;
1069
+ const pad = (s, n) => s.padEnd(n);
1070
+ console.log(`\n Super-skill generated!\n`);
1071
+ console.log(` ${pad("Core:", 11)} ${pad(layers.core.path, 45)} (${layers.core.skill_count} skills, ~${layers.core.estimated_tokens} tokens)`);
1072
+ console.log(` ${pad("Extended:", 11)} ${pad(layers.extended.path, 45)} (${layers.extended.skill_count} skills, ~${layers.extended.estimated_tokens} tokens)`);
1073
+ console.log(` ${pad("Reference:", 11)} ${pad(layers.reference.path, 45)} (${layers.reference.skill_count} skills, ~${layers.reference.estimated_tokens} tokens)`);
1074
+ console.log(`\n Total: ${r.total_skills ?? 0} skills`);
1075
+ if (r.fetch_errors && r.fetch_errors.length > 0) {
1076
+ console.log(`\n Fetch errors (${r.fetch_errors.length}):`);
1077
+ for (const err of r.fetch_errors)
1078
+ console.log(` - ${err}`);
1079
+ }
1080
+ }
1081
+ }
1082
+ catch (e) {
1083
+ const msg = e instanceof Error ? e.message : String(e);
1084
+ process.stderr.write(`Error: ${msg}\n`);
1085
+ process.exit(1);
1086
+ }
1087
+ });
1088
+ skillCmd
1089
+ .command("manifest")
1090
+ .description("Print lightweight skill index (no content fetching)")
1091
+ .option("-p, --profile <name>", "Profile: ecc-first, superpowers-first, minimal", "ecc-first")
1092
+ .action(async (opts) => {
1093
+ try {
1094
+ const result = await generateManifest({ profile: opts.profile });
1095
+ console.log(JSON.stringify(result, null, 2));
1096
+ }
1097
+ catch (e) {
1098
+ const msg = e instanceof Error ? e.message : String(e);
1099
+ process.stderr.write(`Error: ${msg}\n`);
1100
+ process.exit(1);
1101
+ }
1102
+ });
1103
+ skillCmd
1104
+ .command("load <skill-id>")
1105
+ .description("Load the full content of a specific skill by ID")
1106
+ .action(async (skillId) => {
1107
+ try {
1108
+ const result = await loadSkillContent(skillId);
1109
+ if (!result.success) {
1110
+ process.stderr.write(`Error: ${result.error}\n`);
1111
+ process.exit(1);
1112
+ }
1113
+ process.stdout.write(result.content ?? "");
1114
+ }
1115
+ catch (e) {
1116
+ const msg = e instanceof Error ? e.message : String(e);
1117
+ process.stderr.write(`Error: ${msg}\n`);
1118
+ process.exit(1);
1119
+ }
1120
+ });
1121
+ skillCmd
1122
+ .command("activate <task>")
1123
+ .description("Smart skill loader — describe your task and get the best-matched skill")
1124
+ .option("-p, --profile <name>", "Profile: ecc-first, superpowers-first, minimal")
1125
+ .option("-d, --domain <domain>", "Domain(s) to load directly, e.g. 'brainstorming' or 'planning,security'")
1126
+ .action(async (task, opts) => {
1127
+ try {
1128
+ const result = await activateSkills({ task, profile: opts.profile, domain: opts.domain });
1129
+ if (!result.success) {
1130
+ process.stderr.write(`Error: ${result.error}\n`);
1131
+ process.exit(1);
1132
+ }
1133
+ if (result.skills_loaded.length === 0) {
1134
+ process.stderr.write(`No skills matched for: "${task}"\n`);
1135
+ process.stderr.write(`Matched domains: ${result.matched_domains.join(", ") || "none"}\n`);
1136
+ process.exit(1);
1137
+ }
1138
+ process.stderr.write(`Loaded ${result.skills_loaded.length} skill(s) for: ${result.matched_domains.join(", ")}\n`);
1139
+ for (const s of result.skills_loaded) {
1140
+ process.stderr.write(` → ${s.id} (${s.name})\n`);
1141
+ }
1142
+ process.stderr.write(` ~${result.total_tokens} tokens\n`);
1143
+ process.stdout.write(result.content);
1144
+ }
1145
+ catch (e) {
1146
+ const msg = e instanceof Error ? e.message : String(e);
1147
+ process.stderr.write(`Error: ${msg}\n`);
1148
+ process.exit(1);
1149
+ }
1150
+ });
1151
+ // ── setup / teardown ─────────────────────────────────
1152
+ registerSetupCommands(program);
1153
+ program.parse();
1154
+ process.on("unhandledRejection", (reason) => {
1155
+ console.error("Unhandled rejection:", reason);
1156
+ process.exit(1);
1157
+ });
1158
+ //# sourceMappingURL=cli.js.map