scythe-context-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +21 -0
- package/CHANGELOG.md +27 -0
- package/LICENSE +201 -0
- package/README.en.md +197 -0
- package/README.md +197 -0
- package/README.zh-CN.md +197 -0
- package/dist/config.js +61 -0
- package/dist/index.js +16 -0
- package/dist/indexing/binary.js +15 -0
- package/dist/indexing/chunker.js +64 -0
- package/dist/indexing/contextPack.js +54 -0
- package/dist/indexing/defaults.js +6 -0
- package/dist/indexing/dryRun.js +48 -0
- package/dist/indexing/embeddingWriter.js +102 -0
- package/dist/indexing/hash.js +4 -0
- package/dist/indexing/hybridSearch.js +67 -0
- package/dist/indexing/indexStatus.js +224 -0
- package/dist/indexing/indexWriter.js +106 -0
- package/dist/indexing/keywordSearch.js +86 -0
- package/dist/indexing/relatedFiles.js +137 -0
- package/dist/indexing/relatedSnippets.js +105 -0
- package/dist/indexing/resultFormat.js +69 -0
- package/dist/indexing/scanner.js +123 -0
- package/dist/indexing/semanticSearch.js +48 -0
- package/dist/indexing/symbolGraph.js +121 -0
- package/dist/indexing/types.js +1 -0
- package/dist/providers/gemini.js +149 -0
- package/dist/providers/types.js +1 -0
- package/dist/storage/schema.js +187 -0
- package/dist/storage/sqliteVec.js +17 -0
- package/dist/tools/registerTools.js +364 -0
- package/docs/architecture.md +280 -0
- package/docs/codex-integration.md +114 -0
- package/docs/development-plan.md +218 -0
- package/docs/gemini-compatibility.md +214 -0
- package/docs/tech-stack.md +122 -0
- package/package.json +58 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# Scythe Context MCP 架構設計
|
|
2
|
+
|
|
3
|
+
## 目標
|
|
4
|
+
|
|
5
|
+
Scythe Context MCP 的目標是做一個本機、可控、可接 Codex App / CLI 的上下文搜尋層:
|
|
6
|
+
|
|
7
|
+
1. 對 repo 建立本機索引。
|
|
8
|
+
2. 支援自然語言查詢程式碼。
|
|
9
|
+
3. 返回可直接給 Codex 使用的檔案路徑、行號範圍、片段與 grep 建議。
|
|
10
|
+
4. 支援官方 Gemini Embedding 2 與第三方 v1beta 中轉站。
|
|
11
|
+
5. 後續可擴充成 hybrid search、symbol graph、git history 與多 repo context。
|
|
12
|
+
|
|
13
|
+
## 系統邊界
|
|
14
|
+
|
|
15
|
+
Scythe Context 負責:
|
|
16
|
+
|
|
17
|
+
- 掃描工作區檔案。
|
|
18
|
+
- 依語言與結構切 chunk。
|
|
19
|
+
- 產生 embedding。
|
|
20
|
+
- 儲存本機索引。
|
|
21
|
+
- 查詢與排序。
|
|
22
|
+
- 透過 MCP tools 回傳上下文。
|
|
23
|
+
|
|
24
|
+
Codex 負責:
|
|
25
|
+
|
|
26
|
+
- 決定何時呼叫 MCP tool。
|
|
27
|
+
- 根據回傳片段讀取/編輯檔案。
|
|
28
|
+
- 執行測試與修改程式碼。
|
|
29
|
+
|
|
30
|
+
Embedding provider 負責:
|
|
31
|
+
|
|
32
|
+
- 將 query/chunk 轉成向量。
|
|
33
|
+
- 不負責保存程式碼。
|
|
34
|
+
- 不負責判斷搜尋結果。
|
|
35
|
+
|
|
36
|
+
## 高階流程
|
|
37
|
+
|
|
38
|
+
```mermaid
|
|
39
|
+
flowchart TD
|
|
40
|
+
A["Codex App / CLI"] --> B["MCP stdio server"]
|
|
41
|
+
B --> C["Tool router"]
|
|
42
|
+
C --> D["Index manager"]
|
|
43
|
+
D --> E["File scanner"]
|
|
44
|
+
D --> F["Chunker"]
|
|
45
|
+
D --> G["Symbol/dependency extractor"]
|
|
46
|
+
D --> H["Embedding provider"]
|
|
47
|
+
H --> I["Gemini official API or v1beta proxy"]
|
|
48
|
+
D --> J["SQLite metadata + sqlite-vec + FTS5"]
|
|
49
|
+
C --> K["Hybrid ranker"]
|
|
50
|
+
C --> L["Related-file lookup"]
|
|
51
|
+
K --> M["Result formatter"]
|
|
52
|
+
L --> M
|
|
53
|
+
M --> A
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## 模組分層
|
|
57
|
+
|
|
58
|
+
### MCP Layer
|
|
59
|
+
|
|
60
|
+
位置:`src/index.ts`, `src/tools/registerTools.ts`
|
|
61
|
+
|
|
62
|
+
職責:
|
|
63
|
+
|
|
64
|
+
- 啟動 stdio MCP server。
|
|
65
|
+
- 註冊工具。
|
|
66
|
+
- 保持工具輸入 schema 穩定。
|
|
67
|
+
- 將內部錯誤轉成可讀的 tool response。
|
|
68
|
+
|
|
69
|
+
初期 tools:
|
|
70
|
+
|
|
71
|
+
- `repo_index_status`
|
|
72
|
+
- `gemini_embedding_probe`
|
|
73
|
+
- `repo_reindex`
|
|
74
|
+
- `repo_semantic_search`
|
|
75
|
+
- `repo_related_files`
|
|
76
|
+
- `repo_context_pack`
|
|
77
|
+
|
|
78
|
+
後續 tools:
|
|
79
|
+
|
|
80
|
+
- `repo_open_ranges`
|
|
81
|
+
- `repo_grep_suggest`
|
|
82
|
+
|
|
83
|
+
### Config Layer
|
|
84
|
+
|
|
85
|
+
位置:`src/config.ts`
|
|
86
|
+
|
|
87
|
+
職責:
|
|
88
|
+
|
|
89
|
+
- 從環境變數讀取 provider 與索引設定。
|
|
90
|
+
- 支援官方 Gemini 與中轉站差異。
|
|
91
|
+
- 不讀取密鑰到 log 或回傳內容,只回傳 `hasApiKey`。
|
|
92
|
+
|
|
93
|
+
### Embedding Provider Layer
|
|
94
|
+
|
|
95
|
+
位置:`src/providers/*`
|
|
96
|
+
|
|
97
|
+
目前 provider:
|
|
98
|
+
|
|
99
|
+
- `GeminiEmbeddingProvider`
|
|
100
|
+
|
|
101
|
+
設計原則:
|
|
102
|
+
|
|
103
|
+
- 使用 REST,不綁定 Google SDK,方便中轉站相容。
|
|
104
|
+
- provider 介面只暴露 `embed` / `embedBatch`。
|
|
105
|
+
- query/document formatting 在 provider 內處理,避免上層漏掉 Gemini Embedding 2 的 task prefix。
|
|
106
|
+
|
|
107
|
+
### Index Manager
|
|
108
|
+
|
|
109
|
+
職責:
|
|
110
|
+
|
|
111
|
+
- 判斷索引是否過期。
|
|
112
|
+
- 比對檔案 hash。
|
|
113
|
+
- 增量更新 chunk 和 vector。
|
|
114
|
+
- 控制 batch embedding。
|
|
115
|
+
- 控制併發與 rate limit。
|
|
116
|
+
- 每次 reindex 重建單檔 symbol/dependency metadata。
|
|
117
|
+
- 對未變更 chunks 保留 row id,避免重算 embeddings。
|
|
118
|
+
|
|
119
|
+
### File Scanner
|
|
120
|
+
|
|
121
|
+
候選規則:
|
|
122
|
+
|
|
123
|
+
- 尊重 `.gitignore`。
|
|
124
|
+
- 內建排除:`.git`, `node_modules`, `dist`, `build`, `.next`, `coverage`, binary files。
|
|
125
|
+
- 預設只索引可讀文字檔。
|
|
126
|
+
- 可用 allow/deny glob 擴充。
|
|
127
|
+
|
|
128
|
+
### Chunker
|
|
129
|
+
|
|
130
|
+
初期策略:
|
|
131
|
+
|
|
132
|
+
- 通用文字 chunk:依行數與 token 粗估切分。
|
|
133
|
+
- 每 chunk 保留 `path`, `startLine`, `endLine`, `language`, `hash`, `text`。
|
|
134
|
+
- chunk 大小目標:300-900 tokens。
|
|
135
|
+
- 相鄰 chunk overlap:30-80 tokens。
|
|
136
|
+
|
|
137
|
+
進階策略:
|
|
138
|
+
|
|
139
|
+
- tree-sitter 依 function/class/module 切分。
|
|
140
|
+
- 對大型檔案建立 summary chunk。
|
|
141
|
+
- 記錄 imports/exports/symbols。
|
|
142
|
+
|
|
143
|
+
### Symbol Graph
|
|
144
|
+
|
|
145
|
+
目前採用輕量 regex extractor,抽取常見 TS/JS/Python/Go/Rust 的 declarations 與 imports:
|
|
146
|
+
|
|
147
|
+
- `file_symbols`: name、kind、line、signature、exported。
|
|
148
|
+
- `file_dependencies`: raw specifier、resolved relative path、line。
|
|
149
|
+
|
|
150
|
+
這層刻意獨立於 chunk/embedding storage,升級 extractor 或之後換成 tree-sitter 時,不會破壞既有 embedding cache。查詢上先提供 `repo_related_files`,讓 Codex 在搜尋命中後按需展開 imports / reverse imports,而不是每次搜尋都塞入大量相關檔案。
|
|
151
|
+
|
|
152
|
+
### Context Packer
|
|
153
|
+
|
|
154
|
+
`repo_context_pack` 是 Codex 實際查找上下文的主要入口。它會:
|
|
155
|
+
|
|
156
|
+
- 執行 semantic/hybrid search。
|
|
157
|
+
- 對 primary snippets 套用 `max_context_chars`。
|
|
158
|
+
- 為命中的前幾個檔案附上 symbols、imports、importedBy。
|
|
159
|
+
- 依 `related_depth` 做 bounded BFS,沿著 imports / importedBy 展開多跳 related files。
|
|
160
|
+
- 對 related paths 做輕量分類,source 優先,test/mock/fixture/generated/docs 後置但不硬排除。
|
|
161
|
+
- 產出 `suggestedPaths`,讓 Codex 判斷下一步要讀哪些檔案。
|
|
162
|
+
- 可選擇打包 related snippets,但使用獨立 `max_related_context_chars`,不擠壓 primary snippets。
|
|
163
|
+
|
|
164
|
+
related snippets 預設關閉,避免 context 膨脹。開啟時只讀 related graph 中非 primary result 的檔案片段,並受每檔 snippet 數、每段長度、總字元數三層限制。
|
|
165
|
+
|
|
166
|
+
### Storage Layer
|
|
167
|
+
|
|
168
|
+
MVP 儲存選型:
|
|
169
|
+
|
|
170
|
+
- metadata: SQLite
|
|
171
|
+
- vector: sqlite-vec
|
|
172
|
+
- keyword: SQLite FTS5 + rg fallback
|
|
173
|
+
|
|
174
|
+
不建議先用 JSON vector 當正式 MVP。1536 維向量若用 JSON 存放,索引體積、解析成本與相似度掃描成本都會太早變成瓶頸。可以在單元測試中保留 in-memory vector store,但實際索引從 Phase 2 開始使用 sqlite-vec。
|
|
175
|
+
|
|
176
|
+
資料表草案:
|
|
177
|
+
|
|
178
|
+
```sql
|
|
179
|
+
files(
|
|
180
|
+
id integer primary key,
|
|
181
|
+
project_path text not null,
|
|
182
|
+
path text not null,
|
|
183
|
+
mtime_ms integer not null,
|
|
184
|
+
size integer not null,
|
|
185
|
+
hash text not null,
|
|
186
|
+
unique(project_path, path)
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
embedding_sets(
|
|
190
|
+
id integer primary key,
|
|
191
|
+
provider text not null,
|
|
192
|
+
base_url_hash text not null,
|
|
193
|
+
model text not null,
|
|
194
|
+
dimensions integer not null,
|
|
195
|
+
created_at text not null,
|
|
196
|
+
unique(provider, base_url_hash, model, dimensions)
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
chunks(
|
|
200
|
+
id integer primary key,
|
|
201
|
+
file_id integer not null,
|
|
202
|
+
start_line integer not null,
|
|
203
|
+
end_line integer not null,
|
|
204
|
+
language text,
|
|
205
|
+
title text,
|
|
206
|
+
text text not null,
|
|
207
|
+
hash text not null,
|
|
208
|
+
unique(file_id, start_line, end_line, hash)
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
embeddings(
|
|
212
|
+
chunk_id integer not null,
|
|
213
|
+
embedding_set_id integer not null,
|
|
214
|
+
primary key(chunk_id, embedding_set_id)
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
file_symbols(
|
|
218
|
+
id integer primary key,
|
|
219
|
+
file_id integer not null,
|
|
220
|
+
name text not null,
|
|
221
|
+
kind text not null,
|
|
222
|
+
line integer not null,
|
|
223
|
+
signature text not null,
|
|
224
|
+
exported integer not null
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
file_dependencies(
|
|
228
|
+
id integer primary key,
|
|
229
|
+
file_id integer not null,
|
|
230
|
+
specifier text not null,
|
|
231
|
+
resolved_path text,
|
|
232
|
+
line integer not null
|
|
233
|
+
);
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Ranking Layer
|
|
237
|
+
|
|
238
|
+
初期 hybrid score:
|
|
239
|
+
|
|
240
|
+
```text
|
|
241
|
+
score = 0.70 * vector_similarity
|
|
242
|
+
+ 0.20 * keyword_score
|
|
243
|
+
+ 0.05 * path_score
|
|
244
|
+
+ 0.05 * recency_or_open_file_boost
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Codex 使用情境下,結果要比一般 RAG 更偏向「可操作」:
|
|
248
|
+
|
|
249
|
+
- 返回完整檔案路徑。
|
|
250
|
+
- 返回行號範圍。
|
|
251
|
+
- 返回短片段。
|
|
252
|
+
- 返回為何匹配。
|
|
253
|
+
- 返回建議 grep keywords。
|
|
254
|
+
- 返回 context budget summary,並在超出 `max_context_chars` 時截斷 snippets。
|
|
255
|
+
|
|
256
|
+
## 設計取捨
|
|
257
|
+
|
|
258
|
+
Scythe Context 優先做本機索引、可配置 provider、可診斷 tool output 與 Codex 可操作上下文。MVP 目前不包含:
|
|
259
|
+
|
|
260
|
+
- 團隊級跨 repo 權限系統。
|
|
261
|
+
- 即時 IDE active context。
|
|
262
|
+
- 完整 knowledge graph。
|
|
263
|
+
- commit/issue/design docs 深度整合。
|
|
264
|
+
- 商業級 context compression。
|
|
265
|
+
|
|
266
|
+
可逐步補:
|
|
267
|
+
|
|
268
|
+
- git history indexing。
|
|
269
|
+
- symbol graph。
|
|
270
|
+
- 多 repo workspace。
|
|
271
|
+
- docs/tickets connector。
|
|
272
|
+
|
|
273
|
+
## 安全與隱私
|
|
274
|
+
|
|
275
|
+
- 索引資料預設存在 repo 內 `.scythe-context/`。
|
|
276
|
+
- 原始程式碼不送到 Codex 以外的地方,除非呼叫 embedding provider。
|
|
277
|
+
- 若使用 Gemini Embedding,chunk text 會送到 configured endpoint。
|
|
278
|
+
- 若使用第三方中轉站,應視為會看到 query/chunk text。
|
|
279
|
+
- 不在 tool output 顯示 API key。
|
|
280
|
+
- 對私有或敏感 repo,應提供 `SCYTHE_CONTEXT_DISABLE_REMOTE_EMBEDDINGS=true` 這類後續開關,避免意外送出 chunk。
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Codex App / CLI Integration Review
|
|
2
|
+
|
|
3
|
+
## Sources Checked
|
|
4
|
+
|
|
5
|
+
- Official OpenAI Codex manual fetched by the `openai-docs` skill on 2026-06-13.
|
|
6
|
+
- Official Codex MCP documentation.
|
|
7
|
+
- Official Codex `AGENTS.md` documentation.
|
|
8
|
+
- `openai/codex` GitHub README, current public repository page.
|
|
9
|
+
|
|
10
|
+
## Findings
|
|
11
|
+
|
|
12
|
+
### MCP transport
|
|
13
|
+
|
|
14
|
+
Scythe Context is aligned with Codex's local MCP path:
|
|
15
|
+
|
|
16
|
+
- Codex supports local STDIO MCP servers.
|
|
17
|
+
- Scythe Context runs as a STDIO server through `node dist/index.js`.
|
|
18
|
+
- Configuration should use `[mcp_servers.scythe_context]` and `[mcp_servers.scythe_context.env]` tables in `config.toml`.
|
|
19
|
+
- Secrets should be forwarded with `env_vars = ["GEMINI_API_KEY"]` instead of written into project config.
|
|
20
|
+
|
|
21
|
+
This is preferable to a remote HTTP MCP server for the current project because the index database and scanner are local to the repo.
|
|
22
|
+
|
|
23
|
+
### Server instructions
|
|
24
|
+
|
|
25
|
+
Codex reads the MCP server `instructions` field during initialization. The most important guidance should appear early because Codex may use the beginning of the instructions while deciding whether to call a server.
|
|
26
|
+
|
|
27
|
+
Scythe Context's server instructions now put the key workflow first:
|
|
28
|
+
|
|
29
|
+
1. Check `repo_index_status`.
|
|
30
|
+
2. Run metadata reindex only when needed.
|
|
31
|
+
3. Prefer `repo_context_pack` for task lookup.
|
|
32
|
+
4. Only embed when semantic vectors are needed.
|
|
33
|
+
5. Keep context budgets bounded.
|
|
34
|
+
|
|
35
|
+
### Codex surfaces
|
|
36
|
+
|
|
37
|
+
Codex CLI and the IDE extension share MCP configuration through `config.toml`. The Codex app also exposes plugins/MCP-related extension points, but local setup behavior can vary by App settings and installed plugins. For direct reproducible setup, document CLI/IDE `config.toml` first and keep App usage phrased as "Codex local MCP compatible" rather than assuming every App install auto-loads a project config.
|
|
38
|
+
|
|
39
|
+
### AGENTS.md
|
|
40
|
+
|
|
41
|
+
Codex reads `AGENTS.md` before work and layers global plus project guidance. Scythe Context's `AGENTS.md` is intentionally short enough to fit comfortably under the default project instruction limit and focuses on:
|
|
42
|
+
|
|
43
|
+
- Preferred tool workflow.
|
|
44
|
+
- Privacy rules for `.scythe-context/` and `local/`.
|
|
45
|
+
- Verification commands.
|
|
46
|
+
|
|
47
|
+
This is aligned with Codex's expected durable instruction surface.
|
|
48
|
+
|
|
49
|
+
### Tool output shape
|
|
50
|
+
|
|
51
|
+
The current MCP output is optimized for Codex use:
|
|
52
|
+
|
|
53
|
+
- JSON text responses are deterministic and easy to inspect.
|
|
54
|
+
- `repo_context_pack` is the preferred single-call workflow for code lookup.
|
|
55
|
+
- `max_context_chars` and `max_related_context_chars` keep output bounded.
|
|
56
|
+
- `suggestedPaths`, line ranges, `matchReason`, `grepKeywords`, symbols, imports, reverse imports, and related snippets give Codex actionable next steps without forcing whole-file reads.
|
|
57
|
+
|
|
58
|
+
### Tool policy
|
|
59
|
+
|
|
60
|
+
Recommended config should expose all tools by default during development, but `enabled_tools` is documented so users can pin the expected tool surface. Keep `gemini_embedding_probe` available because it is the fastest way to debug official Gemini or proxy compatibility.
|
|
61
|
+
|
|
62
|
+
## Optimizations Already Applied
|
|
63
|
+
|
|
64
|
+
- STDIO MCP server.
|
|
65
|
+
- Early, self-contained server instructions.
|
|
66
|
+
- `AGENTS.md` project guidance.
|
|
67
|
+
- Valid Codex TOML examples using `[mcp_servers.scythe_context.env]`.
|
|
68
|
+
- Secret-safe config examples using `env_vars` for `GEMINI_API_KEY`.
|
|
69
|
+
- `cwd` in MCP config so relative `.env` loading is predictable.
|
|
70
|
+
- `startup_timeout_sec` and `tool_timeout_sec` tuned above defaults.
|
|
71
|
+
- Bounded context output for primary and related snippets.
|
|
72
|
+
- Explicit opt-in embedding and opt-in related snippet packing.
|
|
73
|
+
- `repo_index_status` freshness diagnostics for stale/new/modified/missing files.
|
|
74
|
+
|
|
75
|
+
## Remaining Work
|
|
76
|
+
|
|
77
|
+
- Consider a plugin package later if Codex App plugin distribution becomes the preferred installation route.
|
|
78
|
+
- Add tree-sitter symbol extraction only if regex extraction becomes a retrieval-quality bottleneck.
|
|
79
|
+
- Continue expanding provider capability caching and error-specific remediation hints.
|
|
80
|
+
|
|
81
|
+
## Troubleshooting
|
|
82
|
+
|
|
83
|
+
### MCP server does not appear
|
|
84
|
+
|
|
85
|
+
1. In the Codex TUI, run `/mcp` and confirm `scythe_context` appears.
|
|
86
|
+
2. Confirm the config is in `~/.codex/config.toml` or in a trusted project's `.codex/config.toml`.
|
|
87
|
+
3. Restart Codex after changing config. Codex reads MCP config at session startup.
|
|
88
|
+
4. Check that `command`, `args`, and `cwd` point to the built repo and that `npm run build` has produced `dist/index.js`.
|
|
89
|
+
5. If startup is slow on WSL or a cold Node install, raise `startup_timeout_sec`.
|
|
90
|
+
|
|
91
|
+
### Tool starts but embedding fails
|
|
92
|
+
|
|
93
|
+
1. Run `gemini_embedding_probe` with a short test string.
|
|
94
|
+
2. Verify `GEMINI_API_KEY` is present in the environment Codex launches from.
|
|
95
|
+
3. For proxy endpoints, verify `GEMINI_BASE_URL` can include or omit a trailing slash and can include or omit `/v1beta`.
|
|
96
|
+
4. If batch indexing fails but single requests work, run `repo_reindex(index_embeddings=true, max_embedding_chunks=...)` again; the embedding writer falls back to single requests.
|
|
97
|
+
|
|
98
|
+
### Search returns index missing
|
|
99
|
+
|
|
100
|
+
1. Run `repo_index_status`.
|
|
101
|
+
2. Run `repo_reindex(dry_run=false)` for metadata.
|
|
102
|
+
3. Run `repo_reindex(dry_run=false, index_embeddings=true)` only when semantic search or context packs need vectors.
|
|
103
|
+
4. Keep `max_embedding_chunks` low for the first pass on large repos.
|
|
104
|
+
|
|
105
|
+
### Context output is too large
|
|
106
|
+
|
|
107
|
+
1. Lower `max_context_chars`.
|
|
108
|
+
2. Keep `include_related_snippets=false` for broad exploration.
|
|
109
|
+
3. Lower `max_related_files`, `related_depth`, or `max_related_context_chars`.
|
|
110
|
+
4. Use `repo_related_files` for one focused file instead of a broad context pack.
|
|
111
|
+
|
|
112
|
+
### AGENTS.md changes do not apply
|
|
113
|
+
|
|
114
|
+
Codex reads `AGENTS.md` when a run or TUI session starts. Restart Codex in the project root after changing guidance. If using nested instructions, remember that closer files override earlier root guidance.
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# 開發設計方案
|
|
2
|
+
|
|
3
|
+
## Phase 0: 初始化與設計
|
|
4
|
+
|
|
5
|
+
狀態:已完成。
|
|
6
|
+
|
|
7
|
+
交付:
|
|
8
|
+
|
|
9
|
+
- Git repository 初始化。
|
|
10
|
+
- TypeScript MCP server 骨架。
|
|
11
|
+
- Gemini Embedding 2 REST provider。
|
|
12
|
+
- 官方 Gemini / 第三方 v1beta 中轉站設定。
|
|
13
|
+
- 架構與開發文檔。
|
|
14
|
+
|
|
15
|
+
驗收:
|
|
16
|
+
|
|
17
|
+
- `npm run build` 成功。
|
|
18
|
+
- Codex 可啟動 MCP server。
|
|
19
|
+
- `repo_index_status` 可回傳狀態。
|
|
20
|
+
- `gemini_embedding_probe` 可測 provider。
|
|
21
|
+
|
|
22
|
+
## Phase 1: File Scanner + Chunker
|
|
23
|
+
|
|
24
|
+
狀態:已完成 dry-run MVP。
|
|
25
|
+
|
|
26
|
+
目標:能掃描 repo 並產生穩定 chunks。
|
|
27
|
+
|
|
28
|
+
工作項:
|
|
29
|
+
|
|
30
|
+
1. 實作 `.gitignore` 載入。
|
|
31
|
+
2. 實作內建 ignore 清單。
|
|
32
|
+
3. 偵測 binary / 大檔。
|
|
33
|
+
4. 實作文字 chunker。
|
|
34
|
+
5. 產出 chunk hash。
|
|
35
|
+
6. 加入 `repo_reindex` dry-run 模式。
|
|
36
|
+
7. 加入 scanner/chunker 單元測試。
|
|
37
|
+
|
|
38
|
+
工具變更:
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
repo_reindex(project_path, force, dry_run)
|
|
42
|
+
repo_index_status(project_path)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
驗收:
|
|
46
|
+
|
|
47
|
+
- 能列出會被索引的檔案數與 chunk 數。
|
|
48
|
+
- dry-run 會輸出 skipped files 與 skip reasons。
|
|
49
|
+
- 超過預設大小限制的檔案會被跳過或截斷,不能拖垮索引。
|
|
50
|
+
- HTML 參考檔這類大檔不會讓索引失控。
|
|
51
|
+
- chunk hash 對同內容穩定,換行與路徑處理有測試覆蓋。
|
|
52
|
+
|
|
53
|
+
## Phase 2: Local Storage
|
|
54
|
+
|
|
55
|
+
狀態:已完成。
|
|
56
|
+
|
|
57
|
+
目標:能把檔案、chunk、embedding metadata 存到本機。
|
|
58
|
+
|
|
59
|
+
MVP 儲存選型:
|
|
60
|
+
|
|
61
|
+
- SQLite metadata。
|
|
62
|
+
- sqlite-vec vector index。
|
|
63
|
+
- SQLite FTS5 keyword index。
|
|
64
|
+
- 測試可用 in-memory fake store,但正式索引不走 JSON vector。
|
|
65
|
+
|
|
66
|
+
工作項:
|
|
67
|
+
|
|
68
|
+
1. 建立 schema migration。
|
|
69
|
+
2. 實作 file/chunk upsert。
|
|
70
|
+
3. 實作 stale chunk cleanup。
|
|
71
|
+
4. 實作 embedding cache。
|
|
72
|
+
5. 記錄 provider/model/dimensions。
|
|
73
|
+
6. 建立 `embedding_sets`,避免不同 base URL/model/dimensions 的向量混用。
|
|
74
|
+
7. `embedBatch` 不支援時 fallback 到逐筆 `embedContent`。
|
|
75
|
+
8. 加入 embedding rate limit 與 batch size 設定。
|
|
76
|
+
9. sqlite-vec rowid 寫入使用 `BigInt`,避免 better-sqlite3 綁定成非整數型別。
|
|
77
|
+
|
|
78
|
+
已完成:
|
|
79
|
+
|
|
80
|
+
- SQLite metadata schema。
|
|
81
|
+
- dimension-specific sqlite-vec virtual table,例如 `vec_embeddings_1536`。
|
|
82
|
+
- file upsert。
|
|
83
|
+
- chunk insert de-duplication。
|
|
84
|
+
- embedding set de-duplication。
|
|
85
|
+
- embedding metadata id 與 sqlite-vec rowid 的連結測試。
|
|
86
|
+
- `repo_reindex(dry_run=false)` 寫入 `.scythe-context/index.sqlite` 的 metadata index。
|
|
87
|
+
- `repo_reindex(dry_run=false, index_embeddings=true)` 會顯式呼叫 embedding provider,寫入 `embeddings` 與 `vec_embeddings_1536`。
|
|
88
|
+
- `max_embedding_chunks` 限制單次 embedding 工作量,避免成本失控。
|
|
89
|
+
- batch embedding 失敗時 fallback 到逐筆 embedding。
|
|
90
|
+
- `file_symbols` 與 `file_dependencies` 已加入 schema,與 chunk/embedding cache 解耦。
|
|
91
|
+
|
|
92
|
+
驗收:
|
|
93
|
+
|
|
94
|
+
- 重跑索引不重複 embedding 未變更 chunks。
|
|
95
|
+
- 更換 `GEMINI_MODEL` 或 dimensions 時會建立新 embedding set。
|
|
96
|
+
- 中轉站不支援 batch 時,索引仍可完成。
|
|
97
|
+
- 1536 維向量會被驗證 dimensions,一旦 provider 回傳維度不符就 fail fast。
|
|
98
|
+
|
|
99
|
+
## Phase 3: Semantic Search + Minimal Keyword
|
|
100
|
+
|
|
101
|
+
狀態:已完成。
|
|
102
|
+
|
|
103
|
+
目標:`repo_semantic_search` 真正返回相關程式碼片段。
|
|
104
|
+
|
|
105
|
+
工作項:
|
|
106
|
+
|
|
107
|
+
1. query embedding。
|
|
108
|
+
2. cosine similarity。
|
|
109
|
+
3. topK retrieve。
|
|
110
|
+
4. result formatter。
|
|
111
|
+
5. line range merge。
|
|
112
|
+
6. grep keyword suggestion。
|
|
113
|
+
7. 對 path、filename、symbol-looking tokens 加最低限度 boost。
|
|
114
|
+
|
|
115
|
+
回傳格式草案:
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"query": "payment logging flow",
|
|
120
|
+
"results": [
|
|
121
|
+
{
|
|
122
|
+
"path": "src/services/payments.ts",
|
|
123
|
+
"startLine": 42,
|
|
124
|
+
"endLine": 96,
|
|
125
|
+
"score": 0.88,
|
|
126
|
+
"matchType": "semantic",
|
|
127
|
+
"snippet": "...",
|
|
128
|
+
"grepKeywords": ["processPayment", "logger", "payment"]
|
|
129
|
+
}
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
驗收:
|
|
135
|
+
|
|
136
|
+
- 自然語言查詢可找到非同字面命中的檔案。
|
|
137
|
+
- 返回結果可讓 Codex 直接接著 Read/Edit。
|
|
138
|
+
- 精確函式名查詢不應被純語義結果完全蓋掉。
|
|
139
|
+
|
|
140
|
+
已完成:
|
|
141
|
+
|
|
142
|
+
- query embedding。
|
|
143
|
+
- sqlite-vec KNN lookup。
|
|
144
|
+
- 回傳 path、line range、distance、snippet。
|
|
145
|
+
- index missing 時回傳可修復訊息。
|
|
146
|
+
- SQLite FTS5 keyword search。
|
|
147
|
+
- hybrid ranker 合併 semantic/keyword 結果。
|
|
148
|
+
- result formatter 回傳 `matchReason` 與 `grepKeywords`。
|
|
149
|
+
|
|
150
|
+
## Phase 4: Advanced Hybrid Search
|
|
151
|
+
|
|
152
|
+
狀態:MVP 已完成。
|
|
153
|
+
|
|
154
|
+
目標:改善 precision,避免純 embedding 漏掉符號名稱。
|
|
155
|
+
|
|
156
|
+
工作項:
|
|
157
|
+
|
|
158
|
+
1. 加入 keyword search。
|
|
159
|
+
2. path/name boost。
|
|
160
|
+
3. symbols boost。
|
|
161
|
+
4. query rewrite:從自然語言抽 grep keywords。
|
|
162
|
+
5. 結果去重與合併。
|
|
163
|
+
|
|
164
|
+
工具:
|
|
165
|
+
|
|
166
|
+
```text
|
|
167
|
+
repo_semantic_search(query, project_path, max_results, mode="hybrid")
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
驗收:
|
|
171
|
+
|
|
172
|
+
- 已知函式名搜尋優先命中精確檔案。
|
|
173
|
+
- 中文 query 仍可找到英文程式碼片段。
|
|
174
|
+
|
|
175
|
+
## Phase 5: Symbol Graph
|
|
176
|
+
|
|
177
|
+
狀態:輕量 MVP 已完成;bounded multi-hop traversal 已完成;tree-sitter / deeper semantic graph 尚未實作。
|
|
178
|
+
|
|
179
|
+
目標:接近 context engine 的「關係理解」。
|
|
180
|
+
|
|
181
|
+
工作項:
|
|
182
|
+
|
|
183
|
+
1. 解析 imports/exports。已完成常見 TS/JS/Python/Go/Rust 的保守 regex 抽取。
|
|
184
|
+
2. 記錄 function/class/interface symbols。已完成常見 declarations。
|
|
185
|
+
3. 建立 file dependency graph。已完成 relative import resolution 與 reverse-import 查詢。
|
|
186
|
+
4. 查詢時加入 related files。已完成 `repo_related_files`,採按需展開。
|
|
187
|
+
5. 支援從 router -> service -> model 的鏈路返回。已完成 bounded BFS traversal 與 source-first related path ranking,後續可加入語言感知排序與 schema/test boost。
|
|
188
|
+
|
|
189
|
+
驗收:
|
|
190
|
+
|
|
191
|
+
- `repo_reindex(dry_run=false)` 會寫入 symbols/dependencies 統計。
|
|
192
|
+
- `repo_index_status` 會回報 symbol/dependency rows。
|
|
193
|
+
- `repo_related_files(path)` 會返回該檔 symbols、imports、importedBy。
|
|
194
|
+
- 查詢 API 行為時,可透過 context pack 同時返回 route、handler、service、schema/test 候選路徑;更精準的語言感知排序留待後續優化。
|
|
195
|
+
|
|
196
|
+
## Phase 6: Codex Workflow Polish
|
|
197
|
+
|
|
198
|
+
狀態:context budget、context packer、bounded multi-hop related-file traversal、related snippet packing、server instructions、AGENTS.md、provider diagnostics、index freshness diagnostics 已完成。
|
|
199
|
+
|
|
200
|
+
目標:讓 Codex 更穩定地使用工具。
|
|
201
|
+
|
|
202
|
+
工作項:
|
|
203
|
+
|
|
204
|
+
1. 補 server instructions。
|
|
205
|
+
2. 加一份可放入 `AGENTS.md` 的使用指南。
|
|
206
|
+
3. 對結果加 token budget。已完成字元級 MVP。
|
|
207
|
+
4. 支援 `max_context_chars`。已完成 `repo_semantic_search` 的 snippet 總字元限制。
|
|
208
|
+
5. 新增 context packer。已完成 `repo_context_pack`,會打包 primary snippets、related metadata 與 suggested paths。
|
|
209
|
+
6. 新增 related snippet packing。已完成 opt-in `include_related_snippets` 與獨立 `max_related_context_chars`。
|
|
210
|
+
7. 錯誤訊息加入可修復建議。已完成 Gemini probe diagnostics 與 secret-safe provider errors。
|
|
211
|
+
8. 新增 index freshness diagnostics。已完成 `repo_index_status` 的 new/modified/missing/metadata_changed stale reason samples。
|
|
212
|
+
|
|
213
|
+
## 風險與取捨
|
|
214
|
+
|
|
215
|
+
- Gemini Embedding 2 品質高,但會把 chunk 送出本機;敏感 repo 要允許 provider 關閉或換本地 embedding。
|
|
216
|
+
- 第三方中轉站相容性不一致,所以 provider 必須保留 header/query/bearer 三種 auth。
|
|
217
|
+
- 大型 repo 需要增量索引和 rate limit,不能每次全量 embedding。
|
|
218
|
+
- 純 vector search 對精確 symbol 不一定好,hybrid search 是必要項。
|