opencode-rag-plugin 1.12.17 → 1.14.6
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.
- package/ReadMe.md +15 -13
- package/dist/api.d.ts +54 -2
- package/dist/api.js +41 -1
- package/dist/api.js.map +1 -1
- package/dist/chunker/base.js +2 -0
- package/dist/chunker/base.js.map +1 -1
- package/dist/chunker/bash.d.ts +5 -0
- package/dist/chunker/bash.js +5 -0
- package/dist/chunker/bash.js.map +1 -1
- package/dist/chunker/c.d.ts +6 -0
- package/dist/chunker/c.js +6 -0
- package/dist/chunker/c.js.map +1 -1
- package/dist/chunker/cpp.d.ts +6 -0
- package/dist/chunker/cpp.js +6 -0
- package/dist/chunker/cpp.js.map +1 -1
- package/dist/chunker/csharp.d.ts +6 -0
- package/dist/chunker/csharp.js +6 -0
- package/dist/chunker/csharp.js.map +1 -1
- package/dist/chunker/css.d.ts +6 -0
- package/dist/chunker/css.js +6 -0
- package/dist/chunker/css.js.map +1 -1
- package/dist/chunker/doc.d.ts +18 -0
- package/dist/chunker/doc.js +18 -0
- package/dist/chunker/doc.js.map +1 -1
- package/dist/chunker/dockerfile.d.ts +6 -0
- package/dist/chunker/dockerfile.js +6 -0
- package/dist/chunker/dockerfile.js.map +1 -1
- package/dist/chunker/docx.d.ts +18 -0
- package/dist/chunker/docx.js +18 -0
- package/dist/chunker/docx.js.map +1 -1
- package/dist/chunker/excel.d.ts +19 -0
- package/dist/chunker/excel.js +19 -0
- package/dist/chunker/excel.js.map +1 -1
- package/dist/chunker/go.d.ts +5 -0
- package/dist/chunker/go.js +5 -0
- package/dist/chunker/go.js.map +1 -1
- package/dist/chunker/grammar.d.ts +62 -0
- package/dist/chunker/grammar.js +133 -0
- package/dist/chunker/grammar.js.map +1 -1
- package/dist/chunker/html.d.ts +5 -0
- package/dist/chunker/html.js +5 -0
- package/dist/chunker/html.js.map +1 -1
- package/dist/chunker/image.d.ts +31 -0
- package/dist/chunker/image.js +50 -4
- package/dist/chunker/image.js.map +1 -1
- package/dist/chunker/ini.d.ts +5 -0
- package/dist/chunker/ini.js +5 -0
- package/dist/chunker/ini.js.map +1 -1
- package/dist/chunker/java.d.ts +5 -0
- package/dist/chunker/java.js +5 -0
- package/dist/chunker/java.js.map +1 -1
- package/dist/chunker/javascript.d.ts +6 -0
- package/dist/chunker/javascript.js +6 -0
- package/dist/chunker/javascript.js.map +1 -1
- package/dist/chunker/json.d.ts +5 -0
- package/dist/chunker/json.js +5 -0
- package/dist/chunker/json.js.map +1 -1
- package/dist/chunker/kotlin.d.ts +6 -0
- package/dist/chunker/kotlin.js +6 -0
- package/dist/chunker/kotlin.js.map +1 -1
- package/dist/chunker/loader.d.ts +11 -0
- package/dist/chunker/loader.js +20 -0
- package/dist/chunker/loader.js.map +1 -1
- package/dist/chunker/markdown.d.ts +5 -0
- package/dist/chunker/markdown.js +5 -0
- package/dist/chunker/markdown.js.map +1 -1
- package/dist/chunker/pdf.d.ts +19 -0
- package/dist/chunker/pdf.js +30 -0
- package/dist/chunker/pdf.js.map +1 -1
- package/dist/chunker/php.d.ts +5 -0
- package/dist/chunker/php.js +5 -0
- package/dist/chunker/php.js.map +1 -1
- package/dist/chunker/powershell.d.ts +5 -0
- package/dist/chunker/powershell.js +5 -0
- package/dist/chunker/powershell.js.map +1 -1
- package/dist/chunker/python.d.ts +5 -0
- package/dist/chunker/python.js +5 -0
- package/dist/chunker/python.js.map +1 -1
- package/dist/chunker/razor.d.ts +12 -0
- package/dist/chunker/razor.js +25 -0
- package/dist/chunker/razor.js.map +1 -1
- package/dist/chunker/ruby.d.ts +5 -0
- package/dist/chunker/ruby.js +5 -0
- package/dist/chunker/ruby.js.map +1 -1
- package/dist/chunker/rust.d.ts +6 -0
- package/dist/chunker/rust.js +6 -0
- package/dist/chunker/rust.js.map +1 -1
- package/dist/chunker/sln.d.ts +11 -0
- package/dist/chunker/sln.js +11 -0
- package/dist/chunker/sln.js.map +1 -1
- package/dist/chunker/sql.d.ts +5 -0
- package/dist/chunker/sql.js +5 -0
- package/dist/chunker/sql.js.map +1 -1
- package/dist/chunker/ssl.d.ts +12 -0
- package/dist/chunker/ssl.js +21 -2
- package/dist/chunker/ssl.js.map +1 -1
- package/dist/chunker/swift.d.ts +5 -0
- package/dist/chunker/swift.js +5 -0
- package/dist/chunker/swift.js.map +1 -1
- package/dist/chunker/tex.d.ts +12 -0
- package/dist/chunker/tex.js +12 -0
- package/dist/chunker/tex.js.map +1 -1
- package/dist/chunker/toml.d.ts +5 -0
- package/dist/chunker/toml.js +5 -0
- package/dist/chunker/toml.js.map +1 -1
- package/dist/chunker/typescript.d.ts +6 -0
- package/dist/chunker/typescript.js +6 -0
- package/dist/chunker/typescript.js.map +1 -1
- package/dist/chunker/xml.d.ts +5 -0
- package/dist/chunker/xml.js +5 -0
- package/dist/chunker/xml.js.map +1 -1
- package/dist/chunker/yaml.d.ts +5 -0
- package/dist/chunker/yaml.js +5 -0
- package/dist/chunker/yaml.js.map +1 -1
- package/dist/cli/commands/clear.d.ts +12 -0
- package/dist/cli/commands/clear.js +81 -0
- package/dist/cli/commands/clear.js.map +1 -0
- package/dist/cli/commands/describe-image.d.ts +14 -0
- package/dist/cli/commands/describe-image.js +68 -0
- package/dist/cli/commands/describe-image.js.map +1 -0
- package/dist/cli/commands/dump.d.ts +13 -0
- package/dist/cli/commands/dump.js +55 -0
- package/dist/cli/commands/dump.js.map +1 -0
- package/dist/cli/commands/eval.d.ts +32 -0
- package/dist/cli/commands/eval.js +158 -0
- package/dist/cli/commands/eval.js.map +1 -0
- package/dist/cli/commands/index-command.d.ts +17 -0
- package/dist/cli/commands/index-command.js +167 -0
- package/dist/cli/commands/index-command.js.map +1 -0
- package/dist/cli/commands/index.d.ts +16 -0
- package/dist/cli/commands/index.js +17 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/init-helpers.d.ts +101 -0
- package/dist/cli/commands/init-helpers.js +397 -0
- package/dist/cli/commands/init-helpers.js.map +1 -0
- package/dist/cli/commands/init.d.ts +19 -0
- package/dist/cli/commands/init.js +251 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/list.d.ts +13 -0
- package/dist/cli/commands/list.js +46 -0
- package/dist/cli/commands/list.js.map +1 -0
- package/dist/cli/commands/mcp.d.ts +14 -0
- package/dist/cli/commands/mcp.js +35 -0
- package/dist/cli/commands/mcp.js.map +1 -0
- package/dist/cli/commands/query.d.ts +14 -0
- package/dist/cli/commands/query.js +86 -0
- package/dist/cli/commands/query.js.map +1 -0
- package/dist/cli/commands/show.d.ts +13 -0
- package/dist/cli/commands/show.js +51 -0
- package/dist/cli/commands/show.js.map +1 -0
- package/dist/cli/commands/status.d.ts +14 -0
- package/dist/cli/commands/status.js +104 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/ui.d.ts +14 -0
- package/dist/cli/commands/ui.js +69 -0
- package/dist/cli/commands/ui.js.map +1 -0
- package/dist/cli/commands/update.d.ts +14 -0
- package/dist/cli/commands/update.js +76 -0
- package/dist/cli/commands/update.js.map +1 -0
- package/dist/cli/format.d.ts +112 -0
- package/dist/cli/format.js +184 -0
- package/dist/cli/format.js.map +1 -0
- package/dist/cli/helpers.d.ts +51 -0
- package/dist/cli/helpers.js +86 -0
- package/dist/cli/helpers.js.map +1 -0
- package/dist/cli/index.d.ts +28 -0
- package/dist/cli/index.js +104 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/progress.d.ts +39 -0
- package/dist/cli/progress.js +137 -0
- package/dist/cli/progress.js.map +1 -0
- package/dist/cli/types.d.ts +40 -0
- package/dist/cli/types.js +3 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli.d.ts +11 -4
- package/dist/cli.js +9 -1253
- package/dist/cli.js.map +1 -1
- package/dist/content/doc.d.ts +1 -1
- package/dist/content/doc.js +1 -1
- package/dist/content/doc.js.map +1 -1
- package/dist/content/docx.d.ts +1 -1
- package/dist/content/docx.js +1 -1
- package/dist/content/docx.js.map +1 -1
- package/dist/content/excel.d.ts +1 -1
- package/dist/content/excel.js +1 -1
- package/dist/content/excel.js.map +1 -1
- package/dist/content/pdf.d.ts +1 -1
- package/dist/content/pdf.js +1 -1
- package/dist/content/pdf.js.map +1 -1
- package/dist/content/reader.d.ts +3 -1
- package/dist/content/reader.js +42 -10
- package/dist/content/reader.js.map +1 -1
- package/dist/core/bootstrap.d.ts +18 -0
- package/dist/core/bootstrap.js +9 -15
- package/dist/core/bootstrap.js.map +1 -1
- package/dist/core/config.d.ts +144 -0
- package/dist/core/config.js +65 -14
- package/dist/core/config.js.map +1 -1
- package/dist/core/doc-progress.d.ts +15 -0
- package/dist/core/doc-progress.js +61 -0
- package/dist/core/doc-progress.js.map +1 -0
- package/dist/core/fileLogger.d.ts +7 -0
- package/dist/core/fileLogger.js +2 -0
- package/dist/core/fileLogger.js.map +1 -1
- package/dist/core/interfaces.d.ts +52 -1
- package/dist/core/manifest.d.ts +25 -0
- package/dist/core/manifest.js +15 -1
- package/dist/core/manifest.js.map +1 -1
- package/dist/core/provider-defaults.d.ts +8 -0
- package/dist/core/provider-defaults.js +3 -0
- package/dist/core/provider-defaults.js.map +1 -1
- package/dist/core/rag-injection-flag.d.ts +3 -0
- package/dist/core/rag-injection-flag.js +2 -0
- package/dist/core/rag-injection-flag.js.map +1 -1
- package/dist/core/resolve-api-key.d.ts +1 -0
- package/dist/core/resolve-api-key.js +1 -0
- package/dist/core/resolve-api-key.js.map +1 -1
- package/dist/core/runtime-overrides.d.ts +4 -0
- package/dist/core/runtime-overrides.js +4 -1
- package/dist/core/runtime-overrides.js.map +1 -1
- package/dist/describer/anthropic.d.ts +22 -2
- package/dist/describer/anthropic.js +42 -110
- package/dist/describer/anthropic.js.map +1 -1
- package/dist/describer/describer.d.ts +21 -4
- package/dist/describer/describer.js +52 -111
- package/dist/describer/describer.js.map +1 -1
- package/dist/describer/gemini.d.ts +1 -2
- package/dist/describer/gemini.js +20 -113
- package/dist/describer/gemini.js.map +1 -1
- package/dist/describer/shared.d.ts +3 -0
- package/dist/describer/shared.js +19 -0
- package/dist/describer/shared.js.map +1 -0
- package/dist/embedder/factory.d.ts +25 -0
- package/dist/embedder/factory.js +25 -0
- package/dist/embedder/factory.js.map +1 -1
- package/dist/embedder/health.d.ts +10 -0
- package/dist/embedder/health.js +26 -14
- package/dist/embedder/health.js.map +1 -1
- package/dist/embedder/http.d.ts +47 -0
- package/dist/embedder/http.js +61 -3
- package/dist/embedder/http.js.map +1 -1
- package/dist/eval/index.d.ts +6 -0
- package/dist/eval/index.js.map +1 -1
- package/dist/eval/run-token-test.js +1 -5
- package/dist/eval/run-token-test.js.map +1 -1
- package/dist/eval/session-logger.d.ts +5 -0
- package/dist/eval/session-logger.js +4 -0
- package/dist/eval/session-logger.js.map +1 -1
- package/dist/eval/storage.d.ts +9 -0
- package/dist/eval/storage.js +9 -5
- package/dist/eval/storage.js.map +1 -1
- package/dist/eval/token-analysis.d.ts +8 -0
- package/dist/eval/token-analysis.js +6 -2
- package/dist/eval/token-analysis.js.map +1 -1
- package/dist/eval/token-counter.d.ts +1 -3
- package/dist/eval/token-counter.js +4 -5
- package/dist/eval/token-counter.js.map +1 -1
- package/dist/eval/types.d.ts +6 -0
- package/dist/eval/types.js +2 -0
- package/dist/eval/types.js.map +1 -1
- package/dist/index.d.ts +11 -0
- package/dist/index.js +12 -3
- package/dist/index.js.map +1 -1
- package/dist/indexer/description-stage.js +11 -2
- package/dist/indexer/description-stage.js.map +1 -1
- package/dist/indexer/embed-stage.js +0 -8
- package/dist/indexer/embed-stage.js.map +1 -1
- package/dist/indexer/pipeline.d.ts +27 -3
- package/dist/indexer/pipeline.js +314 -143
- package/dist/indexer/pipeline.js.map +1 -1
- package/dist/indexer/stats.d.ts +35 -0
- package/dist/indexer/stats.js +9 -0
- package/dist/indexer/stats.js.map +1 -1
- package/dist/indexer/watch.d.ts +25 -0
- package/dist/indexer/watch.js +21 -0
- package/dist/indexer/watch.js.map +1 -1
- package/dist/indexer/worker.d.ts +90 -2
- package/dist/indexer/worker.js +109 -24
- package/dist/indexer/worker.js.map +1 -1
- package/dist/indexer.d.ts +11 -1
- package/dist/indexer.js +9 -0
- package/dist/indexer.js.map +1 -1
- package/dist/mcp/cli.d.ts +3 -0
- package/dist/mcp/cli.js +1 -0
- package/dist/mcp/cli.js.map +1 -1
- package/dist/mcp/handlers.d.ts +41 -0
- package/dist/mcp/handlers.js +40 -1
- package/dist/mcp/handlers.js.map +1 -1
- package/dist/mcp/server.d.ts +8 -0
- package/dist/mcp/server.js +18 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/opencode/create-read-tool.js +1 -0
- package/dist/opencode/create-read-tool.js.map +1 -1
- package/dist/opencode/tools.d.ts +8 -17
- package/dist/opencode/tools.js +74 -109
- package/dist/opencode/tools.js.map +1 -1
- package/dist/plugin-entry.d.ts +6 -0
- package/dist/plugin-entry.js +6 -0
- package/dist/plugin-entry.js.map +1 -1
- package/dist/plugin.d.ts +37 -0
- package/dist/plugin.js +265 -40
- package/dist/plugin.js.map +1 -1
- package/dist/retriever/keyword-index.js +9 -9
- package/dist/retriever/keyword-index.js.map +1 -1
- package/dist/retriever/retriever.js +14 -4
- package/dist/retriever/retriever.js.map +1 -1
- package/dist/tui.d.ts +5 -0
- package/dist/tui.js +100 -12
- package/dist/tui.js.map +1 -1
- package/dist/types/opencode-plugin.d.ts +4 -1
- package/dist/updater.d.ts +23 -1
- package/dist/updater.js +55 -16
- package/dist/updater.js.map +1 -1
- package/dist/vectorstore/factory.d.ts +13 -0
- package/dist/vectorstore/factory.js +13 -0
- package/dist/vectorstore/factory.js.map +1 -1
- package/dist/vectorstore/lancedb.d.ts +78 -1
- package/dist/vectorstore/lancedb.js +195 -21
- package/dist/vectorstore/lancedb.js.map +1 -1
- package/dist/vectorstore/memory.d.ts +5 -0
- package/dist/vectorstore/memory.js +11 -0
- package/dist/vectorstore/memory.js.map +1 -1
- package/dist/watcher.d.ts +24 -0
- package/dist/watcher.js +17 -35
- package/dist/watcher.js.map +1 -1
- package/dist/web/api.d.ts +37 -0
- package/dist/web/api.js +54 -0
- package/dist/web/api.js.map +1 -1
- package/dist/web/server.d.ts +15 -0
- package/dist/web/server.js +14 -0
- package/dist/web/server.js.map +1 -1
- package/dist/web/static.d.ts +8 -0
- package/dist/web/static.js +8 -0
- package/dist/web/static.js.map +1 -1
- package/package.json +11 -15
package/dist/plugin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { tool } from "@opencode-ai/plugin/tool";
|
|
2
|
-
import { loadConfig, DEFAULT_CONFIG, resolveLogConfig } from "./core/config.js";
|
|
2
|
+
import { loadConfig, findConfigFile, DEFAULT_CONFIG, resolveLogConfig } from "./core/config.js";
|
|
3
3
|
import { createEmbedder } from "./embedder/factory.js";
|
|
4
4
|
import { createDescriptionProvider } from "./describer/factory.js";
|
|
5
5
|
import { createVectorStore } from "./vectorstore/factory.js";
|
|
@@ -9,9 +9,11 @@ import { appendDebugLog } from "./core/fileLogger.js";
|
|
|
9
9
|
import { loadRuntimeOverrides, applyRuntimeOverrides } from "./core/runtime-overrides.js";
|
|
10
10
|
import { createBackgroundIndexer } from "./watcher.js";
|
|
11
11
|
import { createRagReadTool } from "./opencode/create-read-tool.js";
|
|
12
|
-
import { createFileSkeletonTool, createFindUsagesTool, } from "./opencode/tools.js";
|
|
12
|
+
import { createFileSkeletonTool, createFindUsagesTool, createDescribeImageTool, } from "./opencode/tools.js";
|
|
13
13
|
import { resolveApiKey } from "./core/resolve-api-key.js";
|
|
14
14
|
import { consumePendingRagInjection } from "./core/rag-injection-flag.js";
|
|
15
|
+
import { loadDocProgress, markSubdirectoryDocumented } from "./core/doc-progress.js";
|
|
16
|
+
import { loadManifest } from "./core/manifest.js";
|
|
15
17
|
import { createSessionLogger } from "./eval/session-logger.js";
|
|
16
18
|
import { countTokens } from "./eval/token-counter.js";
|
|
17
19
|
import { checkForUpdate } from "./updater.js";
|
|
@@ -20,12 +22,22 @@ import path from "node:path";
|
|
|
20
22
|
import { fileURLToPath } from "node:url";
|
|
21
23
|
import { spawn, execSync } from "node:child_process";
|
|
22
24
|
import { tmpdir } from "node:os";
|
|
25
|
+
/** Cache of loaded RAG configurations keyed by workspace directory. */
|
|
23
26
|
const configCache = new Map();
|
|
27
|
+
/** Active background indexer instances keyed by workspace directory. */
|
|
24
28
|
const backgroundIndexers = new Map();
|
|
29
|
+
/** Active MCP server instances keyed by workspace directory. */
|
|
25
30
|
const mcpServers = new Map();
|
|
31
|
+
/** Pending update notifications keyed by workspace directory. */
|
|
26
32
|
const pendingUpdateInfo = new Map();
|
|
33
|
+
/** Name of the semantic search tool as exposed to the LLM. */
|
|
27
34
|
const CONTEXT_TOOL_NAME = "search_semantic";
|
|
35
|
+
/** Marker string injected into context output to identify RAG-sourced content. */
|
|
28
36
|
const CONTEXT_MARKER = "search_semantic retrieved context";
|
|
37
|
+
/**
|
|
38
|
+
* Append a verbose log entry with an optional structured payload.
|
|
39
|
+
* The payload is serialised using formatLogPayload for readability.
|
|
40
|
+
*/
|
|
29
41
|
function appendVerboseLog(logFilePath, scope, message, payload, logLevel) {
|
|
30
42
|
appendDebugLog(logFilePath, {
|
|
31
43
|
scope,
|
|
@@ -34,6 +46,10 @@ function appendVerboseLog(logFilePath, scope, message, payload, logLevel) {
|
|
|
34
46
|
: message,
|
|
35
47
|
}, logLevel);
|
|
36
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Format an arbitrary value as a human-readable indented string
|
|
51
|
+
* for debug logging. Handles null, primitives, arrays, and nested objects.
|
|
52
|
+
*/
|
|
37
53
|
function formatLogPayload(value, indent = 0) {
|
|
38
54
|
const prefix = " ".repeat(indent);
|
|
39
55
|
if (value === null) {
|
|
@@ -89,6 +105,10 @@ function formatLogPayload(value, indent = 0) {
|
|
|
89
105
|
}
|
|
90
106
|
return `${prefix}${String(value)}`;
|
|
91
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Indent every line of a multi-line string by the given number of
|
|
110
|
+
* two-space indentation levels.
|
|
111
|
+
*/
|
|
92
112
|
function indentMultiline(text, indent) {
|
|
93
113
|
const prefix = " ".repeat(indent);
|
|
94
114
|
return text
|
|
@@ -96,15 +116,17 @@ function indentMultiline(text, indent) {
|
|
|
96
116
|
.map((line) => `${prefix}${line}`)
|
|
97
117
|
.join("\n");
|
|
98
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Load the RAG configuration for a directory, searching in order:
|
|
121
|
+
* opencode-rag.json, .opencode/opencode-rag.json, .opencode/rag.json.
|
|
122
|
+
* Caches the result per directory.
|
|
123
|
+
*/
|
|
99
124
|
async function getConfig(directory) {
|
|
100
125
|
const cached = configCache.get(directory);
|
|
101
126
|
if (cached)
|
|
102
127
|
return cached;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (!existsSync(configPath)) {
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
128
|
+
const configPath = findConfigFile(directory);
|
|
129
|
+
if (configPath) {
|
|
108
130
|
try {
|
|
109
131
|
const cfg = loadConfig(configPath);
|
|
110
132
|
await loadChunkersFromConfig(cfg, path.dirname(configPath));
|
|
@@ -122,6 +144,10 @@ async function getConfig(directory) {
|
|
|
122
144
|
configCache.set(directory, DEFAULT_CONFIG);
|
|
123
145
|
return DEFAULT_CONFIG;
|
|
124
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* Format retrieval results into a Markdown context block for LLM injection.
|
|
149
|
+
* Includes per-chunk file paths, line numbers, relevance scores, and descriptions.
|
|
150
|
+
*/
|
|
125
151
|
function formatContext(results) {
|
|
126
152
|
if (results.length === 0)
|
|
127
153
|
return "";
|
|
@@ -142,6 +168,10 @@ function formatContext(results) {
|
|
|
142
168
|
parts.push("---\n");
|
|
143
169
|
return parts.join("\n");
|
|
144
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Format auto-injected context results, trimming to a token budget.
|
|
173
|
+
* Results are sorted by relevance and included up to maxChunks.
|
|
174
|
+
*/
|
|
145
175
|
function formatAutoInjectContext(results, worktree, maxTokens, maxChunks) {
|
|
146
176
|
if (results.length === 0)
|
|
147
177
|
return "";
|
|
@@ -177,6 +207,10 @@ function formatAutoInjectContext(results, worktree, maxTokens, maxChunks) {
|
|
|
177
207
|
}
|
|
178
208
|
return formatted;
|
|
179
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* Build the effective query string from a RetrievalQueryHints object,
|
|
212
|
+
* appending path and language hints as additional context.
|
|
213
|
+
*/
|
|
180
214
|
function buildRetrievalQuery(hints) {
|
|
181
215
|
const parts = [hints.query.trim()];
|
|
182
216
|
const pathHints = hints.pathHints?.map((hint) => hint.trim()).filter((hint) => hint.length > 0) ?? [];
|
|
@@ -189,6 +223,10 @@ function buildRetrievalQuery(hints) {
|
|
|
189
223
|
}
|
|
190
224
|
return parts.join("\n").trim();
|
|
191
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* Remove duplicate results based on file path + line range + content.
|
|
228
|
+
* Keeps the first occurrence of each unique result.
|
|
229
|
+
*/
|
|
192
230
|
function dedupeResults(results) {
|
|
193
231
|
const seen = new Set();
|
|
194
232
|
const deduped = [];
|
|
@@ -207,11 +245,19 @@ function dedupeResults(results) {
|
|
|
207
245
|
}
|
|
208
246
|
return deduped;
|
|
209
247
|
}
|
|
248
|
+
/**
|
|
249
|
+
* Perform a retrieval query against the vector store with the given parameters.
|
|
250
|
+
* Returns an empty array for blank queries.
|
|
251
|
+
*/
|
|
210
252
|
async function retrieveContext(query, embedder, store, topK, retrieveFn = retrieve, minScore = 0, keywordIndex, keywordWeight, queryPrefix, explain = false) {
|
|
211
253
|
if (query.trim().length === 0)
|
|
212
254
|
return [];
|
|
213
255
|
return retrieveFn(query, embedder, store, { topK, minScore, keywordIndex, keywordWeight, queryPrefix, explain });
|
|
214
256
|
}
|
|
257
|
+
/**
|
|
258
|
+
* Load results from one or two queries (primary + optional extra), deduplicate,
|
|
259
|
+
* sort by descending score, and limit to maxContextChunks from config.
|
|
260
|
+
*/
|
|
215
261
|
async function loadRetrievedResults(query, embedder, store, cfg, retrieveFn = retrieve, topK = cfg.retrieval.topK, extraQuery, keywordIndex, queryPrefix, explain = false) {
|
|
216
262
|
const minScore = cfg.retrieval.minScore;
|
|
217
263
|
const kw = cfg.retrieval.hybridSearch?.keywordWeight;
|
|
@@ -223,11 +269,17 @@ async function loadRetrievedResults(query, embedder, store, cfg, retrieveFn = re
|
|
|
223
269
|
.sort((a, b) => b.score - a.score)
|
|
224
270
|
.slice(0, cfg.openCode.maxContextChunks);
|
|
225
271
|
}
|
|
272
|
+
/** Default set of plugin dependencies using the real implementations. */
|
|
226
273
|
const defaultDependencies = {
|
|
227
274
|
createEmbedder,
|
|
228
275
|
createStore: (storePath, dimension, config) => createVectorStore(config, storePath, dimension),
|
|
229
276
|
retrieve,
|
|
230
277
|
};
|
|
278
|
+
/**
|
|
279
|
+
* Format a list of relevant files (aggregated from chunks) for display.
|
|
280
|
+
* Groups chunks by file path and sorts by maximum relevance score.
|
|
281
|
+
* Includes an AGENTS.md-style tool usage reminder at the end.
|
|
282
|
+
*/
|
|
231
283
|
function formatFileList(results, worktree, maxFiles = 10) {
|
|
232
284
|
const fileMap = new Map();
|
|
233
285
|
for (const r of results) {
|
|
@@ -268,8 +320,12 @@ function formatFileList(results, worktree, maxFiles = 10) {
|
|
|
268
320
|
*
|
|
269
321
|
* Attempts to find the user's message content from output.message first
|
|
270
322
|
* (via parts/text), then falls back to input fields.
|
|
323
|
+
*
|
|
324
|
+
* @param input - The incoming hook input containing session and message metadata.
|
|
325
|
+
* @param output - The output object potentially containing the user's message parts.
|
|
326
|
+
* @returns The extracted user message text, or an empty string if not found.
|
|
271
327
|
*/
|
|
272
|
-
function extractUserMessageText(
|
|
328
|
+
function extractUserMessageText(_input, output) {
|
|
273
329
|
// Try to extract from output.parts first (most common path)
|
|
274
330
|
if (output?.message) {
|
|
275
331
|
const msg = output.message;
|
|
@@ -291,6 +347,19 @@ function extractUserMessageText(input, output) {
|
|
|
291
347
|
}
|
|
292
348
|
return "";
|
|
293
349
|
}
|
|
350
|
+
/**
|
|
351
|
+
* Create the RAG plugin hook implementations for an OpenCode workspace.
|
|
352
|
+
*
|
|
353
|
+
* Wires together the vector store, embedder, keyword index, and description
|
|
354
|
+
* provider into OpenCode's hook system. Handles:
|
|
355
|
+
* - Automatic context injection on chat messages
|
|
356
|
+
* - Documentation mode auto-kickoff
|
|
357
|
+
* - Tool registration (semantic search, file skeleton, find usages, describe image)
|
|
358
|
+
* - Session-level caching and evaluation logging
|
|
359
|
+
*
|
|
360
|
+
* @param options - Configuration and dependencies for building the hooks.
|
|
361
|
+
* @returns A complete set of OpenCode hooks for RAG functionality.
|
|
362
|
+
*/
|
|
294
363
|
export function createRagHooks(options) {
|
|
295
364
|
const dependencies = {
|
|
296
365
|
...defaultDependencies,
|
|
@@ -313,11 +382,6 @@ export function createRagHooks(options) {
|
|
|
313
382
|
// Session-level caches for lazy retrieval
|
|
314
383
|
const sessionLastMessage = new Map();
|
|
315
384
|
const sessionRetrievalCache = new Map();
|
|
316
|
-
// Session-level tool usage tracking for nudge mechanism
|
|
317
|
-
const RAG_TOOL_NAMES = new Set(["search_semantic", "get_file_skeleton", "find_usages"]);
|
|
318
|
-
const sessionRagToolCalls = new Map();
|
|
319
|
-
const sessionMessageCount = new Map();
|
|
320
|
-
const sessionSkeletonCalls = new Map(); // sessionID → set of filePaths
|
|
321
385
|
// Evaluation session logger — captures OpenCode events for analysis
|
|
322
386
|
const sessionLogger = createSessionLogger(options.storePath);
|
|
323
387
|
appendDebugLog(options.logFilePath, {
|
|
@@ -464,6 +528,20 @@ export function createRagHooks(options) {
|
|
|
464
528
|
error: err,
|
|
465
529
|
});
|
|
466
530
|
}
|
|
531
|
+
try {
|
|
532
|
+
const describeImageTool = createDescribeImageTool({
|
|
533
|
+
worktree: options.worktree,
|
|
534
|
+
config: effectiveCfg,
|
|
535
|
+
});
|
|
536
|
+
tools["describe_image"] = describeImageTool;
|
|
537
|
+
}
|
|
538
|
+
catch (err) {
|
|
539
|
+
appendDebugLog(options.logFilePath, {
|
|
540
|
+
scope: "plugin",
|
|
541
|
+
message: "Failed to register describe_image tool",
|
|
542
|
+
error: err,
|
|
543
|
+
});
|
|
544
|
+
}
|
|
467
545
|
if (readOverride) {
|
|
468
546
|
const readTool = createRagReadTool({
|
|
469
547
|
worktree: options.worktree,
|
|
@@ -491,24 +569,6 @@ export function createRagHooks(options) {
|
|
|
491
569
|
sessionLogger.onEvent(event);
|
|
492
570
|
},
|
|
493
571
|
tool: tools,
|
|
494
|
-
async "tool.execute.after"(input, output) {
|
|
495
|
-
// Track RAG tool usage per session
|
|
496
|
-
if (RAG_TOOL_NAMES.has(input.tool)) {
|
|
497
|
-
const prev = sessionRagToolCalls.get(input.sessionID) ?? 0;
|
|
498
|
-
sessionRagToolCalls.set(input.sessionID, prev + 1);
|
|
499
|
-
}
|
|
500
|
-
},
|
|
501
|
-
async "tool.execute.before"(input, output) {
|
|
502
|
-
// Track skeleton calls per session for read-interception analytics
|
|
503
|
-
if (input.tool === "get_file_skeleton") {
|
|
504
|
-
const filePath = output.args?.filePath;
|
|
505
|
-
if (filePath) {
|
|
506
|
-
const set = sessionSkeletonCalls.get(input.sessionID) ?? new Set();
|
|
507
|
-
set.add(filePath);
|
|
508
|
-
sessionSkeletonCalls.set(input.sessionID, set);
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
},
|
|
512
572
|
async "experimental.chat.system.transform"(_input, output) {
|
|
513
573
|
appendDebugLog(options.logFilePath, {
|
|
514
574
|
scope: "experimental.chat.system.transform",
|
|
@@ -519,18 +579,21 @@ export function createRagHooks(options) {
|
|
|
519
579
|
"- `search_semantic(query)`: retrieve relevant code chunks. Call BEFORE planning, editing, or answering. Accepts `pathHints` and `languageHints`.",
|
|
520
580
|
"- `get_file_skeleton(filePath)`: structural overview of a file. Call BEFORE reading any file.",
|
|
521
581
|
"- `find_usages(symbolName)`: find all references. Call BEFORE editing any function, class, or variable.",
|
|
582
|
+
"- `describe_image(filePath)`: describe an image file using a vision model. Call when user refers to a screenshot, diagram, or image.",
|
|
522
583
|
"",
|
|
523
584
|
"Decision tree — ALWAYS follow this order:",
|
|
524
585
|
"1. User mentions code behavior/architecture → `search_semantic(query)`",
|
|
525
586
|
"2. User mentions a file path → `get_file_skeleton(filePath)` THEN `read` on specific lines",
|
|
526
587
|
"3. User mentions a function/class/variable to edit → `find_usages(symbolName)` THEN `search_semantic` THEN `edit`",
|
|
527
588
|
"4. User asks a code question → `search_semantic` to gather context before answering",
|
|
589
|
+
"5. User asks about an image or visual asset → `describe_image(filePath)` to retrieve its generated description, then optionally `search_semantic` for related code",
|
|
528
590
|
"",
|
|
529
591
|
"Proactive triggers — you MUST call these tools when:",
|
|
530
592
|
"- User asks about code behavior, architecture, or implementation details",
|
|
531
593
|
"- User asks to edit, refactor, or fix code — call `find_usages` first",
|
|
532
594
|
"- User references files or functions you haven't read yet",
|
|
533
595
|
"- User says \"find\", \"search\", \"look up\", \"where is\", \"how does\"",
|
|
596
|
+
"- User refers to an image, screenshot, diagram, or visual asset",
|
|
534
597
|
"- Before answering ANY code-related question, retrieve context first",
|
|
535
598
|
"- Before reading ANY file, call `get_file_skeleton` to orient first",
|
|
536
599
|
"",
|
|
@@ -539,6 +602,7 @@ export function createRagHooks(options) {
|
|
|
539
602
|
"- Editing a function without calling `find_usages` first (breaks call sites)",
|
|
540
603
|
"- Answering code questions without calling `search_semantic` first (you guess at behavior)",
|
|
541
604
|
"- Using `grep`/`glob` when `search_semantic` would find the answer faster",
|
|
605
|
+
"- Treating image files as text — use `describe_image` instead of reading raw bytes",
|
|
542
606
|
];
|
|
543
607
|
output.system.unshift(guidance.join("\n"));
|
|
544
608
|
// Inject update notification if available
|
|
@@ -547,6 +611,11 @@ export function createRagHooks(options) {
|
|
|
547
611
|
output.system.unshift(`OpenCodeRAG update available: ${updateInfo.currentVersion} → ${updateInfo.latestVersion}. ` +
|
|
548
612
|
`Run \`opencode-rag update\` to install.`);
|
|
549
613
|
}
|
|
614
|
+
// Inject documentation mode system prompt if enabled
|
|
615
|
+
const docMode = getEffectiveCfg().documentationMode;
|
|
616
|
+
if (docMode?.enabled && docMode.systemPrompt) {
|
|
617
|
+
output.system.unshift(docMode.systemPrompt);
|
|
618
|
+
}
|
|
550
619
|
},
|
|
551
620
|
async "chat.message"(input, output) {
|
|
552
621
|
try {
|
|
@@ -554,9 +623,90 @@ export function createRagHooks(options) {
|
|
|
554
623
|
if (text.length === 0)
|
|
555
624
|
return;
|
|
556
625
|
sessionLastMessage.set(input.sessionID, text);
|
|
557
|
-
//
|
|
558
|
-
|
|
559
|
-
|
|
626
|
+
// Handle /doc slash command
|
|
627
|
+
if (text.startsWith("/doc")) {
|
|
628
|
+
const docMode = getEffectiveCfg().documentationMode;
|
|
629
|
+
if (!docMode?.enabled) {
|
|
630
|
+
const parts = output?.parts ?? output?.message?.parts;
|
|
631
|
+
if (Array.isArray(parts) && parts.length > 0) {
|
|
632
|
+
const first = parts[0];
|
|
633
|
+
if (typeof first.text === "string") {
|
|
634
|
+
parts[0] = { ...first, text: "Documentation mode is not enabled. Set `documentationMode.enabled` to `true` in opencode-rag.json." };
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
const arg = text.slice(4).trim();
|
|
640
|
+
try {
|
|
641
|
+
const manifest = await loadManifest(options.storePath);
|
|
642
|
+
const allFiles = Object.keys(manifest.manifest.files);
|
|
643
|
+
if (allFiles.length === 0) {
|
|
644
|
+
const parts = output?.parts ?? output?.message?.parts;
|
|
645
|
+
if (Array.isArray(parts) && parts.length > 0) {
|
|
646
|
+
const first = parts[0];
|
|
647
|
+
if (typeof first.text === "string") {
|
|
648
|
+
parts[0] = { ...first, text: "No indexed files found. Run indexing first, then use `/doc`." };
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
if (arg) {
|
|
654
|
+
markSubdirectoryDocumented(options.storePath, arg, allFiles);
|
|
655
|
+
}
|
|
656
|
+
const progress = loadDocProgress(options.storePath);
|
|
657
|
+
const remaining = allFiles.filter((f) => !progress.documented.includes(f));
|
|
658
|
+
let docMsg;
|
|
659
|
+
if (remaining.length === 0) {
|
|
660
|
+
docMsg = `**All ${allFiles.length} indexed files have been documented.** No remaining files.`;
|
|
661
|
+
}
|
|
662
|
+
else {
|
|
663
|
+
const grouped = {};
|
|
664
|
+
for (const f of remaining) {
|
|
665
|
+
const dir = path.dirname(f);
|
|
666
|
+
(grouped[dir] ??= []).push(f);
|
|
667
|
+
}
|
|
668
|
+
const lines = [
|
|
669
|
+
"## Documentation",
|
|
670
|
+
"",
|
|
671
|
+
"Pick a subdirectory and document ALL files within it using Google JSDoc style.",
|
|
672
|
+
`When done, type \`/doc <subdirectory>\` to mark it complete and see what's left.`,
|
|
673
|
+
"",
|
|
674
|
+
];
|
|
675
|
+
for (const [dir, files] of Object.entries(grouped).sort(([a], [b]) => a.localeCompare(b))) {
|
|
676
|
+
lines.push(`### ${dir} (${files.length} file${files.length === 1 ? "" : "s"})`);
|
|
677
|
+
for (const f of files) {
|
|
678
|
+
lines.push(`- \`${f}\``);
|
|
679
|
+
}
|
|
680
|
+
lines.push("");
|
|
681
|
+
}
|
|
682
|
+
lines.push(`Progress: ${progress.documented.length} / ${allFiles.length} files documented.`);
|
|
683
|
+
lines.push(`Remaining: ${remaining.length} files.`);
|
|
684
|
+
docMsg = lines.join("\n");
|
|
685
|
+
}
|
|
686
|
+
const parts = output?.parts ?? output?.message?.parts;
|
|
687
|
+
if (Array.isArray(parts) && parts.length > 0) {
|
|
688
|
+
const first = parts[0];
|
|
689
|
+
if (typeof first.text === "string") {
|
|
690
|
+
parts[0] = { ...first, text: docMsg };
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
catch (err) {
|
|
695
|
+
appendDebugLog(options.logFilePath, {
|
|
696
|
+
scope: "chat.message",
|
|
697
|
+
message: "Failed to handle /doc command",
|
|
698
|
+
error: err,
|
|
699
|
+
});
|
|
700
|
+
const parts = output?.parts ?? output?.message?.parts;
|
|
701
|
+
if (Array.isArray(parts) && parts.length > 0) {
|
|
702
|
+
const first = parts[0];
|
|
703
|
+
if (typeof first.text === "string") {
|
|
704
|
+
parts[0] = { ...first, text: "Failed to start documentation. Ensure the workspace is indexed." };
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
560
710
|
const pendingInjection = consumePendingRagInjection(options.storePath);
|
|
561
711
|
const count = await store.count();
|
|
562
712
|
if (count === 0)
|
|
@@ -583,9 +733,32 @@ export function createRagHooks(options) {
|
|
|
583
733
|
return;
|
|
584
734
|
}
|
|
585
735
|
if (pendingInjection === "chunks") {
|
|
586
|
-
const
|
|
587
|
-
|
|
588
|
-
|
|
736
|
+
const autoInjectCfg = effectiveCfg.openCode.autoInject;
|
|
737
|
+
if (autoInjectCfg?.enabled === false) {
|
|
738
|
+
sessionLogger.onRagContext(input.sessionID, input.messageID, {
|
|
739
|
+
chunkCount: 0,
|
|
740
|
+
uniqueFiles: 0,
|
|
741
|
+
contextTokens: 0,
|
|
742
|
+
topScore: 0,
|
|
743
|
+
retrievalTimeMs,
|
|
744
|
+
});
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
const minScore = autoInjectCfg?.minScore ?? 0.85;
|
|
748
|
+
const maxChunks = autoInjectCfg?.maxChunks ?? 5;
|
|
749
|
+
const filtered = results.filter((r) => r.score >= minScore);
|
|
750
|
+
if (filtered.length === 0) {
|
|
751
|
+
sessionLogger.onRagContext(input.sessionID, input.messageID, {
|
|
752
|
+
chunkCount: 0,
|
|
753
|
+
uniqueFiles: 0,
|
|
754
|
+
contextTokens: 0,
|
|
755
|
+
topScore: 0,
|
|
756
|
+
retrievalTimeMs,
|
|
757
|
+
});
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
const topChunks = filtered.slice(0, maxChunks);
|
|
761
|
+
const chunkContext = formatAutoInjectContext(topChunks, options.worktree, autoInjectCfg?.maxTokens ?? 3000, maxChunks);
|
|
589
762
|
sessionLogger.onRagContext(input.sessionID, input.messageID, {
|
|
590
763
|
chunkCount: topChunks.length,
|
|
591
764
|
uniqueFiles: new Set(topChunks.map((r) => r.chunk.metadata.filePath)).size,
|
|
@@ -605,12 +778,35 @@ export function createRagHooks(options) {
|
|
|
605
778
|
return;
|
|
606
779
|
}
|
|
607
780
|
if (pendingInjection === "files") {
|
|
608
|
-
const
|
|
781
|
+
const autoInjectCfg = effectiveCfg.openCode.autoInject;
|
|
782
|
+
if (autoInjectCfg?.enabled === false) {
|
|
783
|
+
sessionLogger.onRagContext(input.sessionID, input.messageID, {
|
|
784
|
+
chunkCount: 0,
|
|
785
|
+
uniqueFiles: 0,
|
|
786
|
+
contextTokens: 0,
|
|
787
|
+
topScore: 0,
|
|
788
|
+
retrievalTimeMs,
|
|
789
|
+
});
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
const minScore = autoInjectCfg?.minScore ?? 0.85;
|
|
793
|
+
const filtered = results.filter((r) => r.score >= minScore);
|
|
794
|
+
if (filtered.length === 0) {
|
|
795
|
+
sessionLogger.onRagContext(input.sessionID, input.messageID, {
|
|
796
|
+
chunkCount: 0,
|
|
797
|
+
uniqueFiles: 0,
|
|
798
|
+
contextTokens: 0,
|
|
799
|
+
topScore: 0,
|
|
800
|
+
retrievalTimeMs,
|
|
801
|
+
});
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
const fileList = formatFileList(filtered, options.worktree, effectiveCfg.retrieval.topK);
|
|
609
805
|
sessionLogger.onRagContext(input.sessionID, input.messageID, {
|
|
610
806
|
chunkCount: 0,
|
|
611
807
|
uniqueFiles: 0,
|
|
612
808
|
contextTokens: fileList ? countTokens(fileList) : 0,
|
|
613
|
-
topScore:
|
|
809
|
+
topScore: filtered[0]?.score ?? 0,
|
|
614
810
|
retrievalTimeMs,
|
|
615
811
|
});
|
|
616
812
|
if (!fileList)
|
|
@@ -675,6 +871,10 @@ export function createRagHooks(options) {
|
|
|
675
871
|
},
|
|
676
872
|
};
|
|
677
873
|
}
|
|
874
|
+
/**
|
|
875
|
+
* Load the persistent keyword index from disk, falling back to an empty
|
|
876
|
+
* index if loading fails.
|
|
877
|
+
*/
|
|
678
878
|
async function loadKeywordIndex(storePath, logFilePath, logLevel) {
|
|
679
879
|
const { KeywordIndex } = await import("./retriever/keyword-index.js");
|
|
680
880
|
try {
|
|
@@ -695,6 +895,10 @@ async function loadKeywordIndex(storePath, logFilePath, logLevel) {
|
|
|
695
895
|
}
|
|
696
896
|
}
|
|
697
897
|
let _cachedNodeExecutable;
|
|
898
|
+
/**
|
|
899
|
+
* Resolve the path to the Node.js executable, caching the result.
|
|
900
|
+
* Checks `process.execPath` first, then falls back to `where`/`which`.
|
|
901
|
+
*/
|
|
698
902
|
function resolveNodeExecutable() {
|
|
699
903
|
if (_cachedNodeExecutable !== undefined)
|
|
700
904
|
return _cachedNodeExecutable;
|
|
@@ -719,6 +923,10 @@ function resolveNodeExecutable() {
|
|
|
719
923
|
_cachedNodeExecutable = found;
|
|
720
924
|
return _cachedNodeExecutable;
|
|
721
925
|
}
|
|
926
|
+
/**
|
|
927
|
+
* Resolve the MCP CLI entry point script path.
|
|
928
|
+
* Checks `dist/cli.js` first, then falls back to `src/cli.ts`.
|
|
929
|
+
*/
|
|
722
930
|
function resolveMcpCliEntry() {
|
|
723
931
|
const selfDir = path.dirname(fileURLToPath(import.meta.url));
|
|
724
932
|
const packageRoot = path.resolve(selfDir, "..");
|
|
@@ -730,6 +938,11 @@ function resolveMcpCliEntry() {
|
|
|
730
938
|
return srcCli;
|
|
731
939
|
return null;
|
|
732
940
|
}
|
|
941
|
+
/**
|
|
942
|
+
* Start an MCP server process for the given workspace directory.
|
|
943
|
+
* Spawns the CLI in MCP mode as a child process and wires stdout/stderr
|
|
944
|
+
* to the debug log. Returns a handle for graceful shutdown.
|
|
945
|
+
*/
|
|
733
946
|
function startMcpServerProcess(cwd, logFilePath, logLevel) {
|
|
734
947
|
const cliEntry = resolveMcpCliEntry();
|
|
735
948
|
if (!cliEntry) {
|
|
@@ -797,6 +1010,18 @@ function startMcpServerProcess(cwd, logFilePath, logLevel) {
|
|
|
797
1010
|
},
|
|
798
1011
|
};
|
|
799
1012
|
}
|
|
1013
|
+
/**
|
|
1014
|
+
* OpenCodeRAG plugin factory — invoked by OpenCode's plugin system for each workspace.
|
|
1015
|
+
*
|
|
1016
|
+
* Bootstraps the full RAG pipeline: loads config, probes vector dimensions,
|
|
1017
|
+
* creates embedder/store, starts the background auto-indexer (if enabled),
|
|
1018
|
+
* launches the MCP server (if enabled), checks for updates, and returns
|
|
1019
|
+
* the RAG hooks that power tools and automatic context injection.
|
|
1020
|
+
*
|
|
1021
|
+
* @param input - Plugin input containing the workspace directory and runtime context.
|
|
1022
|
+
* @param _options - Optional additional plugin options (unused).
|
|
1023
|
+
* @returns A complete set of OpenCode hooks for RAG functionality.
|
|
1024
|
+
*/
|
|
800
1025
|
export const ragPlugin = async (input, _options) => {
|
|
801
1026
|
const cfg = await getConfig(input.directory);
|
|
802
1027
|
const logFilePath = path.resolve(input.directory, resolveLogConfig(cfg).logFilePath);
|
|
@@ -898,7 +1123,7 @@ export const ragPlugin = async (input, _options) => {
|
|
|
898
1123
|
descriptionProvider,
|
|
899
1124
|
});
|
|
900
1125
|
// Start background auto-indexer if enabled
|
|
901
|
-
const autoIndexCfg = effectiveCfg.openCode.autoIndex ?? { enabled:
|
|
1126
|
+
const autoIndexCfg = effectiveCfg.openCode.autoIndex ?? { enabled: false, debounceMs: 5000, intervalMs: 300000 };
|
|
902
1127
|
if (autoIndexCfg.enabled) {
|
|
903
1128
|
const indexer = createBackgroundIndexer({
|
|
904
1129
|
cwd: input.directory,
|