vemora 0.1.0-alpha.15

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 (254) hide show
  1. package/README.md +851 -0
  2. package/dist/cli.d.ts +16 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +682 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/ask.d.ts +14 -0
  7. package/dist/commands/ask.d.ts.map +1 -0
  8. package/dist/commands/ask.js +137 -0
  9. package/dist/commands/ask.js.map +1 -0
  10. package/dist/commands/audit.d.ts +17 -0
  11. package/dist/commands/audit.d.ts.map +1 -0
  12. package/dist/commands/audit.js +398 -0
  13. package/dist/commands/audit.js.map +1 -0
  14. package/dist/commands/brief.d.ts +16 -0
  15. package/dist/commands/brief.d.ts.map +1 -0
  16. package/dist/commands/brief.js +84 -0
  17. package/dist/commands/brief.js.map +1 -0
  18. package/dist/commands/chat.d.ts +7 -0
  19. package/dist/commands/chat.d.ts.map +1 -0
  20. package/dist/commands/chat.js +155 -0
  21. package/dist/commands/chat.js.map +1 -0
  22. package/dist/commands/context.d.ts +63 -0
  23. package/dist/commands/context.d.ts.map +1 -0
  24. package/dist/commands/context.js +794 -0
  25. package/dist/commands/context.js.map +1 -0
  26. package/dist/commands/dead-code.d.ts +15 -0
  27. package/dist/commands/dead-code.d.ts.map +1 -0
  28. package/dist/commands/dead-code.js +206 -0
  29. package/dist/commands/dead-code.js.map +1 -0
  30. package/dist/commands/deps.d.ts +20 -0
  31. package/dist/commands/deps.d.ts.map +1 -0
  32. package/dist/commands/deps.js +138 -0
  33. package/dist/commands/deps.js.map +1 -0
  34. package/dist/commands/focus.d.ts +8 -0
  35. package/dist/commands/focus.d.ts.map +1 -0
  36. package/dist/commands/focus.js +310 -0
  37. package/dist/commands/focus.js.map +1 -0
  38. package/dist/commands/index.d.ts +10 -0
  39. package/dist/commands/index.d.ts.map +1 -0
  40. package/dist/commands/index.js +366 -0
  41. package/dist/commands/index.js.map +1 -0
  42. package/dist/commands/init-agent.d.ts +23 -0
  43. package/dist/commands/init-agent.d.ts.map +1 -0
  44. package/dist/commands/init-agent.js +384 -0
  45. package/dist/commands/init-agent.js.map +1 -0
  46. package/dist/commands/init.d.ts +2 -0
  47. package/dist/commands/init.d.ts.map +1 -0
  48. package/dist/commands/init.js +122 -0
  49. package/dist/commands/init.js.map +1 -0
  50. package/dist/commands/knowledge.d.ts +14 -0
  51. package/dist/commands/knowledge.d.ts.map +1 -0
  52. package/dist/commands/knowledge.js +115 -0
  53. package/dist/commands/knowledge.js.map +1 -0
  54. package/dist/commands/plan.d.ts +24 -0
  55. package/dist/commands/plan.d.ts.map +1 -0
  56. package/dist/commands/plan.js +867 -0
  57. package/dist/commands/plan.js.map +1 -0
  58. package/dist/commands/query.d.ts +39 -0
  59. package/dist/commands/query.d.ts.map +1 -0
  60. package/dist/commands/query.js +392 -0
  61. package/dist/commands/query.js.map +1 -0
  62. package/dist/commands/remember.d.ts +11 -0
  63. package/dist/commands/remember.d.ts.map +1 -0
  64. package/dist/commands/remember.js +267 -0
  65. package/dist/commands/remember.js.map +1 -0
  66. package/dist/commands/report.d.ts +10 -0
  67. package/dist/commands/report.d.ts.map +1 -0
  68. package/dist/commands/report.js +243 -0
  69. package/dist/commands/report.js.map +1 -0
  70. package/dist/commands/status.d.ts +2 -0
  71. package/dist/commands/status.d.ts.map +1 -0
  72. package/dist/commands/status.js +127 -0
  73. package/dist/commands/status.js.map +1 -0
  74. package/dist/commands/summarize.d.ts +14 -0
  75. package/dist/commands/summarize.d.ts.map +1 -0
  76. package/dist/commands/summarize.js +170 -0
  77. package/dist/commands/summarize.js.map +1 -0
  78. package/dist/commands/triage.d.ts +33 -0
  79. package/dist/commands/triage.d.ts.map +1 -0
  80. package/dist/commands/triage.js +419 -0
  81. package/dist/commands/triage.js.map +1 -0
  82. package/dist/commands/usages.d.ts +14 -0
  83. package/dist/commands/usages.d.ts.map +1 -0
  84. package/dist/commands/usages.js +236 -0
  85. package/dist/commands/usages.js.map +1 -0
  86. package/dist/core/config.d.ts +35 -0
  87. package/dist/core/config.d.ts.map +1 -0
  88. package/dist/core/config.js +159 -0
  89. package/dist/core/config.js.map +1 -0
  90. package/dist/core/types.d.ts +287 -0
  91. package/dist/core/types.d.ts.map +1 -0
  92. package/dist/core/types.js +4 -0
  93. package/dist/core/types.js.map +1 -0
  94. package/dist/embeddings/factory.d.ts +9 -0
  95. package/dist/embeddings/factory.d.ts.map +1 -0
  96. package/dist/embeddings/factory.js +26 -0
  97. package/dist/embeddings/factory.js.map +1 -0
  98. package/dist/embeddings/noop.d.ts +17 -0
  99. package/dist/embeddings/noop.d.ts.map +1 -0
  100. package/dist/embeddings/noop.js +22 -0
  101. package/dist/embeddings/noop.js.map +1 -0
  102. package/dist/embeddings/ollama.d.ts +11 -0
  103. package/dist/embeddings/ollama.d.ts.map +1 -0
  104. package/dist/embeddings/ollama.js +49 -0
  105. package/dist/embeddings/ollama.js.map +1 -0
  106. package/dist/embeddings/openai.d.ts +10 -0
  107. package/dist/embeddings/openai.d.ts.map +1 -0
  108. package/dist/embeddings/openai.js +67 -0
  109. package/dist/embeddings/openai.js.map +1 -0
  110. package/dist/embeddings/provider.d.ts +19 -0
  111. package/dist/embeddings/provider.d.ts.map +1 -0
  112. package/dist/embeddings/provider.js +3 -0
  113. package/dist/embeddings/provider.js.map +1 -0
  114. package/dist/indexer/callgraph.d.ts +16 -0
  115. package/dist/indexer/callgraph.d.ts.map +1 -0
  116. package/dist/indexer/callgraph.js +154 -0
  117. package/dist/indexer/callgraph.js.map +1 -0
  118. package/dist/indexer/chunkBySlidingWindow.d.ts +6 -0
  119. package/dist/indexer/chunkBySlidingWindow.d.ts.map +1 -0
  120. package/dist/indexer/chunkBySlidingWindow.js +30 -0
  121. package/dist/indexer/chunkBySlidingWindow.js.map +1 -0
  122. package/dist/indexer/chunkBySymbols.d.ts +7 -0
  123. package/dist/indexer/chunkBySymbols.d.ts.map +1 -0
  124. package/dist/indexer/chunkBySymbols.js +57 -0
  125. package/dist/indexer/chunkBySymbols.js.map +1 -0
  126. package/dist/indexer/chunker.d.ts +15 -0
  127. package/dist/indexer/chunker.d.ts.map +1 -0
  128. package/dist/indexer/chunker.js +26 -0
  129. package/dist/indexer/chunker.js.map +1 -0
  130. package/dist/indexer/classHeader.d.ts +7 -0
  131. package/dist/indexer/classHeader.d.ts.map +1 -0
  132. package/dist/indexer/classHeader.js +37 -0
  133. package/dist/indexer/classHeader.js.map +1 -0
  134. package/dist/indexer/deps.d.ts +66 -0
  135. package/dist/indexer/deps.d.ts.map +1 -0
  136. package/dist/indexer/deps.js +412 -0
  137. package/dist/indexer/deps.js.map +1 -0
  138. package/dist/indexer/hasher.d.ts +17 -0
  139. package/dist/indexer/hasher.d.ts.map +1 -0
  140. package/dist/indexer/hasher.js +38 -0
  141. package/dist/indexer/hasher.js.map +1 -0
  142. package/dist/indexer/parser.d.ts +18 -0
  143. package/dist/indexer/parser.d.ts.map +1 -0
  144. package/dist/indexer/parser.js +355 -0
  145. package/dist/indexer/parser.js.map +1 -0
  146. package/dist/indexer/scanner.d.ts +18 -0
  147. package/dist/indexer/scanner.d.ts.map +1 -0
  148. package/dist/indexer/scanner.js +37 -0
  149. package/dist/indexer/scanner.js.map +1 -0
  150. package/dist/indexer/strategy.d.ts +11 -0
  151. package/dist/indexer/strategy.d.ts.map +1 -0
  152. package/dist/indexer/strategy.js +15 -0
  153. package/dist/indexer/strategy.js.map +1 -0
  154. package/dist/indexer/tests.d.ts +15 -0
  155. package/dist/indexer/tests.d.ts.map +1 -0
  156. package/dist/indexer/tests.js +68 -0
  157. package/dist/indexer/tests.js.map +1 -0
  158. package/dist/indexer/todos.d.ts +9 -0
  159. package/dist/indexer/todos.d.ts.map +1 -0
  160. package/dist/indexer/todos.js +29 -0
  161. package/dist/indexer/todos.js.map +1 -0
  162. package/dist/llm/anthropic.d.ts +8 -0
  163. package/dist/llm/anthropic.d.ts.map +1 -0
  164. package/dist/llm/anthropic.js +76 -0
  165. package/dist/llm/anthropic.js.map +1 -0
  166. package/dist/llm/claude-code.d.ts +37 -0
  167. package/dist/llm/claude-code.d.ts.map +1 -0
  168. package/dist/llm/claude-code.js +97 -0
  169. package/dist/llm/claude-code.js.map +1 -0
  170. package/dist/llm/factory.d.ts +7 -0
  171. package/dist/llm/factory.d.ts.map +1 -0
  172. package/dist/llm/factory.js +47 -0
  173. package/dist/llm/factory.js.map +1 -0
  174. package/dist/llm/ollama.d.ts +8 -0
  175. package/dist/llm/ollama.d.ts.map +1 -0
  176. package/dist/llm/ollama.js +83 -0
  177. package/dist/llm/ollama.js.map +1 -0
  178. package/dist/llm/openai.d.ts +8 -0
  179. package/dist/llm/openai.d.ts.map +1 -0
  180. package/dist/llm/openai.js +68 -0
  181. package/dist/llm/openai.js.map +1 -0
  182. package/dist/llm/provider.d.ts +35 -0
  183. package/dist/llm/provider.d.ts.map +1 -0
  184. package/dist/llm/provider.js +3 -0
  185. package/dist/llm/provider.js.map +1 -0
  186. package/dist/search/bm25.d.ts +3 -0
  187. package/dist/search/bm25.d.ts.map +1 -0
  188. package/dist/search/bm25.js +104 -0
  189. package/dist/search/bm25.js.map +1 -0
  190. package/dist/search/formatter.d.ts +43 -0
  191. package/dist/search/formatter.d.ts.map +1 -0
  192. package/dist/search/formatter.js +208 -0
  193. package/dist/search/formatter.js.map +1 -0
  194. package/dist/search/hybrid.d.ts +10 -0
  195. package/dist/search/hybrid.d.ts.map +1 -0
  196. package/dist/search/hybrid.js +53 -0
  197. package/dist/search/hybrid.js.map +1 -0
  198. package/dist/search/merge.d.ts +33 -0
  199. package/dist/search/merge.d.ts.map +1 -0
  200. package/dist/search/merge.js +158 -0
  201. package/dist/search/merge.js.map +1 -0
  202. package/dist/search/mmr.d.ts +23 -0
  203. package/dist/search/mmr.d.ts.map +1 -0
  204. package/dist/search/mmr.js +95 -0
  205. package/dist/search/mmr.js.map +1 -0
  206. package/dist/search/rerank.d.ts +12 -0
  207. package/dist/search/rerank.d.ts.map +1 -0
  208. package/dist/search/rerank.js +113 -0
  209. package/dist/search/rerank.js.map +1 -0
  210. package/dist/search/signature.d.ts +42 -0
  211. package/dist/search/signature.d.ts.map +1 -0
  212. package/dist/search/signature.js +112 -0
  213. package/dist/search/signature.js.map +1 -0
  214. package/dist/search/vector.d.ts +41 -0
  215. package/dist/search/vector.d.ts.map +1 -0
  216. package/dist/search/vector.js +185 -0
  217. package/dist/search/vector.js.map +1 -0
  218. package/dist/storage/cache.d.ts +30 -0
  219. package/dist/storage/cache.d.ts.map +1 -0
  220. package/dist/storage/cache.js +160 -0
  221. package/dist/storage/cache.js.map +1 -0
  222. package/dist/storage/knowledge.d.ts +23 -0
  223. package/dist/storage/knowledge.d.ts.map +1 -0
  224. package/dist/storage/knowledge.js +81 -0
  225. package/dist/storage/knowledge.js.map +1 -0
  226. package/dist/storage/planSession.d.ts +39 -0
  227. package/dist/storage/planSession.d.ts.map +1 -0
  228. package/dist/storage/planSession.js +78 -0
  229. package/dist/storage/planSession.js.map +1 -0
  230. package/dist/storage/repository.d.ts +27 -0
  231. package/dist/storage/repository.d.ts.map +1 -0
  232. package/dist/storage/repository.js +95 -0
  233. package/dist/storage/repository.js.map +1 -0
  234. package/dist/storage/session.d.ts +38 -0
  235. package/dist/storage/session.d.ts.map +1 -0
  236. package/dist/storage/session.js +100 -0
  237. package/dist/storage/session.js.map +1 -0
  238. package/dist/storage/summaries.d.ts +19 -0
  239. package/dist/storage/summaries.d.ts.map +1 -0
  240. package/dist/storage/summaries.js +66 -0
  241. package/dist/storage/summaries.js.map +1 -0
  242. package/dist/storage/usage.d.ts +39 -0
  243. package/dist/storage/usage.d.ts.map +1 -0
  244. package/dist/storage/usage.js +55 -0
  245. package/dist/storage/usage.js.map +1 -0
  246. package/dist/utils/git.d.ts +20 -0
  247. package/dist/utils/git.d.ts.map +1 -0
  248. package/dist/utils/git.js +49 -0
  249. package/dist/utils/git.js.map +1 -0
  250. package/dist/utils/tokenizer.d.ts +32 -0
  251. package/dist/utils/tokenizer.d.ts.map +1 -0
  252. package/dist/utils/tokenizer.js +66 -0
  253. package/dist/utils/tokenizer.js.map +1 -0
  254. package/package.json +71 -0
package/dist/cli.js ADDED
@@ -0,0 +1,682 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * vemora CLI
5
+ *
6
+ * Repository-local memory system for LLM-assisted development.
7
+ * Builds a structured, versioned index of a codebase and enables
8
+ * semantic search over it using local or remote embedding providers.
9
+ *
10
+ * Usage:
11
+ * vemora init Initialize .vemora/ in the current repo
12
+ * vemora index Scan and index the repository (incremental)
13
+ * vemora query "<text>" Find relevant code chunks
14
+ * vemora status Show current index stats
15
+ */
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ const chalk_1 = __importDefault(require("chalk"));
21
+ const commander_1 = require("commander");
22
+ const path_1 = __importDefault(require("path"));
23
+ const ask_1 = require("./commands/ask");
24
+ const brief_1 = require("./commands/brief");
25
+ const audit_1 = require("./commands/audit");
26
+ const focus_1 = require("./commands/focus");
27
+ const plan_1 = require("./commands/plan");
28
+ const planSession_1 = require("./storage/planSession");
29
+ const triage_1 = require("./commands/triage");
30
+ const dead_code_1 = require("./commands/dead-code");
31
+ const chat_1 = require("./commands/chat");
32
+ const context_1 = require("./commands/context");
33
+ const deps_1 = require("./commands/deps");
34
+ const index_1 = require("./commands/index");
35
+ const init_1 = require("./commands/init");
36
+ const init_agent_1 = require("./commands/init-agent");
37
+ const knowledge_1 = require("./commands/knowledge");
38
+ const query_1 = require("./commands/query");
39
+ const remember_1 = require("./commands/remember");
40
+ const usages_1 = require("./commands/usages");
41
+ const report_1 = require("./commands/report");
42
+ const status_1 = require("./commands/status");
43
+ const summarize_1 = require("./commands/summarize");
44
+ const config_1 = require("./core/config");
45
+ const program = new commander_1.Command();
46
+ program
47
+ .name("vemora")
48
+ .description("Repository-local memory system for LLM-assisted development")
49
+ .version(require("../package.json").version);
50
+ // ── init ──────────────────────────────────────────────────────────────────────
51
+ program
52
+ .command("init")
53
+ .description("Initialize vemora in the current repository")
54
+ .option("--root <dir>", "project root directory (default: cwd)", "")
55
+ .action(async (opts) => {
56
+ const rootDir = path_1.default.resolve(opts.root || process.cwd());
57
+ try {
58
+ await (0, init_1.runInit)(rootDir);
59
+ }
60
+ catch (err) {
61
+ console.error(chalk_1.default.red("Error:"), err.message);
62
+ process.exit(1);
63
+ }
64
+ });
65
+ // ── index ─────────────────────────────────────────────────────────────────────
66
+ program
67
+ .command("index")
68
+ .description("Index the repository content")
69
+ .option("--root <dir>", "Project root directory", process.cwd())
70
+ .option("--force", "Re-index all files, ignoring hashes", false)
71
+ .option("--no-embed", "Skip embedding generation", false)
72
+ .option("-w, --watch", "Watch for changes and re-index automatically", false)
73
+ .action(async (opts) => {
74
+ const rootDir = path_1.default.resolve(opts.root || process.cwd());
75
+ try {
76
+ // Commander's --no-embed sets opts.embed = false
77
+ await (0, index_1.runIndex)(rootDir, {
78
+ force: opts.force,
79
+ noEmbed: !opts.embed,
80
+ watch: opts.watch,
81
+ });
82
+ }
83
+ catch (err) {
84
+ console.error(chalk_1.default.red("Error:"), err.message);
85
+ process.exit(1);
86
+ }
87
+ });
88
+ // ── query ─────────────────────────────────────────────────────────────────────
89
+ program
90
+ .command("query <question>")
91
+ .description("Search the vemora index for relevant code")
92
+ .option("--root <dir>", "project root directory (default: cwd)", "")
93
+ .option("-k, --top-k <n>", "number of results to return", "10")
94
+ .option("-c, --show-code", "print code snippets in results", false)
95
+ .option("--keyword", "use keyword search instead of semantic search", false)
96
+ .option("--format <fmt>", "output format: terminal (default), json, markdown", "terminal")
97
+ .option("--rerank", "re-score results with a cross-encoder model (slower but more accurate)", false)
98
+ .option("--hybrid", "use hybrid search (vector + BM25)", false)
99
+ .option("--alpha <n>", "hybrid weight for vector search (0-1, default: 0.7)", "0.7")
100
+ .option("--budget <n>", "max tokens to include across results (overrides top-k as upper bound)")
101
+ .option("--mmr", "apply Maximal Marginal Relevance to diversify results", false)
102
+ .option("--lambda <n>", "MMR relevance weight (0=diverse, 1=relevant, default: 0.5)", "0.5")
103
+ .option("--merge", "merge adjacent or overlapping chunks from the same file", false)
104
+ .option("--merge-gap <n>", "max line gap between chunks to still merge (default: 3)", "3")
105
+ .option("--session", "skip chunks already seen in this session (auto-expires after 30 min idle)", false)
106
+ .option("--fresh", "reset session memory before this query", false)
107
+ .action(async (question, opts) => {
108
+ const rootDir = path_1.default.resolve(opts.root || process.cwd());
109
+ const fmt = opts.format;
110
+ if (!["terminal", "json", "markdown"].includes(fmt)) {
111
+ console.error(chalk_1.default.red(`Unknown format "${fmt}". Use: terminal, json, markdown`));
112
+ process.exit(1);
113
+ }
114
+ try {
115
+ await (0, query_1.runQuery)(rootDir, question, {
116
+ topK: parseInt(opts.topK, 10),
117
+ showCode: opts.showCode,
118
+ keyword: opts.keyword,
119
+ format: fmt,
120
+ rerank: opts.rerank,
121
+ hybrid: opts.hybrid,
122
+ alpha: parseFloat(opts.alpha),
123
+ budget: opts.budget ? parseInt(opts.budget, 10) : undefined,
124
+ mmr: opts.mmr,
125
+ lambda: parseFloat(opts.lambda),
126
+ merge: opts.merge,
127
+ mergeGap: parseInt(opts.mergeGap, 10),
128
+ session: opts.session,
129
+ fresh: opts.fresh,
130
+ });
131
+ }
132
+ catch (err) {
133
+ console.error(chalk_1.default.red("Error:"), err.message);
134
+ process.exit(1);
135
+ }
136
+ });
137
+ // ── status ────────────────────────────────────────────────────────────────────
138
+ program
139
+ .command("status")
140
+ .description("Show current index stats")
141
+ .option("--root <dir>", "project root directory (default: cwd)", "")
142
+ .action(async (opts) => {
143
+ const rootDir = path_1.default.resolve(opts.root || process.cwd());
144
+ try {
145
+ await (0, status_1.runStatus)(rootDir);
146
+ }
147
+ catch (err) {
148
+ console.error(chalk_1.default.red("Error:"), err.message);
149
+ process.exit(1);
150
+ }
151
+ });
152
+ // ── ask ───────────────────────────────────────────────────────────────────────
153
+ program
154
+ .command("ask <question>")
155
+ .description("One-shot Q&A: retrieve relevant context and answer with the configured LLM")
156
+ .option("--root <dir>", "project root directory (default: cwd)", "")
157
+ .option("-k, --top-k <n>", "number of chunks to retrieve", "5")
158
+ .option("--keyword", "use keyword search (no embeddings required)", false)
159
+ .option("--hybrid", "use hybrid vector+BM25 search", false)
160
+ .option("--budget <n>", "max context tokens to send to the LLM (default: 6000)", "6000")
161
+ .option("--show-context", "print the retrieved context before the answer", false)
162
+ .action(async (question, opts) => {
163
+ const rootDir = path_1.default.resolve(opts.root || process.cwd());
164
+ try {
165
+ await (0, ask_1.runAsk)(rootDir, question, {
166
+ topK: Number.parseInt(opts.topK, 10),
167
+ keyword: opts.keyword,
168
+ hybrid: opts.hybrid,
169
+ budget: Number.parseInt(opts.budget, 10),
170
+ showContext: opts.showContext,
171
+ });
172
+ }
173
+ catch (err) {
174
+ console.error(chalk_1.default.red("Error:"), err.message);
175
+ process.exit(1);
176
+ }
177
+ });
178
+ // ── plan ──────────────────────────────────────────────────────────────────────
179
+ program
180
+ .command("plan <task>")
181
+ .description("Planner-executor: a pro LLM decomposes the task, a smaller LLM executes each step")
182
+ .option("--root <dir>", "project root directory (default: cwd)", "")
183
+ .option("-k, --top-k <n>", "chunks to retrieve per step (default: 5)", "5")
184
+ .option("--keyword", "use keyword search (no embeddings required)", false)
185
+ .option("--budget <n>", "max context tokens per step (default: 4000)", "4000")
186
+ .option("--show-context", "print retrieved context for each step", false)
187
+ .option("--confirm", "show the plan and ask for confirmation before executing", false)
188
+ .option("--synthesize", "call the planner again after all steps to produce a single final answer", false)
189
+ .option("--verify", "have the planner verify each write-step diff before applying", false)
190
+ .option("--apply", "apply diffs produced by write steps to the filesystem (via patch -p1)", false)
191
+ .option("--max-retries <n>", "max planner→executor retry cycles per write step when verify rejects (default: 2)", "2")
192
+ .option("--resume <id>", "resume a previous session by ID or 8-char prefix")
193
+ .action(async (task, opts) => {
194
+ const rootDir = path_1.default.resolve(opts.root || process.cwd());
195
+ try {
196
+ await (0, plan_1.runPlan)(rootDir, task, {
197
+ topK: Number.parseInt(opts.topK, 10),
198
+ keyword: opts.keyword,
199
+ budget: Number.parseInt(opts.budget, 10),
200
+ showContext: opts.showContext,
201
+ confirm: opts.confirm,
202
+ synthesize: opts.synthesize,
203
+ verify: opts.verify,
204
+ apply: opts.apply,
205
+ maxRetries: Number.parseInt(opts.maxRetries, 10),
206
+ resumeSession: opts.resume,
207
+ });
208
+ }
209
+ catch (err) {
210
+ console.error(chalk_1.default.red("Error:"), err.message);
211
+ process.exit(1);
212
+ }
213
+ });
214
+ // ── sessions ──────────────────────────────────────────────────────────────────
215
+ program
216
+ .command("sessions")
217
+ .description("list recent plan sessions (use --resume <id> on vemora plan to continue one)")
218
+ .option("--root <dir>", "project root directory (default: cwd)", "")
219
+ .action(async (opts) => {
220
+ const rootDir = path_1.default.resolve(opts.root || process.cwd());
221
+ let config;
222
+ try {
223
+ config = (0, config_1.loadConfig)(rootDir);
224
+ }
225
+ catch (err) {
226
+ console.error(chalk_1.default.red(err.message));
227
+ process.exit(1);
228
+ }
229
+ const storage = new planSession_1.PlanSessionStorage(config.projectId);
230
+ const sessions = storage.list();
231
+ if (sessions.length === 0) {
232
+ console.log(chalk_1.default.gray("No sessions found."));
233
+ return;
234
+ }
235
+ console.log(chalk_1.default.bold.cyan("\n[vemora sessions]\n"));
236
+ for (const s of sessions) {
237
+ const statusColor = s.status === "completed"
238
+ ? chalk_1.default.green
239
+ : s.status === "failed"
240
+ ? chalk_1.default.red
241
+ : chalk_1.default.yellow;
242
+ const age = new Date(s.updatedAt).toLocaleString();
243
+ console.log(` ${chalk_1.default.bold(s.shortId)} ${statusColor(s.status.padEnd(9))} ${chalk_1.default.gray(age)} ${s.task.slice(0, 60)}${s.task.length > 60 ? "…" : ""}`);
244
+ console.log(chalk_1.default.gray(` ${s.completedStepIds.length} step(s) done · resume: vemora plan "<task>" --resume ${s.shortId}`));
245
+ }
246
+ console.log();
247
+ });
248
+ // ── chat ──────────────────────────────────────────────────────────────────────
249
+ program
250
+ .command("chat")
251
+ .description("Interactive chat with the codebase (middleware proxy)")
252
+ .option("--root <dir>", "project root directory (default: cwd)", "")
253
+ .option("--provider <name>", "LLM provider (openai, anthropic, ollama)")
254
+ .option("--model <name>", "LLM model to use")
255
+ .option("-k, --top-k <n>", "number of context chunks to pull per message (default: 5)", "5")
256
+ .action(async (opts) => {
257
+ const rootDir = path_1.default.resolve(opts.root || process.cwd());
258
+ try {
259
+ await (0, chat_1.runChat)(rootDir, {
260
+ provider: opts.provider,
261
+ model: opts.model,
262
+ topK: parseInt(opts.topK, 10),
263
+ });
264
+ }
265
+ catch (err) {
266
+ console.error(chalk_1.default.red("Error:"), err.message);
267
+ process.exit(1);
268
+ }
269
+ });
270
+ // ── context ──────────────────────────────────────────────────────────────────
271
+ program
272
+ .command("context")
273
+ .description("Generate an optimized LLM context block from query and/or file")
274
+ .option("--root <dir>", "project root directory (default: cwd)", "")
275
+ .option("-q, --query <text>", "natural-language query to find relevant code")
276
+ .option("-f, --file <path>", "include a specific file in full with its dependency graph")
277
+ .option("-k, --top-k <n>", "number of search results to include (default: 5)", "5")
278
+ .option("--keyword", "use keyword search instead of semantic search", false)
279
+ .option("--show-code", "show full code (no line cap)", false)
280
+ .option("--format <fmt>", "output format: markdown (default), plain, terse")
281
+ .option("--rerank", "re-score results with a cross-encoder model", false)
282
+ .option("--hybrid", "use hybrid search (vector + BM25)", false)
283
+ .option("--alpha <n>", "hybrid weight for vector search (0-1, default: 0.7)", "0.7")
284
+ .option("--budget <n>", "max tokens to include across retrieved chunks")
285
+ .option("--mmr", "apply Maximal Marginal Relevance to diversify results", false)
286
+ .option("--lambda <n>", "MMR relevance weight (0=diverse, 1=relevant, default: 0.5)", "0.5")
287
+ .option("--merge", "merge adjacent or overlapping chunks from the same file", false)
288
+ .option("--merge-gap <n>", "max line gap between chunks to still merge (default: 3)", "3")
289
+ .option("--structured", "emit a structured context block (Entry Point / Dependencies / Types / Related Patterns)", false)
290
+ .option("--session", "skip chunks already seen in this session (auto-expires after 30 min idle)", false)
291
+ .option("--fresh", "reset session memory before this query", false)
292
+ .option("--since <ref>", "restrict search to files changed since this git ref (e.g. HEAD~5, main)")
293
+ .action(async (opts) => {
294
+ const rootDir = path_1.default.resolve(opts.root || process.cwd());
295
+ const fmt = opts.format;
296
+ if (fmt && !["markdown", "plain", "terse"].includes(fmt)) {
297
+ console.error(chalk_1.default.red(`Unknown format "${fmt}". Use: markdown, plain, terse`));
298
+ process.exit(1);
299
+ }
300
+ try {
301
+ await (0, context_1.runContext)(rootDir, {
302
+ query: opts.query,
303
+ file: opts.file,
304
+ topK: parseInt(opts.topK, 10),
305
+ keyword: opts.keyword,
306
+ showCode: opts.showCode,
307
+ format: fmt,
308
+ rerank: opts.rerank,
309
+ hybrid: opts.hybrid,
310
+ alpha: parseFloat(opts.alpha),
311
+ budget: opts.budget ? parseInt(opts.budget, 10) : undefined,
312
+ mmr: opts.mmr,
313
+ lambda: parseFloat(opts.lambda),
314
+ merge: opts.merge,
315
+ mergeGap: parseInt(opts.mergeGap, 10),
316
+ structured: opts.structured,
317
+ session: opts.session,
318
+ fresh: opts.fresh,
319
+ since: opts.since,
320
+ });
321
+ }
322
+ catch (err) {
323
+ console.error(chalk_1.default.red("Error:"), err.message);
324
+ process.exit(1);
325
+ }
326
+ });
327
+ // ── deps ──────────────────────────────────────────────────────────────────────
328
+ program
329
+ .command("deps <file>")
330
+ .description("Show dependency context for a file (imports + used-by)")
331
+ .option("--root <dir>", "project root directory (default: cwd)", "")
332
+ .option("-d, --depth <n>", "transitive depth for outgoing imports (default: 1)", "1")
333
+ .option("-r, --reverse-depth <n>", "transitive depth for incoming importers (default: 1)", "1")
334
+ .action(async (file, opts) => {
335
+ const rootDir = path_1.default.resolve(opts.root || process.cwd());
336
+ try {
337
+ await (0, deps_1.runDeps)(rootDir, file, {
338
+ depth: parseInt(opts.depth, 10),
339
+ reverseDepth: parseInt(opts.reverseDepth, 10),
340
+ });
341
+ }
342
+ catch (err) {
343
+ console.error(chalk_1.default.red("Error:"), err.message);
344
+ process.exit(1);
345
+ }
346
+ });
347
+ // ── summarize ─────────────────────────────────────────────────────────────────
348
+ program
349
+ .command("summarize")
350
+ .description("Generate LLM summaries for each file and a project overview")
351
+ .option("--root <dir>", "project root directory (default: cwd)", "")
352
+ .option("--force", "re-generate all summaries, ignoring content hashes", false)
353
+ .option("--model <name>", "override LLM model (default: from config)")
354
+ .option("--files-only", "only generate per-file summaries, skip project overview", false)
355
+ .option("--project-only", "(re)generate project overview from existing file summaries", false)
356
+ .option("--show", "print the existing project overview without regenerating", false)
357
+ .action(async (opts) => {
358
+ const rootDir = path_1.default.resolve(opts.root || process.cwd());
359
+ try {
360
+ await (0, summarize_1.runSummarize)(rootDir, {
361
+ force: opts.force,
362
+ model: opts.model,
363
+ filesOnly: opts.filesOnly,
364
+ projectOnly: opts.projectOnly,
365
+ show: opts.show,
366
+ });
367
+ }
368
+ catch (err) {
369
+ console.error(chalk_1.default.red("Error:"), err.message);
370
+ process.exit(1);
371
+ }
372
+ });
373
+ // ── init-agent ────────────────────────────────────────────────────────────────
374
+ program
375
+ .command("init-agent")
376
+ .description("Generate AI agent instruction files (CLAUDE.md, GEMINI.md, .github/copilot-instructions.md, .cursor/rules/vemora.mdc, .windsurfrules)")
377
+ .option("--agent <agent>", "Which agent to target: claude, gemini, copilot, cursor, windsurf (default: all)")
378
+ .option("--force", "Overwrite existing files that have no vemora markers")
379
+ .option("--hooks", "Write Claude Code hooks to .claude/settings.json (claude target only)", false)
380
+ .option("--root <dir>", "Project root directory", process.cwd())
381
+ .action(async (opts) => {
382
+ const ALL_AGENTS = ["claude", "copilot", "cursor", "windsurf", "gemini"];
383
+ const agents = opts.agent
384
+ ? ALL_AGENTS.includes(opts.agent)
385
+ ? [opts.agent]
386
+ : undefined
387
+ : undefined;
388
+ if (opts.agent && !agents) {
389
+ console.error(chalk_1.default.red(`Unknown agent "${opts.agent}". Valid values: claude, gemini, copilot, cursor, windsurf`));
390
+ process.exit(1);
391
+ }
392
+ try {
393
+ await (0, init_agent_1.runInitAgent)(opts.root, { agents, force: opts.force, hooks: opts.hooks });
394
+ }
395
+ catch (err) {
396
+ console.error(chalk_1.default.red("Error:"), err.message);
397
+ process.exit(1);
398
+ }
399
+ });
400
+ // ── remember ──────────────────────────────────────────────────────────────────
401
+ program
402
+ .command("remember <text>")
403
+ .description("Save a knowledge entry (architectural decision, pattern, gotcha, glossary term)")
404
+ .option("--root <dir>", "project root directory (default: cwd)", "")
405
+ .option("--category <cat>", "entry category: decision | pattern | gotcha | glossary (auto-classified if omitted)")
406
+ .option("--title <title>", "short title (auto-derived from text if omitted)")
407
+ .option("--files <paths>", "comma-separated project-relative file paths this entry relates to")
408
+ .option("--symbols <names>", "comma-separated symbol names this entry relates to")
409
+ .option("--confidence <level>", "confidence level: high | medium | low", "medium")
410
+ .option("--supersedes <id>", "ID of an existing entry this replaces")
411
+ .option("--by <author>", "createdBy tag (default: human)", "human")
412
+ .action(async (text, opts) => {
413
+ const rootDir = path_1.default.resolve(opts.root || process.cwd());
414
+ try {
415
+ await (0, remember_1.runRemember)(rootDir, text, {
416
+ category: opts.category,
417
+ title: opts.title,
418
+ files: opts.files,
419
+ symbols: opts.symbols,
420
+ confidence: opts.confidence,
421
+ supersedes: opts.supersedes,
422
+ createdBy: opts.by,
423
+ });
424
+ }
425
+ catch (err) {
426
+ console.error(chalk_1.default.red("Error:"), err.message);
427
+ process.exit(1);
428
+ }
429
+ });
430
+ // ── knowledge ─────────────────────────────────────────────────────────────────
431
+ const knowledge = program
432
+ .command("knowledge")
433
+ .description("Manage the project knowledge store");
434
+ knowledge
435
+ .command("list")
436
+ .description("List knowledge entries, optionally filtered")
437
+ .option("--root <dir>", "project root directory (default: cwd)", "")
438
+ .option("--category <cat>", "filter by category: decision | pattern | gotcha | glossary")
439
+ .option("--file <path>", "filter by related file path (substring match)")
440
+ .option("--symbol <name>", "filter by related symbol name")
441
+ .option("--as-of <date>", "show only entries valid at this ISO date")
442
+ .option("--expired", "show only entries that have been invalidated", false)
443
+ .action(async (opts) => {
444
+ const rootDir = path_1.default.resolve(opts.root || process.cwd());
445
+ try {
446
+ await (0, knowledge_1.runKnowledgeList)(rootDir, {
447
+ category: opts.category,
448
+ file: opts.file,
449
+ symbol: opts.symbol,
450
+ asOf: opts.asOf,
451
+ expired: opts.expired,
452
+ });
453
+ }
454
+ catch (err) {
455
+ console.error(chalk_1.default.red("Error:"), err.message);
456
+ process.exit(1);
457
+ }
458
+ });
459
+ knowledge
460
+ .command("forget <id>")
461
+ .description("Remove a knowledge entry by ID (prefix match supported)")
462
+ .option("--root <dir>", "project root directory (default: cwd)", "")
463
+ .option("--invalidate", "mark as expired instead of deleting (preserves history)", false)
464
+ .action(async (id, opts) => {
465
+ const rootDir = path_1.default.resolve(opts.root || process.cwd());
466
+ try {
467
+ await (0, knowledge_1.runKnowledgeForget)(rootDir, id, { invalidate: opts.invalidate });
468
+ }
469
+ catch (err) {
470
+ console.error(chalk_1.default.red("Error:"), err.message);
471
+ process.exit(1);
472
+ }
473
+ });
474
+ // ── usages ────────────────────────────────────────────────────────────────────
475
+ program
476
+ .command("usages <symbol>")
477
+ .description("Find all files that use a symbol, following re-export chains")
478
+ .option("--root <dir>", "project root directory (default: cwd)", "")
479
+ .option("-d, --depth <n>", "max re-export chain depth to follow (default: 10)", "10")
480
+ .option("--callers-only", "show only files with call graph data (known call sites)", false)
481
+ .action(async (symbol, opts) => {
482
+ const rootDir = path_1.default.resolve(opts.root || process.cwd());
483
+ try {
484
+ await (0, usages_1.runUsages)(rootDir, symbol, {
485
+ depth: parseInt(opts.depth, 10),
486
+ callersOnly: opts.callersOnly,
487
+ });
488
+ }
489
+ catch (err) {
490
+ console.error(chalk_1.default.red("Error:"), err.message);
491
+ process.exit(1);
492
+ }
493
+ });
494
+ // ── report ────────────────────────────────────────────────────────────────────
495
+ program
496
+ .command("report")
497
+ .description("Show usage statistics: token savings, query latency, hot files, and low-signal queries")
498
+ .option("--root <dir>", "project root directory (default: cwd)", "")
499
+ .option("--days <n>", "limit report to events from the last N days")
500
+ .option("-v, --verbose", "show per-query breakdown (last 20 queries)", false)
501
+ .option("--clear", "clear all recorded usage data", false)
502
+ .action(async (opts) => {
503
+ const rootDir = path_1.default.resolve(opts.root || process.cwd());
504
+ try {
505
+ await (0, report_1.runReport)(rootDir, {
506
+ days: opts.days ? parseInt(opts.days, 10) : undefined,
507
+ verbose: opts.verbose,
508
+ clear: opts.clear,
509
+ });
510
+ }
511
+ catch (err) {
512
+ console.error(chalk_1.default.red("Error:"), err.message);
513
+ process.exit(1);
514
+ }
515
+ });
516
+ // ── audit ─────────────────────────────────────────────────────────────────────
517
+ program
518
+ .command("audit")
519
+ .description("Systematic code audit for security vulnerabilities, performance issues, and bugs")
520
+ .option("--root <dir>", "project root directory (default: cwd)", "")
521
+ .option("--type <types>", "comma-separated audit types: security, performance, bugs (default: all)")
522
+ .option("--since <ref>", "only audit files changed since this git ref (e.g. HEAD~5, main)")
523
+ .option("--budget <n>", "max context tokens per step (default: 5000)", "5000")
524
+ .option("--keyword", "use keyword search (no embeddings required)", false)
525
+ .option("--output <fmt>", "output format: terminal (default), json, markdown", "terminal")
526
+ .option("--save", "save critical/high findings as knowledge entries", false)
527
+ .action(async (opts) => {
528
+ const rootDir = path_1.default.resolve(opts.root || process.cwd());
529
+ const validTypes = ["security", "performance", "bugs"];
530
+ let types;
531
+ if (opts.type) {
532
+ const requested = opts.type.split(",").map((t) => t.trim());
533
+ const invalid = requested.filter((t) => !validTypes.includes(t));
534
+ if (invalid.length > 0) {
535
+ console.error(chalk_1.default.red(`Unknown audit type(s): ${invalid.join(", ")}. Valid: security, performance, bugs`));
536
+ process.exit(1);
537
+ }
538
+ types = requested;
539
+ }
540
+ const outputFmt = opts.output;
541
+ if (!["terminal", "json", "markdown"].includes(outputFmt)) {
542
+ console.error(chalk_1.default.red(`Unknown output format "${opts.output}". Use: terminal, json, markdown`));
543
+ process.exit(1);
544
+ }
545
+ try {
546
+ await (0, audit_1.runAudit)(rootDir, {
547
+ types,
548
+ since: opts.since,
549
+ budget: Number.parseInt(opts.budget, 10),
550
+ keyword: opts.keyword,
551
+ output: outputFmt,
552
+ save: opts.save,
553
+ });
554
+ }
555
+ catch (err) {
556
+ console.error(chalk_1.default.red("Error:"), err.message);
557
+ process.exit(1);
558
+ }
559
+ });
560
+ // ── triage ────────────────────────────────────────────────────────────────────
561
+ program
562
+ .command("triage")
563
+ .description("Static heuristic scan for bugs, security issues, and performance problems — no LLM required")
564
+ .option("--root <dir>", "project root directory (default: cwd)", "")
565
+ .option("--type <types>", "comma-separated types: bugs, security, performance (default: all)")
566
+ .option("-k, --top-k <n>", "max findings to return, ranked by score (default: 30)", "30")
567
+ .option("--min-score <n>", "skip findings below this score threshold (default: 1)", "1")
568
+ .option("--file <path>", "restrict scan to files matching this substring")
569
+ .option("--output <fmt>", "output format: terminal (default), json, markdown", "terminal")
570
+ .action(async (opts) => {
571
+ const rootDir = path_1.default.resolve(opts.root || process.cwd());
572
+ const validTypes = ["bugs", "security", "performance"];
573
+ let types;
574
+ if (opts.type) {
575
+ const requested = opts.type.split(",").map((t) => t.trim());
576
+ const invalid = requested.filter((t) => !validTypes.includes(t));
577
+ if (invalid.length > 0) {
578
+ console.error(chalk_1.default.red(`Unknown type(s): ${invalid.join(", ")}. Valid: bugs, security, performance`));
579
+ process.exit(1);
580
+ }
581
+ types = requested;
582
+ }
583
+ const outputFmt = opts.output;
584
+ if (!["terminal", "json", "markdown"].includes(outputFmt)) {
585
+ console.error(chalk_1.default.red(`Unknown output format "${opts.output}". Use: terminal, json, markdown`));
586
+ process.exit(1);
587
+ }
588
+ try {
589
+ await (0, triage_1.runTriage)(rootDir, {
590
+ types,
591
+ topK: Number.parseInt(opts.topK, 10),
592
+ minScore: Number.parseInt(opts.minScore, 10),
593
+ file: opts.file,
594
+ output: outputFmt,
595
+ });
596
+ }
597
+ catch (err) {
598
+ console.error(chalk_1.default.red("Error:"), err.message);
599
+ process.exit(1);
600
+ }
601
+ });
602
+ // ── dead-code ─────────────────────────────────────────────────────────────────
603
+ program
604
+ .command("dead-code")
605
+ .description("Detect unused private symbols, exports nobody imports, and unreachable files — no LLM required")
606
+ .option("--root <dir>", "project root directory (default: cwd)", "")
607
+ .option("--type <types>", "comma-separated types: uncalled-private, unused-export, unreachable-file (default: all)")
608
+ .option("--output <fmt>", "output format: terminal (default), json", "terminal")
609
+ .action(async (opts) => {
610
+ const rootDir = path_1.default.resolve(opts.root || process.cwd());
611
+ const validTypes = ["uncalled-private", "unused-export", "unreachable-file"];
612
+ let types;
613
+ if (opts.type) {
614
+ const requested = opts.type.split(",").map((t) => t.trim());
615
+ const invalid = requested.filter((t) => !validTypes.includes(t));
616
+ if (invalid.length > 0) {
617
+ console.error(chalk_1.default.red(`Unknown type(s): ${invalid.join(", ")}. Valid: uncalled-private, unused-export, unreachable-file`));
618
+ process.exit(1);
619
+ }
620
+ types = requested;
621
+ }
622
+ const outputFmt = opts.output;
623
+ if (!["terminal", "json"].includes(outputFmt)) {
624
+ console.error(chalk_1.default.red(`Unknown output format "${opts.output}". Use: terminal, json`));
625
+ process.exit(1);
626
+ }
627
+ try {
628
+ await (0, dead_code_1.runDeadCode)(rootDir, { types, output: outputFmt });
629
+ }
630
+ catch (err) {
631
+ console.error(chalk_1.default.red("Error:"), err.message);
632
+ process.exit(1);
633
+ }
634
+ });
635
+ // ── focus ─────────────────────────────────────────────────────────────────────
636
+ program
637
+ .command("focus <target>")
638
+ .description("Show implementation, dependencies, callers, tests and knowledge for a file or symbol")
639
+ .option("--root <dir>", "project root directory (default: cwd)", "")
640
+ .option("--format <fmt>", "output format: markdown (default), plain", "markdown")
641
+ .option("--budget <n>", "max tokens to include in output")
642
+ .action(async (target, opts) => {
643
+ const rootDir = path_1.default.resolve(opts.root || process.cwd());
644
+ const fmt = opts.format;
645
+ if (!["markdown", "plain"].includes(fmt)) {
646
+ console.error(chalk_1.default.red(`Unknown format "${fmt}". Use: markdown, plain`));
647
+ process.exit(1);
648
+ }
649
+ try {
650
+ await (0, focus_1.runFocus)(rootDir, target, {
651
+ format: fmt,
652
+ budget: opts.budget ? parseInt(opts.budget, 10) : undefined,
653
+ });
654
+ }
655
+ catch (err) {
656
+ console.error(chalk_1.default.red("Error:"), err.message);
657
+ process.exit(1);
658
+ }
659
+ });
660
+ // ── brief ─────────────────────────────────────────────────────────────────────
661
+ program
662
+ .command("brief")
663
+ .description("Print a compact session primer: project overview + high-confidence knowledge")
664
+ .option("--root <dir>", "project root directory (default: cwd)", "")
665
+ .option("--all", "include all knowledge entries, not only high-confidence ones", false)
666
+ .option("--budget <n>", "max tokens to include in output")
667
+ .action(async (opts) => {
668
+ const rootDir = path_1.default.resolve(opts.root || process.cwd());
669
+ try {
670
+ await (0, brief_1.runBrief)(rootDir, {
671
+ all: opts.all,
672
+ budget: opts.budget ? parseInt(opts.budget, 10) : undefined,
673
+ });
674
+ }
675
+ catch (err) {
676
+ console.error(chalk_1.default.red("Error:"), err.message);
677
+ process.exit(1);
678
+ }
679
+ });
680
+ // ─────────────────────────────────────────────────────────────────────────────
681
+ program.parse(process.argv);
682
+ //# sourceMappingURL=cli.js.map