yandecode 0.1.1 → 0.2.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.
Files changed (226) hide show
  1. package/dist/bin.js +14 -8
  2. package/dist/bin.js.map +7 -1
  3. package/dist/chunks/chunk-23DG7PZZ.js +58 -0
  4. package/dist/chunks/chunk-23DG7PZZ.js.map +7 -0
  5. package/dist/chunks/chunk-2S6B3DDQ.js +1769 -0
  6. package/dist/chunks/chunk-2S6B3DDQ.js.map +7 -0
  7. package/dist/chunks/chunk-6J5CZVCJ.js +120 -0
  8. package/dist/chunks/chunk-6J5CZVCJ.js.map +7 -0
  9. package/dist/chunks/chunk-7L6DD2VD.js +768 -0
  10. package/dist/chunks/chunk-7L6DD2VD.js.map +7 -0
  11. package/dist/chunks/chunk-DWD37AI2.js +39 -0
  12. package/dist/chunks/chunk-DWD37AI2.js.map +7 -0
  13. package/dist/chunks/chunk-KPDBXQ62.js +62 -0
  14. package/dist/chunks/chunk-KPDBXQ62.js.map +7 -0
  15. package/dist/chunks/chunk-KVBKQXTU.js +351 -0
  16. package/dist/chunks/chunk-KVBKQXTU.js.map +7 -0
  17. package/dist/chunks/chunk-L2DDIZPI.js +53 -0
  18. package/dist/chunks/chunk-L2DDIZPI.js.map +7 -0
  19. package/dist/chunks/chunk-OIAMKDTQ.js +27 -0
  20. package/dist/chunks/chunk-OIAMKDTQ.js.map +7 -0
  21. package/dist/chunks/chunk-PUWSEWX3.js +61 -0
  22. package/dist/chunks/chunk-PUWSEWX3.js.map +7 -0
  23. package/dist/chunks/chunk-QCQC73WX.js +122 -0
  24. package/dist/chunks/chunk-QCQC73WX.js.map +7 -0
  25. package/dist/chunks/chunk-TYLH4NIC.js +39 -0
  26. package/dist/chunks/chunk-TYLH4NIC.js.map +7 -0
  27. package/dist/chunks/chunk-VKVJGBNJ.js +72 -0
  28. package/dist/chunks/chunk-VKVJGBNJ.js.map +7 -0
  29. package/dist/chunks/chunk-Y2MIXROU.js +20072 -0
  30. package/dist/chunks/chunk-Y2MIXROU.js.map +7 -0
  31. package/dist/chunks/cli-V6PJTDLM.js +3464 -0
  32. package/dist/chunks/cli-V6PJTDLM.js.map +7 -0
  33. package/dist/chunks/doctor-LLDVEPWL.js +184 -0
  34. package/dist/chunks/doctor-LLDVEPWL.js.map +7 -0
  35. package/dist/chunks/entry-YAOEX3EB.js +187 -0
  36. package/dist/chunks/entry-YAOEX3EB.js.map +7 -0
  37. package/dist/chunks/init-4ZJFCKIJ.js +46 -0
  38. package/dist/chunks/init-4ZJFCKIJ.js.map +7 -0
  39. package/dist/chunks/mcp-serve-KWKMUGWZ.js +22575 -0
  40. package/dist/chunks/mcp-serve-KWKMUGWZ.js.map +7 -0
  41. package/dist/chunks/modules-CJB5IKUJ.js +121 -0
  42. package/dist/chunks/modules-CJB5IKUJ.js.map +7 -0
  43. package/dist/chunks/runtime-3E4NIFAL.js +208 -0
  44. package/dist/chunks/runtime-3E4NIFAL.js.map +7 -0
  45. package/dist/chunks/runtime-7CRR63B5.js +395 -0
  46. package/dist/chunks/runtime-7CRR63B5.js.map +7 -0
  47. package/dist/chunks/runtime-CKMVHAU4.js +64 -0
  48. package/dist/chunks/runtime-CKMVHAU4.js.map +7 -0
  49. package/dist/chunks/runtime-CVZMWIJO.js +318 -0
  50. package/dist/chunks/runtime-CVZMWIJO.js.map +7 -0
  51. package/dist/chunks/runtime-DBNXBOAL.js +295 -0
  52. package/dist/chunks/runtime-DBNXBOAL.js.map +7 -0
  53. package/dist/chunks/runtime-EKHO2JXB.js +197 -0
  54. package/dist/chunks/runtime-EKHO2JXB.js.map +7 -0
  55. package/dist/chunks/runtime-EY6SVZYP.js +539 -0
  56. package/dist/chunks/runtime-EY6SVZYP.js.map +7 -0
  57. package/dist/chunks/runtime-UB2O2HUN.js +212 -0
  58. package/dist/chunks/runtime-UB2O2HUN.js.map +7 -0
  59. package/dist/chunks/runtime-WAFQWW4M.js +755 -0
  60. package/dist/chunks/runtime-WAFQWW4M.js.map +7 -0
  61. package/dist/chunks/runtime-ZGGF6RVA.js +271 -0
  62. package/dist/chunks/runtime-ZGGF6RVA.js.map +7 -0
  63. package/dist/chunks/status-SPIESL4F.js +38 -0
  64. package/dist/chunks/status-SPIESL4F.js.map +7 -0
  65. package/dist/chunks/uninstall-J2OWCX4A.js +54 -0
  66. package/dist/chunks/uninstall-J2OWCX4A.js.map +7 -0
  67. package/dist/chunks/update-OX5MZYQY.js +34 -0
  68. package/dist/chunks/update-OX5MZYQY.js.map +7 -0
  69. package/dist/content/agents/yandecode-reviewer.md +22 -0
  70. package/dist/content/agents/yandecode-security-reviewer.md +23 -0
  71. package/dist/content/skills/NOTICE.md +29 -0
  72. package/dist/content/skills/yandecode-code-review/SKILL.md +37 -0
  73. package/dist/content/skills/yandecode-debugging/SKILL.md +33 -0
  74. package/dist/content/skills/yandecode-instructions/SKILL.md +26 -0
  75. package/dist/content/skills/yandecode-memory/SKILL.md +36 -0
  76. package/dist/content/skills/yandecode-security-review/SKILL.md +24 -0
  77. package/dist/content/skills/yandecode-tdd/SKILL.md +38 -0
  78. package/dist/content/skills/yandecode-verification/SKILL.md +29 -0
  79. package/dist/content/skills/yandecode-workflow/SKILL.md +50 -0
  80. package/package.json +25 -19
  81. package/dist/bin.d.ts +0 -3
  82. package/dist/bin.d.ts.map +0 -1
  83. package/dist/claude-bin.d.ts +0 -2
  84. package/dist/claude-bin.d.ts.map +0 -1
  85. package/dist/claude-bin.js +0 -4
  86. package/dist/claude-bin.js.map +0 -1
  87. package/dist/cli.d.ts +0 -6
  88. package/dist/cli.d.ts.map +0 -1
  89. package/dist/cli.js +0 -21
  90. package/dist/cli.js.map +0 -1
  91. package/dist/commands/doctor.d.ts +0 -2
  92. package/dist/commands/doctor.d.ts.map +0 -1
  93. package/dist/commands/doctor.js +0 -19
  94. package/dist/commands/doctor.js.map +0 -1
  95. package/dist/commands/hook.d.ts +0 -2
  96. package/dist/commands/hook.d.ts.map +0 -1
  97. package/dist/commands/hook.js +0 -23
  98. package/dist/commands/hook.js.map +0 -1
  99. package/dist/commands/index-cmd.d.ts +0 -2
  100. package/dist/commands/index-cmd.d.ts.map +0 -1
  101. package/dist/commands/index-cmd.js +0 -47
  102. package/dist/commands/index-cmd.js.map +0 -1
  103. package/dist/commands/index.d.ts +0 -13
  104. package/dist/commands/index.d.ts.map +0 -1
  105. package/dist/commands/index.js +0 -15
  106. package/dist/commands/index.js.map +0 -1
  107. package/dist/commands/init.d.ts +0 -2
  108. package/dist/commands/init.d.ts.map +0 -1
  109. package/dist/commands/init.js +0 -22
  110. package/dist/commands/init.js.map +0 -1
  111. package/dist/commands/mcp.d.ts +0 -2
  112. package/dist/commands/mcp.d.ts.map +0 -1
  113. package/dist/commands/mcp.js +0 -71
  114. package/dist/commands/mcp.js.map +0 -1
  115. package/dist/commands/rag.d.ts +0 -2
  116. package/dist/commands/rag.d.ts.map +0 -1
  117. package/dist/commands/rag.js +0 -27
  118. package/dist/commands/rag.js.map +0 -1
  119. package/dist/commands/start.d.ts +0 -5
  120. package/dist/commands/start.d.ts.map +0 -1
  121. package/dist/commands/start.js +0 -74
  122. package/dist/commands/start.js.map +0 -1
  123. package/dist/commands/status.d.ts +0 -2
  124. package/dist/commands/status.d.ts.map +0 -1
  125. package/dist/commands/status.js +0 -29
  126. package/dist/commands/status.js.map +0 -1
  127. package/dist/commands/statusline.d.ts +0 -2
  128. package/dist/commands/statusline.d.ts.map +0 -1
  129. package/dist/commands/statusline.js +0 -90
  130. package/dist/commands/statusline.js.map +0 -1
  131. package/dist/commands/swarm.d.ts +0 -4
  132. package/dist/commands/swarm.d.ts.map +0 -1
  133. package/dist/commands/swarm.js +0 -48
  134. package/dist/commands/swarm.js.map +0 -1
  135. package/dist/commands/uninstall.d.ts +0 -2
  136. package/dist/commands/uninstall.d.ts.map +0 -1
  137. package/dist/commands/uninstall.js +0 -16
  138. package/dist/commands/uninstall.js.map +0 -1
  139. package/dist/context.d.ts +0 -13
  140. package/dist/context.d.ts.map +0 -1
  141. package/dist/context.js +0 -31
  142. package/dist/context.js.map +0 -1
  143. package/dist/doctor/checks.d.ts +0 -18
  144. package/dist/doctor/checks.d.ts.map +0 -1
  145. package/dist/doctor/checks.js +0 -270
  146. package/dist/doctor/checks.js.map +0 -1
  147. package/dist/hooks/handlers.d.ts +0 -21
  148. package/dist/hooks/handlers.d.ts.map +0 -1
  149. package/dist/hooks/handlers.js +0 -191
  150. package/dist/hooks/handlers.js.map +0 -1
  151. package/dist/index.d.ts +0 -10
  152. package/dist/index.d.ts.map +0 -1
  153. package/dist/index.js +0 -10
  154. package/dist/index.js.map +0 -1
  155. package/dist/integration/claude-md.d.ts +0 -6
  156. package/dist/integration/claude-md.d.ts.map +0 -1
  157. package/dist/integration/claude-md.js +0 -30
  158. package/dist/integration/claude-md.js.map +0 -1
  159. package/dist/integration/gitignore.d.ts +0 -3
  160. package/dist/integration/gitignore.d.ts.map +0 -1
  161. package/dist/integration/gitignore.js +0 -13
  162. package/dist/integration/gitignore.js.map +0 -1
  163. package/dist/integration/init.d.ts +0 -17
  164. package/dist/integration/init.d.ts.map +0 -1
  165. package/dist/integration/init.js +0 -86
  166. package/dist/integration/init.js.map +0 -1
  167. package/dist/integration/json-utils.d.ts +0 -13
  168. package/dist/integration/json-utils.d.ts.map +0 -1
  169. package/dist/integration/json-utils.js +0 -33
  170. package/dist/integration/json-utils.js.map +0 -1
  171. package/dist/integration/manifest.d.ts +0 -17
  172. package/dist/integration/manifest.d.ts.map +0 -1
  173. package/dist/integration/manifest.js +0 -26
  174. package/dist/integration/manifest.js.map +0 -1
  175. package/dist/integration/materialize.d.ts +0 -9
  176. package/dist/integration/materialize.d.ts.map +0 -1
  177. package/dist/integration/materialize.js +0 -21
  178. package/dist/integration/materialize.js.map +0 -1
  179. package/dist/integration/mcp-config.d.ts +0 -4
  180. package/dist/integration/mcp-config.d.ts.map +0 -1
  181. package/dist/integration/mcp-config.js +0 -11
  182. package/dist/integration/mcp-config.js.map +0 -1
  183. package/dist/integration/settings.d.ts +0 -7
  184. package/dist/integration/settings.d.ts.map +0 -1
  185. package/dist/integration/settings.js +0 -70
  186. package/dist/integration/settings.js.map +0 -1
  187. package/dist/integration/uninstall.d.ts +0 -10
  188. package/dist/integration/uninstall.d.ts.map +0 -1
  189. package/dist/integration/uninstall.js +0 -71
  190. package/dist/integration/uninstall.js.map +0 -1
  191. package/dist/launcher.d.ts +0 -8
  192. package/dist/launcher.d.ts.map +0 -1
  193. package/dist/launcher.js +0 -18
  194. package/dist/launcher.js.map +0 -1
  195. package/dist/mcp/server.d.ts +0 -27
  196. package/dist/mcp/server.d.ts.map +0 -1
  197. package/dist/mcp/server.js +0 -311
  198. package/dist/mcp/server.js.map +0 -1
  199. package/dist/plugin-content.d.ts +0 -21
  200. package/dist/plugin-content.d.ts.map +0 -1
  201. package/dist/plugin-content.js +0 -67
  202. package/dist/plugin-content.js.map +0 -1
  203. package/dist/rag/format.d.ts +0 -3
  204. package/dist/rag/format.d.ts.map +0 -1
  205. package/dist/rag/format.js +0 -12
  206. package/dist/rag/format.js.map +0 -1
  207. package/dist/retrieval-runtime.d.ts +0 -21
  208. package/dist/retrieval-runtime.d.ts.map +0 -1
  209. package/dist/retrieval-runtime.js +0 -47
  210. package/dist/retrieval-runtime.js.map +0 -1
  211. package/dist/status-line/git.d.ts +0 -3
  212. package/dist/status-line/git.d.ts.map +0 -1
  213. package/dist/status-line/git.js +0 -34
  214. package/dist/status-line/git.js.map +0 -1
  215. package/dist/status-line/render.d.ts +0 -29
  216. package/dist/status-line/render.d.ts.map +0 -1
  217. package/dist/status-line/render.js +0 -72
  218. package/dist/status-line/render.js.map +0 -1
  219. package/dist/swarm-runtime.d.ts +0 -11
  220. package/dist/swarm-runtime.d.ts.map +0 -1
  221. package/dist/swarm-runtime.js +0 -76
  222. package/dist/swarm-runtime.js.map +0 -1
  223. package/dist/version.d.ts +0 -2
  224. package/dist/version.d.ts.map +0 -1
  225. package/dist/version.js +0 -5
  226. package/dist/version.js.map +0 -1
@@ -0,0 +1,755 @@
1
+ import { createRequire as __yandecodeCreateRequire } from 'node:module';
2
+ const require = __yandecodeCreateRequire(import.meta.url);
3
+ import {
4
+ splitSections
5
+ } from "./chunk-KPDBXQ62.js";
6
+ import {
7
+ parseSettings
8
+ } from "./chunk-QCQC73WX.js";
9
+ import {
10
+ forgetInput,
11
+ getInput2 as getInput,
12
+ knowledgeSettings,
13
+ parseMemory,
14
+ searchInput3 as searchInput,
15
+ serializeMemory,
16
+ writeInput
17
+ } from "./chunk-7L6DD2VD.js";
18
+ import {
19
+ fitRows
20
+ } from "./chunk-OIAMKDTQ.js";
21
+ import {
22
+ listCandidatePaths
23
+ } from "./chunk-2S6B3DDQ.js";
24
+ import {
25
+ external_exports,
26
+ openDatabase,
27
+ openModuleDb,
28
+ resolveInsideRoot,
29
+ toFtsQuery,
30
+ writeFileAtomic
31
+ } from "./chunk-Y2MIXROU.js";
32
+
33
+ // packages/cli/src/modules/knowledge/runtime.ts
34
+ import { existsSync as existsSync4, readFileSync as readFileSync3 } from "node:fs";
35
+ import { isAbsolute as isAbsolute2, join as join4, relative as relative2 } from "node:path";
36
+
37
+ // packages/cli/src/modules/knowledge/index-store.ts
38
+ import { existsSync, mkdirSync, readdirSync, readFileSync, statSync } from "node:fs";
39
+ import { dirname, isAbsolute, join, relative, sep } from "node:path";
40
+ var MIGRATIONS = [
41
+ `
42
+ CREATE TABLE docs (path TEXT PRIMARY KEY, mtime_ms INTEGER NOT NULL, size INTEGER NOT NULL);
43
+ CREATE TABLE sections (
44
+ id INTEGER PRIMARY KEY,
45
+ source TEXT NOT NULL,
46
+ memory_id TEXT,
47
+ heading TEXT NOT NULL,
48
+ start_line INTEGER NOT NULL,
49
+ end_line INTEGER NOT NULL
50
+ );
51
+ CREATE INDEX sections_source ON sections (source);
52
+ CREATE VIRTUAL TABLE sections_fts USING fts5 (content, heading, title, tokenize = 'porter unicode61');
53
+ CREATE TABLE memories (
54
+ id TEXT PRIMARY KEY,
55
+ title TEXT NOT NULL,
56
+ kind TEXT NOT NULL,
57
+ durability TEXT NOT NULL,
58
+ updated TEXT NOT NULL,
59
+ superseded_by TEXT,
60
+ sources TEXT NOT NULL
61
+ );
62
+ CREATE TABLE meta (key TEXT PRIMARY KEY, value TEXT NOT NULL);
63
+ CREATE TABLE journal (
64
+ session_id TEXT NOT NULL,
65
+ at TEXT NOT NULL,
66
+ tool TEXT NOT NULL,
67
+ detail TEXT NOT NULL,
68
+ failed INTEGER NOT NULL DEFAULT 0
69
+ );
70
+ CREATE INDEX journal_session ON journal (session_id);
71
+ `
72
+ ];
73
+ var MARKDOWN = /\.(md|mdx|markdown)$/i;
74
+ function toPosix(path) {
75
+ return path.split(sep).join("/");
76
+ }
77
+ function walkMarkdown(dir) {
78
+ if (!existsSync(dir)) return [];
79
+ const out = [];
80
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
81
+ if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
82
+ const abs = join(dir, entry.name);
83
+ if (entry.isDirectory()) out.push(...walkMarkdown(abs));
84
+ else if (MARKDOWN.test(entry.name)) out.push(abs);
85
+ }
86
+ return out;
87
+ }
88
+ function repoPathOf(source) {
89
+ if (/^[a-z]+:\/\//i.test(source) || /^[0-9a-f]{7,40}$/i.test(source) || /^o[0-9a-f]{6}$/.test(source))
90
+ return null;
91
+ const path = source.replace(/:\d+(-\d+)?$/, "");
92
+ return /[./]/.test(path) && !/\s/.test(path) ? path : null;
93
+ }
94
+ var KnowledgeIndex = class _KnowledgeIndex {
95
+ constructor(db, options) {
96
+ this.db = db;
97
+ this.options = options;
98
+ }
99
+ db;
100
+ options;
101
+ static open(file, options) {
102
+ mkdirSync(dirname(file), { recursive: true });
103
+ return new _KnowledgeIndex(openModuleDb(file, MIGRATIONS), options);
104
+ }
105
+ close() {
106
+ this.db.close();
107
+ }
108
+ memoryDirRelative() {
109
+ const rel = relative(this.options.root, this.options.memories.dir);
110
+ return rel.startsWith("..") || isAbsolute(rel) ? null : toPosix(rel);
111
+ }
112
+ docPaths() {
113
+ const memoryDir = this.memoryDirRelative();
114
+ const docs = /* @__PURE__ */ new Map();
115
+ for (const rel of listCandidatePaths(this.options.root)) {
116
+ if (!MARKDOWN.test(rel)) continue;
117
+ if (memoryDir && (rel === memoryDir || rel.startsWith(`${memoryDir}/`))) continue;
118
+ if (rel.startsWith(".claude/")) continue;
119
+ docs.set(rel, join(this.options.root, rel));
120
+ }
121
+ for (const dir of this.options.extraDirs ?? []) {
122
+ for (const abs of walkMarkdown(dir)) docs.set(toPosix(abs), abs);
123
+ }
124
+ return docs;
125
+ }
126
+ deleteSource(source) {
127
+ const ids = this.db.prepare("SELECT id FROM sections WHERE source = ?").all(source);
128
+ const del = this.db.prepare("DELETE FROM sections_fts WHERE rowid = ?");
129
+ for (const { id } of ids) del.run(id);
130
+ this.db.prepare("DELETE FROM sections WHERE source = ?").run(source);
131
+ }
132
+ insertSections(source, title, text, memoryId) {
133
+ const insert = this.db.prepare(
134
+ "INSERT INTO sections (source, memory_id, heading, start_line, end_line) VALUES (?, ?, ?, ?, ?)"
135
+ );
136
+ const fts = this.db.prepare(
137
+ "INSERT INTO sections_fts (rowid, content, heading, title) VALUES (?, ?, ?, ?)"
138
+ );
139
+ for (const s of splitSections(text)) {
140
+ const id = insert.run(source, memoryId, s.heading, s.startLine, s.endLine).lastInsertRowid;
141
+ fts.run(id, s.content, s.heading, title);
142
+ }
143
+ }
144
+ syncDocs() {
145
+ const wanted = this.docPaths();
146
+ const known = new Map(
147
+ this.db.prepare("SELECT path, mtime_ms, size FROM docs").all().map((r) => [r.path, r])
148
+ );
149
+ for (const path of known.keys()) {
150
+ if (wanted.has(path)) continue;
151
+ this.deleteSource(path);
152
+ this.db.prepare("DELETE FROM docs WHERE path = ?").run(path);
153
+ }
154
+ for (const [path, abs] of wanted) {
155
+ const st = statSync(abs, { throwIfNoEntry: false });
156
+ if (!st) continue;
157
+ const prev = known.get(path);
158
+ if (prev && prev.mtime_ms === Math.trunc(st.mtimeMs) && prev.size === st.size) continue;
159
+ this.deleteSource(path);
160
+ this.insertSections(path, path, readFileSync(abs, "utf8"), null);
161
+ this.db.prepare("INSERT OR REPLACE INTO docs (path, mtime_ms, size) VALUES (?, ?, ?)").run(path, Math.trunc(st.mtimeMs), st.size);
162
+ }
163
+ }
164
+ /** Memories are few: rebuild them whenever the directory's content signature changes. */
165
+ syncMemories(memories) {
166
+ const signature = memories.map((m) => `${m.id}@${m.updated}@${m.supersedes.join(",")}`).join("|");
167
+ const previous = this.db.prepare("SELECT value FROM meta WHERE key = 'memories'").get();
168
+ if (previous?.value === signature) return;
169
+ const supersededBy = /* @__PURE__ */ new Map();
170
+ for (const m of memories) for (const old of m.supersedes) supersededBy.set(old, m.id);
171
+ for (const { id } of this.db.prepare("SELECT id FROM memories").all()) {
172
+ this.deleteSource(`memory:${id}`);
173
+ }
174
+ this.db.prepare("DELETE FROM memories").run();
175
+ const insert = this.db.prepare(
176
+ "INSERT INTO memories (id, title, kind, durability, updated, superseded_by, sources) VALUES (?, ?, ?, ?, ?, ?, ?)"
177
+ );
178
+ for (const m of memories) {
179
+ insert.run(
180
+ m.id,
181
+ m.title,
182
+ m.kind,
183
+ m.durability,
184
+ m.updated,
185
+ supersededBy.get(m.id) ?? null,
186
+ JSON.stringify(m.sources)
187
+ );
188
+ this.insertSections(
189
+ `memory:${m.id}`,
190
+ m.title,
191
+ `${m.title}
192
+ ${m.tags.join(" ")}
193
+ ${m.body}`,
194
+ m.id
195
+ );
196
+ }
197
+ this.db.prepare("INSERT OR REPLACE INTO meta (key, value) VALUES ('memories', ?)").run(signature);
198
+ }
199
+ /** Repository paths a memory cites that no longer exist (evaluated now: the repo changes). */
200
+ missingSources(sources) {
201
+ return sources.filter((source) => {
202
+ const path = repoPathOf(source);
203
+ return path !== null && !existsSync(join(this.options.root, path));
204
+ });
205
+ }
206
+ sync() {
207
+ this.options.memories.pruneExpired();
208
+ const memories = this.options.memories.list();
209
+ this.db.transaction(() => {
210
+ this.syncDocs();
211
+ this.syncMemories(memories);
212
+ })();
213
+ }
214
+ search(query, options = {}) {
215
+ const fts = toFtsQuery(query);
216
+ if (!fts) return [];
217
+ const limit = options.limit ?? 10;
218
+ const rows = this.db.prepare(
219
+ `SELECT s.source, s.memory_id, s.heading, s.start_line, s.end_line,
220
+ snippet(sections_fts, 0, '', '', ' \u2026 ', 14) AS snippet,
221
+ m.title, m.kind, m.updated, m.superseded_by, m.sources
222
+ FROM sections_fts JOIN sections s ON s.id = sections_fts.rowid
223
+ LEFT JOIN memories m ON m.id = s.memory_id
224
+ WHERE sections_fts MATCH ? ORDER BY bm25(sections_fts, 1.0, 2.0, 3.0) LIMIT ?`
225
+ ).all(fts, limit * 5);
226
+ const hits = [];
227
+ const seen = /* @__PURE__ */ new Set();
228
+ for (const row of rows) {
229
+ const hit = this.toHit(row, options.scope ?? "all", options.includeSuperseded ?? false);
230
+ const key = hit?.type === "memory" ? `m:${hit.id}` : hit ? `d:${hit.path}` : "";
231
+ if (!hit || seen.has(key)) continue;
232
+ seen.add(key);
233
+ hits.push(hit);
234
+ if (hits.length >= limit) break;
235
+ }
236
+ return hits;
237
+ }
238
+ /** A search row as a hit, or null when scope/supersession filters it out. */
239
+ toHit(row, scope, includeSuperseded) {
240
+ const snippet = row.snippet.replace(/\s+/g, " ").trim().slice(0, 140);
241
+ if (row.memory_id === null) {
242
+ if (scope === "memory") return null;
243
+ return {
244
+ type: "doc",
245
+ path: row.source,
246
+ heading: row.heading,
247
+ startLine: row.start_line,
248
+ endLine: row.end_line,
249
+ snippet
250
+ };
251
+ }
252
+ if (scope === "docs" || row.superseded_by && !includeSuperseded) return null;
253
+ return {
254
+ type: "memory",
255
+ id: row.memory_id,
256
+ title: row.title ?? "",
257
+ kind: row.kind ?? "note",
258
+ updated: row.updated ?? "",
259
+ stale: this.missingSources(JSON.parse(row.sources ?? "[]")),
260
+ snippet
261
+ };
262
+ }
263
+ /** Active durable knowledge, newest first, for the SessionStart index. */
264
+ activeMemories() {
265
+ return this.db.prepare(
266
+ "SELECT id, title, kind, updated, durability FROM memories WHERE superseded_by IS NULL ORDER BY updated DESC"
267
+ ).all();
268
+ }
269
+ record(sessionId, entry) {
270
+ this.db.prepare("INSERT INTO journal (session_id, at, tool, detail, failed) VALUES (?, ?, ?, ?, ?)").run(sessionId, entry.at, entry.tool, entry.detail, entry.failed ? 1 : 0);
271
+ }
272
+ /** Returns and clears the activity recorded for a session. */
273
+ drainJournal(sessionId) {
274
+ const rows = this.db.prepare("SELECT at, tool, detail, failed FROM journal WHERE session_id = ? ORDER BY rowid").all(sessionId);
275
+ this.db.prepare("DELETE FROM journal WHERE session_id = ?").run(sessionId);
276
+ return rows.map((r) => ({ at: r.at, tool: r.tool, detail: r.detail, failed: r.failed === 1 }));
277
+ }
278
+ };
279
+
280
+ // packages/cli/src/modules/knowledge/legacy.ts
281
+ import { existsSync as existsSync2, writeFileSync } from "node:fs";
282
+ import { join as join2 } from "node:path";
283
+ var KIND_BY_NAMESPACE = {
284
+ decisions: "decision",
285
+ patterns: "pattern",
286
+ solutions: "fact",
287
+ failures: "failure",
288
+ tasks: "note",
289
+ feedback: "note"
290
+ };
291
+ function importLegacyMemories(legacyDb, repo) {
292
+ const marker = join2(repo.dir, ".imported-v0");
293
+ if (!existsSync2(legacyDb) || existsSync2(marker)) return 0;
294
+ const db = openDatabase(legacyDb);
295
+ try {
296
+ const table = db.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'memories'").get();
297
+ const rows = table ? db.prepare(
298
+ "SELECT id, namespace, content, summary FROM memories WHERE archived_at IS NULL ORDER BY created_at"
299
+ ).all() : [];
300
+ for (const row of rows) {
301
+ const firstLine = row.content.split("\n")[0].slice(0, 80);
302
+ repo.write({
303
+ title: row.summary?.trim() || firstLine,
304
+ body: row.content,
305
+ kind: KIND_BY_NAMESPACE[row.namespace] ?? "note",
306
+ sources: [`yandecode-v0-memory:${row.id}`],
307
+ tags: ["imported-v0"]
308
+ });
309
+ }
310
+ writeFileSync(marker, `${(/* @__PURE__ */ new Date()).toISOString()}
311
+ `);
312
+ return rows.length;
313
+ } finally {
314
+ db.close();
315
+ }
316
+ }
317
+
318
+ // packages/cli/src/modules/knowledge/memories.ts
319
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync2, readFileSync as readFileSync2, statSync as statSync2, unlinkSync } from "node:fs";
320
+ import { join as join3 } from "node:path";
321
+ var DAY_MS = 864e5;
322
+ var DUPLICATE_JACCARD = 0.8;
323
+ function words(text) {
324
+ return new Set(text.toLowerCase().match(/[\p{L}\p{N}]{3,}/gu) ?? []);
325
+ }
326
+ function jaccard(a, b) {
327
+ if (a.size === 0 && b.size === 0) return 1;
328
+ let shared = 0;
329
+ for (const w of a) if (b.has(w)) shared++;
330
+ return shared / (a.size + b.size - shared);
331
+ }
332
+ function slug(title) {
333
+ const base = title.normalize("NFKD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 50).replace(/-$/, "");
334
+ return base || "memory";
335
+ }
336
+ var union = (a, b = []) => [
337
+ .../* @__PURE__ */ new Set([...a, ...b])
338
+ ];
339
+ var MemoryRepository = class {
340
+ constructor(dir, clock = () => /* @__PURE__ */ new Date()) {
341
+ this.dir = dir;
342
+ this.clock = clock;
343
+ }
344
+ dir;
345
+ clock;
346
+ file(id) {
347
+ return join3(this.dir, `${id}.md`);
348
+ }
349
+ files() {
350
+ return existsSync3(this.dir) ? readdirSync2(this.dir).filter((f) => f.endsWith(".md")).sort() : [];
351
+ }
352
+ read(fileName) {
353
+ const path = join3(this.dir, fileName);
354
+ try {
355
+ const memory = parseMemory(readFileSync2(path, "utf8"));
356
+ if (memory.created !== "") return memory;
357
+ const mtime = statSync2(path).mtime.toISOString();
358
+ return { ...memory, created: mtime, updated: memory.updated || mtime };
359
+ } catch {
360
+ return null;
361
+ }
362
+ }
363
+ get(id) {
364
+ return existsSync3(this.file(id)) ? this.read(`${id}.md`) : null;
365
+ }
366
+ /** Valid memories, most recently updated first. */
367
+ list() {
368
+ return this.files().flatMap((f) => this.read(f) ?? []).sort((a, b) => b.updated.localeCompare(a.updated));
369
+ }
370
+ invalidFiles() {
371
+ return this.files().filter((f) => this.read(f) === null);
372
+ }
373
+ write(input) {
374
+ mkdirSync2(this.dir, { recursive: true });
375
+ const now = this.clock().toISOString();
376
+ const durability = input.durability ?? (input.kind === "session" ? "ephemeral" : "durable");
377
+ const expires = durability === "ephemeral" ? new Date(this.clock().getTime() + (input.expiresInDays ?? 14) * DAY_MS).toISOString() : null;
378
+ const fingerprint = words(`${input.title} ${input.body}`);
379
+ const duplicate = (input.dedupe ?? true) && this.list().find(
380
+ (m) => m.kind === input.kind && jaccard(words(`${m.title} ${m.body}`), fingerprint) >= DUPLICATE_JACCARD
381
+ );
382
+ if (duplicate) {
383
+ writeFileAtomic(
384
+ this.file(duplicate.id),
385
+ serializeMemory({
386
+ ...duplicate,
387
+ title: input.title,
388
+ body: input.body,
389
+ updated: now,
390
+ expires: durability === "ephemeral" ? expires : duplicate.expires,
391
+ tags: union(duplicate.tags, input.tags),
392
+ sources: union(duplicate.sources, input.sources),
393
+ supersedes: union(duplicate.supersedes, input.supersedes)
394
+ })
395
+ );
396
+ return { id: duplicate.id, action: "updated" };
397
+ }
398
+ const base = `${now.slice(0, 10).replace(/-/g, "")}-${slug(input.title)}`;
399
+ let id = base;
400
+ for (let n = 2; existsSync3(this.file(id)); n++) id = `${base}-${n}`;
401
+ writeFileAtomic(
402
+ this.file(id),
403
+ serializeMemory({
404
+ id,
405
+ title: input.title,
406
+ kind: input.kind,
407
+ durability,
408
+ created: now,
409
+ updated: now,
410
+ expires,
411
+ supersedes: [...input.supersedes ?? []],
412
+ tags: [...input.tags ?? []],
413
+ sources: [...input.sources ?? []],
414
+ body: input.body
415
+ })
416
+ );
417
+ return { id, action: "created" };
418
+ }
419
+ forget(id) {
420
+ if (!existsSync3(this.file(id))) return false;
421
+ unlinkSync(this.file(id));
422
+ return true;
423
+ }
424
+ /** Deletes ephemeral memories past their expiry; returns their ids. */
425
+ pruneExpired() {
426
+ const now = this.clock().toISOString();
427
+ const expired = this.list().filter((m) => m.expires !== null && m.expires < now);
428
+ for (const m of expired) unlinkSync(this.file(m.id));
429
+ return expired.map((m) => m.id);
430
+ }
431
+ };
432
+
433
+ // packages/cli/src/modules/knowledge/session.ts
434
+ var LISTED_FILES = 15;
435
+ var EDIT_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
436
+ var COMMAND_TOOLS = /* @__PURE__ */ new Set(["Bash", "ctx_run"]);
437
+ function toolUsage(entries) {
438
+ const counts = /* @__PURE__ */ new Map();
439
+ for (const e of entries.filter((e2) => !EDIT_TOOLS.has(e2.tool) && e2.tool !== "Bash")) {
440
+ counts.set(e.tool, (counts.get(e.tool) ?? 0) + 1);
441
+ }
442
+ return [...counts].map(([tool, n]) => `${tool} \xD7${n}`).join(", ");
443
+ }
444
+ function summarizeSession(entries, endedAt) {
445
+ if (entries.length === 0) return null;
446
+ const edited = [...new Set(entries.filter((e) => EDIT_TOOLS.has(e.tool)).map((e) => e.detail))];
447
+ const commands = entries.filter((e) => COMMAND_TOOLS.has(e.tool));
448
+ const failed = [...new Set(commands.filter((e) => e.failed).map((e) => e.detail))];
449
+ const usage = toolUsage(entries);
450
+ const when = endedAt.toISOString().slice(0, 16).replace("T", " ");
451
+ const title = edited.length > 0 ? `Session ${when}: edited ${edited.slice(0, 3).join(", ")}${edited.length > 3 ? ` +${edited.length - 3}` : ""}` : `Session ${when}: ${commands.length} command(s)`;
452
+ const failing = failed.length > 0 ? `; failing: ${failed.slice(0, 5).map((c) => `\`${c}\``).join(", ")}` : "";
453
+ const lines = [
454
+ `Started ${entries[0].at}, ended ${endedAt.toISOString()}.`,
455
+ edited.length > 0 ? `Edited ${edited.length} file(s): ${edited.slice(0, LISTED_FILES).join(", ")}${edited.length > LISTED_FILES ? ", \u2026" : ""}.` : "No files edited.",
456
+ `Ran ${commands.length} command(s)${failing}.`,
457
+ ...usage ? [`yandecode tools: ${usage}.`] : []
458
+ ];
459
+ return { title, body: lines.join("\n"), sources: edited.slice(0, LISTED_FILES) };
460
+ }
461
+ function sessionStartIndex(index, repo, maxChars) {
462
+ const active = index.activeMemories();
463
+ const durable = active.filter((m) => m.durability === "durable");
464
+ const lastSession = active.find((m) => m.kind === "session");
465
+ if (durable.length === 0 && !lastSession) return "";
466
+ const header = "Project memory (YandeCode) \u2014 titles only; read bodies with knowledge_get(ids):";
467
+ const lines = durable.map((m) => `- [${m.id}] (${m.kind}) ${m.title}`);
468
+ const last = lastSession ? repo.get(lastSession.id) : null;
469
+ const tail = last ? [`Last session [${last.id}]: ${last.body.replace(/\n/g, " ")}`] : [];
470
+ let kept = lines;
471
+ const render = () => [
472
+ header,
473
+ ...kept,
474
+ ...kept.length < lines.length ? [`\u2026 ${lines.length - kept.length} older memory(ies): knowledge_search to find them`] : [],
475
+ ...tail
476
+ ].join("\n");
477
+ while (render().length > maxChars && kept.length > 0) kept = kept.slice(0, -1);
478
+ const text = render();
479
+ return text.length > maxChars ? text.slice(0, maxChars) : text;
480
+ }
481
+ var STOPWORDS = /* @__PURE__ */ new Set([
482
+ "the",
483
+ "and",
484
+ "for",
485
+ "with",
486
+ "this",
487
+ "that",
488
+ "from",
489
+ "what",
490
+ "where",
491
+ "como",
492
+ "para",
493
+ "uma",
494
+ "que",
495
+ "com",
496
+ "por",
497
+ "n\xE3o",
498
+ "isso",
499
+ "esse",
500
+ "essa",
501
+ "have",
502
+ "does",
503
+ "should",
504
+ "please",
505
+ "can",
506
+ "you"
507
+ ]);
508
+ function promptRecall(index, prompt, maxItems = 3) {
509
+ const terms = [
510
+ ...new Set(
511
+ (prompt.toLowerCase().match(/[\p{L}\p{N}_]{4,}/gu) ?? []).filter((w) => !STOPWORDS.has(w))
512
+ )
513
+ ];
514
+ if (terms.length < 2) return "";
515
+ const hits = index.search(terms.join(" "), { scope: "memory", limit: 8 }).filter((h) => h.type === "memory").filter((h) => {
516
+ const text = `${h.title} ${h.snippet}`.toLowerCase();
517
+ return terms.filter((t) => text.includes(t)).length >= 2;
518
+ }).slice(0, maxItems);
519
+ if (hits.length === 0) return "";
520
+ return [
521
+ "Possibly relevant project memory (knowledge_get for details):",
522
+ ...hits.map((h) => `- [${h.id}] (${h.kind}) ${h.title}`)
523
+ ].join("\n");
524
+ }
525
+
526
+ // packages/cli/src/modules/knowledge/runtime.ts
527
+ var SYNC_INTERVAL_MS = 1500;
528
+ var states = /* @__PURE__ */ new Map();
529
+ function stateFor(ctx) {
530
+ let state = states.get(ctx.root);
531
+ if (!state) {
532
+ const settings = parseSettings("knowledge", knowledgeSettings, ctx.settings);
533
+ const memoryDir = isAbsolute2(settings.memoryDir) ? settings.memoryDir : join4(ctx.root, settings.memoryDir);
534
+ const repo = new MemoryRepository(memoryDir);
535
+ const imported = importLegacyMemories(ctx.paths.legacyStateDb, repo);
536
+ if (imported > 0) ctx.log("imported_v0_memories", { count: imported });
537
+ const index = KnowledgeIndex.open(join4(ctx.paths.yandecodeDir, "knowledge.db"), {
538
+ root: ctx.root,
539
+ memories: repo,
540
+ extraDirs: settings.extraDirs
541
+ });
542
+ state = { settings, repo, index, lastSync: 0 };
543
+ states.set(ctx.root, state);
544
+ }
545
+ return state;
546
+ }
547
+ function fresh(ctx) {
548
+ const state = stateFor(ctx);
549
+ if (Date.now() - state.lastSync > SYNC_INTERVAL_MS) {
550
+ state.index.sync();
551
+ state.lastSync = Date.now();
552
+ }
553
+ return state;
554
+ }
555
+ function hitRow(hit) {
556
+ if (hit.type === "doc") {
557
+ return `${hit.path}:${hit.startLine}-${hit.endLine}${hit.heading ? ` \xA7 ${hit.heading}` : ""} \u2014 ${hit.snippet}`;
558
+ }
559
+ const stale = hit.stale.length > 0 ? ` (stale: ${hit.stale.join(", ")} missing)` : "";
560
+ return `[${hit.id}] ${hit.kind} \xB7 ${hit.updated.slice(0, 10)} \xB7 ${hit.title}${stale}`;
561
+ }
562
+ function renderMemory(m, index) {
563
+ const missing = index.missingSources(m.sources);
564
+ return [
565
+ `# ${m.title}`,
566
+ `[${m.id}] ${m.kind} \xB7 ${m.durability} \xB7 updated ${m.updated.slice(0, 10)}${m.expires ? ` \xB7 expires ${m.expires.slice(0, 10)}` : ""}`,
567
+ ...m.tags.length > 0 ? [`tags: ${m.tags.join(", ")}`] : [],
568
+ ...m.sources.length > 0 ? [`sources: ${m.sources.join(", ")}`] : [],
569
+ ...m.supersedes.length > 0 ? [`supersedes: ${m.supersedes.join(", ")}`] : [],
570
+ ...missing.length > 0 ? [`WARNING: sources no longer exist (${missing.join(", ")}); verify before relying on this.`] : [],
571
+ "",
572
+ m.body
573
+ ].join("\n");
574
+ }
575
+ function renderDoc(ref, ctx, settings) {
576
+ const match = /^(.*?)(?::(\d+)(?:-(\d+))?)?$/.exec(ref);
577
+ const path = match[1];
578
+ const inExtra = isAbsolute2(path) && settings.extraDirs.some((d) => !relative2(d, path).startsWith(".."));
579
+ let abs;
580
+ try {
581
+ abs = inExtra ? path : resolveInsideRoot(ctx.root, path);
582
+ } catch {
583
+ return null;
584
+ }
585
+ if (!existsSync4(abs)) return null;
586
+ const lines = readFileSync3(abs, "utf8").split("\n");
587
+ const start = match[2] ? Number(match[2]) : 1;
588
+ const end = match[3] ? Number(match[3]) : match[2] ? start : lines.length;
589
+ return [`## ${path}:${start}-${end}`, ...lines.slice(start - 1, end)].join("\n");
590
+ }
591
+ function knowledgeSearch(raw, ctx) {
592
+ const args = external_exports.object(searchInput).parse(raw);
593
+ const { index } = fresh(ctx);
594
+ const hits = index.search(args.query, {
595
+ scope: args.scope ?? "all",
596
+ limit: args.limit ?? 6,
597
+ includeSuperseded: args.include_superseded ?? false
598
+ });
599
+ if (hits.length === 0)
600
+ return Promise.resolve({ text: `No docs or memories match "${args.query}".` });
601
+ return Promise.resolve({
602
+ text: fitRows(
603
+ `knowledge_search "${args.query}" \u2014 knowledge_get(ids) for details`,
604
+ hits.map(hitRow),
605
+ 3e3
606
+ )
607
+ });
608
+ }
609
+ function knowledgeGet(raw, ctx) {
610
+ const args = external_exports.object(getInput).parse(raw);
611
+ const state = fresh(ctx);
612
+ const blocks = args.ids.map((id) => {
613
+ const memory = state.repo.get(id);
614
+ if (memory) return renderMemory(memory, state.index);
615
+ return renderDoc(id, ctx, state.settings) ?? `## ${id}
616
+ not found (unknown memory id or document path)`;
617
+ });
618
+ return Promise.resolve({
619
+ text: fitRows(`${blocks.length} item(s)`, blocks, args.max_chars ?? 8e3)
620
+ });
621
+ }
622
+ function memoryWrite(raw, ctx) {
623
+ const args = external_exports.object(writeInput).parse(raw);
624
+ const state = stateFor(ctx);
625
+ const result = state.repo.write({
626
+ title: args.title,
627
+ body: args.body,
628
+ kind: args.kind,
629
+ ...args.durability ? { durability: args.durability } : {},
630
+ ...args.tags ? { tags: args.tags } : {},
631
+ ...args.sources ? { sources: args.sources } : {},
632
+ ...args.supersedes ? { supersedes: args.supersedes } : {},
633
+ ...args.expires_in_days ? { expiresInDays: args.expires_in_days } : {}
634
+ });
635
+ state.lastSync = 0;
636
+ ctx.log("memory_write", { id: result.id, action: result.action });
637
+ const verb = result.action === "created" ? "Saved" : "Updated near-duplicate";
638
+ return Promise.resolve({
639
+ text: `${verb} memory [${result.id}] (${relative2(ctx.root, join4(state.repo.dir, `${result.id}.md`))}).`
640
+ });
641
+ }
642
+ function memoryForget(raw, ctx) {
643
+ const args = external_exports.object(forgetInput).parse(raw);
644
+ const state = stateFor(ctx);
645
+ const removed = state.repo.forget(args.id);
646
+ state.lastSync = 0;
647
+ return Promise.resolve(
648
+ removed ? { text: `Forgot memory [${args.id}].` } : { isError: true, text: `No memory with id "${args.id}".` }
649
+ );
650
+ }
651
+ function failedTool(response) {
652
+ if (typeof response !== "object" || response === null) return false;
653
+ const r = response;
654
+ if (r.is_error === true || r.interrupted === true) return true;
655
+ return ["exit_code", "exitCode", "returnCode"].some(
656
+ (k) => typeof r[k] === "number" && r[k] !== 0
657
+ );
658
+ }
659
+ var YANDECODE_TOOL = "mcp__yandecode__";
660
+ var EDIT_TOOLS2 = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
661
+ var str = (value) => typeof value === "string" ? value : null;
662
+ function bashEntry(input) {
663
+ const command = str(input.tool_input?.command);
664
+ return command ? { tool: "Bash", detail: command.slice(0, 200), failed: failedTool(input.tool_response) } : null;
665
+ }
666
+ function editEntry(input, root) {
667
+ const path = str(input.tool_input?.file_path) ?? str(input.tool_input?.notebook_path);
668
+ return path ? { tool: input.tool_name, detail: relative2(root, path) || path, failed: false } : null;
669
+ }
670
+ function yandecodeEntry(input) {
671
+ const name = input.tool_name.slice(YANDECODE_TOOL.length);
672
+ const args = input.tool_input ?? {};
673
+ const detail = str(args.command) ?? str(args.title) ?? str(args.query) ?? name;
674
+ const exit = /\(exit (\d+)/.exec(JSON.stringify(input.tool_response ?? ""))?.[1];
675
+ return { tool: name, detail: detail.slice(0, 200), failed: exit !== void 0 && exit !== "0" };
676
+ }
677
+ function journalEntry(input, root) {
678
+ const tool = input.tool_name ?? "";
679
+ if (tool === "Bash") return bashEntry(input);
680
+ if (EDIT_TOOLS2.has(tool)) return editEntry(input, root);
681
+ return tool.startsWith(YANDECODE_TOOL) ? yandecodeEntry(input) : null;
682
+ }
683
+ function onPostToolUse(input, ctx) {
684
+ const state = stateFor(ctx);
685
+ if (!state.settings.capture || !input.session_id) return Promise.resolve({ kind: "none" });
686
+ const entry = journalEntry(input, ctx.root);
687
+ if (entry) state.index.record(input.session_id, { at: (/* @__PURE__ */ new Date()).toISOString(), ...entry });
688
+ return Promise.resolve({ kind: "none" });
689
+ }
690
+ function onSessionEnd(input, ctx) {
691
+ const state = stateFor(ctx);
692
+ if (!input.session_id) return Promise.resolve({ kind: "none" });
693
+ const summary = summarizeSession(state.index.drainJournal(input.session_id), /* @__PURE__ */ new Date());
694
+ if (summary) {
695
+ const { id } = state.repo.write({
696
+ ...summary,
697
+ kind: "session",
698
+ durability: "ephemeral",
699
+ expiresInDays: state.settings.sessionTtlDays,
700
+ dedupe: false
701
+ });
702
+ ctx.log("session_summary", { id });
703
+ }
704
+ return Promise.resolve({ kind: "none" });
705
+ }
706
+ var runtime = {
707
+ tools: {
708
+ knowledge_search: knowledgeSearch,
709
+ knowledge_get: knowledgeGet,
710
+ memory_write: memoryWrite,
711
+ memory_forget: memoryForget
712
+ },
713
+ hooks: {
714
+ SessionStart: (_input, ctx) => {
715
+ const state = fresh(ctx);
716
+ const text = sessionStartIndex(state.index, state.repo, state.settings.sessionStartChars);
717
+ return Promise.resolve(text ? { kind: "context", text } : { kind: "none" });
718
+ },
719
+ UserPromptSubmit: (input, ctx) => {
720
+ const state = fresh(ctx);
721
+ if (!state.settings.promptRecall || typeof input.prompt !== "string")
722
+ return Promise.resolve({ kind: "none" });
723
+ const text = promptRecall(state.index, input.prompt);
724
+ return Promise.resolve(text ? { kind: "context", text } : { kind: "none" });
725
+ },
726
+ PostToolUse: onPostToolUse,
727
+ SessionEnd: onSessionEnd
728
+ },
729
+ doctor: (ctx) => {
730
+ const state = fresh(ctx);
731
+ const invalid = state.repo.invalidFiles();
732
+ return Promise.resolve([
733
+ {
734
+ name: "memories",
735
+ status: "ok",
736
+ detail: `${state.repo.list().length} in ${relative2(ctx.root, state.repo.dir) || state.repo.dir}`
737
+ },
738
+ invalid.length > 0 ? {
739
+ name: "memory files",
740
+ status: "warn",
741
+ detail: `unreadable: ${invalid.join(", ")}`,
742
+ fix: "fix their front matter (id, title) or delete them"
743
+ } : { name: "memory files", status: "ok", detail: "all parse" }
744
+ ]);
745
+ },
746
+ dispose: () => {
747
+ for (const state of states.values()) state.index.close();
748
+ states.clear();
749
+ return Promise.resolve();
750
+ }
751
+ };
752
+ export {
753
+ runtime
754
+ };
755
+ //# sourceMappingURL=runtime-WAFQWW4M.js.map