thincoder 0.12.62 → 0.12.64

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 (231) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +46 -49
  3. package/bin/thincoder.mjs +68 -34
  4. package/package.json +7 -6
  5. package/src/acp/bridge.mjs +35 -15
  6. package/src/acp/client-caps.mjs +86 -0
  7. package/src/acp/ext.mjs +86 -0
  8. package/src/acp/handlers-session.mjs +257 -0
  9. package/src/acp/handlers-slots.mjs +196 -0
  10. package/src/acp/login.mjs +48 -0
  11. package/src/acp/session.mjs +6 -4
  12. package/src/acp.mjs +67 -379
  13. package/src/cli/distill-command.mjs +3 -3
  14. package/src/cli/make-agent.mjs +60 -17
  15. package/src/cli/memory-command.mjs +3 -3
  16. package/src/cli/permission.mjs +4 -48
  17. package/src/cli/setup-wizard.mjs +1 -1
  18. package/src/completions.mjs +3 -1
  19. package/src/crash-reports.mjs +1 -1
  20. package/src/distill.mjs +4 -4
  21. package/src/heap-watch.mjs +1 -1
  22. package/src/prompt-injections.mjs +20 -0
  23. package/src/tui/agent-turn.mjs +40 -9
  24. package/src/tui/cmd-advisor.mjs +5 -5
  25. package/src/tui/cmd-config.mjs +8 -8
  26. package/src/tui/cmd-eng.mjs +35 -9
  27. package/src/tui/cmd-mcp.mjs +9 -8
  28. package/src/tui/cmd-model.mjs +1 -1
  29. package/src/tui/cmd-new.mjs +6 -5
  30. package/src/tui/cmd-plan.mjs +9 -0
  31. package/src/tui/cmd-reindex.mjs +1 -1
  32. package/src/tui/cmd-restore.mjs +2 -2
  33. package/src/tui/cmd-session.mjs +24 -1
  34. package/src/tui/cmd-skills.mjs +1 -1
  35. package/src/tui/cmd-think.mjs +22 -9
  36. package/src/tui/config-helpers.mjs +1 -1
  37. package/src/tui/display-budget.mjs +33 -11
  38. package/src/tui/index.mjs +18 -10
  39. package/src/tui/interaction.mjs +16 -7
  40. package/src/tui/key-modes.mjs +9 -4
  41. package/src/tui/ledger-surface.mjs +22 -59
  42. package/src/tui/model-catalog.mjs +4 -4
  43. package/src/tui/model-picker.mjs +8 -7
  44. package/src/tui/mouse.mjs +11 -6
  45. package/src/tui/pickers.mjs +15 -2
  46. package/src/tui/render-conversation.mjs +1 -1
  47. package/src/tui/render-frame.mjs +15 -6
  48. package/src/tui/render-loop.mjs +1 -1
  49. package/src/tui/render-segments.mjs +3 -1
  50. package/src/tui/slash-commands.mjs +1 -1
  51. package/src/tui/startup.mjs +14 -14
  52. package/src/tui/subagent-blocks.mjs +20 -3
  53. package/src/tui/subagent-freeze.mjs +73 -2
  54. package/src/tui/suspension-drive.mjs +57 -23
  55. package/src/tui/tool-events.mjs +11 -8
  56. package/src/tui/tui-lifecycle.mjs +9 -0
  57. package/src/tui/wizard.mjs +3 -3
  58. package/src/tui/wrapped-spawn.mjs +6 -2
  59. package/src/abort-provenance.mjs +0 -116
  60. package/src/advisor/citations.mjs +0 -139
  61. package/src/advisor/compaction.mjs +0 -174
  62. package/src/advisor/convergence.mjs +0 -80
  63. package/src/advisor/history.mjs +0 -77
  64. package/src/advisor/loop.mjs +0 -293
  65. package/src/advisor/messages.mjs +0 -299
  66. package/src/advisor/project-context.mjs +0 -194
  67. package/src/advisor/repos.mjs +0 -150
  68. package/src/advisor/run.mjs +0 -293
  69. package/src/advisor/truncate.mjs +0 -57
  70. package/src/advisor.mjs +0 -290
  71. package/src/agent/completion.mjs +0 -146
  72. package/src/agent/dispatch.mjs +0 -489
  73. package/src/agent/helpers.mjs +0 -384
  74. package/src/agent/post-turn.mjs +0 -70
  75. package/src/agent/record-results.mjs +0 -174
  76. package/src/agent/relay-prefix.mjs +0 -39
  77. package/src/agent/run-stages.mjs +0 -244
  78. package/src/agent/setup-reminders.mjs +0 -69
  79. package/src/agent/setup.mjs +0 -354
  80. package/src/agent/spawn-child.mjs +0 -243
  81. package/src/agent-tools/advisor-async.mjs +0 -346
  82. package/src/agent-tools/advisor-settle.mjs +0 -231
  83. package/src/agent-tools/advisor.mjs +0 -260
  84. package/src/agent-tools/async-settle.mjs +0 -204
  85. package/src/agent-tools/batch-segment.mjs +0 -195
  86. package/src/agent-tools/consult.mjs +0 -473
  87. package/src/agent-tools/design-token.mjs +0 -117
  88. package/src/agent-tools/digest-budget.mjs +0 -76
  89. package/src/agent-tools/eng.mjs +0 -67
  90. package/src/agent-tools/escalate-async.mjs +0 -295
  91. package/src/agent-tools/goal.mjs +0 -119
  92. package/src/agent-tools/plan.mjs +0 -81
  93. package/src/agent-tools/read-history.mjs +0 -309
  94. package/src/agent-tools/recent-changes.mjs +0 -24
  95. package/src/agent-tools/review-streak.mjs +0 -93
  96. package/src/agent-tools/settings.mjs +0 -265
  97. package/src/agent-tools/skill.mjs +0 -47
  98. package/src/agent-tools/subagent-actions.mjs +0 -482
  99. package/src/agent-tools/subagent-async.mjs +0 -434
  100. package/src/agent-tools/subagent-panel.mjs +0 -160
  101. package/src/agent-tools/subagent-run.mjs +0 -205
  102. package/src/agent-tools/subagent-scheduler.mjs +0 -392
  103. package/src/agent-tools/subagent-spawn.mjs +0 -459
  104. package/src/agent-tools/subagent.mjs +0 -404
  105. package/src/agent-tools/task.mjs +0 -87
  106. package/src/agent-tools/timer.mjs +0 -46
  107. package/src/agent-tools/verify.mjs +0 -271
  108. package/src/agent-tools.mjs +0 -17
  109. package/src/agent.mjs +0 -417
  110. package/src/auto-think.mjs +0 -115
  111. package/src/config-migrate.mjs +0 -70
  112. package/src/config.mjs +0 -496
  113. package/src/context.mjs +0 -392
  114. package/src/conventions.mjs +0 -223
  115. package/src/embedding.mjs +0 -120
  116. package/src/escape.mjs +0 -152
  117. package/src/expand-home.mjs +0 -16
  118. package/src/explore-distill.mjs +0 -155
  119. package/src/generate-title.mjs +0 -88
  120. package/src/git/checkpoint.mjs +0 -448
  121. package/src/git/gitmem.mjs +0 -100
  122. package/src/hooks.mjs +0 -97
  123. package/src/ledger.mjs +0 -227
  124. package/src/log.mjs +0 -195
  125. package/src/markdown.mjs +0 -106
  126. package/src/mcp/helpers.mjs +0 -51
  127. package/src/mcp/transport-http.mjs +0 -248
  128. package/src/mcp/transport-stdio.mjs +0 -140
  129. package/src/mcp/transport-ws.mjs +0 -122
  130. package/src/mcp.mjs +0 -295
  131. package/src/memory/code-index.mjs +0 -219
  132. package/src/memory/code-sync.mjs +0 -415
  133. package/src/memory/core.mjs +0 -299
  134. package/src/memory/delete.mjs +0 -236
  135. package/src/memory/docs.mjs +0 -419
  136. package/src/memory/file-walk.mjs +0 -109
  137. package/src/memory/scan.mjs +0 -95
  138. package/src/memory/schema.mjs +0 -452
  139. package/src/memory.mjs +0 -21
  140. package/src/model-ref.mjs +0 -66
  141. package/src/model-specs.mjs +0 -179
  142. package/src/peer-domains.mjs +0 -265
  143. package/src/peer-instances.mjs +0 -231
  144. package/src/prompt-overlays.mjs +0 -82
  145. package/src/prompts/advisor-design.md +0 -41
  146. package/src/prompts/advisor-round1.md +0 -41
  147. package/src/prompts/advisor-round2.md +0 -46
  148. package/src/prompts/advisor-round3.md +0 -42
  149. package/src/prompts/common.md +0 -115
  150. package/src/prompts/consult-base.md +0 -19
  151. package/src/prompts/discipline-engineering.md +0 -258
  152. package/src/prompts/discipline-normal.md +0 -185
  153. package/src/prompts/persona-coder.md +0 -21
  154. package/src/prompts/persona-eng-coder.md +0 -37
  155. package/src/prompts/persona-eng-designer.md +0 -60
  156. package/src/prompts/persona-engineering.md +0 -55
  157. package/src/prompts/persona-explore.md +0 -15
  158. package/src/prompts/persona-normal.md +0 -27
  159. package/src/prompts/persona-plan.md +0 -26
  160. package/src/provider/anthropic.mjs +0 -225
  161. package/src/provider/core.mjs +0 -476
  162. package/src/provider/errors.mjs +0 -101
  163. package/src/provider/google.mjs +0 -257
  164. package/src/provider/index.mjs +0 -7
  165. package/src/provider/list-models.mjs +0 -93
  166. package/src/provider/normalize.mjs +0 -81
  167. package/src/provider/rate.mjs +0 -108
  168. package/src/provider/responses.mjs +0 -495
  169. package/src/provider/retry.mjs +0 -88
  170. package/src/provider/sse.mjs +0 -264
  171. package/src/proxy.mjs +0 -261
  172. package/src/rules.mjs +0 -53
  173. package/src/session-gc.mjs +0 -221
  174. package/src/session-guard.mjs +0 -59
  175. package/src/session-migrate.mjs +0 -48
  176. package/src/session-rename.mjs +0 -38
  177. package/src/session-segments.mjs +0 -100
  178. package/src/session-slots.mjs +0 -492
  179. package/src/session-store.mjs +0 -441
  180. package/src/session.mjs +0 -492
  181. package/src/skills.mjs +0 -153
  182. package/src/text-budget.mjs +0 -46
  183. package/src/token-ttl.mjs +0 -274
  184. package/src/tools/apply_patch.md +0 -15
  185. package/src/tools/bash.md +0 -37
  186. package/src/tools/bash.mjs +0 -268
  187. package/src/tools/checklist-sync.mjs +0 -181
  188. package/src/tools/checklist.md +0 -13
  189. package/src/tools/checklist.mjs +0 -299
  190. package/src/tools/delete.md +0 -13
  191. package/src/tools/edit-batch.mjs +0 -191
  192. package/src/tools/edit-diff.mjs +0 -348
  193. package/src/tools/edit.md +0 -30
  194. package/src/tools/execute.md +0 -21
  195. package/src/tools/execute.mjs +0 -228
  196. package/src/tools/fetch.md +0 -12
  197. package/src/tools/file.mjs +0 -469
  198. package/src/tools/file_ops.md +0 -17
  199. package/src/tools/get_current_time.md +0 -8
  200. package/src/tools/git-checkpoint.mjs +0 -143
  201. package/src/tools/git-ext.mjs +0 -173
  202. package/src/tools/git.md +0 -54
  203. package/src/tools/git.mjs +0 -356
  204. package/src/tools/glob-dialect.mjs +0 -130
  205. package/src/tools/glob.md +0 -11
  206. package/src/tools/grep.md +0 -19
  207. package/src/tools/hashline_edit.md +0 -14
  208. package/src/tools/index.mjs +0 -36
  209. package/src/tools/insert_after.md +0 -15
  210. package/src/tools/lint.md +0 -10
  211. package/src/tools/linter.mjs +0 -128
  212. package/src/tools/ls.md +0 -12
  213. package/src/tools/lsp.md +0 -10
  214. package/src/tools/lsp.mjs +0 -316
  215. package/src/tools/ops.mjs +0 -299
  216. package/src/tools/patch.mjs +0 -282
  217. package/src/tools/process.md +0 -10
  218. package/src/tools/question.md +0 -16
  219. package/src/tools/question.mjs +0 -26
  220. package/src/tools/read.md +0 -20
  221. package/src/tools/read_image.md +0 -8
  222. package/src/tools/repomap.mjs +0 -314
  223. package/src/tools/search.mjs +0 -236
  224. package/src/tools/shared.mjs +0 -446
  225. package/src/tools/tree.md +0 -14
  226. package/src/tools/tree.mjs +0 -66
  227. package/src/tools/wait_for.md +0 -22
  228. package/src/tools/web.mjs +0 -224
  229. package/src/tools/websearch.md +0 -16
  230. package/src/tools/write.md +0 -11
  231. package/src/traces/trace-store.mjs +0 -355
@@ -1,452 +0,0 @@
1
- /**
2
- * memory/schema.mjs — database schema definition, migration, CJK segmentation
3
- * v1: node:sqlite + FTS5 standalone implementation, zero dependencies.
4
- *
5
- * Chinese search strategy: FTS5 unicode61 tokenizer + CJK character-by-character spacing (applied to both write and query sides).
6
- * Effect: Chinese indexed by character; two-character words like "分号" still match; ASCII stays whole-word.
7
- */
8
-
9
- import { DatabaseSync } from "node:sqlite"
10
- import { mkdirSync } from "node:fs"
11
- import { dirname } from "node:path"
12
-
13
- export const VALID_TYPES = new Set(["rule", "knowledge", "decision", "pattern"])
14
- export const SCHEMA_VERSION = 9
15
- export const SQLITE_BUSY_TIMEOUT = 3000
16
-
17
- // Code index: source file extensions. Curated DEFAULTS — a project can declare
18
- // more (union) through .thincoder/conventions.json → index.codeExtensions
19
- // (PORTABILITY PO-9: an unlisted extension used to be invisible AND undeclarable).
20
- export const CODE_EXTS = new Set([
21
- ".mjs", ".js", ".cjs", ".mts", ".cts", ".ts", ".tsx", ".jsx",
22
- ".py", ".rs", ".go", ".java", ".c", ".h", ".cpp", ".hpp",
23
- ".rb", ".swift", ".kt", ".dart", ".lua", ".cs", ".fs", ".fsx",
24
- ".clj", ".cljs", ".ex", ".exs", ".erl", ".hrl", ".scala", ".groovy",
25
- ".pl", ".pm", ".r", ".jl", ".zig", ".ps1",
26
- ".sh", ".bash", ".sql", ".yaml", ".yml", ".toml", ".json",
27
- ".proto", ".graphql", ".tf", ".hcl",
28
- ".css", ".html", ".vue", ".svelte",
29
- ])
30
- // Doc index: markdown / plain text (separate index makes it easier for LLM to distinguish "design specs" from "existing code")
31
- // Same declaration rule as CODE_EXTS (index.docExtensions).
32
- export const DOC_EXTS = new Set([".md", ".mdc", ".mdx", ".txt", ".rst", ".adoc", ".org", ".wiki", ".tex"])
33
- // Directory names always skipped during code/doc indexing
34
- // NOTE: these are case-sensitive basename matches; add common platform-specific dirs
35
- export const SKIP_DIRS = new Set([
36
- "node_modules", ".git", "dist", "build", ".turbo", "coverage",
37
- "__pycache__", ".venv", "venv", "target", ".next", ".nuxt", ".svelte-kit",
38
- // Windows user profile directories (never contain project code)
39
- "AppData", "Application Data", "Desktop", "Documents", "Downloads",
40
- "Music", "Pictures", "Videos", "OneDrive", "Contacts", "Favorites",
41
- "Links", "Saved Games", "Searches",
42
- // Other common non-code directories
43
- "Program Files", "Program Files (x86)", "Windows", "$Recycle.Bin",
44
- ])
45
- // Files larger than these limits are skipped during bulk indexing
46
- // (minified bundles, test fixtures, generated code, etc.)
47
- export const MAX_CODE_FILE_BYTES = 1024 * 1024 // 1 MB
48
- export const MAX_DOC_FILE_BYTES = 512 * 1024 // 512 KB
49
- export const BIG_FILE_LINES = 2000
50
-
51
- /**
52
- * CJK character-by-character spacing: makes unicode61 treat each Han/Kana/Hangul character as an independent token.
53
- * Both write and query must use the same processing for retrieval to match.
54
- */
55
- export function segmentCJK(text) {
56
- return text.replace(
57
- /[぀-ヿ㐀-䶿一-鿿豈-﫿가-힯]+/g,
58
- (run) => [...run].join(" "),
59
- )
60
- }
61
-
62
- /**
63
- * Open/initialize the memory store. dbPath is auto-created if missing.
64
- * The returned memory object is the interface; all subsequent functions take it as their first argument.
65
- */
66
- export function createMemory({ dbPath }) {
67
- mkdirSync(dirname(dbPath), { recursive: true })
68
- const db = new DatabaseSync(dbPath)
69
- // WAL: reads and writes don't block each other (TUI search and background indexing can run concurrently); busy_timeout prevents SQLITE_BUSY from multi-process same-db access
70
- db.exec(`PRAGMA journal_mode = WAL`)
71
- db.exec(`PRAGMA busy_timeout = ${SQLITE_BUSY_TIMEOUT}`)
72
-
73
- db.exec(`
74
- CREATE TABLE IF NOT EXISTS entries (
75
- id INTEGER PRIMARY KEY AUTOINCREMENT,
76
- type TEXT NOT NULL CHECK(type IN ('rule','knowledge','decision','pattern')),
77
- title TEXT NOT NULL,
78
- content TEXT NOT NULL,
79
- tags TEXT NOT NULL DEFAULT '',
80
- seg_title TEXT NOT NULL DEFAULT '',
81
- seg_content TEXT NOT NULL DEFAULT '',
82
- seg_tags TEXT NOT NULL DEFAULT '',
83
- created_at INTEGER NOT NULL,
84
- updated_at INTEGER NOT NULL
85
- )
86
- `)
87
-
88
- migrate(db)
89
- return { db }
90
- }
91
-
92
- /** Step-by-step migration by user_version. Single transaction — any step failure rolls back, no half-finished schema left behind. */
93
- export function migrate(db) {
94
- const { user_version: version } = db.prepare(`PRAGMA user_version`).get()
95
- if (version >= SCHEMA_VERSION) return
96
-
97
- db.exec("BEGIN IMMEDIATE")
98
- try {
99
- if (version < 2) {
100
- // v1 (trigram) or empty DB → v2 (unicode61 + CJK char-by-char): rebuild FTS and triggers
101
- db.exec(`
102
- DROP TRIGGER IF EXISTS entries_ai;
103
- DROP TRIGGER IF EXISTS entries_ad;
104
- DROP TRIGGER IF EXISTS entries_au;
105
- DROP TABLE IF EXISTS entries_fts;
106
- `)
107
- // Old DB (v1) has no seg columns — add them
108
- const columns = db.prepare(`PRAGMA table_info(entries)`).all().map((c) => c.name)
109
- for (const col of ["seg_title", "seg_content", "seg_tags"]) {
110
- if (!columns.includes(col)) {
111
- db.exec(`ALTER TABLE entries ADD COLUMN ${col} TEXT NOT NULL DEFAULT ''`)
112
- }
113
- }
114
- // Backfill seg columns (segmentation done in JS; SQL can't do it)
115
- const rows = db.prepare(`SELECT id, title, content, tags FROM entries`).all()
116
- const update = db.prepare(`UPDATE entries SET seg_title = ?, seg_content = ?, seg_tags = ? WHERE id = ?`)
117
- for (const r of rows) {
118
- update.run(segmentCJK(r.title), segmentCJK(r.content), segmentCJK(r.tags), r.id)
119
- }
120
-
121
- db.exec(`
122
- CREATE VIRTUAL TABLE entries_fts USING fts5(
123
- seg_title, seg_content, seg_tags,
124
- content='entries', content_rowid='id',
125
- tokenize='unicode61'
126
- )
127
- `)
128
- db.exec(`
129
- CREATE TRIGGER entries_ai AFTER INSERT ON entries BEGIN
130
- INSERT INTO entries_fts(rowid, seg_title, seg_content, seg_tags)
131
- VALUES (new.id, new.seg_title, new.seg_content, new.seg_tags);
132
- END;
133
- CREATE TRIGGER entries_ad AFTER DELETE ON entries BEGIN
134
- INSERT INTO entries_fts(entries_fts, rowid, seg_title, seg_content, seg_tags)
135
- VALUES ('delete', old.id, old.seg_title, old.seg_content, old.seg_tags);
136
- END;
137
- CREATE TRIGGER entries_au AFTER UPDATE ON entries BEGIN
138
- INSERT INTO entries_fts(entries_fts, rowid, seg_title, seg_content, seg_tags)
139
- VALUES ('delete', old.id, old.seg_title, old.seg_content, old.seg_tags);
140
- INSERT INTO entries_fts(rowid, seg_title, seg_content, seg_tags)
141
- VALUES (new.id, new.seg_title, new.seg_content, new.seg_tags);
142
- END;
143
- `)
144
- db.exec(`INSERT INTO entries_fts(entries_fts) VALUES('rebuild')`)
145
- db.exec(`PRAGMA user_version = 2`)
146
- }
147
-
148
- if (version < 3) {
149
- // v3: markdown layer (project/team) files table + FTS + triggers
150
- db.exec(`
151
- CREATE TABLE IF NOT EXISTS files (
152
- layer TEXT NOT NULL CHECK(layer IN ('project','team')),
153
- path TEXT NOT NULL,
154
- type TEXT NOT NULL CHECK(type IN ('rule','knowledge','decision','pattern')),
155
- title TEXT NOT NULL,
156
- content TEXT NOT NULL,
157
- tags TEXT NOT NULL DEFAULT '',
158
- author TEXT NOT NULL DEFAULT '',
159
- embedding BLOB,
160
- mtime_ms INTEGER NOT NULL DEFAULT 0,
161
- seg_title TEXT NOT NULL DEFAULT '',
162
- seg_content TEXT NOT NULL DEFAULT '',
163
- seg_tags TEXT NOT NULL DEFAULT '',
164
- updated_at INTEGER NOT NULL,
165
- PRIMARY KEY (layer, path)
166
- )
167
- `)
168
- db.exec(`
169
- CREATE VIRTUAL TABLE IF NOT EXISTS files_fts USING fts5(
170
- seg_title, seg_content, seg_tags,
171
- content='files', content_rowid='rowid',
172
- tokenize='unicode61'
173
- )
174
- `)
175
- db.exec(`
176
- CREATE TRIGGER files_ai AFTER INSERT ON files BEGIN
177
- INSERT INTO files_fts(rowid, seg_title, seg_content, seg_tags)
178
- VALUES (new.rowid, new.seg_title, new.seg_content, new.seg_tags);
179
- END;
180
- CREATE TRIGGER files_ad AFTER DELETE ON files BEGIN
181
- INSERT INTO files_fts(files_fts, rowid, seg_title, seg_content, seg_tags)
182
- VALUES ('delete', old.rowid, old.seg_title, old.seg_content, old.seg_tags);
183
- END;
184
- CREATE TRIGGER files_au AFTER UPDATE ON files BEGIN
185
- INSERT INTO files_fts(files_fts, rowid, seg_title, seg_content, seg_tags)
186
- VALUES ('delete', old.rowid, old.seg_title, old.seg_content, old.seg_tags);
187
- INSERT INTO files_fts(rowid, seg_title, seg_content, seg_tags)
188
- VALUES (new.rowid, new.seg_title, new.seg_content, new.seg_tags);
189
- END;
190
- `)
191
- db.exec(`PRAGMA user_version = 3`)
192
- }
193
-
194
- if (version < 4) {
195
- // v4: add vector column to personal entries table (files table already had it since v3); meta table stores embedding model name
196
- const columns = db.prepare(`PRAGMA table_info(entries)`).all().map((c) => c.name)
197
- if (!columns.includes("embedding")) {
198
- db.exec(`ALTER TABLE entries ADD COLUMN embedding BLOB`)
199
- }
200
- db.exec(`CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT)`)
201
- db.exec(`PRAGMA user_version = 4`)
202
- }
203
-
204
- if (version < 5) {
205
- // v5: add origin column to files table (absolute project path), prevent cross-project memory collision
206
- const columns = db.prepare(`PRAGMA table_info(files)`).all().map((c) => c.name)
207
- if (!columns.includes("origin")) {
208
- db.exec(`ALTER TABLE files ADD COLUMN origin TEXT NOT NULL DEFAULT ''`)
209
- }
210
- db.exec(`PRAGMA user_version = 5`)
211
- }
212
-
213
- if (version < 6) {
214
- // v6: code index — code_chunks table + FTS5 (same pattern as files table)
215
- db.exec(`
216
- CREATE TABLE IF NOT EXISTS code_chunks (
217
- path TEXT NOT NULL,
218
- language TEXT NOT NULL,
219
- chunk_type TEXT NOT NULL CHECK(chunk_type IN ('file','symbol')),
220
- symbol_name TEXT NOT NULL DEFAULT '',
221
- content TEXT NOT NULL,
222
- line_start INTEGER NOT NULL DEFAULT 0,
223
- line_end INTEGER NOT NULL DEFAULT 0,
224
- mtime_ms INTEGER NOT NULL DEFAULT 0,
225
- embedding BLOB,
226
- seg_content TEXT NOT NULL DEFAULT '',
227
- PRIMARY KEY (path, line_start)
228
- )
229
- `)
230
- db.exec(`
231
- CREATE VIRTUAL TABLE IF NOT EXISTS code_chunks_fts USING fts5(
232
- path, symbol_name, seg_content,
233
- content='code_chunks', content_rowid='rowid',
234
- tokenize='unicode61'
235
- )
236
- `)
237
- db.exec(`
238
- CREATE TRIGGER code_chunks_ai AFTER INSERT ON code_chunks BEGIN
239
- INSERT INTO code_chunks_fts(rowid, path, symbol_name, seg_content)
240
- VALUES (new.rowid, new.path, new.symbol_name, new.seg_content);
241
- END;
242
- CREATE TRIGGER code_chunks_ad AFTER DELETE ON code_chunks BEGIN
243
- INSERT INTO code_chunks_fts(code_chunks_fts, rowid, path, symbol_name, seg_content)
244
- VALUES ('delete', old.rowid, old.path, old.symbol_name, old.seg_content);
245
- END;
246
- CREATE TRIGGER code_chunks_au AFTER UPDATE ON code_chunks BEGIN
247
- INSERT INTO code_chunks_fts(code_chunks_fts, rowid, path, symbol_name, seg_content)
248
- VALUES ('delete', old.rowid, old.path, old.symbol_name, old.seg_content);
249
- INSERT INTO code_chunks_fts(rowid, path, symbol_name, seg_content)
250
- VALUES (new.rowid, new.path, new.symbol_name, new.seg_content);
251
- END;
252
- `)
253
- db.exec(`PRAGMA user_version = 6`)
254
- }
255
-
256
- if (version < 7) {
257
- // v7: doc index — doc_chunks table + FTS5 (same pattern as code_chunks), markdown chunked by ## headings
258
- db.exec(`
259
- CREATE TABLE IF NOT EXISTS doc_chunks (
260
- path TEXT NOT NULL,
261
- language TEXT NOT NULL DEFAULT 'markdown',
262
- heading TEXT NOT NULL DEFAULT '',
263
- content TEXT NOT NULL,
264
- line_start INTEGER NOT NULL DEFAULT 0,
265
- line_end INTEGER NOT NULL DEFAULT 0,
266
- mtime_ms INTEGER NOT NULL DEFAULT 0,
267
- embedding BLOB,
268
- seg_content TEXT NOT NULL DEFAULT '',
269
- PRIMARY KEY (path, line_start)
270
- )
271
- `)
272
- db.exec(`
273
- CREATE VIRTUAL TABLE IF NOT EXISTS doc_chunks_fts USING fts5(
274
- path, heading, seg_content,
275
- content='doc_chunks', content_rowid='rowid',
276
- tokenize='unicode61'
277
- )
278
- `)
279
- db.exec(`
280
- CREATE TRIGGER doc_chunks_ai AFTER INSERT ON doc_chunks BEGIN
281
- INSERT INTO doc_chunks_fts(rowid, path, heading, seg_content)
282
- VALUES (new.rowid, new.path, new.heading, new.seg_content);
283
- END;
284
- CREATE TRIGGER doc_chunks_ad AFTER DELETE ON doc_chunks BEGIN
285
- INSERT INTO doc_chunks_fts(doc_chunks_fts, rowid, path, heading, seg_content)
286
- VALUES ('delete', old.rowid, old.path, old.heading, old.seg_content);
287
- END;
288
- CREATE TRIGGER doc_chunks_au AFTER UPDATE ON doc_chunks BEGIN
289
- INSERT INTO doc_chunks_fts(doc_chunks_fts, rowid, path, heading, seg_content)
290
- VALUES ('delete', old.rowid, old.path, old.heading, old.seg_content);
291
- INSERT INTO doc_chunks_fts(rowid, path, heading, seg_content)
292
- VALUES (new.rowid, new.path, new.heading, new.seg_content);
293
- END;
294
- `)
295
- db.exec(`PRAGMA user_version = 7`)
296
- }
297
-
298
- if (version < 8) {
299
- // v8: add origin column to code_chunks/doc_chunks (absolute project root), PK changed to (origin, path, line_start).
300
- // SQLite can't ALTER primary key → drop and recreate table (auto-reindexed by next codeSync/docSync).
301
- db.exec(`
302
- DROP TRIGGER IF EXISTS code_chunks_ai;
303
- DROP TRIGGER IF EXISTS code_chunks_ad;
304
- DROP TRIGGER IF EXISTS code_chunks_au;
305
- DROP TABLE IF EXISTS code_chunks_fts;
306
- DROP TABLE IF EXISTS code_chunks;
307
- DROP TRIGGER IF EXISTS doc_chunks_ai;
308
- DROP TRIGGER IF EXISTS doc_chunks_ad;
309
- DROP TRIGGER IF EXISTS doc_chunks_au;
310
- DROP TABLE IF EXISTS doc_chunks_fts;
311
- DROP TABLE IF EXISTS doc_chunks;
312
- `)
313
- db.exec(`
314
- CREATE TABLE code_chunks (
315
- origin TEXT NOT NULL DEFAULT '',
316
- path TEXT NOT NULL,
317
- language TEXT NOT NULL,
318
- chunk_type TEXT NOT NULL CHECK(chunk_type IN ('file','symbol')),
319
- symbol_name TEXT NOT NULL DEFAULT '',
320
- content TEXT NOT NULL,
321
- line_start INTEGER NOT NULL DEFAULT 0,
322
- line_end INTEGER NOT NULL DEFAULT 0,
323
- mtime_ms INTEGER NOT NULL DEFAULT 0,
324
- embedding BLOB,
325
- seg_content TEXT NOT NULL DEFAULT '',
326
- PRIMARY KEY (origin, path, line_start)
327
- )
328
- `)
329
- db.exec(`
330
- CREATE VIRTUAL TABLE code_chunks_fts USING fts5(
331
- path, symbol_name, seg_content,
332
- content='code_chunks', content_rowid='rowid',
333
- tokenize='unicode61'
334
- )
335
- `)
336
- db.exec(`
337
- CREATE TRIGGER code_chunks_ai AFTER INSERT ON code_chunks BEGIN
338
- INSERT INTO code_chunks_fts(rowid, path, symbol_name, seg_content)
339
- VALUES (new.rowid, new.path, new.symbol_name, new.seg_content);
340
- END;
341
- CREATE TRIGGER code_chunks_ad AFTER DELETE ON code_chunks BEGIN
342
- INSERT INTO code_chunks_fts(code_chunks_fts, rowid, path, symbol_name, seg_content)
343
- VALUES ('delete', old.rowid, old.path, old.symbol_name, old.seg_content);
344
- END;
345
- CREATE TRIGGER code_chunks_au AFTER UPDATE ON code_chunks BEGIN
346
- INSERT INTO code_chunks_fts(code_chunks_fts, rowid, path, symbol_name, seg_content)
347
- VALUES ('delete', old.rowid, old.path, old.symbol_name, old.seg_content);
348
- INSERT INTO code_chunks_fts(rowid, path, symbol_name, seg_content)
349
- VALUES (new.rowid, new.path, new.symbol_name, new.seg_content);
350
- END;
351
- `)
352
- db.exec(`
353
- CREATE TABLE doc_chunks (
354
- origin TEXT NOT NULL DEFAULT '',
355
- path TEXT NOT NULL,
356
- language TEXT NOT NULL DEFAULT 'markdown',
357
- heading TEXT NOT NULL DEFAULT '',
358
- content TEXT NOT NULL,
359
- line_start INTEGER NOT NULL DEFAULT 0,
360
- line_end INTEGER NOT NULL DEFAULT 0,
361
- mtime_ms INTEGER NOT NULL DEFAULT 0,
362
- embedding BLOB,
363
- seg_content TEXT NOT NULL DEFAULT '',
364
- PRIMARY KEY (origin, path, line_start)
365
- )
366
- `)
367
- db.exec(`
368
- CREATE VIRTUAL TABLE doc_chunks_fts USING fts5(
369
- path, heading, seg_content,
370
- content='doc_chunks', content_rowid='rowid',
371
- tokenize='unicode61'
372
- )
373
- `)
374
- db.exec(`
375
- CREATE TRIGGER doc_chunks_ai AFTER INSERT ON doc_chunks BEGIN
376
- INSERT INTO doc_chunks_fts(rowid, path, heading, seg_content)
377
- VALUES (new.rowid, new.path, new.heading, new.seg_content);
378
- END;
379
- CREATE TRIGGER doc_chunks_ad AFTER DELETE ON doc_chunks BEGIN
380
- INSERT INTO doc_chunks_fts(doc_chunks_fts, rowid, path, heading, seg_content)
381
- VALUES ('delete', old.rowid, old.path, old.heading, old.seg_content);
382
- END;
383
- CREATE TRIGGER doc_chunks_au AFTER UPDATE ON doc_chunks BEGIN
384
- INSERT INTO doc_chunks_fts(doc_chunks_fts, rowid, path, heading, seg_content)
385
- VALUES ('delete', old.rowid, old.path, old.heading, old.seg_content);
386
- INSERT INTO doc_chunks_fts(rowid, path, heading, seg_content)
387
- VALUES (new.rowid, new.path, new.heading, new.seg_content);
388
- END;
389
- `)
390
- db.exec(`PRAGMA user_version = 8`)
391
- }
392
-
393
- if (version < 9) {
394
- // v9: files table PK gains origin, prevents cross-project project-layer memory overwrite
395
- // SQLite can't ALTER primary key → drop and recreate table (auto-reindexed by next syncDir)
396
- db.exec(`
397
- DROP TRIGGER IF EXISTS files_ai;
398
- DROP TRIGGER IF EXISTS files_ad;
399
- DROP TRIGGER IF EXISTS files_au;
400
- DROP TABLE IF EXISTS files_fts;
401
- DROP TABLE IF EXISTS files;
402
- `)
403
- db.exec(`
404
- CREATE TABLE files (
405
- layer TEXT NOT NULL CHECK(layer IN ('project','team')),
406
- origin TEXT NOT NULL DEFAULT '',
407
- path TEXT NOT NULL,
408
- type TEXT NOT NULL CHECK(type IN ('rule','knowledge','decision','pattern')),
409
- title TEXT NOT NULL,
410
- content TEXT NOT NULL,
411
- tags TEXT NOT NULL DEFAULT '',
412
- author TEXT NOT NULL DEFAULT '',
413
- embedding BLOB,
414
- mtime_ms INTEGER NOT NULL DEFAULT 0,
415
- seg_title TEXT NOT NULL DEFAULT '',
416
- seg_content TEXT NOT NULL DEFAULT '',
417
- seg_tags TEXT NOT NULL DEFAULT '',
418
- updated_at INTEGER NOT NULL,
419
- PRIMARY KEY (layer, origin, path)
420
- )
421
- `)
422
- db.exec(`
423
- CREATE VIRTUAL TABLE files_fts USING fts5(
424
- seg_title, seg_content, seg_tags,
425
- content='files', content_rowid='rowid',
426
- tokenize='unicode61'
427
- )
428
- `)
429
- db.exec(`
430
- CREATE TRIGGER files_ai AFTER INSERT ON files BEGIN
431
- INSERT INTO files_fts(rowid, seg_title, seg_content, seg_tags)
432
- VALUES (new.rowid, new.seg_title, new.seg_content, new.seg_tags);
433
- END;
434
- CREATE TRIGGER files_ad AFTER DELETE ON files BEGIN
435
- INSERT INTO files_fts(files_fts, rowid, seg_title, seg_content, seg_tags)
436
- VALUES ('delete', old.rowid, old.seg_title, old.seg_content, old.seg_tags);
437
- END;
438
- CREATE TRIGGER files_au AFTER UPDATE ON files BEGIN
439
- INSERT INTO files_fts(files_fts, rowid, seg_title, seg_content, seg_tags)
440
- VALUES ('delete', old.rowid, old.seg_title, old.seg_content, old.seg_tags);
441
- INSERT INTO files_fts(rowid, seg_title, seg_content, seg_tags)
442
- VALUES (new.rowid, new.seg_title, new.seg_content, new.seg_tags);
443
- END;
444
- `)
445
- db.exec(`PRAGMA user_version = 9`)
446
- }
447
- db.exec("COMMIT")
448
- } catch (err) {
449
- db.exec("ROLLBACK")
450
- throw err
451
- }
452
- }
package/src/memory.mjs DELETED
@@ -1,21 +0,0 @@
1
- /**
2
- * memory.mjs — memory system re-export hub
3
- * Submodules in src/memory/ directory, split by responsibility.
4
- */
5
-
6
- // schema + constants
7
- export { createMemory, migrate, segmentCJK, VALID_TYPES, SCHEMA_VERSION, CODE_EXTS, DOC_EXTS, SKIP_DIRS, BIG_FILE_LINES } from "./memory/schema.mjs"
8
-
9
- // CRUD + search + ensureEmbeddings
10
- // (delete.mjs owns the disk-truth row match + deletion family — see its header)
11
- export { put, search, ftsSearch, fetchEntry, ensureEmbeddings, putMarkdown, syncDir, indexMarkdownFile, list, clearPersonal, buildFtsQuery } from "./memory/core.mjs"
12
- export { matchMemoryRows, deleteWhere, deleteByUid, remove } from "./memory/delete.mjs"
13
-
14
- // code chunking + markdown chunking
15
- export { detectLanguage, extractSymbols, extractPySymbols, chunkCode, extractLeadingDoc, yieldTick, _upsertCodeFile, chunkMarkdown, _upsertDocFile } from "./memory/code-index.mjs"
16
-
17
- // code sync + search + reindex
18
- export { gitSync, codeSync, markIndexedCommit, codeSearch, ensureCodeEmbeddings, codeSearchTool, reindexFile } from "./memory/code-sync.mjs"
19
-
20
- // doc sync + search + memoryTools
21
- export { docSync, docSearch, ensureDocEmbeddings, docSearchTool, memoryTools } from "./memory/docs.mjs"
package/src/model-ref.mjs DELETED
@@ -1,66 +0,0 @@
1
- /**
2
- * model-ref.mjs — composite model reference parser (MODEL-MERGE-SESSION; v2 2026-09-10).
3
- * A model is an explicit "provider:model" composite — config.defaultModel (top level,
4
- * new-session starting point) and session slots both speak this language. 有效域 = **provider 存在
5
- * + 双段非空**:清单不再人工维护(模型清单由 provider 运行期 `GET /models` 拉取决定——
6
- * PROVIDER.md §16),候选成员校验**已废除**——显式 `p:m` 一律放行(含多冒号首分割)。
7
- * providers[].model 是渠道默认模型(单值)——候选清单字段 models[] 已整字段退场。
8
- *
9
- * Strict first-colon split — deliberately does NOT reuse resolveChildProvider's loose
10
- * three-state resolution: ① legacy single-provider configs and ② model-name-only refs
11
- * are gone with activeProvider/activeModel (F-1), so a bare provider or bare model is
12
- * invalid everywhere (裁定③——裸 provider 拒——显式 p:m)。
13
- *
14
- * Runtime model resolution:
15
- * parseModelRef(ref, providers) → { ok, provider, model } | { ok:false, reason }
16
- * resolveRuntimeProvider(providers, defaultModel)
17
- * → provider object with `.model` set, or {} when
18
- * defaultModel is null/invalid (D-S1: callers mark
19
- * _providerInvalid — never throws)
20
- * defaultModelReason(providers, defaultModel) → human reason for the D-S1 marker
21
- *
22
- * Consumers: config.mjs loadConfig (re-exported as the config hub), make-agent.mjs.
23
- */
24
- export function parseModelRef(ref, providers) {
25
- if (typeof ref !== "string" || !ref.trim()) {
26
- return { ok: false, reason: 'model reference expected as "provider:model" (e.g. deepseek:deepseek-v4-pro)' }
27
- }
28
- // 首冒号分割——`a:b:c` → provider=a、model=`b:c`(`ollama:llama3:70b` 式模型名可用,M4)
29
- const sep = ref.indexOf(":")
30
- if (sep <= 0) {
31
- return { ok: false, reason: `invalid model reference "${ref}" — expected provider:model (bare provider/model names are not accepted)` }
32
- }
33
- const providerName = ref.slice(0, sep)
34
- const model = ref.slice(sep + 1)
35
- if (!model) {
36
- return { ok: false, reason: `invalid model reference "${ref}" — model part is empty (expected provider:model)` }
37
- }
38
- const list = Array.isArray(providers) ? providers : []
39
- const provider = list.find((p) => p?.name === providerName)
40
- if (!provider) {
41
- const available = list.map((p) => p.name).join(", ") || "(none)"
42
- return { ok: false, reason: `unknown provider "${providerName}" in model reference (available: ${available})` }
43
- }
44
- return { ok: true, provider, model }
45
- }
46
-
47
- /** Resolve the runtime provider object for config.defaultModel: provider clone carrying
48
- * `.model` = the parsed concrete model (API/spec consumers read provider.model unchanged).
49
- * Invalid/missing defaultModel → {} (D-S1 shape — name/model/baseURL absent so
50
- * validateProvider flags it; TUI/headless surface the reason from defaultModelReason). */
51
- export function resolveRuntimeProvider(providers, defaultModel) {
52
- const r = parseModelRef(defaultModel, providers)
53
- if (!r.ok) return {}
54
- return { ...r.provider, model: r.model }
55
- }
56
-
57
- /** Human-readable reason behind an invalid/empty runtime resolution (D-S1 原因). */
58
- export function defaultModelReason(providers, defaultModel) {
59
- const list = Array.isArray(providers) ? providers : []
60
- if (!defaultModel) {
61
- return list.length > 0
62
- ? "defaultModel 未设置(config 顶层 defaultModel — 新会话起点;/config → 默认模型 设置)"
63
- : "未配置任何 provider"
64
- }
65
- return parseModelRef(defaultModel, list).reason ?? `defaultModel "${defaultModel}" 无效`
66
- }