@tekmidian/pai 0.5.7 → 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 +87 -1
  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 +1482 -1628
  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 +11 -8
  12. package/dist/daemon/index.mjs.map +1 -1
  13. package/dist/{daemon-2ND5WO2j.mjs → daemon-D3hYb5_C.mjs} +669 -218
  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-DdUperSl.mjs +110 -0
  18. package/dist/db-DdUperSl.mjs.map +1 -0
  19. package/dist/{detect-BU3Nx_2L.mjs → detect-CdaA48EI.mjs} +1 -1
  20. package/dist/{detect-BU3Nx_2L.mjs.map → detect-CdaA48EI.mjs.map} +1 -1
  21. package/dist/{detector-Bp-2SM3x.mjs → detector-jGBuYQJM.mjs} +2 -2
  22. package/dist/{detector-Bp-2SM3x.mjs.map → detector-jGBuYQJM.mjs.map} +1 -1
  23. package/dist/{factory-Bzcy70G9.mjs → factory-Ygqe_bVZ.mjs} +7 -5
  24. package/dist/{factory-Bzcy70G9.mjs.map → factory-Ygqe_bVZ.mjs.map} +1 -1
  25. package/dist/helpers-BEST-4Gx.mjs +420 -0
  26. package/dist/helpers-BEST-4Gx.mjs.map +1 -0
  27. package/dist/hooks/capture-all-events.mjs +2 -2
  28. package/dist/hooks/capture-all-events.mjs.map +3 -3
  29. package/dist/hooks/capture-session-summary.mjs +38 -0
  30. package/dist/hooks/capture-session-summary.mjs.map +3 -3
  31. package/dist/hooks/cleanup-session-files.mjs +6 -12
  32. package/dist/hooks/cleanup-session-files.mjs.map +4 -4
  33. package/dist/hooks/context-compression-hook.mjs +93 -104
  34. package/dist/hooks/context-compression-hook.mjs.map +4 -4
  35. package/dist/hooks/initialize-session.mjs +14 -11
  36. package/dist/hooks/initialize-session.mjs.map +4 -4
  37. package/dist/hooks/inject-observations.mjs +220 -0
  38. package/dist/hooks/inject-observations.mjs.map +7 -0
  39. package/dist/hooks/load-core-context.mjs +2 -2
  40. package/dist/hooks/load-core-context.mjs.map +3 -3
  41. package/dist/hooks/load-project-context.mjs +90 -91
  42. package/dist/hooks/load-project-context.mjs.map +4 -4
  43. package/dist/hooks/observe.mjs +354 -0
  44. package/dist/hooks/observe.mjs.map +7 -0
  45. package/dist/hooks/stop-hook.mjs +94 -107
  46. package/dist/hooks/stop-hook.mjs.map +4 -4
  47. package/dist/hooks/sync-todo-to-md.mjs +31 -33
  48. package/dist/hooks/sync-todo-to-md.mjs.map +4 -4
  49. package/dist/index.d.mts +30 -7
  50. package/dist/index.d.mts.map +1 -1
  51. package/dist/index.mjs +5 -8
  52. package/dist/indexer-D53l5d1U.mjs +1 -0
  53. package/dist/{indexer-backend-CIMXedqk.mjs → indexer-backend-jcJFsmB4.mjs} +37 -127
  54. package/dist/indexer-backend-jcJFsmB4.mjs.map +1 -0
  55. package/dist/{ipc-client-Bjg_a1dc.mjs → ipc-client-CoyUHPod.mjs} +2 -7
  56. package/dist/{ipc-client-Bjg_a1dc.mjs.map → ipc-client-CoyUHPod.mjs.map} +1 -1
  57. package/dist/latent-ideas-bTJo6Omd.mjs +191 -0
  58. package/dist/latent-ideas-bTJo6Omd.mjs.map +1 -0
  59. package/dist/neighborhood-BYYbEkUJ.mjs +135 -0
  60. package/dist/neighborhood-BYYbEkUJ.mjs.map +1 -0
  61. package/dist/note-context-BK24bX8Y.mjs +126 -0
  62. package/dist/note-context-BK24bX8Y.mjs.map +1 -0
  63. package/dist/postgres-CKf-EDtS.mjs +846 -0
  64. package/dist/postgres-CKf-EDtS.mjs.map +1 -0
  65. package/dist/{reranker-D7bRAHi6.mjs → reranker-CMNZcfVx.mjs} +1 -1
  66. package/dist/{reranker-D7bRAHi6.mjs.map → reranker-CMNZcfVx.mjs.map} +1 -1
  67. package/dist/{search-_oHfguA5.mjs → search-DC1qhkKn.mjs} +2 -58
  68. package/dist/search-DC1qhkKn.mjs.map +1 -0
  69. package/dist/{sqlite-WWBq7_2C.mjs → sqlite-l-s9xPjY.mjs} +160 -3
  70. package/dist/sqlite-l-s9xPjY.mjs.map +1 -0
  71. package/dist/state-C6_vqz7w.mjs +102 -0
  72. package/dist/state-C6_vqz7w.mjs.map +1 -0
  73. package/dist/stop-words-BaMEGVeY.mjs +326 -0
  74. package/dist/stop-words-BaMEGVeY.mjs.map +1 -0
  75. package/dist/{indexer-CMPOiY1r.mjs → sync-BOsnEj2-.mjs} +14 -216
  76. package/dist/sync-BOsnEj2-.mjs.map +1 -0
  77. package/dist/themes-BvYF0W8T.mjs +148 -0
  78. package/dist/themes-BvYF0W8T.mjs.map +1 -0
  79. package/dist/{tools-DV_lsiCc.mjs → tools-DcaJlYDN.mjs} +162 -273
  80. package/dist/tools-DcaJlYDN.mjs.map +1 -0
  81. package/dist/trace-CRx9lPuc.mjs +137 -0
  82. package/dist/trace-CRx9lPuc.mjs.map +1 -0
  83. package/dist/{vault-indexer-k-kUlaZ-.mjs → vault-indexer-Bi2cRmn7.mjs} +134 -132
  84. package/dist/vault-indexer-Bi2cRmn7.mjs.map +1 -0
  85. package/dist/zettelkasten-cdajbnPr.mjs +708 -0
  86. package/dist/zettelkasten-cdajbnPr.mjs.map +1 -0
  87. package/package.json +1 -2
  88. package/src/hooks/ts/lib/project-utils/index.ts +50 -0
  89. package/src/hooks/ts/lib/project-utils/notify.ts +75 -0
  90. package/src/hooks/ts/lib/project-utils/paths.ts +218 -0
  91. package/src/hooks/ts/lib/project-utils/session-notes.ts +363 -0
  92. package/src/hooks/ts/lib/project-utils/todo.ts +178 -0
  93. package/src/hooks/ts/lib/project-utils/tokens.ts +39 -0
  94. package/src/hooks/ts/lib/project-utils.ts +40 -1018
  95. package/src/hooks/ts/post-tool-use/observe.ts +327 -0
  96. package/src/hooks/ts/session-end/capture-session-summary.ts +41 -0
  97. package/src/hooks/ts/session-start/inject-observations.ts +254 -0
  98. package/dist/chunker-CbnBe0s0.mjs +0 -191
  99. package/dist/chunker-CbnBe0s0.mjs.map +0 -1
  100. package/dist/config-Cf92lGX_.mjs.map +0 -1
  101. package/dist/daemon-2ND5WO2j.mjs.map +0 -1
  102. package/dist/db-Dp8VXIMR.mjs +0 -212
  103. package/dist/db-Dp8VXIMR.mjs.map +0 -1
  104. package/dist/indexer-CMPOiY1r.mjs.map +0 -1
  105. package/dist/indexer-backend-CIMXedqk.mjs.map +0 -1
  106. package/dist/mcp/index.d.mts +0 -1
  107. package/dist/mcp/index.mjs +0 -500
  108. package/dist/mcp/index.mjs.map +0 -1
  109. package/dist/postgres-FXrHDPcE.mjs +0 -358
  110. package/dist/postgres-FXrHDPcE.mjs.map +0 -1
  111. package/dist/schemas-BFIgGntb.mjs +0 -3405
  112. package/dist/schemas-BFIgGntb.mjs.map +0 -1
  113. package/dist/search-_oHfguA5.mjs.map +0 -1
  114. package/dist/sqlite-WWBq7_2C.mjs.map +0 -1
  115. package/dist/tools-DV_lsiCc.mjs.map +0 -1
  116. package/dist/vault-indexer-k-kUlaZ-.mjs.map +0 -1
  117. package/dist/zettelkasten-e-a4rW_6.mjs +0 -901
  118. package/dist/zettelkasten-e-a4rW_6.mjs.map +0 -1
  119. package/templates/README.md +0 -181
  120. package/templates/skills/CORE/Aesthetic.md +0 -333
  121. package/templates/skills/CORE/CONSTITUTION.md +0 -1502
  122. package/templates/skills/CORE/HistorySystem.md +0 -427
  123. package/templates/skills/CORE/HookSystem.md +0 -1082
  124. package/templates/skills/CORE/Prompting.md +0 -509
  125. package/templates/skills/CORE/ProsodyAgentTemplate.md +0 -53
  126. package/templates/skills/CORE/ProsodyGuide.md +0 -416
  127. package/templates/skills/CORE/SKILL.md +0 -741
  128. package/templates/skills/CORE/SkillSystem.md +0 -213
  129. package/templates/skills/CORE/TerminalTabs.md +0 -119
  130. package/templates/skills/CORE/VOICE.md +0 -106
  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
@@ -1,42 +1,13 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-95iHPtFO.mjs";
2
- import { i as searchMemoryHybrid, n as populateSlugs } from "./search-_oHfguA5.mjs";
3
- import { r as formatDetectionJson, t as detectProject } from "./detect-BU3Nx_2L.mjs";
2
+ import { i as searchMemoryHybrid, n as populateSlugs } from "./search-DC1qhkKn.mjs";
3
+ import { r as formatDetectionJson, t as detectProject } from "./detect-CdaA48EI.mjs";
4
4
  import { existsSync, readFileSync, statSync } from "node:fs";
5
5
  import { isAbsolute, join, resolve } from "node:path";
6
6
 
7
- //#region src/mcp/tools.ts
7
+ //#region src/mcp/tools/types.ts
8
8
  /**
9
- * PAI Knowledge OS Pure tool handler functions (shared by daemon + legacy MCP server)
10
- *
11
- * Each function accepts pre-opened database handles and raw params, executes
12
- * the tool logic, and returns an MCP-style content array.
13
- *
14
- * This module does NOT import indexAll() — indexing is handled by the daemon
15
- * on its own schedule. The search hot path is pure DB read.
9
+ * Shared types and project-row helpers used across all MCP tool handler modules.
16
10
  */
17
- var tools_exports = /* @__PURE__ */ __exportAll({
18
- detectProjectFromPath: () => detectProjectFromPath,
19
- formatProject: () => formatProject,
20
- lookupProjectId: () => lookupProjectId,
21
- toolMemoryGet: () => toolMemoryGet,
22
- toolMemorySearch: () => toolMemorySearch,
23
- toolNotificationConfig: () => toolNotificationConfig,
24
- toolProjectDetect: () => toolProjectDetect,
25
- toolProjectHealth: () => toolProjectHealth,
26
- toolProjectInfo: () => toolProjectInfo,
27
- toolProjectList: () => toolProjectList,
28
- toolProjectTodo: () => toolProjectTodo,
29
- toolRegistrySearch: () => toolRegistrySearch,
30
- toolSessionList: () => toolSessionList,
31
- toolSessionRoute: () => toolSessionRoute,
32
- toolTopicDetect: () => toolTopicDetect,
33
- toolZettelConverse: () => toolZettelConverse,
34
- toolZettelExplore: () => toolZettelExplore,
35
- toolZettelHealth: () => toolZettelHealth,
36
- toolZettelSuggest: () => toolZettelSuggest,
37
- toolZettelSurprise: () => toolZettelSurprise,
38
- toolZettelThemes: () => toolZettelThemes
39
- });
40
11
  function lookupProjectId(registryDb, slug) {
41
12
  const bySlug = registryDb.prepare("SELECT id FROM projects WHERE slug = ?").get(slug);
42
13
  if (bySlug) return bySlug.id;
@@ -75,6 +46,12 @@ function formatProject(registryDb, project) {
75
46
  if (project.archived_at) lines.push(`archived_at: ${new Date(project.archived_at).toISOString().slice(0, 10)}`);
76
47
  return lines.join("\n");
77
48
  }
49
+
50
+ //#endregion
51
+ //#region src/mcp/tools/memory.ts
52
+ /**
53
+ * MCP tool handlers: memory_search, memory_get
54
+ */
78
55
  async function toolMemorySearch(registryDb, federation, params, searchDefaults) {
79
56
  try {
80
57
  const projectIds = params.project ? (() => {
@@ -114,7 +91,7 @@ async function toolMemorySearch(registryDb, federation, params, searchDefaults)
114
91
  }
115
92
  } else results = await federation.searchKeyword(params.query, searchOpts);
116
93
  else {
117
- const { searchMemory, searchMemorySemantic } = await import("./search-_oHfguA5.mjs").then((n) => n.o);
94
+ const { searchMemory, searchMemorySemantic } = await import("./search-DC1qhkKn.mjs").then((n) => n.o);
118
95
  if (mode === "keyword") results = searchMemory(federation, params.query, searchOpts);
119
96
  else if (mode === "semantic" || mode === "hybrid") {
120
97
  const { generateEmbedding } = await import("./embeddings-DGRAPAYb.mjs").then((n) => n.i);
@@ -125,12 +102,12 @@ async function toolMemorySearch(registryDb, federation, params, searchDefaults)
125
102
  }
126
103
  const shouldRerank = params.rerank ?? searchDefaults?.rerank ?? true;
127
104
  if (shouldRerank && results.length > 0) {
128
- const { rerankResults } = await import("./reranker-D7bRAHi6.mjs").then((n) => n.r);
105
+ const { rerankResults } = await import("./reranker-CMNZcfVx.mjs").then((n) => n.r);
129
106
  results = await rerankResults(params.query, results, { topK: searchOpts.maxResults ?? 5 });
130
107
  }
131
108
  const recencyDays = params.recencyBoost ?? searchDefaults?.recencyBoostDays ?? 0;
132
109
  if (recencyDays > 0 && results.length > 0) {
133
- const { applyRecencyBoost } = await import("./search-_oHfguA5.mjs").then((n) => n.o);
110
+ const { applyRecencyBoost } = await import("./search-DC1qhkKn.mjs").then((n) => n.o);
134
111
  results = applyRecencyBoost(results, recencyDays);
135
112
  }
136
113
  const withSlugs = populateSlugs(results, registryDb);
@@ -224,6 +201,48 @@ function toolMemoryGet(registryDb, params) {
224
201
  };
225
202
  }
226
203
  }
204
+ /**
205
+ * Combine keyword + semantic results using min-max normalized scoring.
206
+ * Mirrors the logic in searchMemoryHybrid() from memory/search.ts,
207
+ * but works on pre-computed result arrays so it works for any backend.
208
+ */
209
+ function combineHybridResults(keywordResults, semanticResults, maxResults, keywordWeight = .5, semanticWeight = .5) {
210
+ if (keywordResults.length === 0 && semanticResults.length === 0) return [];
211
+ const keyFor = (r) => `${r.projectId}:${r.path}:${r.startLine}:${r.endLine}`;
212
+ function minMaxNormalize(items) {
213
+ if (items.length === 0) return /* @__PURE__ */ new Map();
214
+ const min = Math.min(...items.map((r) => r.score));
215
+ const range = Math.max(...items.map((r) => r.score)) - min;
216
+ const m = /* @__PURE__ */ new Map();
217
+ for (const r of items) m.set(keyFor(r), range === 0 ? 1 : (r.score - min) / range);
218
+ return m;
219
+ }
220
+ const kwNorm = minMaxNormalize(keywordResults);
221
+ const semNorm = minMaxNormalize(semanticResults);
222
+ const allKeys = new Set([...keywordResults.map(keyFor), ...semanticResults.map(keyFor)]);
223
+ const metaMap = /* @__PURE__ */ new Map();
224
+ for (const r of [...keywordResults, ...semanticResults]) metaMap.set(keyFor(r), r);
225
+ const combined = [];
226
+ for (const key of allKeys) {
227
+ const meta = metaMap.get(key);
228
+ const kwScore = kwNorm.get(key) ?? 0;
229
+ const semScore = semNorm.get(key) ?? 0;
230
+ const combinedScore = keywordWeight * kwScore + semanticWeight * semScore;
231
+ combined.push({
232
+ ...meta,
233
+ score: combinedScore,
234
+ combinedScore
235
+ });
236
+ }
237
+ return combined.sort((a, b) => b.score - a.score).slice(0, maxResults).map(({ combinedScore: _unused, ...r }) => r);
238
+ }
239
+
240
+ //#endregion
241
+ //#region src/mcp/tools/projects.ts
242
+ /**
243
+ * MCP tool handlers: project_info, project_list, project_detect,
244
+ * project_health, project_todo
245
+ */
227
246
  function toolProjectInfo(registryDb, params) {
228
247
  try {
229
248
  let project = null;
@@ -291,77 +310,6 @@ function toolProjectList(registryDb, params) {
291
310
  };
292
311
  }
293
312
  }
294
- function toolSessionList(registryDb, params) {
295
- try {
296
- const projectId = lookupProjectId(registryDb, params.project);
297
- if (projectId == null) return {
298
- content: [{
299
- type: "text",
300
- text: `Project not found: ${params.project}`
301
- }],
302
- isError: true
303
- };
304
- const conditions = ["project_id = ?"];
305
- const queryParams = [projectId];
306
- if (params.status) {
307
- conditions.push("status = ?");
308
- queryParams.push(params.status);
309
- }
310
- const limit = params.limit ?? 10;
311
- queryParams.push(limit);
312
- const sessions = registryDb.prepare(`SELECT number, date, title, filename, status
313
- FROM sessions
314
- WHERE ${conditions.join(" AND ")}
315
- ORDER BY number DESC
316
- LIMIT ?`).all(...queryParams);
317
- if (sessions.length === 0) return { content: [{
318
- type: "text",
319
- text: `No sessions found for project: ${params.project}`
320
- }] };
321
- const lines = sessions.map((s) => `#${String(s.number).padStart(4, "0")} ${s.date} [${s.status}] ${s.title}\n file: Notes/${s.filename}`);
322
- return { content: [{
323
- type: "text",
324
- text: `${sessions.length} session(s) for ${params.project}:\n\n${lines.join("\n\n")}`
325
- }] };
326
- } catch (e) {
327
- return {
328
- content: [{
329
- type: "text",
330
- text: `session_list error: ${String(e)}`
331
- }],
332
- isError: true
333
- };
334
- }
335
- }
336
- function toolRegistrySearch(registryDb, params) {
337
- try {
338
- const q = `%${params.query}%`;
339
- const projects = registryDb.prepare(`SELECT id, slug, display_name, root_path, type, status, updated_at
340
- FROM projects
341
- WHERE slug LIKE ?
342
- OR display_name LIKE ?
343
- OR root_path LIKE ?
344
- ORDER BY updated_at DESC
345
- LIMIT 20`).all(q, q, q);
346
- if (projects.length === 0) return { content: [{
347
- type: "text",
348
- text: `No projects found matching: "${params.query}"`
349
- }] };
350
- const lines = projects.map((p) => `${p.slug} [${p.status}] ${p.root_path}`);
351
- return { content: [{
352
- type: "text",
353
- text: `${projects.length} match(es) for "${params.query}":\n\n${lines.join("\n")}`
354
- }] };
355
- } catch (e) {
356
- return {
357
- content: [{
358
- type: "text",
359
- text: `registry_search error: ${String(e)}`
360
- }],
361
- isError: true
362
- };
363
- }
364
- }
365
313
  function toolProjectDetect(registryDb, params) {
366
314
  try {
367
315
  const detection = detectProject(registryDb, params.cwd);
@@ -630,130 +578,46 @@ function toolProjectTodo(registryDb, params) {
630
578
  };
631
579
  }
632
580
  }
633
- /**
634
- * Handle notification config queries and updates via the daemon IPC.
635
- * Falls back gracefully if the daemon is not running.
636
- */
637
- async function toolNotificationConfig(params) {
581
+
582
+ //#endregion
583
+ //#region src/mcp/tools/sessions.ts
584
+ function toolSessionList(registryDb, params) {
638
585
  try {
639
- const { PaiClient } = await import("./ipc-client-Bjg_a1dc.mjs").then((n) => n.n);
640
- const client = new PaiClient();
641
- if (params.action === "get") {
642
- const { config, activeChannels } = await client.getNotificationConfig();
643
- return { content: [{
644
- type: "text",
645
- text: [
646
- `mode: ${config.mode}`,
647
- `active_channels: ${activeChannels.join(", ") || "(none)"}`,
648
- "",
649
- "channels:",
650
- ...Object.entries(config.channels).map(([ch, cfg]) => {
651
- return ` ${ch}: ${cfg.enabled ? "enabled" : "disabled"}`;
652
- }),
653
- "",
654
- "routing:",
655
- ...Object.entries(config.routing).map(([event, channels]) => ` ${event}: ${channels.join(", ") || "(none)"}`)
656
- ].join("\n")
657
- }] };
658
- }
659
- if (params.action === "set") {
660
- if (!params.mode && !params.channels && !params.routing) return {
661
- content: [{
662
- type: "text",
663
- text: "notification_config set: provide at least one of mode, channels, or routing."
664
- }],
665
- isError: true
666
- };
667
- return { content: [{
668
- type: "text",
669
- text: `Notification config updated. Mode: ${(await client.setNotificationConfig({
670
- mode: params.mode,
671
- channels: params.channels,
672
- routing: params.routing
673
- })).config.mode}`
674
- }] };
675
- }
676
- if (params.action === "send") {
677
- if (!params.message) return {
678
- content: [{
679
- type: "text",
680
- text: "notification_config send: message is required."
681
- }],
682
- isError: true
683
- };
684
- const result = await client.sendNotification({
685
- event: params.event ?? "info",
686
- message: params.message,
687
- title: params.title
688
- });
689
- return { content: [{
690
- type: "text",
691
- text: [
692
- `mode: ${result.mode}`,
693
- `attempted: ${result.channelsAttempted.join(", ") || "(none)"}`,
694
- `succeeded: ${result.channelsSucceeded.join(", ") || "(none)"}`,
695
- ...result.channelsFailed.length > 0 ? [`failed: ${result.channelsFailed.join(", ")}`] : []
696
- ].join("\n")
697
- }] };
698
- }
699
- return {
700
- content: [{
701
- type: "text",
702
- text: `Unknown action: ${String(params.action)}. Use "get", "set", or "send".`
703
- }],
704
- isError: true
705
- };
706
- } catch (e) {
707
- return {
586
+ const projectId = lookupProjectId(registryDb, params.project);
587
+ if (projectId == null) return {
708
588
  content: [{
709
589
  type: "text",
710
- text: `notification_config error: ${String(e)}`
590
+ text: `Project not found: ${params.project}`
711
591
  }],
712
592
  isError: true
713
593
  };
714
- }
715
- }
716
- /**
717
- * Detect whether recent conversation context has shifted to a different project.
718
- * Uses memory_search to find which project best matches the context, then
719
- * compares against the current project.
720
- *
721
- * Calls the daemon via IPC so it has access to the storage backend.
722
- * Falls back gracefully if the daemon is not running.
723
- */
724
- async function toolTopicDetect(params) {
725
- try {
726
- const { PaiClient } = await import("./ipc-client-Bjg_a1dc.mjs").then((n) => n.n);
727
- const result = await new PaiClient().topicCheck({
728
- context: params.context,
729
- currentProject: params.current_project,
730
- threshold: params.threshold
731
- });
732
- const lines = [
733
- `shifted: ${result.shifted}`,
734
- `current_project: ${result.currentProject ?? "(none)"}`,
735
- `suggested_project: ${result.suggestedProject ?? "(none)"}`,
736
- `confidence: ${result.confidence.toFixed(3)}`,
737
- `chunks_scored: ${result.chunkCount}`
738
- ];
739
- if (result.topProjects.length > 0) {
740
- lines.push("");
741
- lines.push("top_matches:");
742
- for (const p of result.topProjects) lines.push(` ${p.slug}: ${(p.score * 100).toFixed(1)}%`);
743
- }
744
- if (result.shifted) {
745
- lines.push("");
746
- lines.push(`TOPIC SHIFT DETECTED: conversation appears to be about "${result.suggestedProject}" (confidence: ${(result.confidence * 100).toFixed(0)}%), not "${result.currentProject}".`);
594
+ const conditions = ["project_id = ?"];
595
+ const queryParams = [projectId];
596
+ if (params.status) {
597
+ conditions.push("status = ?");
598
+ queryParams.push(params.status);
747
599
  }
600
+ const limit = params.limit ?? 10;
601
+ queryParams.push(limit);
602
+ const sessions = registryDb.prepare(`SELECT number, date, title, filename, status
603
+ FROM sessions
604
+ WHERE ${conditions.join(" AND ")}
605
+ ORDER BY number DESC
606
+ LIMIT ?`).all(...queryParams);
607
+ if (sessions.length === 0) return { content: [{
608
+ type: "text",
609
+ text: `No sessions found for project: ${params.project}`
610
+ }] };
611
+ const lines = sessions.map((s) => `#${String(s.number).padStart(4, "0")} ${s.date} [${s.status}] ${s.title}\n file: Notes/${s.filename}`);
748
612
  return { content: [{
749
613
  type: "text",
750
- text: lines.join("\n")
614
+ text: `${sessions.length} session(s) for ${params.project}:\n\n${lines.join("\n\n")}`
751
615
  }] };
752
616
  } catch (e) {
753
617
  return {
754
618
  content: [{
755
619
  type: "text",
756
- text: `topic_detect error: ${String(e)}`
620
+ text: `session_list error: ${String(e)}`
757
621
  }],
758
622
  isError: true
759
623
  };
@@ -772,7 +636,7 @@ async function toolTopicDetect(params) {
772
636
  */
773
637
  async function toolSessionRoute(registryDb, federation, params) {
774
638
  try {
775
- const { autoRoute, formatAutoRouteJson } = await import("./auto-route-BG6I_4B1.mjs");
639
+ const { autoRoute, formatAutoRouteJson } = await import("./auto-route-C-DrW6BL.mjs");
776
640
  const result = await autoRoute(registryDb, federation, params.cwd, params.context);
777
641
  if (!result) return { content: [{
778
642
  type: "text",
@@ -799,10 +663,45 @@ async function toolSessionRoute(registryDb, federation, params) {
799
663
  };
800
664
  }
801
665
  }
802
- async function toolZettelExplore(federationDb, params) {
666
+
667
+ //#endregion
668
+ //#region src/mcp/tools/registry.ts
669
+ function toolRegistrySearch(registryDb, params) {
803
670
  try {
804
- const { zettelExplore } = await import("./zettelkasten-e-a4rW_6.mjs");
805
- const result = zettelExplore(federationDb, {
671
+ const q = `%${params.query}%`;
672
+ const projects = registryDb.prepare(`SELECT id, slug, display_name, root_path, type, status, updated_at
673
+ FROM projects
674
+ WHERE slug LIKE ?
675
+ OR display_name LIKE ?
676
+ OR root_path LIKE ?
677
+ ORDER BY updated_at DESC
678
+ LIMIT 20`).all(q, q, q);
679
+ if (projects.length === 0) return { content: [{
680
+ type: "text",
681
+ text: `No projects found matching: "${params.query}"`
682
+ }] };
683
+ const lines = projects.map((p) => `${p.slug} [${p.status}] ${p.root_path}`);
684
+ return { content: [{
685
+ type: "text",
686
+ text: `${projects.length} match(es) for "${params.query}":\n\n${lines.join("\n")}`
687
+ }] };
688
+ } catch (e) {
689
+ return {
690
+ content: [{
691
+ type: "text",
692
+ text: `registry_search error: ${String(e)}`
693
+ }],
694
+ isError: true
695
+ };
696
+ }
697
+ }
698
+
699
+ //#endregion
700
+ //#region src/mcp/tools/zettel.ts
701
+ async function toolZettelExplore(backend, params) {
702
+ try {
703
+ const { zettelExplore } = await import("./zettelkasten-cdajbnPr.mjs");
704
+ const result = await zettelExplore(backend, {
806
705
  startNote: params.start_note,
807
706
  depth: params.depth,
808
707
  direction: params.direction,
@@ -822,10 +721,10 @@ async function toolZettelExplore(federationDb, params) {
822
721
  };
823
722
  }
824
723
  }
825
- async function toolZettelHealth(federationDb, params) {
724
+ async function toolZettelHealth(backend, params) {
826
725
  try {
827
- const { zettelHealth } = await import("./zettelkasten-e-a4rW_6.mjs");
828
- const result = zettelHealth(federationDb, {
726
+ const { zettelHealth } = await import("./zettelkasten-cdajbnPr.mjs");
727
+ const result = await zettelHealth(backend, {
829
728
  scope: params.scope,
830
729
  projectPath: params.project_path,
831
730
  recentDays: params.recent_days,
@@ -845,10 +744,10 @@ async function toolZettelHealth(federationDb, params) {
845
744
  };
846
745
  }
847
746
  }
848
- async function toolZettelSurprise(federationDb, params) {
747
+ async function toolZettelSurprise(backend, params) {
849
748
  try {
850
- const { zettelSurprise } = await import("./zettelkasten-e-a4rW_6.mjs");
851
- const results = await zettelSurprise(federationDb, {
749
+ const { zettelSurprise } = await import("./zettelkasten-cdajbnPr.mjs");
750
+ const results = await zettelSurprise(backend, {
852
751
  referencePath: params.reference_path,
853
752
  vaultProjectId: params.vault_project_id,
854
753
  limit: params.limit,
@@ -869,10 +768,10 @@ async function toolZettelSurprise(federationDb, params) {
869
768
  };
870
769
  }
871
770
  }
872
- async function toolZettelSuggest(federationDb, params) {
771
+ async function toolZettelSuggest(backend, params) {
873
772
  try {
874
- const { zettelSuggest } = await import("./zettelkasten-e-a4rW_6.mjs");
875
- const results = await zettelSuggest(federationDb, {
773
+ const { zettelSuggest } = await import("./zettelkasten-cdajbnPr.mjs");
774
+ const results = await zettelSuggest(backend, {
876
775
  notePath: params.note_path,
877
776
  vaultProjectId: params.vault_project_id,
878
777
  limit: params.limit,
@@ -892,10 +791,10 @@ async function toolZettelSuggest(federationDb, params) {
892
791
  };
893
792
  }
894
793
  }
895
- async function toolZettelConverse(federationDb, params) {
794
+ async function toolZettelConverse(backend, params) {
896
795
  try {
897
- const { zettelConverse } = await import("./zettelkasten-e-a4rW_6.mjs");
898
- const result = await zettelConverse(federationDb, {
796
+ const { zettelConverse } = await import("./zettelkasten-cdajbnPr.mjs");
797
+ const result = await zettelConverse(backend, {
899
798
  question: params.question,
900
799
  vaultProjectId: params.vault_project_id,
901
800
  depth: params.depth,
@@ -915,10 +814,10 @@ async function toolZettelConverse(federationDb, params) {
915
814
  };
916
815
  }
917
816
  }
918
- async function toolZettelThemes(federationDb, params) {
817
+ async function toolZettelThemes(backend, params) {
919
818
  try {
920
- const { zettelThemes } = await import("./zettelkasten-e-a4rW_6.mjs");
921
- const result = await zettelThemes(federationDb, {
819
+ const { zettelThemes } = await import("./zettelkasten-cdajbnPr.mjs");
820
+ const result = await zettelThemes(backend, {
922
821
  vaultProjectId: params.vault_project_id,
923
822
  lookbackDays: params.lookback_days,
924
823
  minClusterSize: params.min_cluster_size,
@@ -939,42 +838,32 @@ async function toolZettelThemes(federationDb, params) {
939
838
  };
940
839
  }
941
840
  }
942
- /**
943
- * Combine keyword + semantic results using min-max normalized scoring.
944
- * Mirrors the logic in searchMemoryHybrid() from memory/search.ts,
945
- * but works on pre-computed result arrays so it works for any backend.
946
- */
947
- function combineHybridResults(keywordResults, semanticResults, maxResults, keywordWeight = .5, semanticWeight = .5) {
948
- if (keywordResults.length === 0 && semanticResults.length === 0) return [];
949
- const keyFor = (r) => `${r.projectId}:${r.path}:${r.startLine}:${r.endLine}`;
950
- function minMaxNormalize(items) {
951
- if (items.length === 0) return /* @__PURE__ */ new Map();
952
- const min = Math.min(...items.map((r) => r.score));
953
- const range = Math.max(...items.map((r) => r.score)) - min;
954
- const m = /* @__PURE__ */ new Map();
955
- for (const r of items) m.set(keyFor(r), range === 0 ? 1 : (r.score - min) / range);
956
- return m;
957
- }
958
- const kwNorm = minMaxNormalize(keywordResults);
959
- const semNorm = minMaxNormalize(semanticResults);
960
- const allKeys = new Set([...keywordResults.map(keyFor), ...semanticResults.map(keyFor)]);
961
- const metaMap = /* @__PURE__ */ new Map();
962
- for (const r of [...keywordResults, ...semanticResults]) metaMap.set(keyFor(r), r);
963
- const combined = [];
964
- for (const key of allKeys) {
965
- const meta = metaMap.get(key);
966
- const kwScore = kwNorm.get(key) ?? 0;
967
- const semScore = semNorm.get(key) ?? 0;
968
- const combinedScore = keywordWeight * kwScore + semanticWeight * semScore;
969
- combined.push({
970
- ...meta,
971
- score: combinedScore,
972
- combinedScore
973
- });
974
- }
975
- return combined.sort((a, b) => b.score - a.score).slice(0, maxResults).map(({ combinedScore: _unused, ...r }) => r);
976
- }
977
841
 
978
842
  //#endregion
979
- export { toolZettelSurprise as _, toolProjectHealth as a, toolProjectTodo as c, toolSessionRoute as d, toolTopicDetect as f, toolZettelSuggest as g, toolZettelHealth as h, toolProjectDetect as i, toolRegistrySearch as l, toolZettelExplore as m, toolMemorySearch as n, toolProjectInfo as o, toolZettelConverse as p, toolNotificationConfig as r, toolProjectList as s, toolMemoryGet as t, toolSessionList as u, toolZettelThemes as v, tools_exports as y };
980
- //# sourceMappingURL=tools-DV_lsiCc.mjs.map
843
+ //#region src/mcp/tools.ts
844
+ var tools_exports = /* @__PURE__ */ __exportAll({
845
+ combineHybridResults: () => combineHybridResults,
846
+ detectProjectFromPath: () => detectProjectFromPath,
847
+ formatProject: () => formatProject,
848
+ lookupProjectId: () => lookupProjectId,
849
+ toolMemoryGet: () => toolMemoryGet,
850
+ toolMemorySearch: () => toolMemorySearch,
851
+ toolProjectDetect: () => toolProjectDetect,
852
+ toolProjectHealth: () => toolProjectHealth,
853
+ toolProjectInfo: () => toolProjectInfo,
854
+ toolProjectList: () => toolProjectList,
855
+ toolProjectTodo: () => toolProjectTodo,
856
+ toolRegistrySearch: () => toolRegistrySearch,
857
+ toolSessionList: () => toolSessionList,
858
+ toolSessionRoute: () => toolSessionRoute,
859
+ toolZettelConverse: () => toolZettelConverse,
860
+ toolZettelExplore: () => toolZettelExplore,
861
+ toolZettelHealth: () => toolZettelHealth,
862
+ toolZettelSuggest: () => toolZettelSuggest,
863
+ toolZettelSurprise: () => toolZettelSurprise,
864
+ toolZettelThemes: () => toolZettelThemes
865
+ });
866
+
867
+ //#endregion
868
+ export { toolProjectDetect as a, toolProjectList as c, toolMemorySearch as d, toolSessionRoute as i, toolProjectTodo as l, toolRegistrySearch as n, toolProjectHealth as o, toolSessionList as r, toolProjectInfo as s, tools_exports as t, toolMemoryGet as u };
869
+ //# sourceMappingURL=tools-DcaJlYDN.mjs.map