@tekmidian/pai 0.5.6 → 0.6.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 (137) hide show
  1. package/ARCHITECTURE.md +72 -1
  2. package/README.md +107 -3
  3. package/dist/{auto-route-BG6I_4B1.mjs → auto-route-C-DrW6BL.mjs} +3 -3
  4. package/dist/{auto-route-BG6I_4B1.mjs.map → auto-route-C-DrW6BL.mjs.map} +1 -1
  5. package/dist/cli/index.mjs +1897 -1569
  6. package/dist/cli/index.mjs.map +1 -1
  7. package/dist/clusters-JIDQW65f.mjs +201 -0
  8. package/dist/clusters-JIDQW65f.mjs.map +1 -0
  9. package/dist/{config-Cf92lGX_.mjs → config-BuhHWyOK.mjs} +21 -6
  10. package/dist/config-BuhHWyOK.mjs.map +1 -0
  11. package/dist/daemon/index.mjs +12 -9
  12. package/dist/daemon/index.mjs.map +1 -1
  13. package/dist/{daemon-D9evGlgR.mjs → daemon-D3hYb5_C.mjs} +670 -219
  14. package/dist/daemon-D3hYb5_C.mjs.map +1 -0
  15. package/dist/daemon-mcp/index.mjs +4597 -4
  16. package/dist/daemon-mcp/index.mjs.map +1 -1
  17. package/dist/{db-4lSqLFb8.mjs → db-BtuN768f.mjs} +9 -2
  18. package/dist/db-BtuN768f.mjs.map +1 -0
  19. package/dist/db-DdUperSl.mjs +110 -0
  20. package/dist/db-DdUperSl.mjs.map +1 -0
  21. package/dist/{detect-BU3Nx_2L.mjs → detect-CdaA48EI.mjs} +1 -1
  22. package/dist/{detect-BU3Nx_2L.mjs.map → detect-CdaA48EI.mjs.map} +1 -1
  23. package/dist/{detector-Bp-2SM3x.mjs → detector-jGBuYQJM.mjs} +2 -2
  24. package/dist/{detector-Bp-2SM3x.mjs.map → detector-jGBuYQJM.mjs.map} +1 -1
  25. package/dist/{factory-Bzcy70G9.mjs → factory-Ygqe_bVZ.mjs} +7 -5
  26. package/dist/{factory-Bzcy70G9.mjs.map → factory-Ygqe_bVZ.mjs.map} +1 -1
  27. package/dist/helpers-BEST-4Gx.mjs +420 -0
  28. package/dist/helpers-BEST-4Gx.mjs.map +1 -0
  29. package/dist/hooks/capture-all-events.mjs +19 -4
  30. package/dist/hooks/capture-all-events.mjs.map +4 -4
  31. package/dist/hooks/capture-session-summary.mjs +38 -0
  32. package/dist/hooks/capture-session-summary.mjs.map +3 -3
  33. package/dist/hooks/cleanup-session-files.mjs +6 -12
  34. package/dist/hooks/cleanup-session-files.mjs.map +4 -4
  35. package/dist/hooks/context-compression-hook.mjs +105 -111
  36. package/dist/hooks/context-compression-hook.mjs.map +4 -4
  37. package/dist/hooks/initialize-session.mjs +26 -17
  38. package/dist/hooks/initialize-session.mjs.map +4 -4
  39. package/dist/hooks/inject-observations.mjs +220 -0
  40. package/dist/hooks/inject-observations.mjs.map +7 -0
  41. package/dist/hooks/load-core-context.mjs +18 -2
  42. package/dist/hooks/load-core-context.mjs.map +4 -4
  43. package/dist/hooks/load-project-context.mjs +102 -97
  44. package/dist/hooks/load-project-context.mjs.map +4 -4
  45. package/dist/hooks/observe.mjs +354 -0
  46. package/dist/hooks/observe.mjs.map +7 -0
  47. package/dist/hooks/stop-hook.mjs +174 -90
  48. package/dist/hooks/stop-hook.mjs.map +4 -4
  49. package/dist/hooks/sync-todo-to-md.mjs +31 -33
  50. package/dist/hooks/sync-todo-to-md.mjs.map +4 -4
  51. package/dist/index.d.mts +32 -9
  52. package/dist/index.d.mts.map +1 -1
  53. package/dist/index.mjs +6 -9
  54. package/dist/indexer-D53l5d1U.mjs +1 -0
  55. package/dist/{indexer-backend-CIMXedqk.mjs → indexer-backend-jcJFsmB4.mjs} +37 -127
  56. package/dist/indexer-backend-jcJFsmB4.mjs.map +1 -0
  57. package/dist/{ipc-client-Bjg_a1dc.mjs → ipc-client-CoyUHPod.mjs} +2 -7
  58. package/dist/{ipc-client-Bjg_a1dc.mjs.map → ipc-client-CoyUHPod.mjs.map} +1 -1
  59. package/dist/latent-ideas-bTJo6Omd.mjs +191 -0
  60. package/dist/latent-ideas-bTJo6Omd.mjs.map +1 -0
  61. package/dist/neighborhood-BYYbEkUJ.mjs +135 -0
  62. package/dist/neighborhood-BYYbEkUJ.mjs.map +1 -0
  63. package/dist/note-context-BK24bX8Y.mjs +126 -0
  64. package/dist/note-context-BK24bX8Y.mjs.map +1 -0
  65. package/dist/postgres-CKf-EDtS.mjs +846 -0
  66. package/dist/postgres-CKf-EDtS.mjs.map +1 -0
  67. package/dist/{reranker-D7bRAHi6.mjs → reranker-CMNZcfVx.mjs} +1 -1
  68. package/dist/{reranker-D7bRAHi6.mjs.map → reranker-CMNZcfVx.mjs.map} +1 -1
  69. package/dist/{search-_oHfguA5.mjs → search-DC1qhkKn.mjs} +2 -58
  70. package/dist/search-DC1qhkKn.mjs.map +1 -0
  71. package/dist/{sqlite-WWBq7_2C.mjs → sqlite-l-s9xPjY.mjs} +160 -3
  72. package/dist/sqlite-l-s9xPjY.mjs.map +1 -0
  73. package/dist/state-C6_vqz7w.mjs +102 -0
  74. package/dist/state-C6_vqz7w.mjs.map +1 -0
  75. package/dist/stop-words-BaMEGVeY.mjs +326 -0
  76. package/dist/stop-words-BaMEGVeY.mjs.map +1 -0
  77. package/dist/{indexer-CMPOiY1r.mjs → sync-BOsnEj2-.mjs} +14 -216
  78. package/dist/sync-BOsnEj2-.mjs.map +1 -0
  79. package/dist/themes-BvYF0W8T.mjs +148 -0
  80. package/dist/themes-BvYF0W8T.mjs.map +1 -0
  81. package/dist/{tools-DV_lsiCc.mjs → tools-DcaJlYDN.mjs} +162 -273
  82. package/dist/tools-DcaJlYDN.mjs.map +1 -0
  83. package/dist/trace-CRx9lPuc.mjs +137 -0
  84. package/dist/trace-CRx9lPuc.mjs.map +1 -0
  85. package/dist/{vault-indexer-DXWs9pDn.mjs → vault-indexer-Bi2cRmn7.mjs} +174 -138
  86. package/dist/vault-indexer-Bi2cRmn7.mjs.map +1 -0
  87. package/dist/zettelkasten-cdajbnPr.mjs +708 -0
  88. package/dist/zettelkasten-cdajbnPr.mjs.map +1 -0
  89. package/package.json +1 -2
  90. package/src/hooks/ts/capture-all-events.ts +6 -0
  91. package/src/hooks/ts/lib/project-utils/index.ts +50 -0
  92. package/src/hooks/ts/lib/project-utils/notify.ts +75 -0
  93. package/src/hooks/ts/lib/project-utils/paths.ts +218 -0
  94. package/src/hooks/ts/lib/project-utils/session-notes.ts +363 -0
  95. package/src/hooks/ts/lib/project-utils/todo.ts +178 -0
  96. package/src/hooks/ts/lib/project-utils/tokens.ts +39 -0
  97. package/src/hooks/ts/lib/project-utils.ts +40 -999
  98. package/src/hooks/ts/post-tool-use/observe.ts +327 -0
  99. package/src/hooks/ts/pre-compact/context-compression-hook.ts +6 -0
  100. package/src/hooks/ts/session-end/capture-session-summary.ts +41 -0
  101. package/src/hooks/ts/session-start/initialize-session.ts +7 -1
  102. package/src/hooks/ts/session-start/inject-observations.ts +254 -0
  103. package/src/hooks/ts/session-start/load-core-context.ts +7 -0
  104. package/src/hooks/ts/session-start/load-project-context.ts +8 -1
  105. package/src/hooks/ts/stop/stop-hook.ts +28 -0
  106. package/templates/claude-md.template.md +7 -74
  107. package/templates/skills/user/.gitkeep +0 -0
  108. package/dist/chunker-CbnBe0s0.mjs +0 -191
  109. package/dist/chunker-CbnBe0s0.mjs.map +0 -1
  110. package/dist/config-Cf92lGX_.mjs.map +0 -1
  111. package/dist/daemon-D9evGlgR.mjs.map +0 -1
  112. package/dist/db-4lSqLFb8.mjs.map +0 -1
  113. package/dist/db-Dp8VXIMR.mjs +0 -212
  114. package/dist/db-Dp8VXIMR.mjs.map +0 -1
  115. package/dist/indexer-CMPOiY1r.mjs.map +0 -1
  116. package/dist/indexer-backend-CIMXedqk.mjs.map +0 -1
  117. package/dist/mcp/index.d.mts +0 -1
  118. package/dist/mcp/index.mjs +0 -500
  119. package/dist/mcp/index.mjs.map +0 -1
  120. package/dist/postgres-FXrHDPcE.mjs +0 -358
  121. package/dist/postgres-FXrHDPcE.mjs.map +0 -1
  122. package/dist/schemas-BFIgGntb.mjs +0 -3405
  123. package/dist/schemas-BFIgGntb.mjs.map +0 -1
  124. package/dist/search-_oHfguA5.mjs.map +0 -1
  125. package/dist/sqlite-WWBq7_2C.mjs.map +0 -1
  126. package/dist/tools-DV_lsiCc.mjs.map +0 -1
  127. package/dist/vault-indexer-DXWs9pDn.mjs.map +0 -1
  128. package/dist/zettelkasten-e-a4rW_6.mjs +0 -901
  129. package/dist/zettelkasten-e-a4rW_6.mjs.map +0 -1
  130. package/templates/README.md +0 -181
  131. package/templates/skills/createskill-skill.template.md +0 -78
  132. package/templates/skills/history-system.template.md +0 -371
  133. package/templates/skills/hook-system.template.md +0 -913
  134. package/templates/skills/sessions-skill.template.md +0 -102
  135. package/templates/skills/skill-system.template.md +0 -214
  136. package/templates/skills/terminal-tabs.template.md +0 -120
  137. package/templates/templates.md +0 -20
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-C6_vqz7w.mjs","names":[],"sources":["../src/daemon/daemon/state.ts"],"sourcesContent":["/**\n * Shared mutable daemon state — module-level singletons used across all daemon sub-modules.\n */\n\nimport { openRegistry } from \"../../registry/db.js\";\nimport type { StorageBackend } from \"../../storage/interface.js\";\nimport type { NotificationConfig } from \"../../notifications/types.js\";\nimport type { PaiDaemonConfig } from \"../config.js\";\n\n// ---------------------------------------------------------------------------\n// Core singletons (assigned at startup by serve())\n// ---------------------------------------------------------------------------\n\nexport let registryDb: ReturnType<typeof openRegistry>;\nexport let storageBackend: StorageBackend;\nexport let daemonConfig: PaiDaemonConfig;\nexport let startTime = Date.now();\n\n// ---------------------------------------------------------------------------\n// Scheduler state\n// ---------------------------------------------------------------------------\n\n/** True while a project index pass is running. */\nexport let indexInProgress = false;\nexport let lastIndexTime = 0;\nexport let indexSchedulerTimer: ReturnType<typeof setInterval> | null = null;\n\n/** True while an embedding pass is running. */\nexport let embedInProgress = false;\nexport let lastEmbedTime = 0;\nexport let embedSchedulerTimer: ReturnType<typeof setInterval> | null = null;\n\n/** True while a vault index pass is running. */\nexport let vaultIndexInProgress = false;\nexport let lastVaultIndexTime = 0;\n\n// ---------------------------------------------------------------------------\n// Notification state\n// ---------------------------------------------------------------------------\n\n/** Mutable notification config — loaded from disk at startup, patchable at runtime. */\nexport let notificationConfig: NotificationConfig;\n\n// ---------------------------------------------------------------------------\n// Graceful shutdown flag\n// ---------------------------------------------------------------------------\n\n/**\n * Set to true when a SIGTERM/SIGINT is received so that long-running loops\n * (embed, index) can detect the signal and exit their inner loops before the\n * pool/backend is closed.\n */\nexport let shutdownRequested = false;\n\n// ---------------------------------------------------------------------------\n// Setters (TypeScript requires assignment functions for exported `let` vars\n// that need to be mutated across module boundaries)\n// ---------------------------------------------------------------------------\n\nexport function setRegistryDb(db: ReturnType<typeof openRegistry>): void { registryDb = db; }\nexport function setStorageBackend(b: StorageBackend): void { storageBackend = b; }\nexport function setDaemonConfig(c: PaiDaemonConfig): void { daemonConfig = c; }\nexport function setStartTime(t: number): void { startTime = t; }\nexport function setNotificationConfig(c: NotificationConfig): void { notificationConfig = c; }\nexport function setShutdownRequested(v: boolean): void { shutdownRequested = v; }\nexport function setIndexInProgress(v: boolean): void { indexInProgress = v; }\nexport function setLastIndexTime(v: number): void { lastIndexTime = v; }\nexport function setIndexSchedulerTimer(v: ReturnType<typeof setInterval> | null): void { indexSchedulerTimer = v; }\nexport function setEmbedInProgress(v: boolean): void { embedInProgress = v; }\nexport function setLastEmbedTime(v: number): void { lastEmbedTime = v; }\nexport function setEmbedSchedulerTimer(v: ReturnType<typeof setInterval> | null): void { embedSchedulerTimer = v; }\nexport function setVaultIndexInProgress(v: boolean): void { vaultIndexInProgress = v; }\nexport function setLastVaultIndexTime(v: number): void { lastVaultIndexTime = v; }\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAaA,IAAW;AACX,IAAW;AACX,IAAW;AACX,IAAW,YAAY,KAAK,KAAK;;AAOjC,IAAW,kBAAkB;AAC7B,IAAW,gBAAgB;AAC3B,IAAW,sBAA6D;;AAGxE,IAAW,kBAAkB;AAC7B,IAAW,gBAAgB;AAC3B,IAAW,sBAA6D;;AAGxE,IAAW,uBAAuB;AAClC,IAAW,qBAAqB;;AAOhC,IAAW;;;;;;AAWX,IAAW,oBAAoB;AAO/B,SAAgB,cAAc,IAA2C;AAAE,cAAa;;AACxF,SAAgB,kBAAkB,GAAyB;AAAE,kBAAiB;;AAC9E,SAAgB,gBAAgB,GAA0B;AAAE,gBAAe;;AAC3E,SAAgB,aAAa,GAAiB;AAAE,aAAY;;AAC5D,SAAgB,sBAAsB,GAA6B;AAAE,sBAAqB;;AAC1F,SAAgB,qBAAqB,GAAkB;AAAE,qBAAoB;;AAC7E,SAAgB,mBAAmB,GAAkB;AAAE,mBAAkB;;AACzE,SAAgB,iBAAiB,GAAiB;AAAE,iBAAgB;;AACpE,SAAgB,uBAAuB,GAAgD;AAAE,uBAAsB;;AAC/G,SAAgB,mBAAmB,GAAkB;AAAE,mBAAkB;;AACzE,SAAgB,iBAAiB,GAAiB;AAAE,iBAAgB;;AACpE,SAAgB,uBAAuB,GAAgD;AAAE,uBAAsB;;AAC/G,SAAgB,wBAAwB,GAAkB;AAAE,wBAAuB;;AACnF,SAAgB,sBAAsB,GAAiB;AAAE,sBAAqB"}
@@ -0,0 +1,326 @@
1
+ //#region src/utils/stop-words.ts
2
+ /**
3
+ * Shared stop-word list used across memory search, slug generation, graph clustering,
4
+ * and zettelkasten modules. This is the union of all per-file sets that previously
5
+ * existed in 7 different files.
6
+ */
7
+ const STOP_WORDS = new Set([
8
+ "a",
9
+ "an",
10
+ "the",
11
+ "and",
12
+ "or",
13
+ "but",
14
+ "if",
15
+ "then",
16
+ "else",
17
+ "so",
18
+ "because",
19
+ "as",
20
+ "although",
21
+ "however",
22
+ "therefore",
23
+ "thus",
24
+ "hence",
25
+ "meanwhile",
26
+ "moreover",
27
+ "furthermore",
28
+ "otherwise",
29
+ "instead",
30
+ "anyway",
31
+ "at",
32
+ "to",
33
+ "for",
34
+ "of",
35
+ "with",
36
+ "by",
37
+ "from",
38
+ "in",
39
+ "on",
40
+ "out",
41
+ "off",
42
+ "over",
43
+ "under",
44
+ "up",
45
+ "into",
46
+ "without",
47
+ "per",
48
+ "via",
49
+ "i",
50
+ "you",
51
+ "we",
52
+ "they",
53
+ "he",
54
+ "she",
55
+ "it",
56
+ "me",
57
+ "us",
58
+ "him",
59
+ "her",
60
+ "my",
61
+ "your",
62
+ "our",
63
+ "their",
64
+ "his",
65
+ "its",
66
+ "who",
67
+ "whom",
68
+ "what",
69
+ "which",
70
+ "this",
71
+ "that",
72
+ "these",
73
+ "those",
74
+ "is",
75
+ "are",
76
+ "was",
77
+ "were",
78
+ "be",
79
+ "been",
80
+ "being",
81
+ "have",
82
+ "has",
83
+ "had",
84
+ "do",
85
+ "does",
86
+ "did",
87
+ "will",
88
+ "would",
89
+ "could",
90
+ "should",
91
+ "may",
92
+ "might",
93
+ "can",
94
+ "shall",
95
+ "want",
96
+ "need",
97
+ "know",
98
+ "think",
99
+ "see",
100
+ "look",
101
+ "make",
102
+ "get",
103
+ "go",
104
+ "come",
105
+ "take",
106
+ "use",
107
+ "find",
108
+ "give",
109
+ "tell",
110
+ "say",
111
+ "said",
112
+ "try",
113
+ "keep",
114
+ "run",
115
+ "set",
116
+ "put",
117
+ "add",
118
+ "show",
119
+ "check",
120
+ "let",
121
+ "not",
122
+ "no",
123
+ "yes",
124
+ "just",
125
+ "also",
126
+ "very",
127
+ "really",
128
+ "about",
129
+ "after",
130
+ "before",
131
+ "more",
132
+ "most",
133
+ "some",
134
+ "any",
135
+ "all",
136
+ "each",
137
+ "every",
138
+ "both",
139
+ "few",
140
+ "many",
141
+ "much",
142
+ "other",
143
+ "another",
144
+ "such",
145
+ "only",
146
+ "own",
147
+ "same",
148
+ "than",
149
+ "too",
150
+ "ok",
151
+ "okay",
152
+ "sure",
153
+ "please",
154
+ "thanks",
155
+ "thank",
156
+ "here",
157
+ "there",
158
+ "now",
159
+ "well",
160
+ "like",
161
+ "going",
162
+ "done",
163
+ "got",
164
+ "https",
165
+ "http",
166
+ "www",
167
+ "com",
168
+ "org",
169
+ "net",
170
+ "io",
171
+ "null",
172
+ "undefined",
173
+ "true",
174
+ "false",
175
+ "ll",
176
+ "ve",
177
+ "re",
178
+ "don",
179
+ "thats",
180
+ "heres",
181
+ "theres",
182
+ "youre",
183
+ "theyre",
184
+ "didnt",
185
+ "dont",
186
+ "doesnt",
187
+ "havent",
188
+ "hasnt",
189
+ "wont",
190
+ "cant",
191
+ "shouldnt",
192
+ "wouldnt",
193
+ "couldnt",
194
+ "isnt",
195
+ "arent",
196
+ "wasnt",
197
+ "werent",
198
+ "never",
199
+ "ever",
200
+ "still",
201
+ "already",
202
+ "yet",
203
+ "back",
204
+ "away",
205
+ "down",
206
+ "right",
207
+ "left",
208
+ "next",
209
+ "last",
210
+ "first",
211
+ "second",
212
+ "third",
213
+ "then",
214
+ "again",
215
+ "once",
216
+ "twice",
217
+ "since",
218
+ "while",
219
+ "though",
220
+ "actually",
221
+ "basically",
222
+ "literally",
223
+ "simply",
224
+ "exactly",
225
+ "probably",
226
+ "possibly",
227
+ "maybe",
228
+ "perhaps",
229
+ "certainly",
230
+ "definitely",
231
+ "absolutely",
232
+ "completely",
233
+ "totally",
234
+ "quite",
235
+ "rather",
236
+ "fairly",
237
+ "nearly",
238
+ "almost",
239
+ "barely",
240
+ "hardly",
241
+ "quickly",
242
+ "slowly",
243
+ "easily",
244
+ "likely",
245
+ "unlikely",
246
+ "one",
247
+ "two",
248
+ "three",
249
+ "four",
250
+ "five",
251
+ "six",
252
+ "seven",
253
+ "eight",
254
+ "nine",
255
+ "ten",
256
+ "time",
257
+ "way",
258
+ "thing",
259
+ "something",
260
+ "anything",
261
+ "nothing",
262
+ "everything",
263
+ "someone",
264
+ "anyone",
265
+ "everyone",
266
+ "new",
267
+ "note",
268
+ "untitled",
269
+ "page",
270
+ "file",
271
+ "doc",
272
+ "code",
273
+ "session",
274
+ "notes",
275
+ "moc",
276
+ "template",
277
+ "content",
278
+ "attachment",
279
+ "etc",
280
+ "ie",
281
+ "eg",
282
+ "vs",
283
+ "les",
284
+ "des",
285
+ "une",
286
+ "est",
287
+ "que",
288
+ "qui",
289
+ "dans",
290
+ "pour",
291
+ "sur",
292
+ "par",
293
+ "pas",
294
+ "son",
295
+ "ses",
296
+ "aux",
297
+ "avec",
298
+ "tout",
299
+ "mais",
300
+ "und",
301
+ "der",
302
+ "die",
303
+ "das",
304
+ "ein",
305
+ "eine",
306
+ "ist",
307
+ "den",
308
+ "dem",
309
+ "von",
310
+ "mit",
311
+ "auf",
312
+ "nicht",
313
+ "sich",
314
+ "auch",
315
+ "noch",
316
+ "wie"
317
+ ]);
318
+ /**
319
+ * Alias used by graph modules that need stop-word filtering specifically for
320
+ * vault note titles (same set, just semantically named for clarity).
321
+ */
322
+ const TITLE_STOP_WORDS = STOP_WORDS;
323
+
324
+ //#endregion
325
+ export { TITLE_STOP_WORDS as n, STOP_WORDS as t };
326
+ //# sourceMappingURL=stop-words-BaMEGVeY.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stop-words-BaMEGVeY.mjs","names":[],"sources":["../src/utils/stop-words.ts"],"sourcesContent":["/**\n * Shared stop-word list used across memory search, slug generation, graph clustering,\n * and zettelkasten modules. This is the union of all per-file sets that previously\n * existed in 7 different files.\n */\n\nexport const STOP_WORDS = new Set([\n // Articles / determiners\n \"a\", \"an\", \"the\",\n // Conjunctions\n \"and\", \"or\", \"but\", \"if\", \"then\", \"else\", \"so\", \"because\", \"as\",\n \"although\", \"however\", \"therefore\", \"thus\", \"hence\", \"meanwhile\",\n \"moreover\", \"furthermore\", \"otherwise\", \"instead\", \"anyway\",\n // Prepositions\n \"at\", \"to\", \"for\", \"of\", \"with\", \"by\", \"from\", \"in\", \"on\", \"out\",\n \"off\", \"over\", \"under\", \"up\", \"into\", \"without\", \"per\", \"via\",\n // Pronouns\n \"i\", \"you\", \"we\", \"they\", \"he\", \"she\", \"it\", \"me\", \"us\", \"him\", \"her\",\n \"my\", \"your\", \"our\", \"their\", \"his\", \"its\", \"who\", \"whom\", \"what\",\n \"which\", \"this\", \"that\", \"these\", \"those\",\n // Common verbs\n \"is\", \"are\", \"was\", \"were\", \"be\", \"been\", \"being\",\n \"have\", \"has\", \"had\", \"do\", \"does\", \"did\",\n \"will\", \"would\", \"could\", \"should\", \"may\", \"might\", \"can\", \"shall\",\n \"want\", \"need\", \"know\", \"think\", \"see\", \"look\", \"make\", \"get\", \"go\",\n \"come\", \"take\", \"use\", \"find\", \"give\", \"tell\", \"say\", \"said\", \"try\",\n \"keep\", \"run\", \"set\", \"put\", \"add\", \"show\", \"check\", \"let\",\n // Negation / common function words\n \"not\", \"no\", \"yes\", \"just\", \"also\", \"very\", \"really\",\n \"about\", \"after\", \"before\",\n \"more\", \"most\", \"some\", \"any\", \"all\", \"each\", \"every\", \"both\", \"few\",\n \"many\", \"much\", \"other\", \"another\", \"such\", \"only\", \"own\", \"same\",\n \"than\", \"too\", \"ok\", \"okay\", \"sure\",\n \"please\", \"thanks\", \"thank\", \"here\", \"there\", \"now\", \"well\", \"like\",\n \"going\", \"done\", \"got\",\n // Tech/URL junk\n \"https\", \"http\", \"www\", \"com\", \"org\", \"net\", \"io\",\n \"null\", \"undefined\", \"true\", \"false\",\n // Contractions (de-apostrophe'd forms that appear after tokenisation)\n \"ll\", \"ve\", \"re\", \"don\", \"thats\", \"heres\", \"theres\",\n \"youre\", \"theyre\", \"didnt\", \"dont\", \"doesnt\", \"havent\", \"hasnt\",\n \"wont\", \"cant\", \"shouldnt\", \"wouldnt\", \"couldnt\", \"isnt\", \"arent\",\n \"wasnt\", \"werent\",\n // Filler adverbs\n \"never\", \"ever\", \"still\", \"already\", \"yet\", \"back\",\n \"away\", \"down\", \"right\", \"left\", \"next\", \"last\", \"first\", \"second\",\n \"third\",\n \"then\", \"again\", \"once\", \"twice\", \"since\", \"while\", \"though\",\n \"actually\", \"basically\", \"literally\", \"simply\", \"exactly\", \"probably\",\n \"possibly\", \"maybe\", \"perhaps\", \"certainly\", \"definitely\", \"absolutely\",\n \"completely\", \"totally\", \"quite\", \"rather\", \"fairly\", \"nearly\",\n \"almost\", \"barely\", \"hardly\", \"quickly\", \"slowly\", \"easily\", \"likely\",\n \"unlikely\",\n // Numbers (spelled out)\n \"one\", \"two\", \"three\", \"four\", \"five\", \"six\", \"seven\",\n \"eight\", \"nine\", \"ten\",\n // Common nouns (too generic for search/slug)\n \"time\", \"way\", \"thing\", \"something\", \"anything\", \"nothing\",\n \"everything\", \"someone\", \"anyone\", \"everyone\",\n // Zettelkasten / vault-specific noise\n \"new\", \"note\", \"untitled\", \"page\", \"file\", \"doc\", \"code\",\n \"session\", \"notes\", \"moc\", \"template\", \"content\", \"attachment\",\n // Misc abbreviations\n \"etc\", \"ie\", \"eg\", \"vs\",\n // French stop words (for multilingual vaults)\n \"les\", \"des\", \"une\", \"est\", \"que\", \"qui\", \"dans\", \"pour\", \"sur\",\n \"par\", \"pas\", \"son\", \"ses\", \"aux\", \"avec\", \"tout\", \"mais\",\n // German stop words (for multilingual vaults)\n \"und\", \"der\", \"die\", \"das\", \"ein\", \"eine\", \"ist\", \"den\", \"dem\",\n \"von\", \"mit\", \"auf\", \"nicht\", \"sich\", \"auch\", \"noch\", \"wie\",\n]);\n\n/**\n * Alias used by graph modules that need stop-word filtering specifically for\n * vault note titles (same set, just semantically named for clarity).\n */\nexport const TITLE_STOP_WORDS = STOP_WORDS;\n"],"mappings":";;;;;;AAMA,MAAa,aAAa,IAAI,IAAI;CAEhC;CAAK;CAAM;CAEX;CAAO;CAAM;CAAO;CAAM;CAAQ;CAAQ;CAAM;CAAW;CAC3D;CAAY;CAAW;CAAa;CAAQ;CAAS;CACrD;CAAY;CAAe;CAAa;CAAW;CAEnD;CAAM;CAAM;CAAO;CAAM;CAAQ;CAAM;CAAQ;CAAM;CAAM;CAC3D;CAAO;CAAQ;CAAS;CAAM;CAAQ;CAAW;CAAO;CAExD;CAAK;CAAO;CAAM;CAAQ;CAAM;CAAO;CAAM;CAAM;CAAM;CAAO;CAChE;CAAM;CAAQ;CAAO;CAAS;CAAO;CAAO;CAAO;CAAQ;CAC3D;CAAS;CAAQ;CAAQ;CAAS;CAElC;CAAM;CAAO;CAAO;CAAQ;CAAM;CAAQ;CAC1C;CAAQ;CAAO;CAAO;CAAM;CAAQ;CACpC;CAAQ;CAAS;CAAS;CAAU;CAAO;CAAS;CAAO;CAC3D;CAAQ;CAAQ;CAAQ;CAAS;CAAO;CAAQ;CAAQ;CAAO;CAC/D;CAAQ;CAAQ;CAAO;CAAQ;CAAQ;CAAQ;CAAO;CAAQ;CAC9D;CAAQ;CAAO;CAAO;CAAO;CAAO;CAAQ;CAAS;CAErD;CAAO;CAAM;CAAO;CAAQ;CAAQ;CAAQ;CAC5C;CAAS;CAAS;CAClB;CAAQ;CAAQ;CAAQ;CAAO;CAAO;CAAQ;CAAS;CAAQ;CAC/D;CAAQ;CAAQ;CAAS;CAAW;CAAQ;CAAQ;CAAO;CAC3D;CAAQ;CAAO;CAAM;CAAQ;CAC7B;CAAU;CAAU;CAAS;CAAQ;CAAS;CAAO;CAAQ;CAC7D;CAAS;CAAQ;CAEjB;CAAS;CAAQ;CAAO;CAAO;CAAO;CAAO;CAC7C;CAAQ;CAAa;CAAQ;CAE7B;CAAM;CAAM;CAAM;CAAO;CAAS;CAAS;CAC3C;CAAS;CAAU;CAAS;CAAQ;CAAU;CAAU;CACxD;CAAQ;CAAQ;CAAY;CAAW;CAAW;CAAQ;CAC1D;CAAS;CAET;CAAS;CAAQ;CAAS;CAAW;CAAO;CAC5C;CAAQ;CAAQ;CAAS;CAAQ;CAAQ;CAAQ;CAAS;CAC1D;CACA;CAAQ;CAAS;CAAQ;CAAS;CAAS;CAAS;CACpD;CAAY;CAAa;CAAa;CAAU;CAAW;CAC3D;CAAY;CAAS;CAAW;CAAa;CAAc;CAC3D;CAAc;CAAW;CAAS;CAAU;CAAU;CACtD;CAAU;CAAU;CAAU;CAAW;CAAU;CAAU;CAC7D;CAEA;CAAO;CAAO;CAAS;CAAQ;CAAQ;CAAO;CAC9C;CAAS;CAAQ;CAEjB;CAAQ;CAAO;CAAS;CAAa;CAAY;CACjD;CAAc;CAAW;CAAU;CAEnC;CAAO;CAAQ;CAAY;CAAQ;CAAQ;CAAO;CAClD;CAAW;CAAS;CAAO;CAAY;CAAW;CAElD;CAAO;CAAM;CAAM;CAEnB;CAAO;CAAO;CAAO;CAAO;CAAO;CAAO;CAAQ;CAAQ;CAC1D;CAAO;CAAO;CAAO;CAAO;CAAO;CAAQ;CAAQ;CAEnD;CAAO;CAAO;CAAO;CAAO;CAAO;CAAQ;CAAO;CAAO;CACzD;CAAO;CAAO;CAAO;CAAS;CAAQ;CAAQ;CAAQ;CACvD,CAAC;;;;;AAMF,MAAa,mBAAmB"}
@@ -1,12 +1,10 @@
1
- import { t as chunkMarkdown } from "./chunker-CbnBe0s0.mjs";
2
- import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
3
- import { homedir } from "node:os";
4
- import { basename, join, normalize, relative } from "node:path";
5
- import { createHash } from "node:crypto";
1
+ import { a as parseSessionTitleChunk, c as yieldToEventLoop, f as sha256File, i as isPathTooBroadForContentScan, l as chunkMarkdown, n as chunkId, o as walkContentFiles, r as detectTier, s as walkMdFiles, t as INDEX_YIELD_EVERY } from "./helpers-BEST-4Gx.mjs";
2
+ import { existsSync, readFileSync, statSync } from "node:fs";
3
+ import { basename, join, relative } from "node:path";
6
4
 
7
- //#region src/memory/indexer.ts
5
+ //#region src/memory/indexer/sync.ts
8
6
  /**
9
- * File indexer for the PAI federation memory engine.
7
+ * Synchronous (SQLite) indexer for the PAI federation memory engine.
10
8
  *
11
9
  * Scans project memory/ and Notes/ directories, chunks markdown files, and
12
10
  * inserts the resulting chunks into federation.db for BM25 search.
@@ -14,41 +12,10 @@ import { createHash } from "node:crypto";
14
12
  * Change detection: files whose SHA-256 hash has not changed since the last
15
13
  * index run are skipped, keeping incremental re-indexing fast.
16
14
  *
17
- * Phase 2.5: adds embedChunks() for generating vector embeddings on indexed
18
- * chunks that do not yet have an embedding stored.
15
+ * Uses raw better-sqlite3 Database directly for maximum SQLite performance
16
+ * (synchronous transactions, no serialisation overhead).
19
17
  */
20
18
  /**
21
- * Classify a relative file path into one of the four memory tiers.
22
- *
23
- * Rules (in priority order):
24
- * - MEMORY.md anywhere in memory/ → 'evergreen'
25
- * - YYYY-MM-DD.md in memory/ → 'daily'
26
- * - anything else in memory/ → 'topic'
27
- * - anything in Notes/ → 'session'
28
- */
29
- function detectTier(relativePath) {
30
- const p = relativePath.replace(/\\/g, "/").replace(/^\.\//, "");
31
- if (p.startsWith("Notes/") || p === "Notes") return "session";
32
- const fileName = basename(p);
33
- if (fileName === "MEMORY.md") return "evergreen";
34
- if (/^\d{4}-\d{2}-\d{2}\.md$/.test(fileName)) return "daily";
35
- return "topic";
36
- }
37
- /**
38
- * Generate a deterministic chunk ID from its coordinates.
39
- * Format: sha256("projectId:path:chunkIndex:startLine:endLine")
40
- *
41
- * The chunkIndex (0-based position within the file) is included so that
42
- * chunks with approximated line numbers (e.g. from splitBySentences) never
43
- * produce colliding IDs even when multiple chunks share the same startLine/endLine.
44
- */
45
- function chunkId(projectId, path, chunkIndex, startLine, endLine) {
46
- return createHash("sha256").update(`${projectId}:${path}:${chunkIndex}:${startLine}:${endLine}`).digest("hex");
47
- }
48
- function sha256File(content) {
49
- return createHash("sha256").update(content).digest("hex");
50
- }
51
- /**
52
19
  * Index a single file into the federation database.
53
20
  *
54
21
  * @returns true if the file was re-indexed (changed or new), false if skipped.
@@ -106,169 +73,15 @@ function indexFile(db, projectId, rootPath, relativePath, source, tier) {
106
73
  return true;
107
74
  }
108
75
  /**
109
- * Safety cap: maximum number of .md files collected per project scan.
110
- * Prevents runaway scans on huge root paths (e.g. home directory).
111
- * Projects with more files than this are scanned up to the cap only.
112
- */
113
- const MAX_FILES_PER_PROJECT = 5e3;
114
- /**
115
- * Maximum recursion depth for directory walks.
116
- * Prevents deep traversal of large directory trees (e.g. development repos).
117
- * Depth 0 = the given directory itself (no recursion).
118
- * Value 6 allows: root → subdirs → sub-subdirs → ... up to 6 levels.
119
- * Sufficient for memory/, Notes/, and typical docs structures.
120
- */
121
- const MAX_WALK_DEPTH = 6;
122
- /**
123
- * Recursively collect all .md files under a directory.
124
- * Returns absolute paths. Stops early if the accumulated count hits the cap
125
- * or if the recursion depth exceeds MAX_WALK_DEPTH.
126
- *
127
- * @param dir Directory to scan.
128
- * @param acc Shared accumulator array (mutated in place for early exit).
129
- * @param cap Maximum number of files to collect (across all recursive calls).
130
- * @param depth Current recursion depth (0 = the initial call).
131
- */
132
- function walkMdFiles(dir, acc, cap = MAX_FILES_PER_PROJECT, depth = 0) {
133
- const results = acc ?? [];
134
- if (!existsSync(dir)) return results;
135
- if (results.length >= cap) return results;
136
- if (depth > MAX_WALK_DEPTH) return results;
137
- try {
138
- for (const entry of readdirSync(dir, { withFileTypes: true })) {
139
- if (results.length >= cap) break;
140
- if (entry.isSymbolicLink()) continue;
141
- if (ALWAYS_SKIP_DIRS.has(entry.name)) continue;
142
- const full = join(dir, entry.name);
143
- if (entry.isDirectory()) walkMdFiles(full, results, cap, depth + 1);
144
- else if (entry.isFile() && entry.name.endsWith(".md")) results.push(full);
145
- }
146
- } catch {}
147
- return results;
148
- }
149
- /**
150
- * Directories to ALWAYS skip, at any depth, during any directory walk.
151
- * These are build artifacts, dependency trees, and VCS internals that
152
- * should never be indexed regardless of where they appear in the tree.
153
- */
154
- const ALWAYS_SKIP_DIRS = new Set([
155
- ".git",
156
- "node_modules",
157
- "vendor",
158
- "Pods",
159
- "dist",
160
- "build",
161
- "out",
162
- "DerivedData",
163
- ".next",
164
- ".venv",
165
- "venv",
166
- "__pycache__",
167
- ".cache",
168
- ".bun"
169
- ]);
170
- /**
171
- * Directories to skip when doing a root-level content scan.
172
- * These are either already handled by dedicated scans or should never be indexed.
173
- */
174
- const ROOT_SCAN_SKIP_DIRS = new Set([
175
- "memory",
176
- "Notes",
177
- ".claude",
178
- ".DS_Store",
179
- ...ALWAYS_SKIP_DIRS
180
- ]);
181
- /**
182
- * Additional directories to skip at the content-scan level (first level below root).
183
- * These are common macOS/Linux home-directory or repo noise directories that are
184
- * never meaningful as project content.
185
- */
186
- const CONTENT_SCAN_SKIP_DIRS = new Set([
187
- "Library",
188
- "Applications",
189
- "Music",
190
- "Movies",
191
- "Pictures",
192
- "Desktop",
193
- "Downloads",
194
- "Public",
195
- "coverage",
196
- ...ALWAYS_SKIP_DIRS
197
- ]);
198
- /**
199
- * Recursively collect all .md files under rootPath, excluding directories
200
- * that are already covered by dedicated scans (memory/, Notes/) and
201
- * common noise directories (.git, node_modules, etc.).
202
- *
203
- * Returns absolute paths for files NOT already handled by the specific scanners.
204
- * Stops collecting once MAX_FILES_PER_PROJECT is reached.
205
- */
206
- function walkContentFiles(rootPath) {
207
- if (!existsSync(rootPath)) return [];
208
- const results = [];
209
- try {
210
- for (const entry of readdirSync(rootPath, { withFileTypes: true })) {
211
- if (results.length >= MAX_FILES_PER_PROJECT) break;
212
- if (entry.isSymbolicLink()) continue;
213
- if (ROOT_SCAN_SKIP_DIRS.has(entry.name)) continue;
214
- if (CONTENT_SCAN_SKIP_DIRS.has(entry.name)) continue;
215
- const full = join(rootPath, entry.name);
216
- if (entry.isDirectory()) walkMdFiles(full, results, MAX_FILES_PER_PROJECT);
217
- else if (entry.isFile() && entry.name.endsWith(".md")) {
218
- if (entry.name !== "MEMORY.md") results.push(full);
219
- }
220
- }
221
- } catch {}
222
- return results;
223
- }
224
- /**
225
76
  * Index all memory, Notes, and content files for a single registered project.
226
77
  *
227
78
  * Scans:
228
79
  * - {rootPath}/MEMORY.md → source='memory', tier='evergreen'
229
80
  * - {rootPath}/memory/ → source='memory', tier from detectTier()
230
81
  * - {rootPath}/Notes/ → source='notes', tier='session'
231
- * - {rootPath}/**\/\*.md → source='content', tier='topic' (all other .md files, recursive)
82
+ * - {rootPath}/**\/*.md → source='content', tier='topic' (all other .md files, recursive)
232
83
  * - {claudeNotesDir}/ → source='notes', tier='session' (if set and different)
233
- *
234
- * The content scan covers projects like job-discussions where markdown files
235
- * live in date/topic subdirectories rather than a memory/ folder. The
236
- * memory/, Notes/, .git/, and node_modules/ directories are excluded from
237
- * the content scan to avoid double-indexing.
238
- *
239
- * The claudeNotesDir parameter points to ~/.claude/projects/{encoded}/Notes/
240
- * where Claude Code writes session notes for a given working directory.
241
- * It is stored on the project row as claude_notes_dir after a registry scan.
242
84
  */
243
- /**
244
- * Number of files to process before yielding to the event loop inside
245
- * indexProject. Keeps IPC responsive even while indexing large projects.
246
- * Lower = more responsive but more overhead. 10 is a good balance.
247
- */
248
- const INDEX_YIELD_EVERY = 10;
249
- /**
250
- * Returns true if rootPath should skip the recursive content scan.
251
- *
252
- * Skips content scanning for:
253
- * - The home directory itself or any ancestor (too broad — millions of files)
254
- * - Git repositories (code repos — index memory/ and Notes/ only, not all .md files)
255
- *
256
- * The content scan is still useful for Obsidian vaults, Notes folders, and
257
- * other doc-centric project trees where ALL markdown files are meaningful.
258
- *
259
- * The memory/, Notes/, and claude_notes_dir scans always run regardless.
260
- */
261
- function isPathTooBroadForContentScan(rootPath) {
262
- const normalized = normalize(rootPath);
263
- const home = homedir();
264
- if (home.startsWith(normalized) || normalized === "/") return true;
265
- if (normalized.startsWith(home)) {
266
- const rel = normalized.slice(home.length).replace(/^\//, "");
267
- if ((rel ? rel.split("/").length : 0) === 0) return true;
268
- }
269
- if (existsSync(join(normalized, ".git"))) return true;
270
- return false;
271
- }
272
85
  async function indexProject(db, projectId, rootPath, claudeNotesDir) {
273
86
  const result = {
274
87
  filesProcessed: 0,
@@ -301,7 +114,6 @@ async function indexProject(db, projectId, rootPath, claudeNotesDir) {
301
114
  tier: "session"
302
115
  });
303
116
  {
304
- const SESSION_TITLE_RE = /^(\d{4})\s*-\s*(\d{4}-\d{2}-\d{2})\s*-\s*(.+)\.md$/;
305
117
  const titleInsertChunk = db.prepare(`
306
118
  INSERT OR IGNORE INTO memory_chunks (id, project_id, source, tier, path, start_line, end_line, hash, text, updated_at)
307
119
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
@@ -312,11 +124,8 @@ async function indexProject(db, projectId, rootPath, claudeNotesDir) {
312
124
  `);
313
125
  const updatedAt = Date.now();
314
126
  for (const absPath of walkMdFiles(notesDir)) {
315
- const fileName = basename(absPath);
316
- const m = SESSION_TITLE_RE.exec(fileName);
317
- if (!m) continue;
318
- const [, num, date, title] = m;
319
- const text = `Session #${num} ${date}: ${title}`;
127
+ const text = parseSessionTitleChunk(basename(absPath));
128
+ if (!text) continue;
320
129
  const syntheticPath = `${relative(rootPath, absPath)}::title`;
321
130
  const id = chunkId(projectId, syntheticPath, 0, 0, 0);
322
131
  const hash = sha256File(text);
@@ -340,7 +149,6 @@ async function indexProject(db, projectId, rootPath, claudeNotesDir) {
340
149
  tier: "session"
341
150
  });
342
151
  {
343
- const SESSION_TITLE_RE_CLAUDE = /^(\d{4})\s*-\s*(\d{4}-\d{2}-\d{2})\s*-\s*(.+)\.md$/;
344
152
  const updatedAt = Date.now();
345
153
  const titleInsertChunk2 = db.prepare(`
346
154
  INSERT OR IGNORE INTO memory_chunks (id, project_id, source, tier, path, start_line, end_line, hash, text, updated_at)
@@ -351,11 +159,8 @@ async function indexProject(db, projectId, rootPath, claudeNotesDir) {
351
159
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)
352
160
  `);
353
161
  for (const absPath of walkMdFiles(claudeNotesDir)) {
354
- const fileName = basename(absPath);
355
- const m = SESSION_TITLE_RE_CLAUDE.exec(fileName);
356
- if (!m) continue;
357
- const [, num, date, title] = m;
358
- const text = `Session #${num} ${date}: ${title}`;
162
+ const text = parseSessionTitleChunk(basename(absPath));
163
+ if (!text) continue;
359
164
  const syntheticPath = `${relative(claudeNotesDir, absPath)}::title`;
360
165
  const id = chunkId(projectId, syntheticPath, 0, 0, 0);
361
166
  const hash = sha256File(text);
@@ -425,13 +230,6 @@ async function indexProject(db, projectId, rootPath, claudeNotesDir) {
425
230
  return result;
426
231
  }
427
232
  /**
428
- * Yield to the Node.js event loop between projects so the IPC server
429
- * remains responsive during long index runs.
430
- */
431
- function yieldToEventLoop() {
432
- return new Promise((resolve) => setImmediate(resolve));
433
- }
434
- /**
435
233
  * Index all active projects registered in the registry DB.
436
234
  *
437
235
  * Async: yields to the event loop between each project so that the daemon's
@@ -508,5 +306,5 @@ async function embedChunks(db, projectId, batchSize = 50, onProgress) {
508
306
  }
509
307
 
510
308
  //#endregion
511
- export { indexProject as a, indexFile as i, embedChunks as n, indexAll as r, detectTier as t };
512
- //# sourceMappingURL=indexer-CMPOiY1r.mjs.map
309
+ export { indexProject as i, indexAll as n, indexFile as r, embedChunks as t };
310
+ //# sourceMappingURL=sync-BOsnEj2-.mjs.map