opencode-rag-plugin 1.15.1 → 1.17.2

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 (240) hide show
  1. package/ReadMe.md +52 -9
  2. package/dist/api.js +44 -24
  3. package/dist/chunker/base.d.ts +34 -3
  4. package/dist/chunker/base.js +70 -21
  5. package/dist/chunker/factory.d.ts +4 -1
  6. package/dist/chunker/factory.js +12 -1
  7. package/dist/chunker/grammar.js +3 -0
  8. package/dist/chunker/image.js +8 -8
  9. package/dist/chunker/pdf.js +11 -13
  10. package/dist/chunker/xml.d.ts +2 -0
  11. package/dist/chunker/xml.js +2 -0
  12. package/dist/cli/commands/index-command.js +0 -4
  13. package/dist/cli/commands/index.d.ts +1 -0
  14. package/dist/cli/commands/index.js +1 -0
  15. package/dist/cli/commands/init-helpers.d.ts +12 -0
  16. package/dist/cli/commands/init-helpers.js +87 -2
  17. package/dist/cli/commands/init.js +20 -2
  18. package/dist/cli/commands/query.js +1 -0
  19. package/dist/cli/commands/setup.d.ts +2 -0
  20. package/dist/cli/commands/setup.js +113 -0
  21. package/dist/cli/commands/status.js +64 -2
  22. package/dist/cli/commands/update.d.ts +4 -6
  23. package/dist/cli/commands/update.js +44 -58
  24. package/dist/cli/index.js +2 -1
  25. package/dist/content/image.js +24 -3
  26. package/dist/content/reader.d.ts +6 -1
  27. package/dist/content/reader.js +49 -4
  28. package/dist/core/config.d.ts +29 -1
  29. package/dist/core/config.js +105 -8
  30. package/dist/core/desc-cache.d.ts +31 -0
  31. package/dist/core/desc-cache.js +124 -0
  32. package/dist/core/interfaces.d.ts +58 -3
  33. package/dist/core/manifest.d.ts +24 -1
  34. package/dist/core/manifest.js +34 -3
  35. package/dist/core/resolve-api-key.js +4 -2
  36. package/dist/core/runtime-overrides.js +12 -8
  37. package/dist/core/setup-runtime.d.ts +23 -0
  38. package/dist/core/setup-runtime.js +231 -0
  39. package/dist/core/version-check.d.ts +85 -0
  40. package/dist/core/version-check.js +160 -0
  41. package/dist/describer/anthropic.d.ts +2 -2
  42. package/dist/describer/anthropic.js +5 -7
  43. package/dist/describer/describer.d.ts +2 -2
  44. package/dist/describer/describer.js +6 -8
  45. package/dist/describer/gemini.d.ts +2 -2
  46. package/dist/describer/gemini.js +5 -7
  47. package/dist/embedder/cohere.d.ts +1 -1
  48. package/dist/embedder/cohere.js +2 -2
  49. package/dist/embedder/factory.d.ts +3 -1
  50. package/dist/embedder/factory.js +8 -2
  51. package/dist/embedder/health.js +5 -1
  52. package/dist/embedder/http.d.ts +1 -1
  53. package/dist/embedder/http.js +74 -43
  54. package/dist/embedder/ollama.d.ts +1 -1
  55. package/dist/embedder/ollama.js +2 -2
  56. package/dist/embedder/openai.d.ts +1 -1
  57. package/dist/embedder/openai.js +2 -2
  58. package/dist/eval/compare-merge.d.ts +10 -0
  59. package/dist/eval/compare-merge.js +537 -0
  60. package/dist/eval/compare-rankings.d.ts +10 -0
  61. package/dist/eval/compare-rankings.js +245 -0
  62. package/dist/eval/dump-descriptions.d.ts +7 -0
  63. package/dist/eval/dump-descriptions.js +58 -0
  64. package/dist/eval/fast-index.d.ts +8 -0
  65. package/dist/eval/fast-index.js +283 -0
  66. package/dist/eval/run-branch-compare.d.ts +7 -0
  67. package/dist/eval/run-branch-compare.js +220 -0
  68. package/dist/eval/run-token-test.js +1 -0
  69. package/dist/eval/test-kw.d.ts +1 -0
  70. package/dist/eval/test-kw.js +22 -0
  71. package/dist/eval/update-descriptions.d.ts +7 -0
  72. package/dist/eval/update-descriptions.js +84 -0
  73. package/dist/index.d.ts +4 -0
  74. package/dist/index.js +3 -0
  75. package/dist/indexer/embed-stage.js +2 -1
  76. package/dist/indexer/git-diff.js +21 -9
  77. package/dist/indexer/pipeline.d.ts +6 -0
  78. package/dist/indexer/pipeline.js +304 -40
  79. package/dist/indexer/watch.js +1 -3
  80. package/dist/indexer/worker.d.ts +15 -2
  81. package/dist/indexer/worker.js +25 -12
  82. package/dist/mcp/handlers.d.ts +9 -0
  83. package/dist/mcp/handlers.js +23 -6
  84. package/dist/mcp/server.js +2 -0
  85. package/dist/opencode/create-read-tool.d.ts +2 -0
  86. package/dist/opencode/create-read-tool.js +8 -2
  87. package/dist/opencode/read-fallback.d.ts +1 -5
  88. package/dist/opencode/read-fallback.js +1 -18
  89. package/dist/opencode/read-format.js +5 -3
  90. package/dist/opencode/tools.js +5 -7
  91. package/dist/plugin.js +223 -71
  92. package/dist/retriever/keyword-index.d.ts +3 -2
  93. package/dist/retriever/keyword-index.js +25 -1
  94. package/dist/retriever/retriever.d.ts +4 -1
  95. package/dist/retriever/retriever.js +34 -56
  96. package/dist/tui.js +18 -1
  97. package/dist/vectorstore/lancedb.d.ts +35 -4
  98. package/dist/vectorstore/lancedb.js +146 -23
  99. package/dist/vectorstore/memory.d.ts +6 -1
  100. package/dist/vectorstore/memory.js +58 -0
  101. package/dist/watcher.d.ts +2 -0
  102. package/dist/watcher.js +5 -1
  103. package/dist/web/api.js +10 -2
  104. package/dist/web/server.js +18 -3
  105. package/package.json +8 -9
  106. package/scripts/postinstall-setup.js +82 -0
  107. package/dist/api.js.map +0 -1
  108. package/dist/chunker/base.js.map +0 -1
  109. package/dist/chunker/bash.js.map +0 -1
  110. package/dist/chunker/c.js.map +0 -1
  111. package/dist/chunker/cpp.js.map +0 -1
  112. package/dist/chunker/csharp.js.map +0 -1
  113. package/dist/chunker/css.js.map +0 -1
  114. package/dist/chunker/doc.js.map +0 -1
  115. package/dist/chunker/dockerfile.js.map +0 -1
  116. package/dist/chunker/docx.js.map +0 -1
  117. package/dist/chunker/excel.js.map +0 -1
  118. package/dist/chunker/factory.js.map +0 -1
  119. package/dist/chunker/fallback.js.map +0 -1
  120. package/dist/chunker/go.js.map +0 -1
  121. package/dist/chunker/grammar.js.map +0 -1
  122. package/dist/chunker/html.js.map +0 -1
  123. package/dist/chunker/image.js.map +0 -1
  124. package/dist/chunker/ini.js.map +0 -1
  125. package/dist/chunker/java.js.map +0 -1
  126. package/dist/chunker/javascript.js.map +0 -1
  127. package/dist/chunker/json.js.map +0 -1
  128. package/dist/chunker/kotlin.js.map +0 -1
  129. package/dist/chunker/loader.js.map +0 -1
  130. package/dist/chunker/markdown.js.map +0 -1
  131. package/dist/chunker/pdf.js.map +0 -1
  132. package/dist/chunker/php.js.map +0 -1
  133. package/dist/chunker/powershell.js.map +0 -1
  134. package/dist/chunker/python.js.map +0 -1
  135. package/dist/chunker/razor.js.map +0 -1
  136. package/dist/chunker/ruby.js.map +0 -1
  137. package/dist/chunker/rust.js.map +0 -1
  138. package/dist/chunker/sln.js.map +0 -1
  139. package/dist/chunker/sql.js.map +0 -1
  140. package/dist/chunker/ssl.js.map +0 -1
  141. package/dist/chunker/swift.js.map +0 -1
  142. package/dist/chunker/tex.js.map +0 -1
  143. package/dist/chunker/toml.js.map +0 -1
  144. package/dist/chunker/typescript.js.map +0 -1
  145. package/dist/chunker/uuid.js.map +0 -1
  146. package/dist/chunker/xml.js.map +0 -1
  147. package/dist/chunker/yaml.js.map +0 -1
  148. package/dist/cli/commands/clear.js.map +0 -1
  149. package/dist/cli/commands/describe-image.js.map +0 -1
  150. package/dist/cli/commands/dump.js.map +0 -1
  151. package/dist/cli/commands/eval.js.map +0 -1
  152. package/dist/cli/commands/index-command.js.map +0 -1
  153. package/dist/cli/commands/index.js.map +0 -1
  154. package/dist/cli/commands/init-helpers.js.map +0 -1
  155. package/dist/cli/commands/init.js.map +0 -1
  156. package/dist/cli/commands/list.js.map +0 -1
  157. package/dist/cli/commands/mcp.js.map +0 -1
  158. package/dist/cli/commands/query.js.map +0 -1
  159. package/dist/cli/commands/show.js.map +0 -1
  160. package/dist/cli/commands/status.js.map +0 -1
  161. package/dist/cli/commands/ui.js.map +0 -1
  162. package/dist/cli/commands/update.js.map +0 -1
  163. package/dist/cli/format.js.map +0 -1
  164. package/dist/cli/helpers.js.map +0 -1
  165. package/dist/cli/index.js.map +0 -1
  166. package/dist/cli/progress.d.ts +0 -42
  167. package/dist/cli/progress.js +0 -137
  168. package/dist/cli/progress.js.map +0 -1
  169. package/dist/cli/types.js.map +0 -1
  170. package/dist/cli.js.map +0 -1
  171. package/dist/content/doc.js.map +0 -1
  172. package/dist/content/docx.js.map +0 -1
  173. package/dist/content/excel.js.map +0 -1
  174. package/dist/content/image.js.map +0 -1
  175. package/dist/content/pdf.js.map +0 -1
  176. package/dist/content/reader.js.map +0 -1
  177. package/dist/content/types.js.map +0 -1
  178. package/dist/core/bootstrap.js.map +0 -1
  179. package/dist/core/config.js.map +0 -1
  180. package/dist/core/doc-progress.js.map +0 -1
  181. package/dist/core/fileLogger.js.map +0 -1
  182. package/dist/core/interfaces.js.map +0 -1
  183. package/dist/core/manifest.js.map +0 -1
  184. package/dist/core/provider-defaults.js.map +0 -1
  185. package/dist/core/rag-injection-flag.js.map +0 -1
  186. package/dist/core/resolve-api-key.js.map +0 -1
  187. package/dist/core/runtime-overrides.js.map +0 -1
  188. package/dist/describer/anthropic.js.map +0 -1
  189. package/dist/describer/describer.js.map +0 -1
  190. package/dist/describer/factory.js.map +0 -1
  191. package/dist/describer/gemini.js.map +0 -1
  192. package/dist/describer/shared.js.map +0 -1
  193. package/dist/embedder/cohere.js.map +0 -1
  194. package/dist/embedder/factory.js.map +0 -1
  195. package/dist/embedder/health.js.map +0 -1
  196. package/dist/embedder/http.js.map +0 -1
  197. package/dist/embedder/ollama.js.map +0 -1
  198. package/dist/embedder/openai.js.map +0 -1
  199. package/dist/eval/index.js.map +0 -1
  200. package/dist/eval/run-token-test.js.map +0 -1
  201. package/dist/eval/session-logger.js.map +0 -1
  202. package/dist/eval/storage.js.map +0 -1
  203. package/dist/eval/token-analysis.js.map +0 -1
  204. package/dist/eval/token-counter.js.map +0 -1
  205. package/dist/eval/types.js.map +0 -1
  206. package/dist/index.js.map +0 -1
  207. package/dist/indexer/description-stage.js.map +0 -1
  208. package/dist/indexer/embed-stage.js.map +0 -1
  209. package/dist/indexer/git-diff.js.map +0 -1
  210. package/dist/indexer/metadata.js.map +0 -1
  211. package/dist/indexer/pipeline.js.map +0 -1
  212. package/dist/indexer/stats.js.map +0 -1
  213. package/dist/indexer/watch.js.map +0 -1
  214. package/dist/indexer/worker.js.map +0 -1
  215. package/dist/indexer.js.map +0 -1
  216. package/dist/mcp/cli.js.map +0 -1
  217. package/dist/mcp/handlers.js.map +0 -1
  218. package/dist/mcp/server.js.map +0 -1
  219. package/dist/opencode/create-read-tool.js.map +0 -1
  220. package/dist/opencode/read-fallback.js.map +0 -1
  221. package/dist/opencode/read-format.js.map +0 -1
  222. package/dist/opencode/read-query.js.map +0 -1
  223. package/dist/opencode/tool-args.js.map +0 -1
  224. package/dist/opencode/tools.js.map +0 -1
  225. package/dist/plugin-entry.js.map +0 -1
  226. package/dist/plugin.js.map +0 -1
  227. package/dist/retriever/context-optimizer.js.map +0 -1
  228. package/dist/retriever/keyword-index.js.map +0 -1
  229. package/dist/retriever/retriever.js.map +0 -1
  230. package/dist/tui.js.map +0 -1
  231. package/dist/updater.d.ts +0 -45
  232. package/dist/updater.js +0 -175
  233. package/dist/updater.js.map +0 -1
  234. package/dist/vectorstore/factory.js.map +0 -1
  235. package/dist/vectorstore/lancedb.js.map +0 -1
  236. package/dist/vectorstore/memory.js.map +0 -1
  237. package/dist/watcher.js.map +0 -1
  238. package/dist/web/api.js.map +0 -1
  239. package/dist/web/server.js.map +0 -1
  240. package/dist/web/static.js.map +0 -1
@@ -8,6 +8,7 @@
8
8
  import path from "node:path";
9
9
  import os from "node:os";
10
10
  import { existsSync, mkdirSync, rmSync, symlinkSync, } from "node:fs";
11
+ import { execSync } from "node:child_process";
11
12
  import { DEFAULT_CONFIG } from "../../core/config.js";
12
13
  import { c } from "../format.js";
13
14
  import { getStringRecord, readJsonObject, writeJsonFile, } from "../helpers.js";
@@ -61,7 +62,7 @@ export function buildOpencodeConfig(existing) {
61
62
  // Plugin is loaded via .opencode/plugins/rag-plugin.js auto-discovery,
62
63
  // not via npm package resolution. Stale "plugin" entries from older
63
64
  // init versions would trigger npm install (which fails due to native
64
- // dependencies like canvas) and produce "Plugin export is not a function".
65
+ // dependencies like sharp) and produce "Plugin export is not a function".
65
66
  delete next.plugin;
66
67
  return next;
67
68
  }
@@ -247,6 +248,48 @@ export function mergeGitignoreContent(existingContent) {
247
248
  merged.push("# OpenCodeRAG workspace state", ...missing, "");
248
249
  return merged.join("\n");
249
250
  }
251
+ const BEGIN_MARKER = "<!-- BEGIN opencode-rag -->";
252
+ const END_MARKER = "<!-- END opencode-rag -->";
253
+ const AGENTS_MD_SECTION = [
254
+ BEGIN_MARKER,
255
+ "## Code Navigation",
256
+ "",
257
+ "ALWAYS use OpenCodeRAG tools before reading or editing:",
258
+ "- **Search first** — `search_semantic(query)` instead of grep/glob",
259
+ "- **Skeleton before read** — `get_file_skeleton(filePath)` then read specific lines",
260
+ "- **Usages before edit** — `find_usages(symbolName)` before modifying any symbol",
261
+ "- **Images via describe** — `describe_image(filePath)` — never read raw bytes",
262
+ "",
263
+ "If no results, run `opencode-rag index`.",
264
+ END_MARKER,
265
+ ].join("\n");
266
+ /**
267
+ * Merge the OpenCodeRAG directive section into an existing `AGENTS.md`.
268
+ *
269
+ * The directive is wrapped in sentinel markers so re-runs replace the
270
+ * section in place rather than appending duplicates. Existing content
271
+ * outside the markers is always preserved. If no existing content is
272
+ * provided, the section alone is returned as a new file.
273
+ *
274
+ * @param existingContent - The current `AGENTS.md` content, or `undefined` if absent.
275
+ * @returns The merged `AGENTS.md` content with a trailing newline.
276
+ */
277
+ export function mergeAgentsMdContent(existingContent) {
278
+ if (!existingContent) {
279
+ return `${AGENTS_MD_SECTION}\n`;
280
+ }
281
+ const beginIdx = existingContent.indexOf(BEGIN_MARKER);
282
+ const endIdx = existingContent.indexOf(END_MARKER);
283
+ if (beginIdx !== -1 && endIdx !== -1 && endIdx > beginIdx) {
284
+ const before = existingContent.slice(0, beginIdx);
285
+ const after = existingContent.slice(endIdx + END_MARKER.length);
286
+ const merged = `${before}${AGENTS_MD_SECTION}${after}`;
287
+ return merged.endsWith("\n") ? merged : `${merged}\n`;
288
+ }
289
+ const trimmed = existingContent.trimEnd();
290
+ const separator = trimmed.endsWith(BEGIN_MARKER) ? "" : "\n\n";
291
+ return `${trimmed}${separator}${AGENTS_MD_SECTION}\n`;
292
+ }
250
293
  /**
251
294
  * Get the runtime directory path (`~/.opencode`).
252
295
  *
@@ -290,8 +333,47 @@ export async function installPluginFromGlobal(opencodeDir, packageName, skipInst
290
333
  const globalPluginDir = path.join(runtimeDir, "node_modules", packageName);
291
334
  const workspaceTarget = path.join(opencodeDir, "node_modules", packageName);
292
335
  if (!existsSync(globalPluginDir)) {
336
+ // Fallback: try the global npm prefix
337
+ let globalRoot;
338
+ try {
339
+ globalRoot = execSync("npm root -g", { encoding: "utf-8", timeout: 10_000 }).trim();
340
+ }
341
+ catch {
342
+ throw new Error(`Global plugin cache not found at ${globalPluginDir}. ` +
343
+ "Run 'opencode-rag setup' or install globally with 'npm install -g opencode-rag-plugin' first.");
344
+ }
345
+ const globalNpmPluginDir = path.join(globalRoot, packageName);
346
+ if (existsSync(globalNpmPluginDir) && existsSync(path.join(globalNpmPluginDir, "dist", "cli.js"))) {
347
+ console.log(` ${c.created("Found:")} ${packageName} in global npm prefix, linking...`);
348
+ if (existsSync(workspaceTarget)) {
349
+ rmSync(workspaceTarget, { recursive: true, force: true });
350
+ }
351
+ mkdirSync(path.dirname(workspaceTarget), { recursive: true });
352
+ createJunction(globalNpmPluginDir, workspaceTarget);
353
+ const cliEntry = path.join(workspaceTarget, "dist", "cli.js");
354
+ if (existsSync(cliEntry)) {
355
+ console.log(` ${c.success("Linked:")} ${packageName} from global npm`);
356
+ // Also link @opencode-ai/plugin from global npm
357
+ const globalSdkDir = path.join(globalRoot, "@opencode-ai", "plugin");
358
+ const workspaceSdkDir = path.join(opencodeDir, "node_modules", "@opencode-ai", "plugin");
359
+ if (existsSync(globalSdkDir) && !existsSync(workspaceSdkDir)) {
360
+ mkdirSync(path.dirname(workspaceSdkDir), { recursive: true });
361
+ try {
362
+ createJunction(globalSdkDir, workspaceSdkDir);
363
+ }
364
+ catch {
365
+ const { cpSync } = await import("node:fs");
366
+ cpSync(globalSdkDir, workspaceSdkDir, { recursive: true });
367
+ }
368
+ }
369
+ console.log(` ${c.success("Linked:")} @opencode-ai/plugin from global npm`);
370
+ return;
371
+ }
372
+ // Junction failed or incomplete — fall through to error
373
+ rmSync(workspaceTarget, { recursive: true, force: true });
374
+ }
293
375
  throw new Error(`Global plugin cache not found at ${globalPluginDir}. ` +
294
- "Run 'install.sh compile' / 'install.ps1 compile' first.");
376
+ "Run 'opencode-rag setup' or install globally with 'npm install -g opencode-rag-plugin' first.");
295
377
  }
296
378
  // Remove any stale copy (e.g. from a previous 'npm install' run)
297
379
  if (existsSync(workspaceTarget)) {
@@ -378,6 +460,9 @@ export function generateDefaultConfigJson() {
378
460
  timeoutMs: DEFAULT_CONFIG.description.timeoutMs,
379
461
  maxContentChars: DEFAULT_CONFIG.description.maxContentChars,
380
462
  },
463
+ wikiMode: {
464
+ enabled: DEFAULT_CONFIG.wikiMode.enabled,
465
+ },
381
466
  mcp: {
382
467
  enabled: DEFAULT_CONFIG.mcp.enabled,
383
468
  },
@@ -10,13 +10,13 @@
10
10
  * installation.
11
11
  */
12
12
  import path from "node:path";
13
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
13
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync } from "node:fs";
14
14
  import { loadConfig } from "../../core/config.js";
15
15
  import { checkProviderHealth, pullOllamaModels } from "../../embedder/health.js";
16
16
  import { destroyAllPooledConnections } from "../../embedder/http.js";
17
17
  import { c } from "../format.js";
18
18
  import { getPackageMetadata, readJsonObject, writeJsonFile } from "../helpers.js";
19
- import { buildOpencodeConfig, buildWorkspacePackageJson, generateDefaultConfigJson, generateSkillFile, generateWorkspacePluginFile, generateWorkspaceTuiPluginFile, installPluginFromGlobal, mergeGitignoreContent, } from "./init-helpers.js";
19
+ import { buildOpencodeConfig, buildWorkspacePackageJson, generateDefaultConfigJson, generateSkillFile, generateWorkspacePluginFile, generateWorkspaceTuiPluginFile, installPluginFromGlobal, mergeAgentsMdContent, mergeGitignoreContent, } from "./init-helpers.js";
20
20
  /**
21
21
  * Register the `init` command on the given Commander program.
22
22
  *
@@ -142,6 +142,20 @@ export function registerInitCommand(program) {
142
142
  else {
143
143
  console.log(` ${c.exists("Exists:")} .opencode/skills/opencode-rag/SKILL.md`);
144
144
  }
145
+ const agentsMdPath = path.join(cwd, "AGENTS.md");
146
+ const agentsMdExists = existsSync(agentsMdPath);
147
+ const nextAgentsMd = mergeAgentsMdContent(agentsMdExists ? readFileSync(agentsMdPath, "utf-8") : undefined);
148
+ if (!agentsMdExists || options.force) {
149
+ writeFileSync(agentsMdPath, nextAgentsMd, "utf-8");
150
+ console.log(` ${agentsMdExists ? c.updated("Updated:") : c.created("Created:")} AGENTS.md`);
151
+ }
152
+ else if (readFileSync(agentsMdPath, "utf-8") !== nextAgentsMd) {
153
+ writeFileSync(agentsMdPath, nextAgentsMd, "utf-8");
154
+ console.log(` ${c.updated("Updated:")} AGENTS.md`);
155
+ }
156
+ else {
157
+ console.log(` ${c.exists("Exists:")} AGENTS.md`);
158
+ }
145
159
  const workspacePackageExists = existsSync(opencodePackagePath);
146
160
  const nextWorkspacePackage = buildWorkspacePackageJson(readJsonObject(opencodePackagePath), packageMetadata);
147
161
  if (!workspacePackageExists || options.force) {
@@ -157,6 +171,10 @@ export function registerInitCommand(program) {
157
171
  }
158
172
  const configExists = existsSync(configPath);
159
173
  if (!configExists || options.force) {
174
+ if (configExists && options.force) {
175
+ copyFileSync(configPath, configPath + ".bak");
176
+ console.log(` ${c.dim("Backup:")} ${configPath}.bak`);
177
+ }
160
178
  writeFileSync(configPath, generateDefaultConfigJson(), "utf-8");
161
179
  console.log(` ${configExists ? c.updated("Updated:") : c.created("Created:")} opencode-rag.json`);
162
180
  }
@@ -51,6 +51,7 @@ export function registerQueryCommand(program) {
51
51
  minScore,
52
52
  keywordIndex,
53
53
  keywordWeight: hybridCfg?.keywordWeight,
54
+ hybridEnabled: hybridCfg?.enabled,
54
55
  queryPrefix: config.embedding.queryPrefix,
55
56
  explain: options.explain ?? false,
56
57
  });
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerSetupCommand(program: Command): void;
@@ -0,0 +1,113 @@
1
+ import path from "node:path";
2
+ import { existsSync, lstatSync, rmSync } from "node:fs";
3
+ import { execSync } from "node:child_process";
4
+ import { c } from "../format.js";
5
+ import { getPackageMetadata } from "../helpers.js";
6
+ import { getRuntimeDir, getVersionFile, readVersionFile, setupRuntime, } from "../../core/setup-runtime.js";
7
+ const PLUGIN_NAME = "opencode-rag-plugin";
8
+ function removeIfExists(targetPath) {
9
+ if (existsSync(targetPath)) {
10
+ rmSync(targetPath, { recursive: true, force: true });
11
+ }
12
+ }
13
+ function checkOpenCodeRunning() {
14
+ try {
15
+ const pids = execSync("pgrep -x opencode 2>/dev/null || (Get-Process -Name opencode -ErrorAction SilentlyContinue 2>nul | ForEach-Object { $_.Id })", {
16
+ encoding: "utf-8",
17
+ timeout: 3_000,
18
+ }).trim();
19
+ if (pids) {
20
+ console.log(`\n ${c.warn("OpenCode is currently running.")} Restart it to load the updated plugin.`);
21
+ }
22
+ }
23
+ catch {
24
+ // pgrep/Get-Process aren't available or succeeded silently
25
+ }
26
+ }
27
+ export function registerSetupCommand(program) {
28
+ program
29
+ .command("setup")
30
+ .description("Set up the OpenCodeRAG runtime (~/.opencode/) for OpenCode plugin discovery")
31
+ .option("--uninstall", "remove the runtime and cleanup")
32
+ .option("-f, --force", "force re-setup even if up-to-date")
33
+ .option("--check", "check whether the runtime is correctly installed")
34
+ .action(async (options) => {
35
+ const pkg = getPackageMetadata();
36
+ const pluginVersion = pkg.version;
37
+ const runtimeDir = getRuntimeDir();
38
+ const versionFile = getVersionFile(runtimeDir);
39
+ const runtimePluginDir = path.join(runtimeDir, "node_modules", PLUGIN_NAME);
40
+ const runtimeSdkDir = path.join(runtimeDir, "node_modules", "@opencode-ai");
41
+ const runtimeSdkPluginDir = path.join(runtimeSdkDir, "plugin");
42
+ // --- check status ---
43
+ if (options.check) {
44
+ console.log(`\n${c.heading("OpenCodeRAG Runtime Status")}\n`);
45
+ const runtimeDist = path.join(runtimePluginDir, "dist");
46
+ if (existsSync(runtimeDist)) {
47
+ console.log(` ${c.label("Runtime:")} ${c.success("installed")} at ${c.file(runtimeDir)}`);
48
+ const installedVersion = readVersionFile(versionFile);
49
+ console.log(` ${c.label("Installed:")} ${c.value(installedVersion ?? "?")}`);
50
+ if (installedVersion !== pluginVersion) {
51
+ console.log(` ${c.label("Published:")} ${c.value(pluginVersion)} ${c.warn("(update available — run `opencode-rag setup` to sync)")}`);
52
+ }
53
+ console.log(` ${c.label("Plugin:")} ${existsSync(runtimePluginDir) ? (() => {
54
+ try {
55
+ const stat = lstatSync(runtimePluginDir);
56
+ return stat.isSymbolicLink() ? "junction" : "directory";
57
+ }
58
+ catch {
59
+ return "?";
60
+ }
61
+ })() : "missing"}`);
62
+ console.log(` ${c.label("SDK:")} ${existsSync(runtimeSdkPluginDir) ? "present" : "missing"}`);
63
+ }
64
+ else {
65
+ console.log(` ${c.label("Runtime:")} ${c.warn("not installed")}`);
66
+ console.log(` ${c.label("Run:")} ${c.file("opencode-rag setup")} to install`);
67
+ }
68
+ console.log();
69
+ return;
70
+ }
71
+ // --- uninstall ---
72
+ if (options.uninstall) {
73
+ console.log(`\n${c.heading("Removing OpenCodeRAG runtime...")}\n`);
74
+ removeIfExists(runtimePluginDir);
75
+ removeIfExists(runtimeSdkDir);
76
+ removeIfExists(versionFile);
77
+ console.log(` ${c.updated("Removed:")} ${c.file(runtimeDir)}`);
78
+ console.log(`\n ${c.success("Done.")} Run ${c.file("npm uninstall -g opencode-rag-plugin")} to remove the global package.\n`);
79
+ return;
80
+ }
81
+ // --- install ---
82
+ console.log(`\n${c.heading("Setting up OpenCodeRAG runtime...")}\n`);
83
+ // Check if already installed and up-to-date
84
+ const installedVersion = readVersionFile(versionFile);
85
+ const runtimeDist = path.join(runtimePluginDir, "dist");
86
+ const alreadyInstalled = existsSync(runtimeDist);
87
+ if (alreadyInstalled && installedVersion === pluginVersion && !options.force) {
88
+ console.log(` ${c.success("Already up-to-date.")} (${c.value(pluginVersion)}) at ${c.file(runtimeDir)}\n`);
89
+ console.log(` ${c.dim("Run `opencode-rag setup --force` to re-install.")}\n`);
90
+ return;
91
+ }
92
+ const result = await setupRuntime({ force: options.force, version: pluginVersion });
93
+ if (result.success) {
94
+ console.log(` ${c.created("Updated:")} runtime at ${c.file(runtimeDir)}`);
95
+ console.log(` ${c.created("Version:")} ${c.value(pluginVersion)}`);
96
+ console.log(`\n${c.success("Setup complete.")}`);
97
+ console.log(`\n ${c.dim("Next steps:")}`);
98
+ console.log(` ${c.dim(" 1. Restart OpenCode if it is running")}`);
99
+ console.log(` ${c.dim(" 2. Run `opencode-rag init` in each workspace")}`);
100
+ console.log(` ${c.dim(" 3. Run `opencode-rag index` to build the search index")}`);
101
+ }
102
+ else {
103
+ for (const err of result.errors) {
104
+ console.error(` ${c.error("✗")} ${err}`);
105
+ }
106
+ console.error(`\n ${c.error("Setup failed. Please check the errors above or run with --force.\n")}`);
107
+ process.exit(1);
108
+ }
109
+ checkOpenCodeRunning();
110
+ console.log();
111
+ });
112
+ }
113
+ //# sourceMappingURL=setup.js.map
@@ -5,9 +5,12 @@
5
5
  * `status` command — shows index statistics, store health, and configuration summary.
6
6
  */
7
7
  import path from "node:path";
8
+ import os from "node:os";
8
9
  import fs from "node:fs";
9
10
  import { c, resolveCliContext, cleanupContext, logCliError, logCliInfo, formatTimestamp } from "../format.js";
10
11
  import { getIndexStatusSummary } from "../../indexer.js";
12
+ import { getPackageMetadata } from "../helpers.js";
13
+ import { checkForUpdate } from "../../core/version-check.js";
11
14
  /**
12
15
  * Check for a stale index.lock file and clean it up if the owning process is dead.
13
16
  *
@@ -62,7 +65,7 @@ export function registerStatusCommand(program) {
62
65
  try {
63
66
  const cwd = process.cwd();
64
67
  let logFilePath = path.resolve(cwd, ".opencode", "opencode-rag.log");
65
- const ctx = await resolveCliContext(options, logFilePath, { skipProbe: true, skipKeywordIndex: true });
68
+ const ctx = await resolveCliContext(options, logFilePath, { skipProbe: true });
66
69
  const { config, store, storePath, keywordIndex } = ctx;
67
70
  logFilePath = ctx.logFilePath;
68
71
  checkStaleLock(storePath, logFilePath);
@@ -83,7 +86,34 @@ export function registerStatusCommand(program) {
83
86
  logCliInfo(logFilePath, "status", `${c.label("Pending files:")} ${c.num(summary.pendingFiles)}`);
84
87
  logCliInfo(logFilePath, "status", `${c.label("Indexed chunks:")} ${c.num(summary.storeChunkCount)}`);
85
88
  logCliInfo(logFilePath, "status", `${c.label("Expected chunks:")} ${c.num(summary.manifestExpectedChunks)}`);
86
- logCliInfo(logFilePath, "status", `${c.label("Watch mode:")} ${c.dim("off")}`);
89
+ // Read watcher status from the background auto-indexer
90
+ const watcherStatusPath = path.join(storePath, "watcher-status.json");
91
+ let watchModeDisplay;
92
+ if (fs.existsSync(watcherStatusPath)) {
93
+ try {
94
+ const raw = fs.readFileSync(watcherStatusPath, "utf-8");
95
+ const ws = JSON.parse(raw);
96
+ if (ws.lastRunAt) {
97
+ const lastRun = formatTimestamp(ws.lastRunAt);
98
+ watchModeDisplay = ws.running
99
+ ? c.enabled("active") + c.dim(" (last run: " + lastRun + ")")
100
+ : c.enabled("on") + c.dim(" (last run: " + lastRun + ")");
101
+ }
102
+ else {
103
+ watchModeDisplay = c.enabled("on");
104
+ }
105
+ }
106
+ catch {
107
+ watchModeDisplay = c.enabled("on") + c.dim(" (status unknown)");
108
+ }
109
+ }
110
+ else if (config.openCode.autoIndex?.enabled) {
111
+ watchModeDisplay = c.enabled("enabled (config)");
112
+ }
113
+ else {
114
+ watchModeDisplay = c.dim("off");
115
+ }
116
+ logCliInfo(logFilePath, "status", `${c.label("Watch mode:")} ${watchModeDisplay}`);
87
117
  const kiCount = config.retrieval.hybridSearch?.enabled
88
118
  ? keywordIndex?.count() ?? 0
89
119
  : 0;
@@ -94,6 +124,38 @@ export function registerStatusCommand(program) {
94
124
  if (summary.storeChunkCount > 0 && summary.manifestExpectedChunks > 0 && summary.storeChunkCount < summary.manifestExpectedChunks * 0.5) {
95
125
  logCliInfo(logFilePath, "status", `${c.label("Data loss detected:")} ${c.warn("yes")} — store has fewer chunks than expected. Run 'opencode-rag index' to rebuild.`);
96
126
  }
127
+ // Version & runtime status
128
+ const pkg = getPackageMetadata();
129
+ logCliInfo(logFilePath, "status", `${c.label("Plugin version:")} ${c.value(pkg.version)}`);
130
+ const versionFilePath = path.join(os.homedir(), ".opencode", ".bundle-version");
131
+ const runtimeDir = path.join(os.homedir(), ".opencode", "node_modules", "opencode-rag-plugin", "dist");
132
+ const runtimeOk = fs.existsSync(runtimeDir);
133
+ if (!runtimeOk) {
134
+ logCliInfo(logFilePath, "status", `${c.label("Runtime:")} ${c.warn("not set up — run `opencode-rag setup`")}`);
135
+ }
136
+ else {
137
+ try {
138
+ const installedVersion = fs.readFileSync(versionFilePath, "utf-8").trim();
139
+ if (installedVersion !== pkg.version) {
140
+ logCliInfo(logFilePath, "status", `${c.label("Runtime version:")} ${c.warn(installedVersion)} ${c.dim("(sync with `opencode-rag setup`)")}`);
141
+ }
142
+ else {
143
+ logCliInfo(logFilePath, "status", `${c.label("Runtime:")} ${c.success("up-to-date")}`);
144
+ }
145
+ }
146
+ catch {
147
+ logCliInfo(logFilePath, "status", `${c.label("Runtime:")} ${c.warn("version unknown — run `opencode-rag setup`")}`);
148
+ }
149
+ }
150
+ // Async GitHub update check (fire-and-forget, 5s timeout).
151
+ // Runs unless autoUpdate is explicitly disabled.
152
+ if (config.autoUpdate?.enabled) {
153
+ checkForUpdate(pkg.version).then((info) => {
154
+ if (info.updateAvailable) {
155
+ process.stdout.write(` ${c.label("Update:")} ${c.warn(`v${info.latestVersion} available — run \`opencode-rag update\` to install`)}\n`);
156
+ }
157
+ }).catch(() => { });
158
+ }
97
159
  await cleanupContext(ctx);
98
160
  }
99
161
  catch (err) {
@@ -1,17 +1,15 @@
1
1
  /**
2
- * @fileoverview Update command for checking and installing OpenCodeRAG updates from GitHub.
2
+ * @fileoverview `update` command — checks GitHub for a newer OpenCodeRAG release and installs it.
3
3
  */
4
4
  /**
5
- * `update` command — checks for and installs OpenCodeRAG updates from GitHub.
5
+ * `update` command — checks for a newer published version of OpenCodeRAG and,
6
+ * by default, installs it (via `npm install -g ...@latest`) then re-syncs the
7
+ * OpenCode runtime junctions so the new build is picked up on next restart.
6
8
  */
7
9
  import type { Command } from "commander";
8
10
  /**
9
11
  * Register the `update` command on the given Commander program.
10
12
  *
11
- * Checks the GitHub repository for a newer release, displays the current
12
- * and latest versions, and optionally applies the update by pulling
13
- * the latest code and rebuilding.
14
- *
15
13
  * @param program - The Commander `Command` instance to register on.
16
14
  */
17
15
  export declare function registerUpdateCommand(program: Command): void;
@@ -1,77 +1,63 @@
1
1
  /**
2
- * @fileoverview Update command for checking and installing OpenCodeRAG updates from GitHub.
2
+ * @fileoverview `update` command — checks GitHub for a newer OpenCodeRAG release and installs it.
3
3
  */
4
4
  /**
5
- * `update` command — checks for and installs OpenCodeRAG updates from GitHub.
5
+ * `update` command — checks for a newer published version of OpenCodeRAG and,
6
+ * by default, installs it (via `npm install -g ...@latest`) then re-syncs the
7
+ * OpenCode runtime junctions so the new build is picked up on next restart.
6
8
  */
7
- import path from "node:path";
8
- import { getCurrentVersion, checkForUpdate, applyUpdate } from "../../updater.js";
9
9
  import { c } from "../format.js";
10
- import { getPackageRoot } from "../helpers.js";
10
+ import { checkForUpdate, getCurrentVersion, installLatestUpdate } from "../../core/version-check.js";
11
11
  /**
12
12
  * Register the `update` command on the given Commander program.
13
13
  *
14
- * Checks the GitHub repository for a newer release, displays the current
15
- * and latest versions, and optionally applies the update by pulling
16
- * the latest code and rebuilding.
17
- *
18
14
  * @param program - The Commander `Command` instance to register on.
19
15
  */
20
16
  export function registerUpdateCommand(program) {
21
17
  program
22
18
  .command("update")
23
- .description("Check for and install OpenCodeRAG updates from GitHub")
24
- .option("--check", "only check for updates, don't install")
25
- .option("-y, --yes", "skip confirmation prompt")
26
- .option("-v, --verbose", "show build/install output")
19
+ .description("Check for and install the newest published version of OpenCodeRAG")
20
+ .option("--check", "only check whether an update is available; do not install")
21
+ .option("-v, --verbose", "stream npm/setup output to the console")
27
22
  .action(async (options) => {
23
+ const currentVersion = getCurrentVersion();
24
+ console.log(`\n${c.heading("OpenCodeRAG Update")}\n`);
25
+ console.log(` ${c.label("Current version:")} ${c.value(currentVersion)}`);
26
+ console.log(` ${c.label("Checking...")} `);
27
+ let info;
28
28
  try {
29
- const currentVersion = getCurrentVersion();
30
- console.log(`\n${c.heading("OpenCodeRAG Updater")}\n`);
31
- console.log(` ${c.label("Current version:")} ${c.value(currentVersion)}`);
32
- console.log(` ${c.label("Checking for updates...")}`);
33
- const info = await checkForUpdate(currentVersion);
34
- if (!info.updateAvailable) {
35
- console.log(` ${c.success("Already up to date.")}\n`);
36
- return;
37
- }
38
- console.log(` ${c.label("Latest version:")} ${c.value(info.latestVersion)}`);
39
- if (info.releaseUrl) {
40
- console.log(` ${c.label("Release:")} ${c.file(info.releaseUrl)}`);
41
- }
42
- console.log();
43
- if (options.check) {
44
- console.log(` ${c.warn("Update available. Run `opencode-rag update` to install.")}\n`);
45
- return;
46
- }
47
- if (!options.yes) {
48
- const readline = await import("node:readline");
49
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
50
- const answer = await new Promise((resolve) => {
51
- rl.question(` Install update to ${info.latestVersion}? [y/N] `, resolve);
52
- });
53
- rl.close();
54
- if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
55
- console.log(` ${c.dim("Cancelled.")}\n`);
56
- return;
57
- }
58
- }
59
- console.log(` ${c.label("Applying update...")}\n`);
60
- const result = applyUpdate({
61
- repoRoot: path.resolve(getPackageRoot()),
62
- verbose: options.verbose ?? false,
63
- });
64
- if (result.success) {
65
- console.log(` ${c.success(result.message)}\n`);
66
- }
67
- else {
68
- console.error(` ${c.error(result.message)}\n`);
69
- process.exit(1);
70
- }
29
+ info = await checkForUpdate(currentVersion);
30
+ }
31
+ catch {
32
+ console.log(`\n ${c.warn("Could not reach the update server. Check your network and try again.")}\n`);
33
+ process.exit(1);
34
+ return;
35
+ }
36
+ if (!info.updateAvailable) {
37
+ console.log(`\n ${c.success("Already up-to-date.")} (${c.value(info.latestVersion || currentVersion)})\n`);
38
+ return;
39
+ }
40
+ console.log(` ${c.label("Latest version:")} ${c.value(info.latestVersion)}`);
41
+ if (info.publishedAt) {
42
+ console.log(` ${c.label("Published:")} ${c.dim(info.publishedAt)}`);
43
+ }
44
+ if (info.releaseUrl) {
45
+ console.log(` ${c.label("Release notes:")} ${c.file(info.releaseUrl)}`);
46
+ }
47
+ if (options.check) {
48
+ console.log(`\n ${c.warn("Update available.")} Run ${c.file("opencode-rag update")} to install.\n`);
49
+ return;
50
+ }
51
+ console.log(`\n ${c.dim("Installing newest version...")}\n`);
52
+ const result = await installLatestUpdate({ verbose: options.verbose });
53
+ if (result.success) {
54
+ console.log(` ${c.success("")} ${result.message}`);
55
+ console.log(`\n ${c.dim("Restart OpenCode if it is running to load the new version.")}\n`);
71
56
  }
72
- catch (err) {
73
- const message = err.message || String(err);
74
- console.error(c.error(`\nUpdate failed: ${message}\n`));
57
+ else {
58
+ console.error(` ${c.error("✗")} ${result.message}`);
59
+ console.error(`\n ${c.error("Update failed. You can retry with `opencode-rag update` or install manually:")}\n`);
60
+ console.error(` ${c.dim(" npm install -g opencode-rag-plugin@latest && opencode-rag setup")}\n`);
75
61
  process.exit(1);
76
62
  }
77
63
  });
package/dist/cli/index.js CHANGED
@@ -14,7 +14,7 @@ import { realpathSync } from "node:fs";
14
14
  import { basename, dirname } from "node:path";
15
15
  import { fileURLToPath } from "node:url";
16
16
  import { getPackageMetadata } from "./helpers.js";
17
- import { registerIndexCommand, registerQueryCommand, registerClearCommand, registerStatusCommand, registerListCommand, registerShowCommand, registerDumpCommand, registerInitCommand, registerUiCommand, registerMcpCommand, registerUpdateCommand, registerEvalSessionsCommand, registerEvalAnalyzeCommand, registerEvalCompareCommand, registerDescribeImageCommand, } from "./commands/index.js";
17
+ import { registerIndexCommand, registerQueryCommand, registerClearCommand, registerStatusCommand, registerListCommand, registerShowCommand, registerDumpCommand, registerInitCommand, registerUiCommand, registerMcpCommand, registerSetupCommand, registerUpdateCommand, registerEvalSessionsCommand, registerEvalAnalyzeCommand, registerEvalCompareCommand, registerDescribeImageCommand, } from "./commands/index.js";
18
18
  /**
19
19
  * The top-level Commander program instance that defines the `opencode-rag` CLI.
20
20
  *
@@ -38,6 +38,7 @@ registerDumpCommand(program);
38
38
  registerDescribeImageCommand(program);
39
39
  registerUiCommand(program);
40
40
  registerMcpCommand(program);
41
+ registerSetupCommand(program);
41
42
  registerUpdateCommand(program);
42
43
  registerEvalSessionsCommand(program);
43
44
  registerEvalAnalyzeCommand(program);
@@ -19,14 +19,22 @@ export function isImageFile(fp) {
19
19
  function isBmpFile(fp) {
20
20
  return fp.toLowerCase().endsWith(".bmp");
21
21
  }
22
+ const MAX_BMP_DIMENSION = 10_000;
23
+ const MAX_BMP_ALLOC = 500 * 1024 * 1024; // 500 MB
22
24
  function decodeBmp(buffer) {
23
25
  const signature = buffer.toString("ascii", 0, 2);
24
26
  if (signature !== "BM")
25
27
  throw new Error("Not a BMP file");
28
+ if (buffer.length < 54)
29
+ throw new Error("Truncated BMP header");
26
30
  const dibSize = buffer.readUInt32LE(14);
27
31
  const width = buffer.readInt32LE(18);
28
32
  const rawHeight = buffer.readInt32LE(22);
29
33
  const bitsPerPixel = buffer.readUInt16LE(28);
34
+ if (width <= 0 || Math.abs(rawHeight) <= 0)
35
+ throw new Error("Invalid BMP dimensions");
36
+ if (width > MAX_BMP_DIMENSION || Math.abs(rawHeight) > MAX_BMP_DIMENSION)
37
+ throw new Error(`BMP dimensions (${width}x${rawHeight}) exceed ${MAX_BMP_DIMENSION}x${MAX_BMP_DIMENSION} limit`);
30
38
  if (bitsPerPixel !== 24 && bitsPerPixel !== 32)
31
39
  throw new Error(`Unsupported BMP bit depth: ${bitsPerPixel}. Only 24 and 32 bit are supported.`);
32
40
  if (dibSize < 40)
@@ -38,8 +46,17 @@ function decodeBmp(buffer) {
38
46
  const rowSize = Math.floor((bitsPerPixel * width + 31) / 32) * 4;
39
47
  const topDown = rawHeight < 0;
40
48
  const absHeight = Math.abs(rawHeight);
49
+ const allocSize = width * absHeight * channels;
50
+ if (allocSize > MAX_BMP_ALLOC)
51
+ throw new Error(`BMP allocation (${allocSize} bytes) exceeds ${MAX_BMP_ALLOC} byte limit`);
41
52
  const pixelOffset = buffer.readUInt32LE(10);
42
- const pixels = Buffer.alloc(width * absHeight * channels);
53
+ // Clamp dimensions to prevent OOM from crafted BMP headers.
54
+ const MAX_BMP_DIM = 16384;
55
+ if (width > MAX_BMP_DIM || absHeight > MAX_BMP_DIM) {
56
+ throw new Error(`BMP dimensions too large: ${width}x${absHeight} (max ${MAX_BMP_DIM})`);
57
+ }
58
+ const pixels = Buffer.alloc(allocSize);
59
+ const lastValidSrc = buffer.length - 1;
43
60
  for (let y = 0; y < absHeight; y++) {
44
61
  const srcY = topDown ? y : absHeight - 1 - y;
45
62
  const srcRow = pixelOffset + srcY * rowSize;
@@ -47,6 +64,10 @@ function decodeBmp(buffer) {
47
64
  for (let x = 0; x < width; x++) {
48
65
  const srcPx = srcRow + x * (bitsPerPixel / 8);
49
66
  const dstPx = dstRow + x * channels;
67
+ if (srcPx + 3 > lastValidSrc) {
68
+ pixels.fill(0, dstPx, dstPx + channels);
69
+ continue;
70
+ }
50
71
  if (channels === 4) {
51
72
  pixels[dstPx] = buffer[srcPx + 2];
52
73
  pixels[dstPx + 1] = buffer[srcPx + 1];
@@ -94,8 +115,8 @@ export async function resizeImage(buffer, filePath, maxDimension) {
94
115
  .jpeg({ quality: 80 })
95
116
  .toBuffer();
96
117
  }
97
- catch {
98
- return buffer;
118
+ catch (err) {
119
+ throw new Error(`Image resize failed: ${err instanceof Error ? err.message : String(err)}`);
99
120
  }
100
121
  }
101
122
  /**
@@ -3,6 +3,8 @@
3
3
  */
4
4
  import type { RagConfig } from "../core/config.js";
5
5
  import { type FileManifest } from "../core/manifest.js";
6
+ import { DescriptionCache } from "../core/desc-cache.js";
7
+ import { type ImageVisionProvider } from "../chunker/image.js";
6
8
  /** Metadata and extracted content for a single workspace file discovered during scanning. */
7
9
  export interface WorkspaceFile {
8
10
  filePath: string;
@@ -32,6 +34,9 @@ export declare function walkFiles(dir: string, extensions: Set<string>, excludeD
32
34
  * Scan the workspace directory for indexable files, reading content or dispatching
33
35
  * binary extraction (PDF, DOCX, DOC, Excel, images). Respects the file manifest
34
36
  * for incremental re-indexing by skipping unchanged files.
37
+ *
38
+ * @param descCache - Optional persistent description cache. When set, image
39
+ * descriptions are cached and reused across sessions (survives aborted runs).
35
40
  */
36
- export declare function scanWorkspaceFiles(cwd: string, config: RagConfig, logger?: Logger, manifest?: FileManifest, filterPaths?: string[]): Promise<WorkspaceFile[]>;
41
+ export declare function scanWorkspaceFiles(cwd: string, config: RagConfig, logger?: Logger, manifest?: FileManifest, filterPaths?: string[], injectedVisionProvider?: ImageVisionProvider, descCache?: DescriptionCache): Promise<WorkspaceFile[]>;
37
42
  export {};