squish-memory 1.0.2 → 1.1.5

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 (341) hide show
  1. package/.env.example +130 -0
  2. package/CHANGELOG.md +55 -0
  3. package/README.md +150 -287
  4. package/config/hooks/claude-code-hooks.json +39 -0
  5. package/config/hooks/cursor-hooks.json +30 -0
  6. package/config/hooks/opencode-hooks.json +30 -0
  7. package/config/hooks/windsurf-hooks.json +30 -0
  8. package/config/mcp-mode-semantics.json +23 -21
  9. package/config/plugin-manifest.json +101 -152
  10. package/{plugin.json → config/plugin.json} +2 -2
  11. package/config/settings.json +52 -51
  12. package/{commands → core/commands}/init.md +39 -39
  13. package/dist/config.d.ts +28 -4
  14. package/dist/config.js +97 -29
  15. package/dist/core/adapters/config/claude-code.d.ts +45 -0
  16. package/dist/core/adapters/config/claude-code.js +113 -0
  17. package/dist/core/adapters/config/cursor.d.ts +26 -0
  18. package/dist/core/adapters/config/cursor.js +74 -0
  19. package/dist/core/adapters/config/opencode.d.ts +23 -0
  20. package/dist/core/adapters/config/opencode.js +73 -0
  21. package/dist/core/adapters/config/windsurf.d.ts +26 -0
  22. package/dist/core/adapters/config/windsurf.js +74 -0
  23. package/dist/core/adapters/index.d.ts +45 -0
  24. package/dist/core/adapters/index.js +84 -0
  25. package/dist/core/adapters/scripts/install-adapter.d.ts +19 -0
  26. package/dist/core/adapters/scripts/install-adapter.js +149 -0
  27. package/dist/core/adapters/timeline.d.ts +23 -0
  28. package/dist/core/adapters/timeline.js +88 -0
  29. package/dist/core/adapters/types.d.ts +157 -0
  30. package/dist/core/adapters/types.js +50 -0
  31. package/dist/{algorithms → core/algorithms}/analytics/token-estimator.d.ts +1 -1
  32. package/dist/{algorithms → core/algorithms}/analytics/token-estimator.js +3 -3
  33. package/dist/{algorithms → core/algorithms}/detection/semantic-ranker.d.ts +1 -1
  34. package/dist/{algorithms → core/algorithms}/detection/semantic-ranker.js +1 -1
  35. package/dist/{algorithms → core/algorithms}/detection/two-stage-detector.d.ts +1 -1
  36. package/dist/{algorithms → core/algorithms}/detection/two-stage-detector.js +7 -10
  37. package/dist/{algorithms → core/algorithms}/handlers/approve-merge.js +4 -4
  38. package/dist/{algorithms → core/algorithms}/handlers/detect-duplicates.js +3 -3
  39. package/dist/{algorithms → core/algorithms}/handlers/get-stats.js +3 -3
  40. package/dist/{algorithms → core/algorithms}/handlers/list-proposals.js +3 -3
  41. package/dist/{algorithms → core/algorithms}/handlers/preview-merge.js +3 -3
  42. package/dist/{algorithms → core/algorithms}/handlers/reject-merge.js +3 -3
  43. package/dist/{algorithms → core/algorithms}/handlers/reverse-merge.js +3 -3
  44. package/dist/core/algorithms/index.d.ts +21 -0
  45. package/dist/core/algorithms/index.js +26 -0
  46. package/dist/core/algorithms/operations/cache-maintenance.d.ts +12 -0
  47. package/dist/core/algorithms/operations/cache-maintenance.js +157 -0
  48. package/dist/{algorithms → core/algorithms}/safety/safety-checks.d.ts +1 -1
  49. package/dist/{algorithms → core/algorithms}/strategies/merge-strategies.d.ts +19 -1
  50. package/dist/{algorithms → core/algorithms}/strategies/merge-strategies.js +74 -123
  51. package/dist/core/algorithms/types.d.ts +133 -0
  52. package/dist/core/algorithms/types.js +5 -0
  53. package/dist/core/associations.d.ts +1 -2
  54. package/dist/core/associations.js +1 -2
  55. package/dist/core/autosave.d.ts +19 -0
  56. package/dist/core/autosave.js +16 -0
  57. package/dist/{commands → core/commands}/managed-sync.js +5 -5
  58. package/dist/core/commands/mcp-server.js +739 -0
  59. package/dist/core/context/agent-context.d.ts +106 -0
  60. package/dist/core/context/agent-context.js +274 -0
  61. package/dist/core/{context-paging.d.ts → context/context-paging.d.ts} +2 -12
  62. package/dist/core/{context-paging.js → context/context-paging.js} +19 -39
  63. package/dist/core/context/context-window.d.ts +40 -0
  64. package/dist/core/context/context-window.js +177 -0
  65. package/dist/core/context/context.js +22 -0
  66. package/dist/core/embeddings.d.ts +1 -1
  67. package/dist/core/embeddings.js +54 -2
  68. package/dist/core/error-handling.d.ts +63 -0
  69. package/dist/core/error-handling.js +173 -0
  70. package/dist/core/external-folder/index.d.ts +102 -0
  71. package/dist/core/external-folder/index.js +294 -0
  72. package/dist/core/hooks/agent-hooks.d.ts +74 -0
  73. package/dist/core/hooks/agent-hooks.js +244 -0
  74. package/dist/core/hooks/auto-tagger.d.ts +19 -0
  75. package/dist/core/hooks/auto-tagger.js +155 -0
  76. package/dist/core/hooks/capture-filter.d.ts +41 -0
  77. package/dist/core/hooks/capture-filter.js +128 -0
  78. package/dist/core/index.d.ts +6 -6
  79. package/dist/core/index.js +6 -6
  80. package/dist/core/{agent-memory.js → ingestion/agent-memory.js} +5 -7
  81. package/dist/core/{core-memory.js → ingestion/core-memory.js} +4 -4
  82. package/dist/core/ingestion/learnings.d.ts +57 -0
  83. package/dist/core/ingestion/learnings.js +202 -0
  84. package/dist/core/lib/db-client.d.ts +114 -0
  85. package/dist/core/lib/db-client.js +130 -0
  86. package/dist/core/lib/schemas.d.ts +129 -0
  87. package/dist/core/lib/schemas.js +87 -0
  88. package/dist/core/{utils.d.ts → lib/utils.d.ts} +1 -0
  89. package/dist/core/{utils.js → lib/utils.js} +31 -15
  90. package/dist/core/lib/validation.d.ts +38 -0
  91. package/dist/core/lib/validation.js +151 -0
  92. package/dist/core/lifecycle.d.ts +7 -0
  93. package/dist/core/lifecycle.js +140 -20
  94. package/dist/core/local-embeddings.d.ts +6 -1
  95. package/dist/core/local-embeddings.js +6 -15
  96. package/dist/core/logger.js +7 -1
  97. package/dist/core/mcp/tools.js +35 -3
  98. package/dist/core/memory/categorizer.js +1 -0
  99. package/dist/core/memory/conflict-detector.js +1 -1
  100. package/dist/core/memory/consolidation.d.ts +1 -10
  101. package/dist/core/memory/consolidation.js +2 -11
  102. package/dist/core/memory/context-collector.js +1 -1
  103. package/dist/core/memory/edit-workflow.js +1 -1
  104. package/dist/core/memory/entity-resolver.js +7 -7
  105. package/dist/core/memory/fact-extractor.js +12 -12
  106. package/dist/core/memory/feedback-tracker.js +1 -1
  107. package/dist/core/memory/hooks.d.ts +88 -0
  108. package/dist/core/memory/hooks.js +174 -0
  109. package/dist/core/memory/hybrid-retrieval.js +2 -2
  110. package/dist/core/memory/hybrid-search.d.ts +1 -6
  111. package/dist/core/memory/hybrid-search.js +70 -84
  112. package/dist/core/memory/importance.d.ts +8 -13
  113. package/dist/core/memory/importance.js +47 -74
  114. package/dist/core/memory/loader.d.ts +31 -0
  115. package/dist/core/memory/loader.js +141 -0
  116. package/dist/core/memory/markdown/markdown-storage.d.ts +72 -0
  117. package/dist/core/memory/markdown/markdown-storage.js +243 -0
  118. package/dist/core/memory/memories.d.ts +12 -4
  119. package/dist/core/memory/memories.js +192 -180
  120. package/dist/core/memory/memory-lifecycle.d.ts +8 -0
  121. package/dist/core/memory/memory-lifecycle.js +55 -0
  122. package/dist/core/memory/migrate.d.ts +21 -0
  123. package/dist/core/memory/migrate.js +134 -0
  124. package/dist/core/memory/normalization.d.ts +22 -0
  125. package/dist/core/memory/normalization.js +26 -0
  126. package/dist/core/memory/progressive-disclosure.js +1 -1
  127. package/dist/core/memory/query-rewriter.js +9 -9
  128. package/dist/core/memory/serialization.d.ts +4 -0
  129. package/dist/core/memory/serialization.js +49 -0
  130. package/dist/core/memory/stats.d.ts +5 -0
  131. package/dist/core/memory/stats.js +63 -12
  132. package/dist/core/memory/temporal-facts.js +21 -0
  133. package/dist/core/memory/write-gate.js +1 -1
  134. package/dist/core/obsidian-vault.d.ts +30 -0
  135. package/dist/core/obsidian-vault.js +94 -0
  136. package/dist/core/places/index.d.ts +14 -0
  137. package/dist/core/places/index.js +14 -0
  138. package/dist/core/places/memory-places.d.ts +68 -0
  139. package/dist/core/places/memory-places.js +261 -0
  140. package/dist/core/places/places.d.ts +88 -0
  141. package/dist/core/places/places.js +314 -0
  142. package/dist/core/places/rules.d.ts +74 -0
  143. package/dist/core/places/rules.js +240 -0
  144. package/dist/core/places/walking.d.ts +56 -0
  145. package/dist/core/places/walking.js +121 -0
  146. package/dist/core/projects.d.ts +5 -0
  147. package/dist/core/projects.js +39 -18
  148. package/dist/core/responses.d.ts +96 -0
  149. package/dist/core/responses.js +122 -0
  150. package/dist/core/scheduler/cron-scheduler.js +29 -7
  151. package/dist/core/scheduler/index.d.ts +1 -1
  152. package/dist/core/scheduler/index.js +1 -1
  153. package/dist/core/scheduler/job-runner.js +1 -1
  154. package/dist/core/search/conversations.js +40 -42
  155. package/dist/core/search/entities.js +6 -9
  156. package/dist/core/search/graph-boost.d.ts +7 -0
  157. package/dist/core/search/graph-boost.js +23 -0
  158. package/dist/core/search/qmd-search.js +4 -4
  159. package/dist/core/security/encrypt.d.ts +6 -0
  160. package/dist/core/security/encrypt.js +47 -0
  161. package/dist/core/{governance.d.ts → security/governance.d.ts} +6 -1
  162. package/dist/core/security/governance.js +79 -0
  163. package/dist/core/session/auto-load.js +6 -6
  164. package/dist/core/session/index.d.ts +1 -1
  165. package/dist/core/session/index.js +1 -1
  166. package/dist/core/session/self-iteration-job.d.ts +20 -0
  167. package/dist/core/session/self-iteration-job.js +282 -0
  168. package/dist/core/session/session-hooks.d.ts +18 -0
  169. package/dist/core/session/session-hooks.js +58 -0
  170. package/dist/core/session-hooks/self-iteration-job.js +35 -35
  171. package/dist/core/{cache.js → storage/cache.js} +2 -2
  172. package/dist/core/sync/qmd-sync.d.ts +1 -13
  173. package/dist/core/sync/qmd-sync.js +1 -13
  174. package/dist/core/toon.d.ts +43 -0
  175. package/dist/core/toon.js +160 -0
  176. package/dist/core/utils/memory-operations.js +1 -1
  177. package/dist/core/utils/vector-operations.d.ts +71 -0
  178. package/dist/core/utils/vector-operations.js +129 -0
  179. package/dist/db/adapter.d.ts +3 -3
  180. package/dist/db/adapter.js +99 -88
  181. package/dist/db/bootstrap.js +820 -522
  182. package/dist/{drizzle → db/drizzle}/schema-sqlite.d.ts +74 -25
  183. package/dist/{drizzle → db/drizzle}/schema-sqlite.js +91 -24
  184. package/dist/{drizzle → db/drizzle}/schema.d.ts +79 -32
  185. package/dist/{drizzle → db/drizzle}/schema.js +106 -35
  186. package/dist/db/drizzle.config.d.ts +3 -0
  187. package/dist/db/drizzle.config.js +12 -0
  188. package/dist/db/index.d.ts +1 -5
  189. package/dist/db/index.js +51 -8
  190. package/dist/db/neon.d.ts +8 -0
  191. package/dist/db/neon.js +20 -0
  192. package/dist/db/schema/index.d.ts +40 -0
  193. package/dist/db/schema/index.js +105 -0
  194. package/dist/db/schema/tables/context-sessions.d.ts +9 -0
  195. package/dist/db/schema/tables/context-sessions.js +37 -0
  196. package/dist/db/schema/tables/conversations.d.ts +9 -0
  197. package/dist/db/schema/tables/conversations.js +47 -0
  198. package/dist/db/schema/tables/core-memory.d.ts +9 -0
  199. package/dist/db/schema/tables/core-memory.js +41 -0
  200. package/dist/db/schema/tables/entities.d.ts +9 -0
  201. package/dist/db/schema/tables/entities.js +39 -0
  202. package/dist/db/schema/tables/entity-relations.d.ts +9 -0
  203. package/dist/db/schema/tables/entity-relations.js +31 -0
  204. package/dist/db/schema/tables/learnings.d.ts +9 -0
  205. package/dist/db/schema/tables/learnings.js +66 -0
  206. package/dist/db/schema/tables/memories.d.ts +9 -0
  207. package/dist/db/schema/tables/memories.js +161 -0
  208. package/dist/db/schema/tables/memory-associations.d.ts +9 -0
  209. package/dist/db/schema/tables/memory-associations.js +39 -0
  210. package/dist/db/schema/tables/memory-hash-cache.d.ts +9 -0
  211. package/dist/db/schema/tables/memory-hash-cache.js +29 -0
  212. package/dist/db/schema/tables/memory-merge-history.d.ts +9 -0
  213. package/dist/db/schema/tables/memory-merge-history.js +33 -0
  214. package/dist/db/schema/tables/memory-merge-proposals.d.ts +9 -0
  215. package/dist/db/schema/tables/memory-merge-proposals.js +39 -0
  216. package/dist/db/schema/tables/messages.d.ts +9 -0
  217. package/dist/db/schema/tables/messages.js +41 -0
  218. package/dist/db/schema/tables/namespaces.d.ts +9 -0
  219. package/dist/db/schema/tables/namespaces.js +37 -0
  220. package/dist/db/schema/tables/projects.d.ts +9 -0
  221. package/dist/db/schema/tables/projects.js +31 -0
  222. package/dist/db/schema/tables/users.d.ts +9 -0
  223. package/dist/db/schema/tables/users.js +27 -0
  224. package/dist/db/schema.d.ts +1 -1
  225. package/dist/db/schema.js +2 -2
  226. package/dist/db/supabase.d.ts +9 -0
  227. package/dist/db/supabase.js +24 -0
  228. package/dist/index.d.ts +2 -14
  229. package/dist/index.js +1320 -640
  230. package/dist/vendor/sql.js/sql-wasm.wasm +0 -0
  231. package/dist/webui/server.d.ts +5 -0
  232. package/dist/{api/web/web.js → webui/server.js} +511 -508
  233. package/generated/mcp/manifest.json +1 -1
  234. package/{.mcp.json → mcp.json.example} +1 -1
  235. package/package.json +159 -181
  236. package/scripts/README.md +60 -0
  237. package/scripts/copy-runtime-assets.mjs +26 -0
  238. package/scripts/generate-mcp.mjs +264 -264
  239. package/scripts/github-release.sh +4 -4
  240. package/scripts/install-claude-code.sh +85 -0
  241. package/scripts/install-cursor.sh +56 -0
  242. package/scripts/install-hooks.sh +73 -0
  243. package/scripts/install-interactive.mjs +357 -677
  244. package/scripts/install-opencode.sh +75 -0
  245. package/scripts/install-windsurf.sh +67 -0
  246. package/skills/squish-memory/SKILL.md +104 -114
  247. package/skills/squish-memory/{install.mjs → scripts/install.mjs} +2 -2
  248. package/skills/squish-memory/{install.sh → scripts/install.sh} +2 -2
  249. package/skills/squish-memory/write_skill.js +2 -0
  250. package/.claude-plugin/marketplace.json +0 -20
  251. package/.claude-plugin/plugin.json +0 -32
  252. package/.env.mcp.example +0 -60
  253. package/QUICK-START.md +0 -71
  254. package/bin/squish-add.mjs +0 -32
  255. package/bin/squish-rm.mjs +0 -21
  256. package/commands/observe.md +0 -5
  257. package/dist/api/web/index.d.ts +0 -3
  258. package/dist/api/web/index.js +0 -4
  259. package/dist/api/web/web-server.d.ts +0 -3
  260. package/dist/api/web/web-server.js +0 -6
  261. package/dist/api/web/web.d.ts +0 -4
  262. package/dist/commands/mcp-server.js +0 -393
  263. package/dist/core/context.js +0 -24
  264. package/dist/core/governance.js +0 -64
  265. package/dist/core/observations.d.ts +0 -26
  266. package/dist/core/observations.js +0 -110
  267. package/dist/core/requirements.d.ts +0 -20
  268. package/dist/core/requirements.js +0 -35
  269. package/hooks/hooks.json +0 -52
  270. package/hooks/post-tool-use.js +0 -26
  271. package/hooks/session-end.js +0 -28
  272. package/hooks/session-start.js +0 -33
  273. package/hooks/user-prompt-submit.js +0 -26
  274. package/hooks/utils.js +0 -153
  275. package/npx-installer.js +0 -208
  276. package/packages/plugin-claude-code/README.md +0 -73
  277. package/packages/plugin-claude-code/dist/plugin-wrapper.d.ts +0 -35
  278. package/packages/plugin-claude-code/dist/plugin-wrapper.js +0 -191
  279. package/packages/plugin-claude-code/package.json +0 -31
  280. package/packages/plugin-openclaw/README.md +0 -70
  281. package/packages/plugin-openclaw/dist/index.d.ts +0 -49
  282. package/packages/plugin-openclaw/dist/index.js +0 -262
  283. package/packages/plugin-openclaw/openclaw.plugin.json +0 -94
  284. package/packages/plugin-openclaw/package.json +0 -31
  285. package/packages/plugin-opencode/install.mjs +0 -217
  286. package/packages/plugin-opencode/package.json +0 -21
  287. package/scripts/db/check-db.mjs +0 -88
  288. package/scripts/db/fix-all-columns.mjs +0 -52
  289. package/scripts/db/fix-schema-all.mjs +0 -55
  290. package/scripts/db/fix-schema-full.mjs +0 -46
  291. package/scripts/db/fix-schema.mjs +0 -38
  292. package/scripts/db/init-db.mjs +0 -13
  293. package/scripts/db/recreate-db.mjs +0 -14
  294. package/scripts/install-mcp.mjs +0 -116
  295. package/scripts/install-web.sh +0 -120
  296. package/scripts/install.mjs +0 -340
  297. package/scripts/openclaw-bootstrap.mjs +0 -127
  298. package/scripts/package-release.sh +0 -71
  299. package/scripts/test/test-all-systems.mjs +0 -139
  300. package/scripts/test/test-memory-system.mjs +0 -139
  301. package/scripts/test/test-v0.5.0.mjs +0 -210
  302. package/skills/memory-guide/SKILL.md +0 -332
  303. package/skills/squish-cli/SKILL.md +0 -240
  304. package/skills/squish-mcp/SKILL.md +0 -355
  305. package/skills/squish-memory/claude-desktop.json +0 -12
  306. package/skills/squish-memory/openclaw.json +0 -13
  307. package/skills/squish-memory/opencode.json +0 -14
  308. package/skills/squish-memory/skill.json +0 -32
  309. /package/{commands → core/commands}/context-paging.md +0 -0
  310. /package/{commands → core/commands}/context-status.md +0 -0
  311. /package/{commands → core/commands}/context.md +0 -0
  312. /package/{commands → core/commands}/core-memory.md +0 -0
  313. /package/{commands → core/commands}/health.md +0 -0
  314. /package/{commands → core/commands}/merge.md +0 -0
  315. /package/{commands → core/commands}/recall.md +0 -0
  316. /package/{commands → core/commands}/remember.md +0 -0
  317. /package/{commands → core/commands}/search.md +0 -0
  318. /package/dist/{algorithms → core/algorithms}/detection/hash-filters.d.ts +0 -0
  319. /package/dist/{algorithms → core/algorithms}/detection/hash-filters.js +0 -0
  320. /package/dist/{algorithms → core/algorithms}/handlers/approve-merge.d.ts +0 -0
  321. /package/dist/{algorithms → core/algorithms}/handlers/detect-duplicates.d.ts +0 -0
  322. /package/dist/{algorithms → core/algorithms}/handlers/get-stats.d.ts +0 -0
  323. /package/dist/{algorithms → core/algorithms}/handlers/list-proposals.d.ts +0 -0
  324. /package/dist/{algorithms → core/algorithms}/handlers/preview-merge.d.ts +0 -0
  325. /package/dist/{algorithms → core/algorithms}/handlers/reject-merge.d.ts +0 -0
  326. /package/dist/{algorithms → core/algorithms}/handlers/reverse-merge.d.ts +0 -0
  327. /package/dist/{algorithms → core/algorithms}/safety/safety-checks.js +0 -0
  328. /package/dist/{algorithms → core/algorithms}/utils/response-builder.d.ts +0 -0
  329. /package/dist/{algorithms → core/algorithms}/utils/response-builder.js +0 -0
  330. /package/dist/{commands → core/commands}/managed-sync.d.ts +0 -0
  331. /package/dist/{commands → core/commands}/mcp-server.d.ts +0 -0
  332. /package/dist/core/{context.d.ts → context/context.d.ts} +0 -0
  333. /package/dist/core/{agent-memory.d.ts → ingestion/agent-memory.d.ts} +0 -0
  334. /package/dist/core/{core-memory.d.ts → ingestion/core-memory.d.ts} +0 -0
  335. /package/dist/core/{privacy.d.ts → security/privacy.d.ts} +0 -0
  336. /package/dist/core/{privacy.js → security/privacy.js} +0 -0
  337. /package/dist/core/{secret-detector.d.ts → security/secret-detector.d.ts} +0 -0
  338. /package/dist/core/{secret-detector.js → security/secret-detector.js} +0 -0
  339. /package/dist/core/{cache.d.ts → storage/cache.d.ts} +0 -0
  340. /package/dist/core/{database.d.ts → storage/database.d.ts} +0 -0
  341. /package/dist/core/{database.js → storage/database.js} +0 -0
@@ -0,0 +1,294 @@
1
+ /**
2
+ * External Folder Memory Manager
3
+ *
4
+ * Wraps QMD to treat an external folder as a secondary memory layer.
5
+ * - Writes hot memories to daily notes (YYYY-MM-DD.md) with frontmatter
6
+ * - Uses QMD to search both Squish DB and external folder
7
+ * - Auto-indexes on mount and write
8
+ *
9
+ * Usage:
10
+ * squish mount /path/to/folder # Enable external memory
11
+ * squish mount status # Show status
12
+ * squish mount unmount # Disable
13
+ */
14
+ import { existsSync, mkdirSync, appendFileSync } from 'fs';
15
+ import { join } from 'path';
16
+ import { spawn } from 'child_process';
17
+ import { logger } from '../logger.js';
18
+ import { config } from '../../config.js';
19
+ /**
20
+ * Format a memory as markdown with YAML frontmatter
21
+ */
22
+ function formatMemoryAsMarkdown(memory) {
23
+ const frontmatter = [
24
+ '---',
25
+ `id: ${memory.id}`,
26
+ `type: ${memory.type}`,
27
+ `tags: [${memory.tags.join(', ')}]`,
28
+ `created: ${memory.createdAt}`,
29
+ ];
30
+ if (memory.confidence) {
31
+ frontmatter.push(`confidence: ${memory.confidence}`);
32
+ }
33
+ if (memory.projectId) {
34
+ frontmatter.push(`project: ${memory.projectId}`);
35
+ }
36
+ frontmatter.push('---', '', memory.content);
37
+ return frontmatter.join('\n');
38
+ }
39
+ /**
40
+ * Get the daily note filename for a given date
41
+ */
42
+ function getDailyNotePath(folderPath, date) {
43
+ const year = date.getFullYear();
44
+ const month = String(date.getMonth() + 1).padStart(2, '0');
45
+ const day = String(date.getDate()).padStart(2, '0');
46
+ return join(folderPath, `${year}-${month}-${day}.md`);
47
+ }
48
+ /**
49
+ * Get today's date string
50
+ */
51
+ function getTodayDateStr() {
52
+ const today = new Date();
53
+ const year = today.getFullYear();
54
+ const month = String(today.getMonth() + 1).padStart(2, '0');
55
+ const day = String(today.getDate()).padStart(2, '0');
56
+ return `${year}-${month}-${day}`;
57
+ }
58
+ /**
59
+ * External Folder Memory Manager class
60
+ */
61
+ export class ExternalFolderMemory {
62
+ mountedPath = null;
63
+ /**
64
+ * Check if external memory is enabled and mounted
65
+ */
66
+ isEnabled() {
67
+ return config.externalMemoryEnabled && !!config.externalMemoryPath;
68
+ }
69
+ /**
70
+ * Get the mounted path
71
+ */
72
+ getPath() {
73
+ return this.isEnabled() ? config.externalMemoryPath : null;
74
+ }
75
+ /**
76
+ * Mount external memory at a path
77
+ * Creates folder if needed, initializes structure
78
+ */
79
+ async mount(path) {
80
+ if (!path) {
81
+ return { success: false, error: 'Path is required' };
82
+ }
83
+ // Resolve to absolute path
84
+ const absolutePath = join(process.cwd(), path);
85
+ // Security: validate path doesn't escape cwd (prevent path traversal)
86
+ const resolvedPath = absolutePath.split(/[\\/]/).join('/');
87
+ const cwdPath = process.cwd().split(/[\\/]/).join('/');
88
+ if (!resolvedPath.startsWith(cwdPath + '/') && resolvedPath !== cwdPath) {
89
+ return { success: false, error: 'Path traversal not allowed' };
90
+ }
91
+ // Create folder if it doesn't exist
92
+ if (!existsSync(absolutePath)) {
93
+ try {
94
+ mkdirSync(absolutePath, { recursive: true });
95
+ logger.info(`[ExternalMemory] Created folder: ${absolutePath}`);
96
+ }
97
+ catch (error) {
98
+ return { success: false, error: `Failed to create folder: ${error}` };
99
+ }
100
+ }
101
+ // Initialize QMD index for this folder
102
+ const indexed = await this.ensureIndexed(absolutePath);
103
+ if (!indexed) {
104
+ logger.warn('[ExternalMemory] QMD not found or indexing failed. Install with: bun install -g qmd');
105
+ }
106
+ this.mountedPath = absolutePath;
107
+ logger.info(`[ExternalMemory] Mounted at: ${absolutePath}`);
108
+ return { success: true };
109
+ }
110
+ /**
111
+ * Unmount external memory
112
+ */
113
+ unmount() {
114
+ this.mountedPath = null;
115
+ logger.info('[ExternalMemory] Unmounted');
116
+ return { success: true };
117
+ }
118
+ /**
119
+ * Ensure QMD indexes the external folder
120
+ */
121
+ async ensureIndexed(folderPath) {
122
+ const targetPath = folderPath || this.getPath();
123
+ if (!targetPath) {
124
+ return false;
125
+ }
126
+ return new Promise((resolve) => {
127
+ // Run qmd add to index the folder
128
+ const process = spawn('qmd', ['add', targetPath], {
129
+ stdio: 'ignore'
130
+ });
131
+ process.on('close', (code) => {
132
+ if (code === 0) {
133
+ logger.info(`[ExternalMemory] Indexed folder: ${targetPath}`);
134
+ resolve(true);
135
+ }
136
+ else {
137
+ logger.warn(`[ExternalMemory] QMD add failed with code: ${code}`);
138
+ resolve(false);
139
+ }
140
+ });
141
+ process.on('error', (error) => {
142
+ logger.warn(`[ExternalMemory] QMD add error: ${error}`);
143
+ resolve(false);
144
+ });
145
+ // Timeout after 30 seconds
146
+ setTimeout(() => {
147
+ process.kill();
148
+ resolve(false);
149
+ }, 30000);
150
+ });
151
+ }
152
+ /**
153
+ * Write a memory to the external folder (daily note)
154
+ */
155
+ async writeMemory(memory) {
156
+ const folderPath = this.getPath();
157
+ if (!folderPath) {
158
+ return { success: false, error: 'External memory not enabled' };
159
+ }
160
+ try {
161
+ const date = memory.createdAt ? new Date(memory.createdAt) : new Date();
162
+ const dailyNotePath = getDailyNotePath(folderPath, date);
163
+ const dateStr = getTodayDateStr();
164
+ // Build memory block content
165
+ const memoryBlock = formatMemoryAsMarkdown(memory);
166
+ // Check if daily note exists, if not create with header
167
+ if (!existsSync(dailyNotePath)) {
168
+ const header = `# ${dateStr}\n\n## Squish Memories\n\n---\n\n`;
169
+ appendFileSync(dailyNotePath, header, 'utf-8');
170
+ logger.info(`[ExternalMemory] Created daily note: ${dailyNotePath}`);
171
+ }
172
+ // Append memory block with separator
173
+ appendFileSync(dailyNotePath, '\n---\n\n' + memoryBlock + '\n', 'utf-8');
174
+ logger.info(`[ExternalMemory] Wrote memory ${memory.id} to ${dateStr}.md`);
175
+ // Trigger QMD re-index (background)
176
+ this.triggerReindex().catch(() => { });
177
+ return { success: true };
178
+ }
179
+ catch (error) {
180
+ const errorMsg = error instanceof Error ? error.message : String(error);
181
+ logger.error(`[ExternalMemory] Write failed: ${errorMsg}`);
182
+ return { success: false, error: errorMsg };
183
+ }
184
+ }
185
+ /**
186
+ * Trigger background re-index via QMD
187
+ */
188
+ async triggerReindex() {
189
+ const folderPath = this.getPath();
190
+ if (!folderPath)
191
+ return;
192
+ // Run qmd in background to re-index
193
+ spawn('qmd', ['add', folderPath], {
194
+ stdio: 'ignore',
195
+ detached: true
196
+ });
197
+ }
198
+ /**
199
+ * Get current status of external memory
200
+ */
201
+ async getStatus() {
202
+ const path = this.getPath();
203
+ if (!path || !existsSync(path)) {
204
+ return {
205
+ mounted: false,
206
+ path: null,
207
+ qmdIndexed: false,
208
+ memoryCount: 0,
209
+ lastIndexed: null
210
+ };
211
+ }
212
+ // Count .md files and memories
213
+ let memoryCount = 0;
214
+ try {
215
+ const { readdirSync } = await import('fs');
216
+ const files = readdirSync(path).filter(f => f.endsWith('.md'));
217
+ memoryCount = files.length;
218
+ }
219
+ catch {
220
+ // Ignore
221
+ }
222
+ // Check if QMD has this folder indexed (via qmd list)
223
+ const qmdIndexed = await this.checkQMDIndexed(path);
224
+ return {
225
+ mounted: true,
226
+ path,
227
+ qmdIndexed,
228
+ memoryCount,
229
+ lastIndexed: null
230
+ };
231
+ }
232
+ /**
233
+ * Check if folder is indexed by QMD
234
+ */
235
+ async checkQMDIndexed(folderPath) {
236
+ return new Promise((resolve) => {
237
+ const process = spawn('qmd', ['list'], {
238
+ stdio: 'pipe'
239
+ });
240
+ let output = '';
241
+ process.stdout?.on('data', (data) => {
242
+ output += data.toString();
243
+ });
244
+ process.on('close', () => {
245
+ resolve(output.includes(folderPath));
246
+ });
247
+ process.on('error', () => {
248
+ resolve(false);
249
+ });
250
+ setTimeout(() => {
251
+ process.kill();
252
+ resolve(false);
253
+ }, 5000);
254
+ });
255
+ }
256
+ /**
257
+ * Convert a MemoryRecord to MemoryAsMarkdown format
258
+ */
259
+ toMarkdownFormat(memory) {
260
+ return {
261
+ id: memory.id,
262
+ type: memory.type,
263
+ content: memory.content,
264
+ tags: memory.tags || [],
265
+ createdAt: memory.createdAt || new Date().toISOString(),
266
+ confidence: memory.confidenceLevel || undefined,
267
+ projectId: memory.projectId
268
+ };
269
+ }
270
+ }
271
+ // Singleton instance
272
+ let externalMemoryInstance = null;
273
+ /**
274
+ * Get the singleton ExternalFolderMemory instance
275
+ */
276
+ export function getExternalMemory() {
277
+ if (!externalMemoryInstance) {
278
+ externalMemoryInstance = new ExternalFolderMemory();
279
+ }
280
+ return externalMemoryInstance;
281
+ }
282
+ /**
283
+ * Check if external memory is enabled
284
+ */
285
+ export function isExternalMemoryEnabled() {
286
+ return getExternalMemory().isEnabled();
287
+ }
288
+ /**
289
+ * Get external memory path
290
+ */
291
+ export function getExternalMemoryPath() {
292
+ return getExternalMemory().getPath();
293
+ }
294
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Agent Hooks - Core Logic
3
+ *
4
+ * Universal hooks for auto-capturing agent activities.
5
+ * Works with Claude Code, OpenCode, Cursor, Windsurf.
6
+ *
7
+ * Hook events:
8
+ * - sessionStart: Inject relevant memories on session start
9
+ * - postToolUse: Record observations after tool execution
10
+ * - sessionEnd: Save snapshot and sync learnings
11
+ * - preCompact: Save state before context compaction
12
+ */
13
+ /**
14
+ * Generate a new session ID (universal across agents)
15
+ */
16
+ export declare function generateSessionId(): string;
17
+ /**
18
+ * Get current session ID
19
+ */
20
+ export declare function getCurrentSessionId(): string | null;
21
+ /**
22
+ * Set session ID (for resume/continue)
23
+ */
24
+ export declare function setSessionId(sessionId: string): void;
25
+ /**
26
+ * Session start hook - inject relevant context
27
+ */
28
+ export declare function handleSessionStart(params: {
29
+ projectPath: string;
30
+ mode: 'startup' | 'resume' | 'compact';
31
+ agentType: 'claude-code' | 'opencode' | 'cursor' | 'windsurf';
32
+ }): Promise<{
33
+ memories: string[];
34
+ sessionId: string;
35
+ count: number;
36
+ }>;
37
+ /**
38
+ * Post-tool-use hook - record observations
39
+ */
40
+ export declare function handlePostToolUse(params: {
41
+ toolName: string;
42
+ toolInput: Record<string, unknown>;
43
+ toolResult: unknown;
44
+ projectPath: string;
45
+ agentType: 'claude-code' | 'opencode' | 'cursor' | 'windsurf';
46
+ }): Promise<{
47
+ captured: boolean;
48
+ memoryId?: string;
49
+ reason?: string;
50
+ }>;
51
+ /**
52
+ * Session end hook - save snapshot and sync
53
+ */
54
+ export declare function handleSessionEnd(params: {
55
+ projectPath: string;
56
+ agentType: 'claude-code' | 'opencode' | 'cursor' | 'windsurf';
57
+ workInProgress?: string;
58
+ }): Promise<{
59
+ snapshotId?: string;
60
+ memoriesSaved: number;
61
+ }>;
62
+ /**
63
+ * Pre-compact hook - save state for recovery
64
+ */
65
+ export declare function handlePreCompact(params: {
66
+ projectPath: string;
67
+ agentType: 'claude-code' | 'opencode' | 'cursor' | 'windsurf';
68
+ }): Promise<{
69
+ stateSaved: boolean;
70
+ stateId?: string;
71
+ }>;
72
+ export { shouldCaptureTool, categorizeTool } from './capture-filter.js';
73
+ export { inferTags } from './auto-tagger.js';
74
+ //# sourceMappingURL=agent-hooks.d.ts.map
@@ -0,0 +1,244 @@
1
+ /**
2
+ * Agent Hooks - Core Logic
3
+ *
4
+ * Universal hooks for auto-capturing agent activities.
5
+ * Works with Claude Code, OpenCode, Cursor, Windsurf.
6
+ *
7
+ * Hook events:
8
+ * - sessionStart: Inject relevant memories on session start
9
+ * - postToolUse: Record observations after tool execution
10
+ * - sessionEnd: Save snapshot and sync learnings
11
+ * - preCompact: Save state before context compaction
12
+ */
13
+ import { randomUUID } from 'crypto';
14
+ import { createLearning } from '../ingestion/learnings.js';
15
+ import { getRecent } from '../memory/memories.js';
16
+ import { logger } from '../logger.js';
17
+ import { shouldCaptureTool, categorizeTool } from './capture-filter.js';
18
+ import { inferTags } from './auto-tagger.js';
19
+ import { ensureProject, getProjectByPath } from '../projects.js';
20
+ import { autoAssignMemory, initializeDefaultPlaces } from '../places/index.js';
21
+ /** Session ID for tracking across agents */
22
+ let currentSessionId = null;
23
+ /**
24
+ * Generate a new session ID (universal across agents)
25
+ */
26
+ export function generateSessionId() {
27
+ currentSessionId = randomUUID();
28
+ return currentSessionId;
29
+ }
30
+ /**
31
+ * Get current session ID
32
+ */
33
+ export function getCurrentSessionId() {
34
+ return currentSessionId;
35
+ }
36
+ /**
37
+ * Set session ID (for resume/continue)
38
+ */
39
+ export function setSessionId(sessionId) {
40
+ currentSessionId = sessionId;
41
+ }
42
+ /**
43
+ * Session start hook - inject relevant context
44
+ */
45
+ export async function handleSessionStart(params) {
46
+ const { projectPath, mode, agentType } = params;
47
+ // Ensure project exists
48
+ await ensureProject(projectPath);
49
+ // Generate or get session ID
50
+ if (!currentSessionId) {
51
+ currentSessionId = generateSessionId();
52
+ }
53
+ logger.info(`[Hooks] Session start: ${mode} (agent: ${agentType}, session: ${currentSessionId})`);
54
+ // Get recent memories based on mode
55
+ const limit = mode === 'compact' ? 3 : 5;
56
+ const memories = await getRecent(projectPath, limit);
57
+ // Get spatial memory context (places) for context injection
58
+ let placesContext = '';
59
+ try {
60
+ const { initializeDefaultPlaces, getProjectPlaces } = await import('../places/index.js');
61
+ const { getProjectByPath } = await import('../projects.js');
62
+ const project = await getProjectByPath(projectPath);
63
+ if (project) {
64
+ await initializeDefaultPlaces(project.id);
65
+ const places = await getProjectPlaces(project.id);
66
+ if (places.length > 0) {
67
+ const populatedPlaces = places.filter(p => p.memoryCount > 0).slice(0, 3);
68
+ if (populatedPlaces.length > 0) {
69
+ placesContext = '\n\nActive places: ' + populatedPlaces.map(p => `${p.name} (${p.memoryCount})`).join(', ');
70
+ }
71
+ }
72
+ }
73
+ }
74
+ catch (e) {
75
+ // Don't fail if places not available
76
+ logger.debug(`[Hooks] Places context not available: ${e}`);
77
+ }
78
+ // Format for injection
79
+ const formatted = memories.map((m, i) => `${i + 1}. [${m.type}] ${m.content?.substring(0, 100)}...`).join('\n');
80
+ const allContent = formatted + placesContext;
81
+ logger.info(`[Hooks] Injected ${memories.length} memories for session start`);
82
+ return {
83
+ memories: allContent ? allContent.split('\n') : [],
84
+ sessionId: currentSessionId,
85
+ count: memories.length,
86
+ };
87
+ }
88
+ /**
89
+ * Post-tool-use hook - record observations
90
+ */
91
+ export async function handlePostToolUse(params) {
92
+ const { toolName, toolInput, toolResult, projectPath, agentType } = params;
93
+ // Ensure project exists
94
+ await ensureProject(projectPath);
95
+ // Ensure session ID exists
96
+ if (!currentSessionId) {
97
+ currentSessionId = generateSessionId();
98
+ }
99
+ // Check if we should capture this tool
100
+ if (!shouldCaptureTool(toolName)) {
101
+ return { captured: false, reason: `Tool ${toolName} filtered out` };
102
+ }
103
+ // Extract relevant information
104
+ const category = categorizeTool(toolName);
105
+ const target = extractTarget(toolName, toolInput);
106
+ const content = extractContent(toolName, toolInput, toolResult);
107
+ // Infer tags from context
108
+ const tags = inferTags(toolName, toolInput, content);
109
+ // Create learning/observation
110
+ const learningInput = {
111
+ type: 'insight',
112
+ content: `[${category}] ${content}`,
113
+ action: toolName,
114
+ target,
115
+ project: projectPath,
116
+ autoLink: true,
117
+ };
118
+ try {
119
+ const learning = await createLearning(learningInput);
120
+ logger.info(`[Hooks] Captured ${toolName} → ${learning.id} (session: ${currentSessionId})`);
121
+ // Auto-assign to place (if places are initialized)
122
+ try {
123
+ const project = await getProjectByPath(projectPath);
124
+ if (project) {
125
+ // Initialize default places if they don't exist
126
+ await initializeDefaultPlaces(project.id);
127
+ // Auto-assign the memory to a place
128
+ await autoAssignMemory({
129
+ memoryId: learning.id,
130
+ projectId: project.id,
131
+ toolName,
132
+ content: learningInput.content,
133
+ tags,
134
+ });
135
+ }
136
+ }
137
+ catch (placeError) {
138
+ // Don't fail the hook if place assignment fails
139
+ logger.warn(`[Hooks] Place assignment failed: ${placeError}`);
140
+ }
141
+ return {
142
+ captured: true,
143
+ memoryId: learning.id,
144
+ };
145
+ }
146
+ catch (error) {
147
+ logger.error(`[Hooks] Failed to capture:`, error);
148
+ return { captured: false, reason: 'Failed to create learning' };
149
+ }
150
+ }
151
+ /**
152
+ * Session end hook - save snapshot and sync
153
+ */
154
+ export async function handleSessionEnd(params) {
155
+ const { projectPath, agentType, workInProgress } = params;
156
+ // Ensure project exists
157
+ await ensureProject(projectPath);
158
+ logger.info(`[Hooks] Session end (agent: ${agentType}, session: ${currentSessionId})`);
159
+ // Save session snapshot as a learning
160
+ if (workInProgress) {
161
+ const snapshot = await createLearning({
162
+ type: 'insight',
163
+ content: `[SESSION SNAPSHOT] ${workInProgress}`,
164
+ action: 'session-end',
165
+ project: projectPath,
166
+ autoLink: false,
167
+ });
168
+ logger.info(`[Hooks] Saved session snapshot: ${snapshot.id}`);
169
+ currentSessionId = null; // Clear session
170
+ return {
171
+ snapshotId: snapshot.id,
172
+ memoriesSaved: 1,
173
+ };
174
+ }
175
+ currentSessionId = null;
176
+ return {
177
+ memoriesSaved: 0,
178
+ };
179
+ }
180
+ /**
181
+ * Pre-compact hook - save state for recovery
182
+ */
183
+ export async function handlePreCompact(params) {
184
+ const { projectPath, agentType } = params;
185
+ // Ensure project exists
186
+ await ensureProject(projectPath);
187
+ logger.info(`[Hooks] Pre-compact (agent: ${agentType})`);
188
+ // Get recent work for recovery
189
+ const recent = await getRecent(projectPath, 3);
190
+ // Save state
191
+ const state = await createLearning({
192
+ type: 'insight',
193
+ content: `[PRE-COMPACT] State saved for recovery. Recent: ${recent.map(r => r.content?.substring(0, 50)).join(' | ')}`,
194
+ action: 'pre-compact',
195
+ project: projectPath,
196
+ autoLink: false,
197
+ });
198
+ return {
199
+ stateSaved: true,
200
+ stateId: state.id,
201
+ };
202
+ }
203
+ /**
204
+ * Extract target from tool input
205
+ */
206
+ function extractTarget(toolName, toolInput) {
207
+ switch (toolName) {
208
+ case 'Write':
209
+ case 'Edit':
210
+ return String(toolInput.filePath || toolInput.path || 'unknown');
211
+ case 'Bash':
212
+ return String(toolInput.command || toolInput.cmd || 'unknown');
213
+ case 'Task':
214
+ return String(toolInput.description || toolInput.name || 'unknown');
215
+ default:
216
+ return 'unknown';
217
+ }
218
+ }
219
+ /**
220
+ * Extract content summary from tool result
221
+ */
222
+ function extractContent(toolName, toolInput, toolResult) {
223
+ switch (toolName) {
224
+ case 'Write':
225
+ return `Wrote: ${toolInput.filePath || toolInput.path}`;
226
+ case 'Edit':
227
+ return `Edited: ${toolInput.filePath || toolInput.path}`;
228
+ case 'Bash':
229
+ const cmd = String(toolInput.command || toolInput.cmd || '');
230
+ if (cmd.includes('commit'))
231
+ return `Git commit executed`;
232
+ if (cmd.includes('test'))
233
+ return `Tests run`;
234
+ return `Command: ${cmd.substring(0, 50)}`;
235
+ case 'Task':
236
+ return `Task: ${toolInput.description || toolInput.name || 'unknown'}`;
237
+ default:
238
+ return `Used: ${toolName}`;
239
+ }
240
+ }
241
+ // Re-export for convenience
242
+ export { shouldCaptureTool, categorizeTool } from './capture-filter.js';
243
+ export { inferTags } from './auto-tagger.js';
244
+ //# sourceMappingURL=agent-hooks.js.map
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Auto-Tagger - Infer tags from context
3
+ *
4
+ * Analyzes tool input/output to automatically infer relevant tags.
5
+ * Uses pattern matching to classify actions.
6
+ */
7
+ /**
8
+ * Infer tags based on tool, input, and content
9
+ */
10
+ export declare function inferTags(toolName: string, toolInput: Record<string, unknown>, content: string): string[];
11
+ /**
12
+ * Extract tags from commit message
13
+ */
14
+ export declare function extractCommitTags(commitMessage: string): string[];
15
+ /**
16
+ * Extract tags from file path
17
+ */
18
+ export declare function extractFileTags(filePath: string): string[];
19
+ //# sourceMappingURL=auto-tagger.d.ts.map