@asermax/tachikoma 2.0.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 (345) hide show
  1. package/README.md +64 -0
  2. package/dist/agent/adapter.d.ts +8 -0
  3. package/dist/agent/adapter.js +86 -0
  4. package/dist/agent/adapter.js.map +1 -0
  5. package/dist/agent/manager.d.ts +35 -0
  6. package/dist/agent/manager.js +76 -0
  7. package/dist/agent/manager.js.map +1 -0
  8. package/dist/agent/models.d.ts +46 -0
  9. package/dist/agent/models.js +96 -0
  10. package/dist/agent/models.js.map +1 -0
  11. package/dist/agent/side-run.d.ts +42 -0
  12. package/dist/agent/side-run.js +83 -0
  13. package/dist/agent/side-run.js.map +1 -0
  14. package/dist/app.d.ts +5 -0
  15. package/dist/app.js +79 -0
  16. package/dist/app.js.map +1 -0
  17. package/dist/channels/types.d.ts +37 -0
  18. package/dist/channels/types.js +5 -0
  19. package/dist/channels/types.js.map +1 -0
  20. package/dist/config/default-template.d.ts +1 -0
  21. package/dist/config/default-template.js +49 -0
  22. package/dist/config/default-template.js.map +1 -0
  23. package/dist/config/load.d.ts +8 -0
  24. package/dist/config/load.js +28 -0
  25. package/dist/config/load.js.map +1 -0
  26. package/dist/config/parse.d.ts +5 -0
  27. package/dist/config/parse.js +18 -0
  28. package/dist/config/parse.js.map +1 -0
  29. package/dist/config/schema.d.ts +29 -0
  30. package/dist/config/schema.js +35 -0
  31. package/dist/config/schema.js.map +1 -0
  32. package/dist/coordinator.d.ts +54 -0
  33. package/dist/coordinator.js +344 -0
  34. package/dist/coordinator.js.map +1 -0
  35. package/dist/db/core-schema.d.ts +250 -0
  36. package/dist/db/core-schema.js +19 -0
  37. package/dist/db/core-schema.js.map +1 -0
  38. package/dist/db/index.d.ts +8 -0
  39. package/dist/db/index.js +16 -0
  40. package/dist/db/index.js.map +1 -0
  41. package/dist/db/schema.d.ts +4 -0
  42. package/dist/db/schema.js +7 -0
  43. package/dist/db/schema.js.map +1 -0
  44. package/dist/db/state.d.ts +10 -0
  45. package/dist/db/state.js +36 -0
  46. package/dist/db/state.js.map +1 -0
  47. package/dist/domain/agent-events.d.ts +26 -0
  48. package/dist/domain/agent-events.js +2 -0
  49. package/dist/domain/agent-events.js.map +1 -0
  50. package/dist/domain/message.d.ts +25 -0
  51. package/dist/domain/message.js +17 -0
  52. package/dist/domain/message.js.map +1 -0
  53. package/dist/events.d.ts +9 -0
  54. package/dist/events.js +27 -0
  55. package/dist/events.js.map +1 -0
  56. package/dist/extensions/api.d.ts +118 -0
  57. package/dist/extensions/api.js +7 -0
  58. package/dist/extensions/api.js.map +1 -0
  59. package/dist/extensions/boundary/detector.d.ts +20 -0
  60. package/dist/extensions/boundary/detector.js +57 -0
  61. package/dist/extensions/boundary/detector.js.map +1 -0
  62. package/dist/extensions/boundary/idle.d.ts +10 -0
  63. package/dist/extensions/boundary/idle.js +28 -0
  64. package/dist/extensions/boundary/idle.js.map +1 -0
  65. package/dist/extensions/boundary/index.d.ts +12 -0
  66. package/dist/extensions/boundary/index.js +65 -0
  67. package/dist/extensions/boundary/index.js.map +1 -0
  68. package/dist/extensions/boundary/summary.d.ts +5 -0
  69. package/dist/extensions/boundary/summary.js +33 -0
  70. package/dist/extensions/boundary/summary.js.map +1 -0
  71. package/dist/extensions/commands/index.d.ts +7 -0
  72. package/dist/extensions/commands/index.js +21 -0
  73. package/dist/extensions/commands/index.js.map +1 -0
  74. package/dist/extensions/context/index.d.ts +7 -0
  75. package/dist/extensions/context/index.js +65 -0
  76. package/dist/extensions/context/index.js.map +1 -0
  77. package/dist/extensions/context/processor.d.ts +27 -0
  78. package/dist/extensions/context/processor.js +228 -0
  79. package/dist/extensions/context/processor.js.map +1 -0
  80. package/dist/extensions/detached-processes/index.d.ts +12 -0
  81. package/dist/extensions/detached-processes/index.js +51 -0
  82. package/dist/extensions/detached-processes/index.js.map +1 -0
  83. package/dist/extensions/detached-processes/limits.d.ts +27 -0
  84. package/dist/extensions/detached-processes/limits.js +55 -0
  85. package/dist/extensions/detached-processes/limits.js.map +1 -0
  86. package/dist/extensions/detached-processes/output.d.ts +2 -0
  87. package/dist/extensions/detached-processes/output.js +26 -0
  88. package/dist/extensions/detached-processes/output.js.map +1 -0
  89. package/dist/extensions/detached-processes/reconcile.d.ts +31 -0
  90. package/dist/extensions/detached-processes/reconcile.js +71 -0
  91. package/dist/extensions/detached-processes/reconcile.js.map +1 -0
  92. package/dist/extensions/detached-processes/repository.d.ts +33 -0
  93. package/dist/extensions/detached-processes/repository.js +62 -0
  94. package/dist/extensions/detached-processes/repository.js.map +1 -0
  95. package/dist/extensions/detached-processes/schema.d.ts +252 -0
  96. package/dist/extensions/detached-processes/schema.js +23 -0
  97. package/dist/extensions/detached-processes/schema.js.map +1 -0
  98. package/dist/extensions/detached-processes/spawn.d.ts +40 -0
  99. package/dist/extensions/detached-processes/spawn.js +137 -0
  100. package/dist/extensions/detached-processes/spawn.js.map +1 -0
  101. package/dist/extensions/detached-processes/tools.d.ts +41 -0
  102. package/dist/extensions/detached-processes/tools.js +243 -0
  103. package/dist/extensions/detached-processes/tools.js.map +1 -0
  104. package/dist/extensions/detached-processes/watcher.d.ts +7 -0
  105. package/dist/extensions/detached-processes/watcher.js +19 -0
  106. package/dist/extensions/detached-processes/watcher.js.map +1 -0
  107. package/dist/extensions/external/index.d.ts +11 -0
  108. package/dist/extensions/external/index.js +40 -0
  109. package/dist/extensions/external/index.js.map +1 -0
  110. package/dist/extensions/external/installs.d.ts +39 -0
  111. package/dist/extensions/external/installs.js +98 -0
  112. package/dist/extensions/external/installs.js.map +1 -0
  113. package/dist/extensions/external/loader.d.ts +19 -0
  114. package/dist/extensions/external/loader.js +70 -0
  115. package/dist/extensions/external/loader.js.map +1 -0
  116. package/dist/extensions/external/tools.d.ts +17 -0
  117. package/dist/extensions/external/tools.js +112 -0
  118. package/dist/extensions/external/tools.js.map +1 -0
  119. package/dist/extensions/git/commit.d.ts +19 -0
  120. package/dist/extensions/git/commit.js +44 -0
  121. package/dist/extensions/git/commit.js.map +1 -0
  122. package/dist/extensions/git/git.d.ts +11 -0
  123. package/dist/extensions/git/git.js +29 -0
  124. package/dist/extensions/git/git.js.map +1 -0
  125. package/dist/extensions/git/hooks.d.ts +10 -0
  126. package/dist/extensions/git/hooks.js +88 -0
  127. package/dist/extensions/git/hooks.js.map +1 -0
  128. package/dist/extensions/git/index.d.ts +11 -0
  129. package/dist/extensions/git/index.js +28 -0
  130. package/dist/extensions/git/index.js.map +1 -0
  131. package/dist/extensions/git/processor.d.ts +13 -0
  132. package/dist/extensions/git/processor.js +52 -0
  133. package/dist/extensions/git/processor.js.map +1 -0
  134. package/dist/extensions/git/sync.d.ts +44 -0
  135. package/dist/extensions/git/sync.js +189 -0
  136. package/dist/extensions/git/sync.js.map +1 -0
  137. package/dist/extensions/git/tools.d.ts +21 -0
  138. package/dist/extensions/git/tools.js +101 -0
  139. package/dist/extensions/git/tools.js.map +1 -0
  140. package/dist/extensions/host.d.ts +31 -0
  141. package/dist/extensions/host.js +75 -0
  142. package/dist/extensions/host.js.map +1 -0
  143. package/dist/extensions/index.d.ts +3 -0
  144. package/dist/extensions/index.js +32 -0
  145. package/dist/extensions/index.js.map +1 -0
  146. package/dist/extensions/memory/archive.d.ts +8 -0
  147. package/dist/extensions/memory/archive.js +46 -0
  148. package/dist/extensions/memory/archive.js.map +1 -0
  149. package/dist/extensions/memory/dates.d.ts +2 -0
  150. package/dist/extensions/memory/dates.js +7 -0
  151. package/dist/extensions/memory/dates.js.map +1 -0
  152. package/dist/extensions/memory/extraction.d.ts +17 -0
  153. package/dist/extensions/memory/extraction.js +218 -0
  154. package/dist/extensions/memory/extraction.js.map +1 -0
  155. package/dist/extensions/memory/index.d.ts +20 -0
  156. package/dist/extensions/memory/index.js +67 -0
  157. package/dist/extensions/memory/index.js.map +1 -0
  158. package/dist/extensions/memory/indexes.d.ts +14 -0
  159. package/dist/extensions/memory/indexes.js +64 -0
  160. package/dist/extensions/memory/indexes.js.map +1 -0
  161. package/dist/extensions/memory/layout.d.ts +20 -0
  162. package/dist/extensions/memory/layout.js +79 -0
  163. package/dist/extensions/memory/layout.js.map +1 -0
  164. package/dist/extensions/memory/maintenance.d.ts +21 -0
  165. package/dist/extensions/memory/maintenance.js +357 -0
  166. package/dist/extensions/memory/maintenance.js.map +1 -0
  167. package/dist/extensions/memory/prompts.d.ts +8 -0
  168. package/dist/extensions/memory/prompts.js +125 -0
  169. package/dist/extensions/memory/prompts.js.map +1 -0
  170. package/dist/extensions/memory/transcript.d.ts +18 -0
  171. package/dist/extensions/memory/transcript.js +79 -0
  172. package/dist/extensions/memory/transcript.js.map +1 -0
  173. package/dist/extensions/notifications/format.d.ts +5 -0
  174. package/dist/extensions/notifications/format.js +17 -0
  175. package/dist/extensions/notifications/format.js.map +1 -0
  176. package/dist/extensions/notifications/index.d.ts +13 -0
  177. package/dist/extensions/notifications/index.js +29 -0
  178. package/dist/extensions/notifications/index.js.map +1 -0
  179. package/dist/extensions/notifications/payload.d.ts +22 -0
  180. package/dist/extensions/notifications/payload.js +29 -0
  181. package/dist/extensions/notifications/payload.js.map +1 -0
  182. package/dist/extensions/notifications/router.d.ts +29 -0
  183. package/dist/extensions/notifications/router.js +55 -0
  184. package/dist/extensions/notifications/router.js.map +1 -0
  185. package/dist/extensions/notifications/tools.d.ts +12 -0
  186. package/dist/extensions/notifications/tools.js +41 -0
  187. package/dist/extensions/notifications/tools.js.map +1 -0
  188. package/dist/extensions/projects/context-provider.d.ts +9 -0
  189. package/dist/extensions/projects/context-provider.js +37 -0
  190. package/dist/extensions/projects/context-provider.js.map +1 -0
  191. package/dist/extensions/projects/git.d.ts +28 -0
  192. package/dist/extensions/projects/git.js +91 -0
  193. package/dist/extensions/projects/git.js.map +1 -0
  194. package/dist/extensions/projects/hooks.d.ts +7 -0
  195. package/dist/extensions/projects/hooks.js +42 -0
  196. package/dist/extensions/projects/hooks.js.map +1 -0
  197. package/dist/extensions/projects/index.d.ts +11 -0
  198. package/dist/extensions/projects/index.js +30 -0
  199. package/dist/extensions/projects/index.js.map +1 -0
  200. package/dist/extensions/projects/processor.d.ts +13 -0
  201. package/dist/extensions/projects/processor.js +63 -0
  202. package/dist/extensions/projects/processor.js.map +1 -0
  203. package/dist/extensions/projects/tools.d.ts +21 -0
  204. package/dist/extensions/projects/tools.js +118 -0
  205. package/dist/extensions/projects/tools.js.map +1 -0
  206. package/dist/extensions/registrations.d.ts +21 -0
  207. package/dist/extensions/registrations.js +12 -0
  208. package/dist/extensions/registrations.js.map +1 -0
  209. package/dist/extensions/repl/index.d.ts +2 -0
  210. package/dist/extensions/repl/index.js +85 -0
  211. package/dist/extensions/repl/index.js.map +1 -0
  212. package/dist/extensions/skills/agents.d.ts +17 -0
  213. package/dist/extensions/skills/agents.js +77 -0
  214. package/dist/extensions/skills/agents.js.map +1 -0
  215. package/dist/extensions/skills/delegate.d.ts +22 -0
  216. package/dist/extensions/skills/delegate.js +54 -0
  217. package/dist/extensions/skills/delegate.js.map +1 -0
  218. package/dist/extensions/skills/index.d.ts +11 -0
  219. package/dist/extensions/skills/index.js +43 -0
  220. package/dist/extensions/skills/index.js.map +1 -0
  221. package/dist/extensions/skills/reload.d.ts +8 -0
  222. package/dist/extensions/skills/reload.js +38 -0
  223. package/dist/extensions/skills/reload.js.map +1 -0
  224. package/dist/extensions/tasks/executor.d.ts +43 -0
  225. package/dist/extensions/tasks/executor.js +179 -0
  226. package/dist/extensions/tasks/executor.js.map +1 -0
  227. package/dist/extensions/tasks/expiration.d.ts +12 -0
  228. package/dist/extensions/tasks/expiration.js +17 -0
  229. package/dist/extensions/tasks/expiration.js.map +1 -0
  230. package/dist/extensions/tasks/generation.d.ts +14 -0
  231. package/dist/extensions/tasks/generation.js +70 -0
  232. package/dist/extensions/tasks/generation.js.map +1 -0
  233. package/dist/extensions/tasks/index.d.ts +14 -0
  234. package/dist/extensions/tasks/index.js +75 -0
  235. package/dist/extensions/tasks/index.js.map +1 -0
  236. package/dist/extensions/tasks/repository.d.ts +53 -0
  237. package/dist/extensions/tasks/repository.js +147 -0
  238. package/dist/extensions/tasks/repository.js.map +1 -0
  239. package/dist/extensions/tasks/schedule.d.ts +13 -0
  240. package/dist/extensions/tasks/schedule.js +32 -0
  241. package/dist/extensions/tasks/schedule.js.map +1 -0
  242. package/dist/extensions/tasks/schema.d.ts +423 -0
  243. package/dist/extensions/tasks/schema.js +45 -0
  244. package/dist/extensions/tasks/schema.js.map +1 -0
  245. package/dist/extensions/tasks/session-delivery.d.ts +18 -0
  246. package/dist/extensions/tasks/session-delivery.js +39 -0
  247. package/dist/extensions/tasks/session-delivery.js.map +1 -0
  248. package/dist/extensions/tasks/tools.d.ts +38 -0
  249. package/dist/extensions/tasks/tools.js +181 -0
  250. package/dist/extensions/tasks/tools.js.map +1 -0
  251. package/dist/extensions/telegram/buttons.d.ts +14 -0
  252. package/dist/extensions/telegram/buttons.js +49 -0
  253. package/dist/extensions/telegram/buttons.js.map +1 -0
  254. package/dist/extensions/telegram/channel.d.ts +39 -0
  255. package/dist/extensions/telegram/channel.js +201 -0
  256. package/dist/extensions/telegram/channel.js.map +1 -0
  257. package/dist/extensions/telegram/chunking.d.ts +7 -0
  258. package/dist/extensions/telegram/chunking.js +67 -0
  259. package/dist/extensions/telegram/chunking.js.map +1 -0
  260. package/dist/extensions/telegram/inbound.d.ts +7 -0
  261. package/dist/extensions/telegram/inbound.js +29 -0
  262. package/dist/extensions/telegram/inbound.js.map +1 -0
  263. package/dist/extensions/telegram/index.d.ts +13 -0
  264. package/dist/extensions/telegram/index.js +67 -0
  265. package/dist/extensions/telegram/index.js.map +1 -0
  266. package/dist/extensions/telegram/media.d.ts +39 -0
  267. package/dist/extensions/telegram/media.js +223 -0
  268. package/dist/extensions/telegram/media.js.map +1 -0
  269. package/dist/extensions/telegram/mutex.d.ts +9 -0
  270. package/dist/extensions/telegram/mutex.js +14 -0
  271. package/dist/extensions/telegram/mutex.js.map +1 -0
  272. package/dist/extensions/telegram/sending.d.ts +48 -0
  273. package/dist/extensions/telegram/sending.js +119 -0
  274. package/dist/extensions/telegram/sending.js.map +1 -0
  275. package/dist/extensions/telegram/streaming.d.ts +46 -0
  276. package/dist/extensions/telegram/streaming.js +140 -0
  277. package/dist/extensions/telegram/streaming.js.map +1 -0
  278. package/dist/extensions/telegram/tools.d.ts +80 -0
  279. package/dist/extensions/telegram/tools.js +232 -0
  280. package/dist/extensions/telegram/tools.js.map +1 -0
  281. package/dist/extensions/workflows/cleanup.d.ts +10 -0
  282. package/dist/extensions/workflows/cleanup.js +38 -0
  283. package/dist/extensions/workflows/cleanup.js.map +1 -0
  284. package/dist/extensions/workflows/index.d.ts +11 -0
  285. package/dist/extensions/workflows/index.js +42 -0
  286. package/dist/extensions/workflows/index.js.map +1 -0
  287. package/dist/extensions/workflows/loader.d.ts +27 -0
  288. package/dist/extensions/workflows/loader.js +90 -0
  289. package/dist/extensions/workflows/loader.js.map +1 -0
  290. package/dist/extensions/workflows/model.d.ts +19 -0
  291. package/dist/extensions/workflows/model.js +7 -0
  292. package/dist/extensions/workflows/model.js.map +1 -0
  293. package/dist/extensions/workflows/repository.d.ts +24 -0
  294. package/dist/extensions/workflows/repository.js +61 -0
  295. package/dist/extensions/workflows/repository.js.map +1 -0
  296. package/dist/extensions/workflows/schema.d.ts +193 -0
  297. package/dist/extensions/workflows/schema.js +20 -0
  298. package/dist/extensions/workflows/schema.js.map +1 -0
  299. package/dist/extensions/workflows/tools.d.ts +27 -0
  300. package/dist/extensions/workflows/tools.js +285 -0
  301. package/dist/extensions/workflows/tools.js.map +1 -0
  302. package/dist/log.d.ts +8 -0
  303. package/dist/log.js +15 -0
  304. package/dist/log.js.map +1 -0
  305. package/dist/main.d.ts +2 -0
  306. package/dist/main.js +27 -0
  307. package/dist/main.js.map +1 -0
  308. package/dist/migration/ask.d.ts +8 -0
  309. package/dist/migration/ask.js +24 -0
  310. package/dist/migration/ask.js.map +1 -0
  311. package/dist/migration/config.d.ts +10 -0
  312. package/dist/migration/config.js +122 -0
  313. package/dist/migration/config.js.map +1 -0
  314. package/dist/migration/context.d.ts +3 -0
  315. package/dist/migration/context.js +24 -0
  316. package/dist/migration/context.js.map +1 -0
  317. package/dist/migration/database.d.ts +8 -0
  318. package/dist/migration/database.js +51 -0
  319. package/dist/migration/database.js.map +1 -0
  320. package/dist/migration/fs.d.ts +1 -0
  321. package/dist/migration/fs.js +11 -0
  322. package/dist/migration/fs.js.map +1 -0
  323. package/dist/migration/index.d.ts +11 -0
  324. package/dist/migration/index.js +28 -0
  325. package/dist/migration/index.js.map +1 -0
  326. package/dist/migration/skills.d.ts +19 -0
  327. package/dist/migration/skills.js +77 -0
  328. package/dist/migration/skills.js.map +1 -0
  329. package/dist/scheduler.d.ts +17 -0
  330. package/dist/scheduler.js +53 -0
  331. package/dist/scheduler.js.map +1 -0
  332. package/dist/sessions/registry.d.ts +15 -0
  333. package/dist/sessions/registry.js +42 -0
  334. package/dist/sessions/registry.js.map +1 -0
  335. package/dist/workspace.d.ts +13 -0
  336. package/dist/workspace.js +32 -0
  337. package/dist/workspace.js.map +1 -0
  338. package/drizzle/0000_init.sql +19 -0
  339. package/drizzle/0001_extensions.sql +63 -0
  340. package/drizzle/meta/0000_snapshot.json +134 -0
  341. package/drizzle/meta/0001_snapshot.json +526 -0
  342. package/drizzle/meta/_journal.json +20 -0
  343. package/package.json +63 -0
  344. package/skills/skill-authoring/SKILL.md +168 -0
  345. package/skills/workflow-authoring/SKILL.md +251 -0
@@ -0,0 +1,357 @@
1
+ import { readdir } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { MEMORY_FILE_TOOLS } from "./extraction.js";
4
+ import { fileExists, MEMORY_STORES, storeDir, sweepEmptyMarkdown, } from "./layout.js";
5
+ import { INDEX_LIGHT_MAINTENANCE_SECTION, STORE_PURPOSE_SECTION, scopeSection } from "./prompts.js";
6
+ const episodicMaintenancePrompt = ({ recentDays, weeklyThresholdMonths, monthlyThresholdMonths, }) => `You are a memory maintenance agent performing episodic memory consolidation.
7
+
8
+ ## Directory
9
+
10
+ \`$WORKSPACE/memories/episodic/\`
11
+
12
+ ## Pre-check
13
+
14
+ If the directory is empty or contains no \`.md\` files, stop immediately — nothing to maintain.
15
+
16
+ ## File Handling
17
+
18
+ - Skip empty (0-byte) or malformed files — do not attempt to process them.
19
+ - Only process files with \`.md\` extension.
20
+ - If a file's content looks truncated or garbled, skip it.
21
+
22
+ ## Time Tiers
23
+
24
+ Categorize every non-skipped file by its date (extracted from filename \`YYYY-MM-DD.md\` or from \`YYYY-WNN.md\` / \`YYYY-MM.md\` summary files):
25
+
26
+ ### Tier 1: Recent (last ${recentDays} days) — Clean only
27
+
28
+ - **Goal**: Reduce verbosity without losing substance.
29
+ - Remove repeated information that appears identically across entries.
30
+ - Remove excessive implementation detail (file lists, step-by-step code changes, routine activity status).
31
+ - Preserve: outcomes, decisions, new information, significant events.
32
+ - **NEVER delete files or remove substantive content from this tier.**
33
+ - If an entry is already clean and concise, leave it unchanged.
34
+
35
+ ### Tier 2: Weekly consolidation (${recentDays} days – ${weeklyThresholdMonths} months) — Weekly summaries
36
+
37
+ - Group daily files by ISO week (e.g., files from 2026-04-13 through 2026-04-19 all belong to week 2026-W15).
38
+ - For each group, create a weekly summary file named \`YYYY-WNN.md\` (e.g., \`2026-W15.md\`).
39
+ - The summary should capture the high-level narrative and significant events of that week — decisions, outcomes, notable activities.
40
+ - Discard: routine implementation details, file change lists, repetitive status updates, step-by-step technical minutiae.
41
+ - If a weekly summary \`YYYY-WNN.md\` already exists from a previous run, merge new content into it — do not overwrite.
42
+ - After successful consolidation, delete the original daily files that were consolidated.
43
+ - Partial groups (e.g., only 2 days in a week) are consolidated into a single summary for that period.
44
+
45
+ ### Tier 3: Monthly consolidation (${weeklyThresholdMonths} months – ${monthlyThresholdMonths} months) — Monthly summaries
46
+
47
+ - Group all files (daily or weekly) by month.
48
+ - For each group, create a monthly summary file named \`YYYY-MM.md\` (e.g., \`2026-04.md\`).
49
+ - The summary should capture the most significant themes and events of that month at a high level.
50
+ - Discard: all routine detail — keep only notable outcomes, key decisions, and significant changes.
51
+ - If a monthly summary \`YYYY-MM.md\` already exists from a previous run, merge new content into it — do not overwrite.
52
+ - After successful consolidation, delete the original files.
53
+ - Partial months are consolidated into a single summary.
54
+
55
+ ### Tier 4: Older than ${monthlyThresholdMonths} months — Delete
56
+
57
+ - Delete all files older than ${monthlyThresholdMonths} months.
58
+ - These entries have been through monthly consolidation already — anything remaining at this age is beyond the retention window.
59
+
60
+ ## Idempotency
61
+
62
+ Before acting, check whether the work has already been done:
63
+ - If a weekly/monthly summary already exists and covers the files in its range, do not recreate it.
64
+ - If daily files in Tier 1 are already clean and concise, do not re-edit.
65
+ - If no files need processing, exit with no changes.`;
66
+ const FACTS_MAINTENANCE_PROMPT = `You are a memory maintenance agent performing facts memory cleanup.
67
+
68
+ ## Directory
69
+
70
+ \`$WORKSPACE/memories/facts/\`
71
+
72
+ ## Pre-check
73
+
74
+ If the directory is empty or contains no \`.md\` files, stop immediately — nothing to maintain.
75
+
76
+ ## File Handling
77
+
78
+ - Skip empty (0-byte) or malformed files — do not attempt to process them.
79
+ - Only process files with \`.md\` extension.
80
+
81
+ ## Evaluation Criteria
82
+
83
+ Read all fact files and evaluate each for three issues:
84
+
85
+ ### Staleness
86
+
87
+ An entry is stale when it describes a state that is no longer accurate:
88
+ - References to past dates or completed projects (e.g., "currently working on X" when X shipped months ago).
89
+ - Information contradicted by newer entries.
90
+ - Technical details that reference outdated tools, versions, or configurations.
91
+
92
+ For stale entries:
93
+ - If the entry has a newer, accurate replacement: remove the stale version.
94
+ - If the entry can be updated to reflect current state: edit it.
95
+ - If the entry describes a completed event with no ongoing relevance: remove it.
96
+
97
+ ### Redundancy
98
+
99
+ Same information stated in different files:
100
+ - Keep the most complete and well-organized version.
101
+ - Remove the duplicate entries.
102
+
103
+ ### Overlap
104
+
105
+ Related topics split across multiple files:
106
+ - When files cover overlapping subject areas, merge them into a single consolidated file.
107
+ - Choose the best filename from the originals, or create a more descriptive one.
108
+ - Remove the original files after merging.
109
+
110
+ #### Cluster Consolidation
111
+
112
+ Beyond pairwise overlap, look for clusters of many small files that fragment a single broad topic into per-incident, per-bug, or per-date entries — this is the main driver of facts directory bloat:
113
+
114
+ - List all files in \`$WORKSPACE/memories/facts/\` and group them by shared prefix or core topic (project, system, tool, or domain).
115
+ - When 3 or more files share the same prefix or core topic, treat them as a cluster and consolidate aggressively:
116
+ - Merge all of the cluster's content into a single broad-topic file named \`<project>.md\`, \`<system>.md\`, \`<tool>.md\`, or \`<domain>.md\` — the same broad-topic convention used at extraction time.
117
+ - If a broad-topic file already exists in the cluster, merge the others into it. Otherwise, pick a broad name and create the consolidated file.
118
+ - Delete the original narrow files after merging.
119
+ - Generic examples of clusters to consolidate (patterns, not literal names): files matching \`<project>-<bug-description>-<YYYY-MM-DD>.md\`, \`<project>-patch-<issue-id>.md\`, \`<system>-<incident>-<date>.md\`, \`<topic>-session-<date>.md\` — all of these should fold into the broad \`<project>.md\`, \`<system>.md\`, or \`<topic>.md\` file.
120
+ - Preserve substantive content during the merge; deduplicate restated information and discard incidental detail that does not belong in stable reference facts.
121
+
122
+ ### Size Enforcement
123
+
124
+ Flag any file exceeding 40 lines for consolidation:
125
+ - If a file exceeds 40 lines, it likely contains implementation details or narrative that belongs in project docs or episodic memory rather than stable reference facts
126
+ - Prune implementation details and transient information
127
+ - Consolidate related entries within the file to eliminate restatement
128
+
129
+ ### Context File Overlap
130
+
131
+ Check whether facts are already covered by the context files at the workspace root:
132
+ - Read \`$WORKSPACE/USER.md\` and \`$WORKSPACE/AGENTS.md\` for the same topic
133
+ - If a context file already captures the information, trim the facts file to a brief reference (e.g., "See USER.md for details about X")
134
+ - Context files are more authoritative for their respective categories; facts should supplement, not duplicate
135
+
136
+ ## Deletion
137
+
138
+ - If a fact file is entirely obsolete (all entries stale, no useful content), delete it.
139
+ - Do NOT delete files that contain any useful or current information.
140
+
141
+ ## Idempotency
142
+
143
+ The goal is to leave the store materially smaller and more consolidated than you found it. Treat absence of exact duplicates as insufficient grounds for skipping — semantic overlap and per-incident granularity are also valid triggers for action.
144
+
145
+ ### Consolidate narrow per-incident files into broader topic files
146
+
147
+ When you see multiple narrow files about the same subject (per-date, per-incident, per-PR, per-bug), merge them into a single broader topic file. Example: \`<project>-bug-<YYYY-MM-DD>.md\`, \`<project>-process.md\`, and \`<project>-rollout-notes.md\` should all be folded into \`<project>.md\`. Keep the most durable, generally-useful information; discard the incident-specific noise. Delete the merged-from files after consolidation.
148
+
149
+ ### Aggressively prune resolved incidents
150
+
151
+ Files whose content carries headers like "Status: Completed", "Status: Merged", "Status: Resolved", or "Status: Fixed" describe one-time events — that content belongs in episodic memory, not facts. Delete these files outright. If a fact file mixes durable content with a resolved-incident section, strip the resolved section and keep the rest.
152
+
153
+ If no changes are needed, exit with no changes.`;
154
+ const PREFERENCES_MAINTENANCE_PROMPT = `You are a memory maintenance agent performing preferences memory cleanup.
155
+
156
+ ## Directory
157
+
158
+ \`$WORKSPACE/memories/preferences/\`
159
+
160
+ ## Pre-check
161
+
162
+ If the directory is empty or contains no \`.md\` files, stop immediately — nothing to maintain.
163
+
164
+ ## File Handling
165
+
166
+ - Skip empty (0-byte) or malformed files — do not attempt to process them.
167
+ - Only process files with \`.md\` extension.
168
+
169
+ ## Evaluation Criteria
170
+
171
+ Read all preference files and evaluate each for these issues:
172
+
173
+ ### Redundancy
174
+
175
+ Same preference stated multiple times across or within files:
176
+ - Keep the most complete and well-organized version.
177
+ - Remove the duplicate entries.
178
+
179
+ ### Overlap
180
+
181
+ Related preferences split across multiple files:
182
+ - When files cover overlapping topics (e.g., coding style preferences split across "python-style.md" and "code-formatting.md"), merge them into a single consolidated file.
183
+ - Choose the best filename from the originals, or create a more descriptive one.
184
+ - Remove the original files after merging.
185
+
186
+ #### Cluster Consolidation
187
+
188
+ Beyond pairwise overlap, look for clusters of many small files that fragment a single broad preference topic into per-occasion, per-feedback, or per-date entries — this is the main driver of preferences directory bloat:
189
+
190
+ - List all files in \`$WORKSPACE/memories/preferences/\` and group them by shared prefix or core topic (style, workflow, communication, tooling, project, system, or domain).
191
+ - When 3 or more files share the same prefix or core topic, treat them as a cluster and consolidate aggressively:
192
+ - Merge all of the cluster's content into a single broad-topic file named \`<topic-area>-style.md\`, \`<topic-area>-workflow.md\`, \`<domain>.md\`, or \`<project>.md\` — the same broad-topic convention used at extraction time.
193
+ - If a broad-topic file already exists in the cluster, merge the others into it. Otherwise, pick a broad name and create the consolidated file.
194
+ - Delete the original narrow files after merging.
195
+ - Generic examples of clusters to consolidate (patterns, not literal names): files matching \`<topic-area>-feedback-<YYYY-MM-DD>.md\`, \`<project>-preference-<issue-id>.md\`, \`<topic-area>-session-<date>.md\`, \`<one-off>-incident-<date>.md\` — all of these should fold into the broad \`<topic-area>-style.md\`, \`<topic-area>-workflow.md\`, or \`<topic>.md\` file.
196
+ - Preserve substantive content during the merge; deduplicate restated preferences and keep only one clear statement per preference.
197
+
198
+ ### Misclassification
199
+
200
+ Content that belongs in facts memory, not preferences:
201
+ - Read each file and ask: "Does this describe a subjective choice (preference) or reference information (fact)?"
202
+ - If the file describes how something works, technical specifications, financial structures, system configurations, or procedural workflows → it is misclassified
203
+ - For misclassified files: delete the preferences file. The facts extraction processor will pick the content up on the next relevant conversation.
204
+
205
+ ### Size Enforcement
206
+
207
+ Flag any file exceeding 30 lines for consolidation or pruning:
208
+ - If a file exceeds 30 lines, it likely contains reference information that belongs in facts, or multiple preferences that could be expressed more concisely
209
+ - Prune redundant statements within the file
210
+ - If the excess is factual content, treat as misclassification (see above)
211
+
212
+ ### Cross-Store Overlap with Facts
213
+
214
+ Check \`$WORKSPACE/memories/facts/\` for files covering the same topic:
215
+ - If a facts file already covers the topic, the preferences file should only contain genuinely subjective aspects (how the user wants things done) — not the factual details already captured in facts
216
+ - If a preferences file contains only factual content that a facts file already covers, delete the preferences file — it serves no purpose
217
+
218
+ ## Deletion
219
+
220
+ - If a preference file is entirely superseded (its preferences are all present in a newer, more complete file), delete it.
221
+ - If a preference file describes preferences the user no longer holds (e.g., contradicted by a newer entry), remove only the outdated entries — or delete the file if it becomes empty.
222
+ - Do NOT delete files that contain any current, unique preferences.
223
+
224
+ ## Idempotency
225
+
226
+ Treat absence of exact duplicates as insufficient grounds for skipping — semantic overlap and split topics are also triggers for action. Actively re-apply the Evaluation Criteria and Deletion sections above: merge overlapping files even when they aren't word-for-word duplicates, and remove reversed or superseded preferences even when they aren't explicitly contradicted in a newer file.
227
+
228
+ If no changes are needed, exit with no changes.`;
229
+ const heavyIndexRebuildSection = (store) => `## Memory Index Rebuild (full)
230
+
231
+ Rebuild the MEMORY.md index file in \`$WORKSPACE/memories/${store}/\` from scratch:
232
+
233
+ 1. **List all files**: find all \`.md\` files in \`$WORKSPACE/memories/${store}/\` (exclude \`MEMORY.md\` itself).
234
+
235
+ 2. **If the directory is empty** (no \`.md\` files besides MEMORY.md): write MEMORY.md with only the header \`# Memory Index\` and stop — no further steps needed.
236
+
237
+ 3. **Describe every file**: read each file and produce a concise one-line description (under 80 characters) that captures the file's topic and scope. Focus on WHAT the file contains, not its history.
238
+
239
+ 4. **Analyze for structural improvements**:
240
+ - If multiple files have very similar content (same topic/domain), consider merging them into a single file with a broad name.
241
+ - If a file's name doesn't match its content (e.g., date-based name for general content), rename it: write the content to the new name, then empty the old file.
242
+ - If files are fragmented (many small files about the same thing), consolidate into fewer, broader files.
243
+
244
+ 5. **Write MEMORY.md from scratch** with:
245
+ - Header: \`# Memory Index\`
246
+ - One entry per current file in format: \`[Human-readable Name](./filename.md): One-line description\`
247
+ - Entries listed in alphabetical order by filename
248
+
249
+ ### Entry Format
250
+
251
+ \`\`\`
252
+ [Topic Name](./topic-slug.md): One-line description of what this file contains
253
+ \`\`\`
254
+
255
+ - The name in brackets is a human-readable topic name (Title Case)
256
+ - The path is a relative markdown link starting with \`./\`
257
+ - The description is one line, under 80 characters
258
+ - Separate the link and description with \`: \` (colon + space)`;
259
+ const CONTRADICTION_DETECTION_SECTION = `## Cross-Store Contradiction Detection
260
+
261
+ When reviewing files in this store, check for contradictions against other stores:
262
+
263
+ 1. Read the files listed in the cross-store visibility section above
264
+ 2. Compare their content against the files you're maintaining in this store
265
+ 3. If you find contradictory information:
266
+ - Determine which store is more authoritative per the authority hierarchy (Facts > Context)
267
+ - If this store is LESS authoritative: update or remove the contradicting entry in this store to match the more authoritative source
268
+ - If this store is MORE authoritative: leave this store's entry unchanged (the other store's maintenance tick will handle it)
269
+ 4. When information in this store duplicates detail from a more authoritative store: trim this store's entry to a brief pointer (e.g., "See memories/facts/X.md for details")`;
270
+ const STORE_LABELS = {
271
+ episodic: "Episodic Files",
272
+ facts: "Facts Files",
273
+ preferences: "Preferences Files",
274
+ };
275
+ const CONTEXT_FILE_NAMES = ["SOUL.md", "USER.md", "AGENTS.md"];
276
+ /** Names-only listing of the other stores so the maintenance agent can reconcile across them. */
277
+ export const buildCrossStoreManifest = async (workspaceRoot, current) => {
278
+ const sections = [];
279
+ for (const store of MEMORY_STORES) {
280
+ if (store === current)
281
+ continue;
282
+ let files;
283
+ try {
284
+ files = (await readdir(storeDir(workspaceRoot, store)))
285
+ .filter((name) => name.endsWith(".md"))
286
+ .sort();
287
+ }
288
+ catch {
289
+ continue;
290
+ }
291
+ if (files.length === 0)
292
+ continue;
293
+ sections.push([
294
+ `### ${STORE_LABELS[store]}`,
295
+ "",
296
+ ...files.map((name) => `- \`memories/${store}/${name}\``),
297
+ ].join("\n"));
298
+ }
299
+ const contextFiles = [];
300
+ for (const name of CONTEXT_FILE_NAMES) {
301
+ if (await fileExists(join(workspaceRoot, name)))
302
+ contextFiles.push(name);
303
+ }
304
+ if (contextFiles.length > 0) {
305
+ sections.push([
306
+ "### Context Files",
307
+ "",
308
+ ...contextFiles.map((name) => `- \`${name}\` (workspace root)`),
309
+ ].join("\n"));
310
+ }
311
+ if (sections.length === 0)
312
+ return null;
313
+ return [
314
+ "## Cross-Store Visibility",
315
+ "",
316
+ "Files in other information stores (names and paths only, not content):",
317
+ "",
318
+ sections.join("\n\n"),
319
+ "",
320
+ "If a section in this store duplicates or contradicts content in a listed file, reconcile per the authority hierarchy in your instructions.",
321
+ ].join("\n");
322
+ };
323
+ const basePrompt = (store, settings) => {
324
+ if (store === "episodic")
325
+ return episodicMaintenancePrompt(settings);
326
+ if (store === "facts")
327
+ return FACTS_MAINTENANCE_PROMPT;
328
+ return PREFERENCES_MAINTENANCE_PROMPT;
329
+ };
330
+ export const maintenanceSystemPrompt = async (store, { workspaceRoot, settings, now }) => {
331
+ const parts = [basePrompt(store, settings)];
332
+ // Day-of-week dispatch: weekdays keep the index consistent cheaply,
333
+ // Sunday rebuilds it from scratch with fresh descriptions.
334
+ if (store !== "episodic") {
335
+ const isSunday = (now?.() ?? new Date()).getDay() === 0;
336
+ parts.push(isSunday ? heavyIndexRebuildSection(store) : INDEX_LIGHT_MAINTENANCE_SECTION);
337
+ }
338
+ parts.push(STORE_PURPOSE_SECTION);
339
+ const manifest = await buildCrossStoreManifest(workspaceRoot, store);
340
+ if (manifest != null)
341
+ parts.push(manifest);
342
+ parts.push(CONTRADICTION_DETECTION_SECTION, scopeSection(store));
343
+ return parts.join("\n\n").replaceAll("$WORKSPACE", workspaceRoot);
344
+ };
345
+ /** Daily maintenance pass over one memory store: consolidate, prune, keep indexes in sync. */
346
+ export const runMaintenanceTick = async (store, deps) => {
347
+ deps.log.info({ store }, "memory maintenance tick started");
348
+ await deps.side.run({
349
+ tools: MEMORY_FILE_TOOLS,
350
+ system: await maintenanceSystemPrompt(store, deps),
351
+ prompt: "Perform the maintenance pass now, following your instructions.",
352
+ tier: "processor",
353
+ });
354
+ await sweepEmptyMarkdown(storeDir(deps.workspaceRoot, store), deps.log);
355
+ deps.log.info({ store }, "memory maintenance tick completed");
356
+ };
357
+ //# sourceMappingURL=maintenance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maintenance.js","sourceRoot":"","sources":["../../../src/extensions/memory/maintenance.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { MemoryStore } from "./layout.ts";
2
+ export declare const STORE_PURPOSE_SECTION = "## Store Purpose Definitions\n\nEach information store serves a distinct purpose. Use these definitions to route information correctly:\n\n- **Memory facts** (`memories/facts/`): Stable reference information \u2014 project state, technical decisions, configuration, people, system architecture. Most authoritative store for reference information.\n- **Memory preferences** (`memories/preferences/`): Subjective choices with rationale \u2014 how the user wants things done, with context about why.\n- **Memory episodic** (`memories/episodic/`): Date-stamped summaries of what happened \u2014 events, outcomes, and decisions tied to a specific day.\n- **Context files** (workspace root): Concise summaries and pointers \u2014 personality (SOUL.md), user identity (USER.md), behavioral guidance (AGENTS.md). Context should reference facts rather than inlining their content.\n\nAuthority order: Memory facts > Context files. When information appears in multiple stores, the more authoritative source is correct. Context files should contain summaries and pointers, not detailed operational content.";
3
+ export declare const CLASSIFICATION_EXAMPLES_SECTION = "## Classification Examples\n\nUse these examples to route information correctly between facts and preferences.\n\n### IS a preference (subjective choice about HOW the user wants things done):\n- \"I prefer concise commit messages over detailed ones\" \u2192 style preference\n- \"Always run tests before pushing\" \u2192 workflow preference\n- \"Use dark theme for code editors\" \u2192 tooling preference\n- \"I like getting a summary first, then details on request\" \u2192 communication style preference\n- \"Prefer smaller, focused PRs over large ones\" \u2192 workflow preference\n\n### NOT a preference (describes HOW SOMETHING WORKS \u2014 belongs in facts or project docs):\n- \"The payment gateway has a 2% processing fee\" \u2192 financial reference data \u2192 facts\n- \"The reconciliation process runs nightly at 3am\" \u2192 financial reference data \u2192 facts\n- \"Environment variable FOO must be set to BAR for the service to start\" \u2192 technical specification \u2192 facts\n- \"The SDK has a 200K token context window\" \u2192 technical specification \u2192 facts\n- \"The API rate limit is 100 requests per minute\" \u2192 technical specification \u2192 facts\n- \"The cleanup procedure involves stopping the service, clearing /tmp, and restarting\" \u2192 procedural workflow \u2192 facts\n- \"We configured nginx to proxy /api to port 8080\" \u2192 system configuration record \u2192 facts\n- \"The deployment uses blue-green strategy with health checks\" \u2192 system configuration record \u2192 facts\n\n### IS a fact (stable reference information that stays true across conversations):\n- \"The CI pipeline runs on GitHub Actions\" \u2192 infrastructure fact\n- \"User X is the team lead for project Y\" \u2192 organizational fact\n- \"The database uses PostgreSQL 16 with async replication\" \u2192 technical fact\n- \"The API rate limit is 100 requests per minute\" \u2192 technical fact\n\n### NOT a fact (belongs in episodic memory or project docs):\n- \"We debugged the payment timeout issue on 2026-05-10\" \u2192 one-time event \u2192 episodic\n- \"The full architecture of system X is...\" \u2192 too long for facts \u2192 project docs";
4
+ export declare const CONTEXT_DEDUP_SECTION = "## Context File Deduplication\n\nBefore creating any new memory file, check whether the information is already covered in the foundational context files at the workspace root. These files are maintained as the authoritative source for certain categories of information.\n\n1. Read the context files:\n - `$WORKSPACE/AGENTS.md` \u2014 operational guidelines and workflow preferences\n - `$WORKSPACE/USER.md` \u2014 stable identity and high-level project awareness\n - `$WORKSPACE/SOUL.md` \u2014 personality and communication style\n\n2. For each piece of information you're about to write:\n - If the SAME information is already in one of these files, do NOT create a memory file for it \u2014 the context file is the source of truth\n - If a context file partially covers the topic but the conversation adds genuinely new details not found there, you MAY create a file \u2014 but only for the new information, not a restatement of what's already in the context file\n - If no context file covers the topic, proceed normally\n\nThis check prevents duplicating information across the memory system and the context files, which would create confusion about which is authoritative.";
5
+ export declare const WORKSPACE_VALIDATION_SECTION = "## Workspace Validation\n\nBefore writing a memory that contains claims about workspace state \u2014 file paths, project structure, configuration values, implementation details \u2014 validate each claim against the actual workspace:\n\n1. Identify verifiable claims in the memory you're about to write:\n - References to specific files or directories (do they exist? contain what's claimed?)\n - Configuration values (does the config file actually say that?)\n - Project state (is the project actually in that state?)\n\n2. Verify each claim directly: read the relevant file(s) or grep for the referenced content.\n\n3. Only include claims you could verify:\n - If a claim turns out to be false, omit it\n - If ALL claims are invalid, do not create the file\n\nDo NOT validate: subjective information, preferences, general knowledge, conversation summaries, personal details \u2014 only verifiable claims about workspace state.";
6
+ export declare const INDEX_UPDATE_SECTION = "## Memory Index\n\nWhen you create, modify, or delete a memory file, you MUST also update MEMORY.md in the same directory to keep the index in sync.\n\n### Entry Format\n\nEach entry in MEMORY.md follows this format:\n\n```\n[Human-readable Name](./filename.md): One-line description of contents\n```\n\n### Rules\n\n- **CREATE** a new file: add a new entry with an appropriate description\n- **MODIFY** a file: update the description if the topic, focus, or scope meaningfully changed\n- **DELETE** a file: remove the corresponding entry\n- Always preserve the `# Memory Index` header\n- Keep descriptions concise \u2014 one line, under 80 characters\n- The name in brackets should be a human-readable topic name (Title Case)\n\n### Example Entries\n\n```\n# Memory Index\n\n[API Design](./api-design.md): API architecture decisions and endpoint patterns\n[Work Info](./work-info.md): Job details, team structure, and work schedule\n[Tech Stack](./tech-stack.md): Primary languages, frameworks, and tools used\n```";
7
+ export declare const INDEX_LIGHT_MAINTENANCE_SECTION = "## Memory Index Consistency\n\nVerify index consistency between MEMORY.md and actual files in the directory.\n\n### Steps\n\n1. **List all files**: list all `.md` files in the directory (excluding `MEMORY.md` itself) using the ls or find tool.\n2. **Read MEMORY.md**: Parse the existing index entries.\n3. **Add missing entries**: For files that exist in the directory but have no entry in MEMORY.md, add a placeholder entry:\n ```\n [Topic](./filename.md): Description pending update\n ```\n4. **Remove stale entries**: For entries in MEMORY.md that reference files that no longer exist, remove those entries.\n5. **Preserve existing descriptions**: Do NOT regenerate or modify existing descriptions \u2014 leave them unchanged even if stale. Description regeneration is handled by the weekly full rebuild.\n\n### Rules\n\n- Always preserve the `# Memory Index` header.\n- When you create, modify, or delete memory files during this maintenance run, also update MEMORY.md per the standard index update rules (add new entries, update descriptions on meaningful changes, remove entries for deleted files).\n- The consistency check runs in addition to your normal maintenance tasks.";
8
+ export declare const scopeSection: (store: MemoryStore) => string;
@@ -0,0 +1,125 @@
1
+ export const STORE_PURPOSE_SECTION = `## Store Purpose Definitions
2
+
3
+ Each information store serves a distinct purpose. Use these definitions to route information correctly:
4
+
5
+ - **Memory facts** (\`memories/facts/\`): Stable reference information — project state, technical decisions, configuration, people, system architecture. Most authoritative store for reference information.
6
+ - **Memory preferences** (\`memories/preferences/\`): Subjective choices with rationale — how the user wants things done, with context about why.
7
+ - **Memory episodic** (\`memories/episodic/\`): Date-stamped summaries of what happened — events, outcomes, and decisions tied to a specific day.
8
+ - **Context files** (workspace root): Concise summaries and pointers — personality (SOUL.md), user identity (USER.md), behavioral guidance (AGENTS.md). Context should reference facts rather than inlining their content.
9
+
10
+ Authority order: Memory facts > Context files. When information appears in multiple stores, the more authoritative source is correct. Context files should contain summaries and pointers, not detailed operational content.`;
11
+ export const CLASSIFICATION_EXAMPLES_SECTION = `## Classification Examples
12
+
13
+ Use these examples to route information correctly between facts and preferences.
14
+
15
+ ### IS a preference (subjective choice about HOW the user wants things done):
16
+ - "I prefer concise commit messages over detailed ones" → style preference
17
+ - "Always run tests before pushing" → workflow preference
18
+ - "Use dark theme for code editors" → tooling preference
19
+ - "I like getting a summary first, then details on request" → communication style preference
20
+ - "Prefer smaller, focused PRs over large ones" → workflow preference
21
+
22
+ ### NOT a preference (describes HOW SOMETHING WORKS — belongs in facts or project docs):
23
+ - "The payment gateway has a 2% processing fee" → financial reference data → facts
24
+ - "The reconciliation process runs nightly at 3am" → financial reference data → facts
25
+ - "Environment variable FOO must be set to BAR for the service to start" → technical specification → facts
26
+ - "The SDK has a 200K token context window" → technical specification → facts
27
+ - "The API rate limit is 100 requests per minute" → technical specification → facts
28
+ - "The cleanup procedure involves stopping the service, clearing /tmp, and restarting" → procedural workflow → facts
29
+ - "We configured nginx to proxy /api to port 8080" → system configuration record → facts
30
+ - "The deployment uses blue-green strategy with health checks" → system configuration record → facts
31
+
32
+ ### IS a fact (stable reference information that stays true across conversations):
33
+ - "The CI pipeline runs on GitHub Actions" → infrastructure fact
34
+ - "User X is the team lead for project Y" → organizational fact
35
+ - "The database uses PostgreSQL 16 with async replication" → technical fact
36
+ - "The API rate limit is 100 requests per minute" → technical fact
37
+
38
+ ### NOT a fact (belongs in episodic memory or project docs):
39
+ - "We debugged the payment timeout issue on 2026-05-10" → one-time event → episodic
40
+ - "The full architecture of system X is..." → too long for facts → project docs`;
41
+ export const CONTEXT_DEDUP_SECTION = `## Context File Deduplication
42
+
43
+ Before creating any new memory file, check whether the information is already covered in the foundational context files at the workspace root. These files are maintained as the authoritative source for certain categories of information.
44
+
45
+ 1. Read the context files:
46
+ - \`$WORKSPACE/AGENTS.md\` — operational guidelines and workflow preferences
47
+ - \`$WORKSPACE/USER.md\` — stable identity and high-level project awareness
48
+ - \`$WORKSPACE/SOUL.md\` — personality and communication style
49
+
50
+ 2. For each piece of information you're about to write:
51
+ - If the SAME information is already in one of these files, do NOT create a memory file for it — the context file is the source of truth
52
+ - If a context file partially covers the topic but the conversation adds genuinely new details not found there, you MAY create a file — but only for the new information, not a restatement of what's already in the context file
53
+ - If no context file covers the topic, proceed normally
54
+
55
+ This check prevents duplicating information across the memory system and the context files, which would create confusion about which is authoritative.`;
56
+ export const WORKSPACE_VALIDATION_SECTION = `## Workspace Validation
57
+
58
+ Before writing a memory that contains claims about workspace state — file paths, project structure, configuration values, implementation details — validate each claim against the actual workspace:
59
+
60
+ 1. Identify verifiable claims in the memory you're about to write:
61
+ - References to specific files or directories (do they exist? contain what's claimed?)
62
+ - Configuration values (does the config file actually say that?)
63
+ - Project state (is the project actually in that state?)
64
+
65
+ 2. Verify each claim directly: read the relevant file(s) or grep for the referenced content.
66
+
67
+ 3. Only include claims you could verify:
68
+ - If a claim turns out to be false, omit it
69
+ - If ALL claims are invalid, do not create the file
70
+
71
+ Do NOT validate: subjective information, preferences, general knowledge, conversation summaries, personal details — only verifiable claims about workspace state.`;
72
+ export const INDEX_UPDATE_SECTION = `## Memory Index
73
+
74
+ When you create, modify, or delete a memory file, you MUST also update MEMORY.md in the same directory to keep the index in sync.
75
+
76
+ ### Entry Format
77
+
78
+ Each entry in MEMORY.md follows this format:
79
+
80
+ \`\`\`
81
+ [Human-readable Name](./filename.md): One-line description of contents
82
+ \`\`\`
83
+
84
+ ### Rules
85
+
86
+ - **CREATE** a new file: add a new entry with an appropriate description
87
+ - **MODIFY** a file: update the description if the topic, focus, or scope meaningfully changed
88
+ - **DELETE** a file: remove the corresponding entry
89
+ - Always preserve the \`# Memory Index\` header
90
+ - Keep descriptions concise — one line, under 80 characters
91
+ - The name in brackets should be a human-readable topic name (Title Case)
92
+
93
+ ### Example Entries
94
+
95
+ \`\`\`
96
+ # Memory Index
97
+
98
+ [API Design](./api-design.md): API architecture decisions and endpoint patterns
99
+ [Work Info](./work-info.md): Job details, team structure, and work schedule
100
+ [Tech Stack](./tech-stack.md): Primary languages, frameworks, and tools used
101
+ \`\`\``;
102
+ export const INDEX_LIGHT_MAINTENANCE_SECTION = `## Memory Index Consistency
103
+
104
+ Verify index consistency between MEMORY.md and actual files in the directory.
105
+
106
+ ### Steps
107
+
108
+ 1. **List all files**: list all \`.md\` files in the directory (excluding \`MEMORY.md\` itself) using the ls or find tool.
109
+ 2. **Read MEMORY.md**: Parse the existing index entries.
110
+ 3. **Add missing entries**: For files that exist in the directory but have no entry in MEMORY.md, add a placeholder entry:
111
+ \`\`\`
112
+ [Topic](./filename.md): Description pending update
113
+ \`\`\`
114
+ 4. **Remove stale entries**: For entries in MEMORY.md that reference files that no longer exist, remove those entries.
115
+ 5. **Preserve existing descriptions**: Do NOT regenerate or modify existing descriptions — leave them unchanged even if stale. Description regeneration is handled by the weekly full rebuild.
116
+
117
+ ### Rules
118
+
119
+ - Always preserve the \`# Memory Index\` header.
120
+ - When you create, modify, or delete memory files during this maintenance run, also update MEMORY.md per the standard index update rules (add new entries, update descriptions on meaningful changes, remove entries for deleted files).
121
+ - The consistency check runs in addition to your normal maintenance tasks.`;
122
+ export const scopeSection = (store) => `## Scope
123
+
124
+ You can read files anywhere in the workspace (needed for validation and deduplication). Only create or modify files within \`$WORKSPACE/memories/${store}/\`. You have no delete tool: when a file must go away (merged into another, obsolete, or misnamed), overwrite it with empty content — empty files are cleaned up automatically after you finish.`;
125
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../../src/extensions/memory/prompts.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;6NASwL,CAAC;AAE9N,MAAM,CAAC,MAAM,+BAA+B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gFA6BiC,CAAC;AAEjF,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;uJAckH,CAAC;AAExJ,MAAM,CAAC,MAAM,4BAA4B,GAAG;;;;;;;;;;;;;;;kKAesH,CAAC;AAEnK,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6B7B,CAAC;AAER,MAAM,CAAC,MAAM,+BAA+B,GAAG;;;;;;;;;;;;;;;;;;;2EAmB4B,CAAC;AAE5E,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAkB,EAAU,EAAE,CAAC;;mJAEuF,KAAK,mMAAmM,CAAC"}
@@ -0,0 +1,18 @@
1
+ export interface ConversationTurn {
2
+ role: "user" | "assistant";
3
+ text: string;
4
+ }
5
+ /**
6
+ * Parse a pi session JSONL transcript into conversation turns. Keeps only
7
+ * user/assistant text — tool calls, tool results, thinking, and non-message
8
+ * entries are noise for memory extraction. Malformed lines are skipped.
9
+ */
10
+ export declare const parseTranscript: (jsonl: string) => ConversationTurn[];
11
+ /**
12
+ * Render turns as a readable "role: text" conversation capped at maxChars.
13
+ * When over budget the newest turns win — the tail of a session carries the
14
+ * conclusions worth remembering.
15
+ */
16
+ export declare const renderConversation: (turns: ConversationTurn[], maxChars: number) => string;
17
+ /** Read, parse, and render a transcript file. Returns "" when unreadable or empty. */
18
+ export declare const loadConversation: (path: string, maxChars: number) => Promise<string>;
@@ -0,0 +1,79 @@
1
+ import { readFile } from "node:fs/promises";
2
+ const textOfContent = (content) => {
3
+ if (typeof content === "string")
4
+ return content;
5
+ return content
6
+ .filter((block) => block.type === "text" && block.text != null)
7
+ .map((block) => block.text)
8
+ .join("\n");
9
+ };
10
+ /**
11
+ * Parse a pi session JSONL transcript into conversation turns. Keeps only
12
+ * user/assistant text — tool calls, tool results, thinking, and non-message
13
+ * entries are noise for memory extraction. Malformed lines are skipped.
14
+ */
15
+ export const parseTranscript = (jsonl) => {
16
+ const turns = [];
17
+ for (const line of jsonl.split("\n")) {
18
+ if (line.trim() === "")
19
+ continue;
20
+ let entry;
21
+ try {
22
+ entry = JSON.parse(line);
23
+ }
24
+ catch {
25
+ continue;
26
+ }
27
+ if (entry.type !== "message" || entry.message == null)
28
+ continue;
29
+ const { role, content } = entry.message;
30
+ if ((role !== "user" && role !== "assistant") || content == null)
31
+ continue;
32
+ const text = textOfContent(content).trim();
33
+ if (text === "")
34
+ continue;
35
+ turns.push({ role, text });
36
+ }
37
+ return turns;
38
+ };
39
+ /**
40
+ * Render turns as a readable "role: text" conversation capped at maxChars.
41
+ * When over budget the newest turns win — the tail of a session carries the
42
+ * conclusions worth remembering.
43
+ */
44
+ export const renderConversation = (turns, maxChars) => {
45
+ const kept = [];
46
+ let total = 0;
47
+ let truncated = false;
48
+ for (let index = turns.length - 1; index >= 0; index -= 1) {
49
+ const turn = turns[index];
50
+ if (turn == null)
51
+ continue;
52
+ const line = `${turn.role}: ${turn.text}`;
53
+ if (total + line.length > maxChars) {
54
+ if (kept.length === 0) {
55
+ const budget = Math.max(0, maxChars - turn.role.length - 3);
56
+ kept.push(`${turn.role}: …${turn.text.slice(-budget)}`);
57
+ }
58
+ truncated = true;
59
+ break;
60
+ }
61
+ kept.push(line);
62
+ total += line.length + 2;
63
+ }
64
+ if (truncated)
65
+ kept.push("[earlier conversation truncated]");
66
+ return kept.reverse().join("\n\n");
67
+ };
68
+ /** Read, parse, and render a transcript file. Returns "" when unreadable or empty. */
69
+ export const loadConversation = async (path, maxChars) => {
70
+ let raw;
71
+ try {
72
+ raw = await readFile(path, "utf8");
73
+ }
74
+ catch {
75
+ return "";
76
+ }
77
+ return renderConversation(parseTranscript(raw), maxChars);
78
+ };
79
+ //# sourceMappingURL=transcript.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcript.js","sourceRoot":"","sources":["../../../src/extensions/memory/transcript.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAiB5C,MAAM,aAAa,GAAG,CAAC,OAAgC,EAAU,EAAE;IACjE,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAC;IAEhD,OAAO,OAAO;SACX,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC;SAC9D,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAc,CAAC;SACpC,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,KAAa,EAAsB,EAAE;IACnE,MAAM,KAAK,GAAuB,EAAE,CAAC;IAErC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,SAAS;QAEjC,IAAI,KAAqD,CAAC;QAC1D,IAAI,CAAC;YACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QAED,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,IAAI,IAAI;YAAE,SAAS;QAEhE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC;QACxC,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,WAAW,CAAC,IAAI,OAAO,IAAI,IAAI;YAAE,SAAS;QAE3E,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3C,IAAI,IAAI,KAAK,EAAE;YAAE,SAAS;QAE1B,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7B,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,KAAyB,EAAE,QAAgB,EAAU,EAAE;IACxF,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,KAAK,IAAI,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1B,IAAI,IAAI,IAAI,IAAI;YAAE,SAAS;QAE3B,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;QAE1C,IAAI,KAAK,GAAG,IAAI,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;YACnC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBAC5D,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC1D,CAAC;YAED,SAAS,GAAG,IAAI,CAAC;YACjB,MAAM;QACR,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChB,KAAK,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAC3B,CAAC;IAED,IAAI,SAAS;QAAE,IAAI,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;IAE7D,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACrC,CAAC,CAAC;AAEF,sFAAsF;AACtF,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EAAE,IAAY,EAAE,QAAgB,EAAmB,EAAE;IACxF,IAAI,GAAW,CAAC;IAEhB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,kBAAkB,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC;AAC5D,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { NotifyPayload } from "./payload.ts";
2
+ /** Single notification with the source/time prefix block. */
3
+ export declare const formatNotification: (payload: NotifyPayload, now: Date) => string;
4
+ /** Combined digest for several accumulated notices. */
5
+ export declare const formatDigest: (items: NotifyPayload[], now: Date) => string;
@@ -0,0 +1,17 @@
1
+ const formatTimestamp = (date) => `${date.toISOString().slice(0, 16).replace("T", " ")} UTC`;
2
+ /** Single notification with the source/time prefix block. */
3
+ export const formatNotification = (payload, now) => {
4
+ const body = payload.title != null ? `${payload.title}\n\n${payload.text}` : payload.text;
5
+ return `--- Notification ---\nSource: ${payload.source}\nTime: ${formatTimestamp(now)}\n\n${body}`;
6
+ };
7
+ /** Combined digest for several accumulated notices. */
8
+ export const formatDigest = (items, now) => {
9
+ const parts = [`--- Notifications digest ---\nTime: ${formatTimestamp(now)}`, ""];
10
+ items.forEach((item, index) => {
11
+ parts.push(`— Item ${index + 1} (${item.severity}, source: ${item.source}) —`);
12
+ parts.push(item.title != null ? `${item.title}\n${item.text}` : item.text);
13
+ parts.push("");
14
+ });
15
+ return parts.join("\n");
16
+ };
17
+ //# sourceMappingURL=format.js.map