cognitive-core 0.1.2 → 0.2.1

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 (528) hide show
  1. package/.claude/settings.json +111 -2
  2. package/.sessionlog/settings.json +4 -0
  3. package/CLAUDE.md +233 -0
  4. package/README.md +370 -54
  5. package/dist/atlas.d.ts +10 -10
  6. package/dist/atlas.d.ts.map +1 -1
  7. package/dist/atlas.js +79 -48
  8. package/dist/atlas.js.map +1 -1
  9. package/dist/bin/cli-utils.d.ts +37 -0
  10. package/dist/bin/cli-utils.d.ts.map +1 -0
  11. package/dist/bin/cli-utils.js +176 -0
  12. package/dist/bin/cli-utils.js.map +1 -0
  13. package/dist/bin/cognitive-core.d.ts +2 -12
  14. package/dist/bin/cognitive-core.d.ts.map +1 -1
  15. package/dist/bin/cognitive-core.js +76 -351
  16. package/dist/bin/cognitive-core.js.map +1 -1
  17. package/dist/bin/commands/kb.d.ts +6 -0
  18. package/dist/bin/commands/kb.d.ts.map +1 -0
  19. package/dist/bin/commands/kb.js +240 -0
  20. package/dist/bin/commands/kb.js.map +1 -0
  21. package/dist/bin/commands/learn.d.ts +6 -0
  22. package/dist/bin/commands/learn.d.ts.map +1 -0
  23. package/dist/bin/commands/learn.js +91 -0
  24. package/dist/bin/commands/learn.js.map +1 -0
  25. package/dist/bin/commands/legacy.d.ts +12 -0
  26. package/dist/bin/commands/legacy.d.ts.map +1 -0
  27. package/dist/bin/commands/legacy.js +142 -0
  28. package/dist/bin/commands/legacy.js.map +1 -0
  29. package/dist/bin/commands/run.d.ts +3 -0
  30. package/dist/bin/commands/run.d.ts.map +1 -0
  31. package/dist/bin/commands/run.js +99 -0
  32. package/dist/bin/commands/run.js.map +1 -0
  33. package/dist/bin/commands/sessions.d.ts +9 -0
  34. package/dist/bin/commands/sessions.d.ts.map +1 -0
  35. package/dist/bin/commands/sessions.js +183 -0
  36. package/dist/bin/commands/sessions.js.map +1 -0
  37. package/dist/bin/commands/skills.d.ts +6 -0
  38. package/dist/bin/commands/skills.d.ts.map +1 -0
  39. package/dist/bin/commands/skills.js +135 -0
  40. package/dist/bin/commands/skills.js.map +1 -0
  41. package/dist/embeddings/index.d.ts +1 -0
  42. package/dist/embeddings/index.d.ts.map +1 -1
  43. package/dist/embeddings/index.js +2 -0
  44. package/dist/embeddings/index.js.map +1 -1
  45. package/dist/embeddings/inverted-index.d.ts +47 -0
  46. package/dist/embeddings/inverted-index.d.ts.map +1 -0
  47. package/dist/embeddings/inverted-index.js +122 -0
  48. package/dist/embeddings/inverted-index.js.map +1 -0
  49. package/dist/embeddings/manager.d.ts +3 -1
  50. package/dist/embeddings/manager.d.ts.map +1 -1
  51. package/dist/embeddings/manager.js +12 -7
  52. package/dist/embeddings/manager.js.map +1 -1
  53. package/dist/embeddings/vector-store.d.ts +7 -3
  54. package/dist/embeddings/vector-store.d.ts.map +1 -1
  55. package/dist/embeddings/vector-store.js +22 -6
  56. package/dist/embeddings/vector-store.js.map +1 -1
  57. package/dist/factory.d.ts +11 -12
  58. package/dist/factory.d.ts.map +1 -1
  59. package/dist/factory.js +20 -7
  60. package/dist/factory.js.map +1 -1
  61. package/dist/index.d.ts +8 -7
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +42 -6
  64. package/dist/index.js.map +1 -1
  65. package/dist/learning/analyzer.d.ts.map +1 -1
  66. package/dist/learning/analyzer.js +17 -35
  67. package/dist/learning/analyzer.js.map +1 -1
  68. package/dist/learning/energy-evaluator.d.ts +128 -0
  69. package/dist/learning/energy-evaluator.d.ts.map +1 -0
  70. package/dist/learning/energy-evaluator.js +175 -0
  71. package/dist/learning/energy-evaluator.js.map +1 -0
  72. package/dist/learning/healing-orchestrator.d.ts +182 -0
  73. package/dist/learning/healing-orchestrator.d.ts.map +1 -0
  74. package/dist/learning/healing-orchestrator.js +250 -0
  75. package/dist/learning/healing-orchestrator.js.map +1 -0
  76. package/dist/learning/index.d.ts +7 -2
  77. package/dist/learning/index.d.ts.map +1 -1
  78. package/dist/learning/index.js +13 -2
  79. package/dist/learning/index.js.map +1 -1
  80. package/dist/learning/instant-loop.d.ts +87 -0
  81. package/dist/learning/instant-loop.d.ts.map +1 -0
  82. package/dist/learning/instant-loop.js +264 -0
  83. package/dist/learning/instant-loop.js.map +1 -0
  84. package/dist/learning/loop-coordinator.d.ts +61 -0
  85. package/dist/learning/loop-coordinator.d.ts.map +1 -0
  86. package/dist/learning/loop-coordinator.js +96 -0
  87. package/dist/learning/loop-coordinator.js.map +1 -0
  88. package/dist/learning/maintenance-scheduler.d.ts +141 -0
  89. package/dist/learning/maintenance-scheduler.d.ts.map +1 -0
  90. package/dist/learning/maintenance-scheduler.js +186 -0
  91. package/dist/learning/maintenance-scheduler.js.map +1 -0
  92. package/dist/learning/meta-learner.d.ts.map +1 -1
  93. package/dist/learning/meta-learner.js +4 -21
  94. package/dist/learning/meta-learner.js.map +1 -1
  95. package/dist/learning/pipeline.d.ts +31 -4
  96. package/dist/learning/pipeline.d.ts.map +1 -1
  97. package/dist/learning/pipeline.js +64 -12
  98. package/dist/learning/pipeline.js.map +1 -1
  99. package/dist/learning/reflexion-generator.d.ts +64 -0
  100. package/dist/learning/reflexion-generator.d.ts.map +1 -0
  101. package/dist/learning/reflexion-generator.js +194 -0
  102. package/dist/learning/reflexion-generator.js.map +1 -0
  103. package/dist/learning/trajectory-sources/entire.d.ts +8 -5
  104. package/dist/learning/trajectory-sources/entire.d.ts.map +1 -1
  105. package/dist/learning/trajectory-sources/entire.js +13 -6
  106. package/dist/learning/trajectory-sources/entire.js.map +1 -1
  107. package/dist/learning/trajectory-sources/index.d.ts +1 -1
  108. package/dist/learning/trajectory-sources/index.d.ts.map +1 -1
  109. package/dist/learning/trajectory-sources/index.js +1 -1
  110. package/dist/learning/trajectory-sources/index.js.map +1 -1
  111. package/dist/learning/trajectory-sources/pipeline.d.ts +4 -4
  112. package/dist/learning/trajectory-sources/pipeline.d.ts.map +1 -1
  113. package/dist/learning/trajectory-sources/pipeline.js +2 -2
  114. package/dist/learning/trajectory-sources/pipeline.js.map +1 -1
  115. package/dist/learning/unified-pipeline.d.ts +311 -0
  116. package/dist/learning/unified-pipeline.d.ts.map +1 -0
  117. package/dist/learning/unified-pipeline.js +844 -0
  118. package/dist/learning/unified-pipeline.js.map +1 -0
  119. package/dist/memory/candidate-retrieval.d.ts +43 -0
  120. package/dist/memory/candidate-retrieval.d.ts.map +1 -0
  121. package/dist/memory/candidate-retrieval.js +43 -0
  122. package/dist/memory/candidate-retrieval.js.map +1 -0
  123. package/dist/memory/causal-store.d.ts +97 -0
  124. package/dist/memory/causal-store.d.ts.map +1 -0
  125. package/dist/memory/causal-store.js +209 -0
  126. package/dist/memory/causal-store.js.map +1 -0
  127. package/dist/memory/coherence.d.ts +71 -0
  128. package/dist/memory/coherence.d.ts.map +1 -0
  129. package/dist/memory/coherence.js +176 -0
  130. package/dist/memory/coherence.js.map +1 -0
  131. package/dist/memory/experience.d.ts +39 -6
  132. package/dist/memory/experience.d.ts.map +1 -1
  133. package/dist/memory/experience.js +193 -49
  134. package/dist/memory/experience.js.map +1 -1
  135. package/dist/memory/index.d.ts +7 -0
  136. package/dist/memory/index.d.ts.map +1 -1
  137. package/dist/memory/index.js +12 -0
  138. package/dist/memory/index.js.map +1 -1
  139. package/dist/memory/knowledge-bank.d.ts +14 -0
  140. package/dist/memory/knowledge-bank.d.ts.map +1 -1
  141. package/dist/memory/knowledge-bank.js +45 -0
  142. package/dist/memory/knowledge-bank.js.map +1 -1
  143. package/dist/memory/meta.d.ts +7 -8
  144. package/dist/memory/meta.d.ts.map +1 -1
  145. package/dist/memory/meta.js +73 -79
  146. package/dist/memory/meta.js.map +1 -1
  147. package/dist/memory/playbook.d.ts +26 -9
  148. package/dist/memory/playbook.d.ts.map +1 -1
  149. package/dist/memory/playbook.js +198 -74
  150. package/dist/memory/playbook.js.map +1 -1
  151. package/dist/memory/reasoning-bank.d.ts +130 -0
  152. package/dist/memory/reasoning-bank.d.ts.map +1 -0
  153. package/dist/memory/reasoning-bank.js +342 -0
  154. package/dist/memory/reasoning-bank.js.map +1 -0
  155. package/dist/memory/reflexion.d.ts +59 -0
  156. package/dist/memory/reflexion.d.ts.map +1 -0
  157. package/dist/memory/reflexion.js +96 -0
  158. package/dist/memory/reflexion.js.map +1 -0
  159. package/dist/memory/system.d.ts +7 -2
  160. package/dist/memory/system.d.ts.map +1 -1
  161. package/dist/memory/system.js +19 -7
  162. package/dist/memory/system.js.map +1 -1
  163. package/dist/memory/temporal-compressor.d.ts +126 -0
  164. package/dist/memory/temporal-compressor.d.ts.map +1 -0
  165. package/dist/memory/temporal-compressor.js +335 -0
  166. package/dist/memory/temporal-compressor.js.map +1 -0
  167. package/dist/persistence/index.d.ts +11 -0
  168. package/dist/persistence/index.d.ts.map +1 -0
  169. package/dist/persistence/index.js +11 -0
  170. package/dist/persistence/index.js.map +1 -0
  171. package/dist/persistence/migrator.d.ts +40 -0
  172. package/dist/persistence/migrator.d.ts.map +1 -0
  173. package/dist/persistence/migrator.js +238 -0
  174. package/dist/persistence/migrator.js.map +1 -0
  175. package/dist/persistence/serializers.d.ts +45 -0
  176. package/dist/persistence/serializers.d.ts.map +1 -0
  177. package/dist/persistence/serializers.js +80 -0
  178. package/dist/persistence/serializers.js.map +1 -0
  179. package/dist/persistence/sqlite-persistence.d.ts +228 -0
  180. package/dist/persistence/sqlite-persistence.d.ts.map +1 -0
  181. package/dist/persistence/sqlite-persistence.js +588 -0
  182. package/dist/persistence/sqlite-persistence.js.map +1 -0
  183. package/dist/runtime/flows/learning.d.ts +10 -12
  184. package/dist/runtime/flows/learning.d.ts.map +1 -1
  185. package/dist/runtime/flows/learning.js +10 -23
  186. package/dist/runtime/flows/learning.js.map +1 -1
  187. package/dist/search/index.d.ts +1 -0
  188. package/dist/search/index.d.ts.map +1 -1
  189. package/dist/search/index.js +2 -0
  190. package/dist/search/index.js.map +1 -1
  191. package/dist/search/moe-gate.d.ts +124 -0
  192. package/dist/search/moe-gate.d.ts.map +1 -0
  193. package/dist/search/moe-gate.js +234 -0
  194. package/dist/search/moe-gate.js.map +1 -0
  195. package/dist/search/router.d.ts +32 -2
  196. package/dist/search/router.d.ts.map +1 -1
  197. package/dist/search/router.js +87 -4
  198. package/dist/search/router.js.map +1 -1
  199. package/dist/session-bank/git-reader.d.ts +9 -4
  200. package/dist/session-bank/git-reader.d.ts.map +1 -1
  201. package/dist/session-bank/git-reader.js +22 -15
  202. package/dist/session-bank/git-reader.js.map +1 -1
  203. package/dist/session-bank/index.d.ts +2 -2
  204. package/dist/session-bank/index.d.ts.map +1 -1
  205. package/dist/session-bank/index.js +2 -2
  206. package/dist/session-bank/index.js.map +1 -1
  207. package/dist/session-bank/parser.d.ts +16 -5
  208. package/dist/session-bank/parser.d.ts.map +1 -1
  209. package/dist/session-bank/parser.js +187 -80
  210. package/dist/session-bank/parser.js.map +1 -1
  211. package/dist/session-bank/session-bank.d.ts +5 -0
  212. package/dist/session-bank/session-bank.d.ts.map +1 -1
  213. package/dist/session-bank/session-bank.js +30 -9
  214. package/dist/session-bank/session-bank.js.map +1 -1
  215. package/dist/session-bank/types.d.ts +4 -1
  216. package/dist/session-bank/types.d.ts.map +1 -1
  217. package/dist/session-bank/types.js +3 -3
  218. package/dist/session-bank/types.js.map +1 -1
  219. package/dist/surfacing/skill-publisher.d.ts.map +1 -1
  220. package/dist/surfacing/skill-publisher.js +15 -43
  221. package/dist/surfacing/skill-publisher.js.map +1 -1
  222. package/dist/surfacing/sqlite-storage-adapter.d.ts.map +1 -1
  223. package/dist/surfacing/sqlite-storage-adapter.js +13 -21
  224. package/dist/surfacing/sqlite-storage-adapter.js.map +1 -1
  225. package/dist/types/config.d.ts +100 -0
  226. package/dist/types/config.d.ts.map +1 -1
  227. package/dist/types/config.js +27 -0
  228. package/dist/types/config.js.map +1 -1
  229. package/dist/types/index.d.ts +2 -2
  230. package/dist/types/index.d.ts.map +1 -1
  231. package/dist/types/index.js +1 -1
  232. package/dist/types/index.js.map +1 -1
  233. package/dist/types/memory.d.ts +52 -0
  234. package/dist/types/memory.d.ts.map +1 -1
  235. package/dist/types/memory.js +13 -0
  236. package/dist/types/memory.js.map +1 -1
  237. package/dist/types/playbook.d.ts +4 -0
  238. package/dist/types/playbook.d.ts.map +1 -1
  239. package/dist/types/playbook.js.map +1 -1
  240. package/dist/utils/error-classifier.d.ts +30 -0
  241. package/dist/utils/error-classifier.d.ts.map +1 -0
  242. package/dist/utils/error-classifier.js +85 -0
  243. package/dist/utils/error-classifier.js.map +1 -0
  244. package/dist/utils/index.d.ts +3 -0
  245. package/dist/utils/index.d.ts.map +1 -1
  246. package/dist/utils/index.js +3 -0
  247. package/dist/utils/index.js.map +1 -1
  248. package/dist/utils/partitioned-store.d.ts +93 -0
  249. package/dist/utils/partitioned-store.d.ts.map +1 -0
  250. package/dist/utils/partitioned-store.js +251 -0
  251. package/dist/utils/partitioned-store.js.map +1 -0
  252. package/dist/utils/trajectory-helpers.d.ts +39 -0
  253. package/dist/utils/trajectory-helpers.d.ts.map +1 -0
  254. package/dist/utils/trajectory-helpers.js +57 -0
  255. package/dist/utils/trajectory-helpers.js.map +1 -0
  256. package/dist/workspace/efficacy-toolkit.d.ts +164 -0
  257. package/dist/workspace/efficacy-toolkit.d.ts.map +1 -0
  258. package/dist/workspace/efficacy-toolkit.js +281 -0
  259. package/dist/workspace/efficacy-toolkit.js.map +1 -0
  260. package/dist/workspace/index.d.ts +2 -1
  261. package/dist/workspace/index.d.ts.map +1 -1
  262. package/dist/workspace/index.js +3 -1
  263. package/dist/workspace/index.js.map +1 -1
  264. package/dist/workspace/runner.d.ts +3 -4
  265. package/dist/workspace/runner.d.ts.map +1 -1
  266. package/dist/workspace/runner.js.map +1 -1
  267. package/dist/workspace/templates/index.d.ts +3 -0
  268. package/dist/workspace/templates/index.d.ts.map +1 -1
  269. package/dist/workspace/templates/index.js +6 -0
  270. package/dist/workspace/templates/index.js.map +1 -1
  271. package/dist/workspace/templates/playbook-decay-detection.d.ts +46 -0
  272. package/dist/workspace/templates/playbook-decay-detection.d.ts.map +1 -0
  273. package/dist/workspace/templates/playbook-decay-detection.js +197 -0
  274. package/dist/workspace/templates/playbook-decay-detection.js.map +1 -0
  275. package/dist/workspace/templates/playbook-efficacy-audit.d.ts +46 -0
  276. package/dist/workspace/templates/playbook-efficacy-audit.d.ts.map +1 -0
  277. package/dist/workspace/templates/playbook-efficacy-audit.js +160 -0
  278. package/dist/workspace/templates/playbook-efficacy-audit.js.map +1 -0
  279. package/dist/workspace/templates/playbook-lifecycle-review.d.ts +51 -0
  280. package/dist/workspace/templates/playbook-lifecycle-review.d.ts.map +1 -0
  281. package/dist/workspace/templates/playbook-lifecycle-review.js +187 -0
  282. package/dist/workspace/templates/playbook-lifecycle-review.js.map +1 -0
  283. package/dist/workspace/types.d.ts +9 -2
  284. package/dist/workspace/types.d.ts.map +1 -1
  285. package/dist/workspace/types.js.map +1 -1
  286. package/package.json +12 -4
  287. package/references/sessionlog/.husky/pre-commit +1 -0
  288. package/references/sessionlog/.lintstagedrc.json +4 -0
  289. package/references/sessionlog/.prettierignore +4 -0
  290. package/references/sessionlog/.prettierrc.json +11 -0
  291. package/references/sessionlog/LICENSE +21 -0
  292. package/references/sessionlog/README.md +453 -0
  293. package/references/sessionlog/eslint.config.js +58 -0
  294. package/references/sessionlog/package-lock.json +3672 -0
  295. package/references/sessionlog/package.json +65 -0
  296. package/references/sessionlog/src/__tests__/agent-hooks.test.ts +570 -0
  297. package/references/sessionlog/src/__tests__/agent-registry.test.ts +127 -0
  298. package/references/sessionlog/src/__tests__/claude-code-hooks.test.ts +225 -0
  299. package/references/sessionlog/src/__tests__/claude-generator.test.ts +46 -0
  300. package/references/sessionlog/src/__tests__/commit-msg.test.ts +86 -0
  301. package/references/sessionlog/src/__tests__/cursor-agent.test.ts +224 -0
  302. package/references/sessionlog/src/__tests__/e2e-live.test.ts +890 -0
  303. package/references/sessionlog/src/__tests__/event-log.test.ts +183 -0
  304. package/references/sessionlog/src/__tests__/flush-sentinel.test.ts +105 -0
  305. package/references/sessionlog/src/__tests__/gemini-agent.test.ts +375 -0
  306. package/references/sessionlog/src/__tests__/git-hooks.test.ts +78 -0
  307. package/references/sessionlog/src/__tests__/hook-managers.test.ts +121 -0
  308. package/references/sessionlog/src/__tests__/lifecycle-tasks.test.ts +759 -0
  309. package/references/sessionlog/src/__tests__/opencode-agent.test.ts +338 -0
  310. package/references/sessionlog/src/__tests__/redaction.test.ts +136 -0
  311. package/references/sessionlog/src/__tests__/session-repo.test.ts +353 -0
  312. package/references/sessionlog/src/__tests__/session-store.test.ts +166 -0
  313. package/references/sessionlog/src/__tests__/setup-ccweb.test.ts +466 -0
  314. package/references/sessionlog/src/__tests__/skill-live.test.ts +461 -0
  315. package/references/sessionlog/src/__tests__/summarize.test.ts +348 -0
  316. package/references/sessionlog/src/__tests__/task-plan-e2e.test.ts +610 -0
  317. package/references/sessionlog/src/__tests__/task-plan-live.test.ts +632 -0
  318. package/references/sessionlog/src/__tests__/transcript-timestamp.test.ts +121 -0
  319. package/references/sessionlog/src/__tests__/types.test.ts +166 -0
  320. package/references/sessionlog/src/__tests__/utils.test.ts +333 -0
  321. package/references/sessionlog/src/__tests__/validation.test.ts +103 -0
  322. package/references/sessionlog/src/__tests__/worktree.test.ts +57 -0
  323. package/references/sessionlog/src/agent/agents/claude-code.ts +1089 -0
  324. package/references/sessionlog/src/agent/agents/cursor.ts +361 -0
  325. package/references/sessionlog/src/agent/agents/gemini-cli.ts +632 -0
  326. package/references/sessionlog/src/agent/agents/opencode.ts +540 -0
  327. package/references/sessionlog/src/agent/registry.ts +143 -0
  328. package/references/sessionlog/src/agent/session-types.ts +113 -0
  329. package/references/sessionlog/src/agent/types.ts +220 -0
  330. package/references/sessionlog/src/cli.ts +597 -0
  331. package/references/sessionlog/src/commands/clean.ts +133 -0
  332. package/references/sessionlog/src/commands/disable.ts +84 -0
  333. package/references/sessionlog/src/commands/doctor.ts +145 -0
  334. package/references/sessionlog/src/commands/enable.ts +202 -0
  335. package/references/sessionlog/src/commands/explain.ts +261 -0
  336. package/references/sessionlog/src/commands/reset.ts +105 -0
  337. package/references/sessionlog/src/commands/resume.ts +180 -0
  338. package/references/sessionlog/src/commands/rewind.ts +195 -0
  339. package/references/sessionlog/src/commands/setup-ccweb.ts +275 -0
  340. package/references/sessionlog/src/commands/status.ts +172 -0
  341. package/references/sessionlog/src/config.ts +165 -0
  342. package/references/sessionlog/src/events/event-log.ts +126 -0
  343. package/references/sessionlog/src/git-operations.ts +558 -0
  344. package/references/sessionlog/src/hooks/git-hooks.ts +165 -0
  345. package/references/sessionlog/src/hooks/lifecycle.ts +391 -0
  346. package/references/sessionlog/src/index.ts +650 -0
  347. package/references/sessionlog/src/security/redaction.ts +283 -0
  348. package/references/sessionlog/src/session/state-machine.ts +452 -0
  349. package/references/sessionlog/src/store/checkpoint-store.ts +509 -0
  350. package/references/sessionlog/src/store/native-store.ts +173 -0
  351. package/references/sessionlog/src/store/provider-types.ts +99 -0
  352. package/references/sessionlog/src/store/session-store.ts +266 -0
  353. package/references/sessionlog/src/strategy/attribution.ts +296 -0
  354. package/references/sessionlog/src/strategy/common.ts +207 -0
  355. package/references/sessionlog/src/strategy/content-overlap.ts +228 -0
  356. package/references/sessionlog/src/strategy/manual-commit.ts +988 -0
  357. package/references/sessionlog/src/strategy/types.ts +279 -0
  358. package/references/sessionlog/src/summarize/claude-generator.ts +115 -0
  359. package/references/sessionlog/src/summarize/summarize.ts +432 -0
  360. package/references/sessionlog/src/types.ts +508 -0
  361. package/references/sessionlog/src/utils/chunk-files.ts +49 -0
  362. package/references/sessionlog/src/utils/commit-message.ts +65 -0
  363. package/references/sessionlog/src/utils/detect-agent.ts +36 -0
  364. package/references/sessionlog/src/utils/hook-managers.ts +125 -0
  365. package/references/sessionlog/src/utils/ide-tags.ts +32 -0
  366. package/references/sessionlog/src/utils/paths.ts +79 -0
  367. package/references/sessionlog/src/utils/preview-rewind.ts +80 -0
  368. package/references/sessionlog/src/utils/rewind-conflict.ts +121 -0
  369. package/references/sessionlog/src/utils/shadow-branch.ts +109 -0
  370. package/references/sessionlog/src/utils/string-utils.ts +46 -0
  371. package/references/sessionlog/src/utils/todo-extract.ts +188 -0
  372. package/references/sessionlog/src/utils/trailers.ts +187 -0
  373. package/references/sessionlog/src/utils/transcript-parse.ts +177 -0
  374. package/references/sessionlog/src/utils/transcript-timestamp.ts +59 -0
  375. package/references/sessionlog/src/utils/tree-ops.ts +219 -0
  376. package/references/sessionlog/src/utils/tty.ts +72 -0
  377. package/references/sessionlog/src/utils/validation.ts +65 -0
  378. package/references/sessionlog/src/utils/worktree.ts +58 -0
  379. package/references/sessionlog/src/wire-types.ts +59 -0
  380. package/references/sessionlog/templates/setup-env.sh +153 -0
  381. package/references/sessionlog/tsconfig.json +18 -0
  382. package/references/sessionlog/vitest.config.ts +12 -0
  383. package/references/skill-tree/.sudocode/issues.jsonl +8 -0
  384. package/references/skill-tree/.sudocode/specs.jsonl +2 -0
  385. package/references/skill-tree/CLAUDE.md +56 -80
  386. package/references/skill-tree/README.md +188 -140
  387. package/references/skill-tree/examples/basic-usage.ts +95 -121
  388. package/references/skill-tree/package-lock.json +369 -26
  389. package/references/skill-tree/package.json +1 -1
  390. package/src/atlas.ts +97 -67
  391. package/src/bin/cli-utils.ts +220 -0
  392. package/src/bin/cognitive-core.ts +84 -392
  393. package/src/bin/commands/kb.ts +266 -0
  394. package/src/bin/commands/learn.ts +100 -0
  395. package/src/bin/commands/legacy.ts +182 -0
  396. package/src/bin/commands/run.ts +113 -0
  397. package/src/bin/commands/sessions.ts +221 -0
  398. package/src/bin/commands/skills.ts +146 -0
  399. package/src/embeddings/index.ts +3 -0
  400. package/src/embeddings/inverted-index.ts +134 -0
  401. package/src/embeddings/manager.ts +13 -8
  402. package/src/embeddings/vector-store.ts +21 -9
  403. package/src/factory.ts +33 -16
  404. package/src/index.ts +136 -9
  405. package/src/learning/analyzer.ts +21 -37
  406. package/src/learning/energy-evaluator.ts +282 -0
  407. package/src/learning/healing-orchestrator.ts +383 -0
  408. package/src/learning/index.ts +66 -9
  409. package/src/learning/instant-loop.ts +357 -0
  410. package/src/learning/maintenance-scheduler.ts +271 -0
  411. package/src/learning/meta-learner.ts +5 -23
  412. package/src/learning/reflexion-generator.ts +273 -0
  413. package/src/learning/trajectory-sources/entire.ts +24 -13
  414. package/src/learning/trajectory-sources/index.ts +2 -2
  415. package/src/learning/trajectory-sources/pipeline.ts +5 -5
  416. package/src/learning/unified-pipeline.ts +1191 -0
  417. package/src/memory/candidate-retrieval.ts +72 -0
  418. package/src/memory/causal-store.ts +273 -0
  419. package/src/memory/coherence.ts +252 -0
  420. package/src/memory/experience.ts +217 -50
  421. package/src/memory/index.ts +43 -0
  422. package/src/memory/knowledge-bank.ts +57 -0
  423. package/src/memory/meta.ts +78 -96
  424. package/src/memory/playbook.ts +239 -75
  425. package/src/memory/reasoning-bank.ts +458 -0
  426. package/src/memory/reflexion.ts +122 -0
  427. package/src/memory/system.ts +21 -5
  428. package/src/memory/temporal-compressor.ts +409 -0
  429. package/src/persistence/index.ts +37 -0
  430. package/src/persistence/migrator.ts +298 -0
  431. package/src/persistence/serializers.ts +79 -0
  432. package/src/persistence/sqlite-persistence.ts +925 -0
  433. package/src/runtime/flows/learning.ts +25 -42
  434. package/src/search/index.ts +10 -0
  435. package/src/search/moe-gate.ts +304 -0
  436. package/src/search/router.ts +111 -4
  437. package/src/session-bank/git-reader.ts +29 -19
  438. package/src/session-bank/index.ts +4 -2
  439. package/src/session-bank/parser.ts +280 -98
  440. package/src/session-bank/session-bank.ts +33 -12
  441. package/src/session-bank/types.ts +8 -5
  442. package/src/surfacing/skill-publisher.ts +17 -49
  443. package/src/surfacing/sqlite-storage-adapter.ts +16 -32
  444. package/src/types/config.ts +30 -0
  445. package/src/types/index.ts +3 -0
  446. package/src/types/memory.ts +30 -0
  447. package/src/types/playbook.ts +4 -0
  448. package/src/utils/error-classifier.ts +113 -0
  449. package/src/utils/index.ts +18 -0
  450. package/src/utils/partitioned-store.ts +299 -0
  451. package/src/utils/trajectory-helpers.ts +79 -0
  452. package/src/workspace/efficacy-toolkit.ts +496 -0
  453. package/src/workspace/index.ts +29 -0
  454. package/src/workspace/runner.ts +3 -3
  455. package/src/workspace/templates/index.ts +24 -0
  456. package/src/workspace/templates/playbook-decay-detection.ts +272 -0
  457. package/src/workspace/templates/playbook-efficacy-audit.ts +246 -0
  458. package/src/workspace/templates/playbook-lifecycle-review.ts +274 -0
  459. package/src/workspace/types.ts +10 -2
  460. package/tests/embeddings/inverted-index.test.ts +138 -0
  461. package/tests/feature-toggles.test.ts +275 -0
  462. package/tests/fixtures/behavioral-trajectories.ts +210 -0
  463. package/tests/gap-fixes.test.ts +17 -4
  464. package/tests/integration/cli-e2e.test.ts +621 -0
  465. package/tests/integration/e2e.test.ts +6 -5
  466. package/tests/integration/entire-e2e.test.ts +314 -125
  467. package/tests/integration/persistence-e2e.test.ts +741 -0
  468. package/tests/integration/phase-e2e.test.ts +1143 -0
  469. package/tests/integration/pipeline-data-correctness.test.ts +794 -0
  470. package/tests/integration/session-bank.test.ts +20 -14
  471. package/tests/integration/sessionlog-e2e.test.ts +329 -0
  472. package/tests/integration/unified-pipeline-e2e.test.ts +634 -0
  473. package/tests/learning/analyzer.test.ts +1 -1
  474. package/tests/learning/energy-evaluator.test.ts +180 -0
  475. package/tests/learning/entire-trajectory-source.test.ts +25 -25
  476. package/tests/learning/healing-orchestrator.test.ts +269 -0
  477. package/tests/learning/instant-loop.test.ts +243 -0
  478. package/tests/learning/maintenance-scheduler.test.ts +191 -0
  479. package/tests/learning/meta-learner.test.ts +418 -0
  480. package/tests/learning/pipeline-memory-updates.test.ts +721 -0
  481. package/tests/learning/reflexion-generator.test.ts +411 -0
  482. package/tests/learning/trajectory-sources.test.ts +12 -4
  483. package/tests/learning/unified-pipeline-efficacy.test.ts +232 -0
  484. package/tests/learning/unified-pipeline.test.ts +322 -0
  485. package/tests/mcp/playbook-server.test.ts +6 -1
  486. package/tests/memory/candidate-retrieval.test.ts +167 -0
  487. package/tests/memory/causal-store.test.ts +276 -0
  488. package/tests/memory/coherence.test.ts +232 -0
  489. package/tests/memory/experience.test.ts +8 -3
  490. package/tests/memory/meta.test.ts +399 -0
  491. package/tests/memory/playbook.test.ts +307 -1
  492. package/tests/memory/provenance.test.ts +11 -2
  493. package/tests/memory/reasoning-bank.test.ts +239 -0
  494. package/tests/memory/reflexion.test.ts +166 -0
  495. package/tests/memory/skill-exporter.test.ts +6 -1
  496. package/tests/memory/system.test.ts +6 -1
  497. package/tests/memory/temporal-compressor.test.ts +318 -0
  498. package/tests/persistence/migrator.test.ts +1009 -0
  499. package/tests/persistence/sqlite-persistence.test.ts +635 -0
  500. package/tests/runtime/agent-manager.test.ts +6 -1
  501. package/tests/runtime/delegate.test.ts +6 -1
  502. package/tests/search/evaluator.test.ts +257 -0
  503. package/tests/search/moe-gate.test.ts +250 -0
  504. package/tests/search/refinement-loop.test.ts +11 -2
  505. package/tests/search/router.test.ts +81 -2
  506. package/tests/search/verification-runner.test.ts +357 -0
  507. package/tests/session-bank/fixtures/sessionlog-root-metadata.json +16 -0
  508. package/tests/session-bank/fixtures/sessionlog-session/full.jsonl +6 -0
  509. package/tests/session-bank/fixtures/sessionlog-session/metadata.json +55 -0
  510. package/tests/session-bank/git-reader.test.ts +13 -13
  511. package/tests/session-bank/parser.test.ts +135 -3
  512. package/tests/session-bank/session-bank.test.ts +1 -1
  513. package/tests/surfacing/skill-library.test.ts +6 -1
  514. package/tests/surfacing/skill-publisher.test.ts +24 -58
  515. package/tests/surfacing/sqlite-storage-adapter.test.ts +11 -23
  516. package/tests/utils/error-classifier.test.ts +149 -0
  517. package/tests/utils/partitioned-store.test.ts +230 -0
  518. package/tests/utils/trajectory-helpers.test.ts +163 -0
  519. package/tests/workspace/efficacy-toolkit.test.ts +404 -0
  520. package/tests/workspace/full-flow.test.ts +10 -4
  521. package/tests/workspace/runner.test.ts +10 -4
  522. package/tests/workspace/templates/playbook-efficacy.test.ts +377 -0
  523. package/docs/DESIGN-workspace-migration.md +0 -1079
  524. package/docs/PLAN-agentic-workspace-implementation.md +0 -717
  525. package/docs/PLAN-graph-migration.md +0 -299
  526. package/docs/PLAN-session-bank-implementation.md +0 -474
  527. package/src/learning/pipeline.ts +0 -323
  528. package/tests/learning/pipeline.test.ts +0 -176
@@ -0,0 +1,890 @@
1
+ /**
2
+ * Comprehensive E2E Live Tests for Sessionlog
3
+ *
4
+ * Tests the full sessionlog lifecycle with real Claude Code sessions:
5
+ * session creation, file tracking, commit handling, status reporting,
6
+ * doctor/clean, token usage, and checkpoint verification via CLI binary.
7
+ *
8
+ * Note on checkpoints: In single-turn `-p` mode, Claude creates files and
9
+ * commits within one turn. The checkpoint trailer requires a shadow branch
10
+ * (created during saveStep/TurnEnd), which doesn't exist yet when
11
+ * prepare-commit-msg fires within the same turn. Checkpoint verification
12
+ * is therefore tested deterministically via CLI binary piping (Suite 7).
13
+ *
14
+ * Gated behind LIVE_AGENT=1 environment variable:
15
+ * LIVE_AGENT=1 npx vitest run src/__tests__/e2e-live.test.ts
16
+ *
17
+ * Prerequisites:
18
+ * - `claude` CLI installed and authenticated (Claude Max or API key)
19
+ * - `npm run build` has been run (dist/ exists)
20
+ * - `npm link` has been run (sessionlog available in PATH)
21
+ */
22
+
23
+ import { describe, it, expect, beforeAll, beforeEach, afterEach } from 'vitest';
24
+ import * as fs from 'node:fs';
25
+ import * as path from 'node:path';
26
+ import * as os from 'node:os';
27
+ import { execFileSync, execSync } from 'node:child_process';
28
+
29
+ const LIVE = process.env.LIVE_AGENT === '1';
30
+ const HOOK_WAIT_MS = 2000;
31
+
32
+ // ============================================================================
33
+ // Helpers
34
+ // ============================================================================
35
+
36
+ function initRepo(dir: string): void {
37
+ execFileSync('git', ['init'], { cwd: dir, stdio: 'pipe' });
38
+ execFileSync('git', ['config', 'user.email', 'test@test.com'], { cwd: dir, stdio: 'pipe' });
39
+ execFileSync('git', ['config', 'user.name', 'Test'], { cwd: dir, stdio: 'pipe' });
40
+ fs.writeFileSync(path.join(dir, 'README.md'), '# Test Project\n\nA simple test project.');
41
+ execFileSync('git', ['add', '.'], { cwd: dir, stdio: 'pipe' });
42
+ execFileSync('git', ['commit', '-m', 'initial commit'], { cwd: dir, stdio: 'pipe' });
43
+ }
44
+
45
+ function enableSessionlog(dir: string): void {
46
+ execFileSync('sessionlog', ['enable', '--force', '--agent', 'claude-code'], {
47
+ cwd: dir,
48
+ stdio: 'pipe',
49
+ });
50
+ }
51
+
52
+ /**
53
+ * Read all session state files from .git/sessionlog-sessions/.
54
+ */
55
+ function readSessionStates(dir: string): Record<string, unknown>[] {
56
+ const sessionsDir = path.join(dir, '.git', 'sessionlog-sessions');
57
+ if (!fs.existsSync(sessionsDir)) return [];
58
+
59
+ return fs
60
+ .readdirSync(sessionsDir)
61
+ .filter((f) => f.endsWith('.json'))
62
+ .map((f) => {
63
+ try {
64
+ return JSON.parse(fs.readFileSync(path.join(sessionsDir, f), 'utf-8'));
65
+ } catch {
66
+ return null;
67
+ }
68
+ })
69
+ .filter(Boolean) as Record<string, unknown>[];
70
+ }
71
+
72
+ /**
73
+ * Run claude in print mode with the given prompt.
74
+ */
75
+ function runClaude(
76
+ dir: string,
77
+ prompt: string,
78
+ opts?: {
79
+ allowedTools?: string[];
80
+ systemPrompt?: string;
81
+ timeoutMs?: number;
82
+ model?: string;
83
+ },
84
+ ): string {
85
+ const args = ['-p', '--dangerously-skip-permissions'];
86
+
87
+ if (opts?.model) {
88
+ args.push('--model', opts.model);
89
+ } else {
90
+ args.push('--model', 'sonnet');
91
+ }
92
+
93
+ if (opts?.allowedTools?.length) {
94
+ args.push('--allowedTools', opts.allowedTools.join(','));
95
+ }
96
+
97
+ if (opts?.systemPrompt) {
98
+ args.push('--system-prompt', opts.systemPrompt);
99
+ }
100
+
101
+ args.push('--', prompt);
102
+
103
+ const cmd = ['claude', ...args].map((a) => `'${a.replace(/'/g, "'\\''")}'`).join(' ');
104
+
105
+ const result = execSync(cmd, {
106
+ cwd: dir,
107
+ timeout: opts?.timeoutMs ?? 120_000,
108
+ encoding: 'utf-8',
109
+ env: {
110
+ ...process.env,
111
+ CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: '1',
112
+ },
113
+ });
114
+
115
+ return result;
116
+ }
117
+
118
+ /**
119
+ * Run a sessionlog CLI command and return stdout.
120
+ */
121
+ function runSessionlog(dir: string, args: string[], timeoutMs = 30_000): string {
122
+ return execSync(`sessionlog ${args.join(' ')}`, {
123
+ cwd: dir,
124
+ timeout: timeoutMs,
125
+ encoding: 'utf-8',
126
+ env: { ...process.env },
127
+ });
128
+ }
129
+
130
+ /**
131
+ * Parse sessionlog status --json output.
132
+ */
133
+ function getStatus(dir: string): Record<string, unknown> {
134
+ const output = runSessionlog(dir, ['status', '--json']);
135
+ return JSON.parse(output);
136
+ }
137
+
138
+ /**
139
+ * Get the last commit message (full body with trailers).
140
+ */
141
+ function getLastCommitMessage(dir: string): string {
142
+ return execFileSync('git', ['log', '-1', '--format=%B'], {
143
+ cwd: dir,
144
+ encoding: 'utf-8',
145
+ });
146
+ }
147
+
148
+ /**
149
+ * Count commits on current branch.
150
+ */
151
+ function getCommitCount(dir: string): number {
152
+ const output = execFileSync('git', ['rev-list', '--count', 'HEAD'], {
153
+ cwd: dir,
154
+ encoding: 'utf-8',
155
+ });
156
+ return parseInt(output.trim(), 10);
157
+ }
158
+
159
+ /**
160
+ * List git branches matching a pattern.
161
+ */
162
+ function listGitBranches(dir: string, pattern?: string): string[] {
163
+ const args = ['branch', '--list'];
164
+ if (pattern) args.push(pattern);
165
+ const output = execFileSync('git', args, { cwd: dir, encoding: 'utf-8' });
166
+ return output
167
+ .trim()
168
+ .split('\n')
169
+ .map((b) => b.replace('* ', '').trim())
170
+ .filter(Boolean);
171
+ }
172
+
173
+ /**
174
+ * Get HEAD commit SHA.
175
+ */
176
+ function getHead(dir: string): string {
177
+ return execFileSync('git', ['rev-parse', 'HEAD'], {
178
+ cwd: dir,
179
+ encoding: 'utf-8',
180
+ }).trim();
181
+ }
182
+
183
+ // ============================================================================
184
+ // Tests
185
+ // ============================================================================
186
+
187
+ describe.skipIf(!LIVE)('Live E2E — Core Sessionlog', () => {
188
+ let tmpDir: string;
189
+
190
+ beforeAll(() => {
191
+ // Verify prerequisites
192
+ try {
193
+ execFileSync('which', ['sessionlog'], { stdio: 'pipe' });
194
+ } catch {
195
+ throw new Error('sessionlog not found in PATH. Run: npm run build && npm link');
196
+ }
197
+ try {
198
+ execFileSync('which', ['claude'], { stdio: 'pipe' });
199
+ } catch {
200
+ throw new Error('claude CLI not found in PATH');
201
+ }
202
+ });
203
+
204
+ beforeEach(() => {
205
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'sessionlog-live-e2e-'));
206
+ initRepo(tmpDir);
207
+ enableSessionlog(tmpDir);
208
+ });
209
+
210
+ afterEach(() => {
211
+ fs.rmSync(tmpDir, { recursive: true, force: true });
212
+ });
213
+
214
+ // ==========================================================================
215
+ // Suite 1: Session Lifecycle
216
+ // ==========================================================================
217
+
218
+ describe('Session Lifecycle', () => {
219
+ it('should create session state when Claude edits a file', async () => {
220
+ const output = runClaude(
221
+ tmpDir,
222
+ 'Create a file called src/hello.ts with this exact content: export function hello() { return "Hello"; }',
223
+ {
224
+ allowedTools: ['Write'],
225
+ systemPrompt: 'Create only the requested file. Do not run any other commands.',
226
+ timeoutMs: 120_000,
227
+ },
228
+ );
229
+
230
+ console.log('Claude output:', output.slice(0, 500));
231
+
232
+ await new Promise((r) => setTimeout(r, HOOK_WAIT_MS));
233
+
234
+ // Verify file was created
235
+ const srcDir = path.join(tmpDir, 'src');
236
+ const fileCreated =
237
+ fs.existsSync(path.join(srcDir, 'hello.ts')) ||
238
+ fs.existsSync(path.join(tmpDir, 'hello.ts'));
239
+ console.log('File created:', fileCreated);
240
+
241
+ // Verify session state
242
+ const sessions = readSessionStates(tmpDir);
243
+ console.log('Sessions found:', sessions.length);
244
+
245
+ expect(sessions.length).toBeGreaterThan(0);
246
+
247
+ const session = sessions[0];
248
+ expect(session.agentType).toBe('Claude Code');
249
+ expect(session.startedAt).toBeDefined();
250
+ expect(typeof session.startedAt).toBe('string');
251
+ expect(session.baseCommit).toBeDefined();
252
+ expect(typeof session.baseCommit).toBe('string');
253
+ expect((session.baseCommit as string).length).toBe(40);
254
+ }, 180_000);
255
+
256
+ it('should track files and commit when Claude creates and commits', async () => {
257
+ const initialHead = getHead(tmpDir);
258
+
259
+ const output = runClaude(
260
+ tmpDir,
261
+ [
262
+ 'Do these two steps exactly:',
263
+ '1. Create a file at src/greet.ts with content: export const greet = (n: string) => "Hi " + n;',
264
+ '2. Then run these exact shell commands: git add src/greet.ts && git commit -m "feat: add greet function"',
265
+ ].join('\n'),
266
+ {
267
+ allowedTools: ['Write', 'Bash'],
268
+ systemPrompt:
269
+ 'Create the file and commit it using the exact commands specified. Do not do anything else.',
270
+ timeoutMs: 120_000,
271
+ },
272
+ );
273
+
274
+ console.log('Claude output:', output.slice(0, 500));
275
+
276
+ await new Promise((r) => setTimeout(r, HOOK_WAIT_MS));
277
+
278
+ // Verify file exists
279
+ const fileExists = fs.existsSync(path.join(tmpDir, 'src', 'greet.ts'));
280
+ console.log('File exists:', fileExists);
281
+ expect(fileExists).toBe(true);
282
+
283
+ // Verify a new commit was made
284
+ const commitCount = getCommitCount(tmpDir);
285
+ console.log('Commit count:', commitCount);
286
+ expect(commitCount).toBeGreaterThan(1);
287
+
288
+ // Verify HEAD changed
289
+ const newHead = getHead(tmpDir);
290
+ console.log('HEAD changed:', initialHead !== newHead);
291
+ expect(newHead).not.toBe(initialHead);
292
+
293
+ // Check commit message for checkpoint trailer (informational only).
294
+ // In single-turn -p mode, the shadow branch doesn't exist yet when
295
+ // prepare-commit-msg fires, so the trailer won't be injected.
296
+ // Checkpoint creation is tested deterministically in Suite 7 via CLI piping.
297
+ const commitMsg = getLastCommitMessage(tmpDir);
298
+ console.log('Commit message:', commitMsg.trim());
299
+ const hasCheckpointTrailer = /Sessionlog-Checkpoint:\s*[0-9a-f]{12}/.test(commitMsg);
300
+ console.log('Has checkpoint trailer:', hasCheckpointTrailer);
301
+
302
+ // Check for sessionlog branches (informational)
303
+ const checkpointBranches = listGitBranches(tmpDir, 'sessionlog/*');
304
+ console.log('Sessionlog branches:', checkpointBranches);
305
+
306
+ // Session state should exist with tracked files
307
+ const sessions = readSessionStates(tmpDir);
308
+ expect(sessions.length).toBeGreaterThan(0);
309
+
310
+ const session = sessions[0];
311
+ console.log(
312
+ 'Session state:',
313
+ JSON.stringify(
314
+ {
315
+ phase: session.phase,
316
+ baseCommit: (session.baseCommit as string)?.slice(0, 8),
317
+ stepCount: session.stepCount,
318
+ filesTouched: session.filesTouched,
319
+ },
320
+ null,
321
+ 2,
322
+ ),
323
+ );
324
+
325
+ // Session should track the file Claude touched
326
+ const filesTouched = session.filesTouched as string[];
327
+ expect(filesTouched.length).toBeGreaterThan(0);
328
+ }, 180_000);
329
+
330
+ it('should mark session as ended after -p mode completes', async () => {
331
+ runClaude(tmpDir, 'Create a file called END_TEST.md with content: # End Test', {
332
+ allowedTools: ['Write'],
333
+ timeoutMs: 120_000,
334
+ });
335
+
336
+ await new Promise((r) => setTimeout(r, HOOK_WAIT_MS));
337
+
338
+ const sessions = readSessionStates(tmpDir);
339
+ expect(sessions.length).toBeGreaterThan(0);
340
+
341
+ const session = sessions[0];
342
+ console.log('Session phase:', session.phase, 'endedAt:', session.endedAt);
343
+
344
+ // In -p mode, session_end hook fires, so phase should be 'ended'
345
+ // or at minimum endedAt should be set
346
+ const isEnded = session.phase === 'ended' || session.endedAt !== undefined;
347
+ expect(isEnded).toBe(true);
348
+ }, 180_000);
349
+ });
350
+
351
+ // ==========================================================================
352
+ // Suite 2: Commit & Explain
353
+ // ==========================================================================
354
+
355
+ describe('Commit & Explain', () => {
356
+ it('should show commit info via explain command after Claude commits', async () => {
357
+ runClaude(
358
+ tmpDir,
359
+ [
360
+ 'Do these two steps exactly:',
361
+ '1. Create a file at lib/utils.ts with content: export const noop = () => {};',
362
+ '2. Then run: git add lib/utils.ts && git commit -m "feat: add noop utility"',
363
+ ].join('\n'),
364
+ {
365
+ allowedTools: ['Write', 'Bash'],
366
+ systemPrompt: 'Create the file and commit it. Do exactly as instructed.',
367
+ timeoutMs: 120_000,
368
+ },
369
+ );
370
+
371
+ await new Promise((r) => setTimeout(r, HOOK_WAIT_MS));
372
+
373
+ const commitCount = getCommitCount(tmpDir);
374
+ console.log('Commit count:', commitCount);
375
+
376
+ if (commitCount <= 1) {
377
+ console.warn('Claude did not commit — skipping explain test');
378
+ return;
379
+ }
380
+
381
+ // Run explain command — should always show commit info
382
+ const output = runSessionlog(tmpDir, ['explain', 'HEAD']);
383
+ console.log('Explain output:', output);
384
+
385
+ expect(output).toContain('Commit:');
386
+ expect(output).toContain('Message:');
387
+
388
+ // Checkpoint details are only present if shadow branch existed during commit.
389
+ // In single-turn -p mode this won't happen. Tested deterministically in Suite 7.
390
+ const hasCheckpoint = output.includes('Checkpoint:');
391
+ console.log('Has checkpoint in explain (expected false in single-turn):', hasCheckpoint);
392
+ }, 180_000);
393
+
394
+ it('should run rewind --list without errors after a session', async () => {
395
+ runClaude(tmpDir, 'Create a file called REWIND_TEST.md with content: # Rewind Test', {
396
+ allowedTools: ['Write'],
397
+ timeoutMs: 120_000,
398
+ });
399
+
400
+ await new Promise((r) => setTimeout(r, HOOK_WAIT_MS));
401
+
402
+ // rewind --list should return valid JSON even with no checkpoints
403
+ const output = runSessionlog(tmpDir, ['rewind', '--list']);
404
+ console.log('Rewind list output:', output.slice(0, 300));
405
+
406
+ const points = JSON.parse(output);
407
+ expect(Array.isArray(points)).toBe(true);
408
+ console.log('Rewind points:', points.length);
409
+ }, 180_000);
410
+ });
411
+
412
+ // ==========================================================================
413
+ // Suite 3: Status Command
414
+ // ==========================================================================
415
+
416
+ describe('Status Command', () => {
417
+ it('should report enabled state and sessions after Claude session', async () => {
418
+ runClaude(tmpDir, 'Create a file called HELLO.md with content: # Hello', {
419
+ allowedTools: ['Write'],
420
+ systemPrompt: 'Only create the file.',
421
+ timeoutMs: 120_000,
422
+ });
423
+
424
+ await new Promise((r) => setTimeout(r, HOOK_WAIT_MS));
425
+
426
+ const status = getStatus(tmpDir);
427
+ console.log('Status:', JSON.stringify(status, null, 2));
428
+
429
+ expect(status.enabled).toBe(true);
430
+ expect(status.strategy).toBe('manual-commit');
431
+ expect(status.gitHooksInstalled).toBe(true);
432
+ expect(status.agents).toBeDefined();
433
+ expect(status.agents as string[]).toContain('claude-code');
434
+
435
+ const sessions = status.sessions as Record<string, unknown>[];
436
+ expect(sessions.length).toBeGreaterThan(0);
437
+
438
+ const session = sessions[0];
439
+ expect(session.agentType).toBe('Claude Code');
440
+ expect(session.startedAt).toBeDefined();
441
+ expect(['idle', 'active', 'ended']).toContain(session.phase);
442
+ }, 180_000);
443
+
444
+ it('should report zero sessions before any Claude invocation', () => {
445
+ const status = getStatus(tmpDir);
446
+ console.log('Status (no sessions):', JSON.stringify(status, null, 2));
447
+
448
+ expect(status.enabled).toBe(true);
449
+ expect(status.strategy).toBe('manual-commit');
450
+ expect(status.gitHooksInstalled).toBe(true);
451
+
452
+ const sessions = status.sessions as Record<string, unknown>[];
453
+ expect(sessions).toHaveLength(0);
454
+ });
455
+ });
456
+
457
+ // ==========================================================================
458
+ // Suite 4: Doctor & Clean (no live Claude needed)
459
+ // ==========================================================================
460
+
461
+ describe('Doctor & Clean', () => {
462
+ it('should diagnose stuck sessions', () => {
463
+ // Create a synthetic stuck session
464
+ const sessionsDir = path.join(tmpDir, '.git', 'sessionlog-sessions');
465
+ fs.mkdirSync(sessionsDir, { recursive: true });
466
+
467
+ const head = getHead(tmpDir);
468
+ const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString();
469
+
470
+ const stuckState = {
471
+ sessionID: 'stuck-session-001',
472
+ baseCommit: head,
473
+ startedAt: twoHoursAgo,
474
+ lastInteractionTime: twoHoursAgo,
475
+ phase: 'active',
476
+ turnCheckpointIDs: [],
477
+ stepCount: 0,
478
+ checkpointTranscriptStart: 0,
479
+ untrackedFilesAtStart: [],
480
+ filesTouched: [],
481
+ agentType: 'Claude Code',
482
+ };
483
+
484
+ fs.writeFileSync(
485
+ path.join(sessionsDir, 'stuck-session-001.json'),
486
+ JSON.stringify(stuckState, null, 2),
487
+ );
488
+
489
+ const output = runSessionlog(tmpDir, ['doctor']);
490
+ console.log('Doctor output:', output);
491
+
492
+ expect(output).toContain('stuck');
493
+ });
494
+
495
+ it('should fix stuck sessions with --force', () => {
496
+ const sessionsDir = path.join(tmpDir, '.git', 'sessionlog-sessions');
497
+ fs.mkdirSync(sessionsDir, { recursive: true });
498
+
499
+ const head = getHead(tmpDir);
500
+ const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString();
501
+
502
+ const stuckState = {
503
+ sessionID: 'stuck-session-fix',
504
+ baseCommit: head,
505
+ startedAt: twoHoursAgo,
506
+ lastInteractionTime: twoHoursAgo,
507
+ phase: 'active',
508
+ turnCheckpointIDs: [],
509
+ stepCount: 0,
510
+ checkpointTranscriptStart: 0,
511
+ untrackedFilesAtStart: [],
512
+ filesTouched: [],
513
+ agentType: 'Claude Code',
514
+ };
515
+
516
+ fs.writeFileSync(
517
+ path.join(sessionsDir, 'stuck-session-fix.json'),
518
+ JSON.stringify(stuckState, null, 2),
519
+ );
520
+
521
+ const output = runSessionlog(tmpDir, ['doctor', '--force']);
522
+ console.log('Doctor --force output:', output);
523
+
524
+ expect(output).toContain('Discarded:');
525
+
526
+ // Session file should be deleted
527
+ const sessionFile = path.join(sessionsDir, 'stuck-session-fix.json');
528
+ expect(fs.existsSync(sessionFile)).toBe(false);
529
+ });
530
+
531
+ it('should report nothing to clean in a healthy repo', () => {
532
+ const output = runSessionlog(tmpDir, ['clean']);
533
+ console.log('Clean output:', output);
534
+
535
+ expect(output).toContain('Nothing to clean');
536
+ });
537
+
538
+ it('should detect orphaned shadow branches', () => {
539
+ // Create an orphaned shadow branch
540
+ execFileSync('git', ['branch', 'sessionlog/0000000'], { cwd: tmpDir, stdio: 'pipe' });
541
+
542
+ const branches = listGitBranches(tmpDir, 'sessionlog/*');
543
+ console.log('Branches before clean:', branches);
544
+ expect(branches).toContain('sessionlog/0000000');
545
+
546
+ const output = runSessionlog(tmpDir, ['clean']);
547
+ console.log('Clean output:', output);
548
+
549
+ // Should detect the orphaned branch
550
+ expect(output).toContain('sessionlog/0000000');
551
+ });
552
+ });
553
+
554
+ // ==========================================================================
555
+ // Suite 5: Token Usage
556
+ // ==========================================================================
557
+
558
+ describe('Token Usage', () => {
559
+ it('should populate token usage after a Claude session', async () => {
560
+ runClaude(tmpDir, 'What is 2 plus 2? Answer with just the number.', {
561
+ timeoutMs: 60_000,
562
+ });
563
+
564
+ await new Promise((r) => setTimeout(r, HOOK_WAIT_MS));
565
+
566
+ const sessions = readSessionStates(tmpDir);
567
+ console.log('Sessions found:', sessions.length);
568
+ expect(sessions.length).toBeGreaterThan(0);
569
+
570
+ const session = sessions[0];
571
+ console.log('Token usage:', JSON.stringify(session.tokenUsage, null, 2));
572
+
573
+ // Token usage depends on transcript parsing which may not fire in -p mode.
574
+ // Use soft assertions.
575
+ if (session.tokenUsage) {
576
+ const usage = session.tokenUsage as Record<string, number>;
577
+ expect.soft(usage.inputTokens, 'Expected inputTokens > 0').toBeGreaterThan(0);
578
+ expect.soft(usage.outputTokens, 'Expected outputTokens > 0').toBeGreaterThan(0);
579
+ } else {
580
+ console.warn('tokenUsage not populated — this is timing-dependent and may be expected');
581
+ }
582
+ }, 180_000);
583
+ });
584
+
585
+ // ==========================================================================
586
+ // Suite 6: Multiple Sessions
587
+ // ==========================================================================
588
+
589
+ describe('Multiple Sessions', () => {
590
+ it('should create separate session states for sequential invocations', async () => {
591
+ // First invocation: create a file
592
+ runClaude(tmpDir, 'Create a file called app/main.ts with content: console.log("hello");', {
593
+ allowedTools: ['Write'],
594
+ timeoutMs: 120_000,
595
+ });
596
+
597
+ await new Promise((r) => setTimeout(r, HOOK_WAIT_MS));
598
+
599
+ const sessionsAfterFirst = readSessionStates(tmpDir);
600
+ console.log('Sessions after first invocation:', sessionsAfterFirst.length);
601
+
602
+ // Second invocation: modify the file
603
+ runClaude(tmpDir, 'Read the file app/main.ts and add a second line: console.log("world");', {
604
+ allowedTools: ['Edit', 'Read', 'Write'],
605
+ timeoutMs: 120_000,
606
+ });
607
+
608
+ await new Promise((r) => setTimeout(r, HOOK_WAIT_MS));
609
+
610
+ const sessionsAfterSecond = readSessionStates(tmpDir);
611
+ console.log('Sessions after second invocation:', sessionsAfterSecond.length);
612
+
613
+ // Each -p invocation creates a new session, so we should have >= 2
614
+ expect(sessionsAfterSecond.length).toBeGreaterThanOrEqual(2);
615
+
616
+ // Verify sessions have different IDs
617
+ const sessionIDs = sessionsAfterSecond.map((s) => s.sessionID);
618
+ const uniqueIDs = new Set(sessionIDs);
619
+ expect(uniqueIDs.size).toBeGreaterThanOrEqual(2);
620
+
621
+ // Status should list all sessions
622
+ const status = getStatus(tmpDir);
623
+ const statusSessions = status.sessions as Record<string, unknown>[];
624
+ console.log('Status sessions count:', statusSessions.length);
625
+ expect(statusSessions.length).toBeGreaterThanOrEqual(2);
626
+ }, 300_000);
627
+ });
628
+
629
+ // ==========================================================================
630
+ // Suite 7: Checkpoint Lifecycle via CLI Binary (deterministic, no timing issues)
631
+ // ==========================================================================
632
+
633
+ describe('Checkpoint Lifecycle — CLI Binary', () => {
634
+ /**
635
+ * These tests pipe hook events directly to the sessionlog CLI binary,
636
+ * bypassing the need for a real Claude session. This allows deterministic
637
+ * testing of the checkpoint creation, rewind, and explain flows.
638
+ */
639
+
640
+ let sessionsDir: string;
641
+
642
+ beforeEach(() => {
643
+ sessionsDir = path.join(tmpDir, '.git', 'sessionlog-sessions');
644
+ fs.mkdirSync(sessionsDir, { recursive: true });
645
+
646
+ // Pre-create an active session state
647
+ const head = getHead(tmpDir);
648
+ const sessionState = {
649
+ sessionID: 'cli-e2e-session',
650
+ baseCommit: head,
651
+ startedAt: new Date().toISOString(),
652
+ phase: 'active',
653
+ turnCheckpointIDs: [],
654
+ stepCount: 0,
655
+ checkpointTranscriptStart: 0,
656
+ untrackedFilesAtStart: [],
657
+ filesTouched: [],
658
+ agentType: 'Claude Code',
659
+ };
660
+ fs.writeFileSync(
661
+ path.join(sessionsDir, 'cli-e2e-session.json'),
662
+ JSON.stringify(sessionState, null, 2),
663
+ );
664
+ });
665
+
666
+ it('should dispatch session_start through the CLI and create session state', () => {
667
+ const payload = JSON.stringify({
668
+ session_id: 'cli-e2e-session',
669
+ transcript_path: '/path/to/transcript.jsonl',
670
+ });
671
+
672
+ execSync(`echo ${JSON.stringify(payload)} | sessionlog hooks claude-code session-start`, {
673
+ cwd: tmpDir,
674
+ timeout: 10_000,
675
+ stdio: 'pipe',
676
+ });
677
+
678
+ const sessionFile = path.join(sessionsDir, 'cli-e2e-session.json');
679
+ const state = JSON.parse(fs.readFileSync(sessionFile, 'utf-8'));
680
+ expect(state.sessionID).toBe('cli-e2e-session');
681
+ expect(state.agentType).toBe('Claude Code');
682
+ });
683
+
684
+ it('should dispatch session_end and mark session as ended', () => {
685
+ const payload = JSON.stringify({
686
+ session_id: 'cli-e2e-session',
687
+ transcript_path: '/path/to/transcript.jsonl',
688
+ });
689
+
690
+ execSync(`echo ${JSON.stringify(payload)} | sessionlog hooks claude-code session-end`, {
691
+ cwd: tmpDir,
692
+ timeout: 10_000,
693
+ stdio: 'pipe',
694
+ });
695
+
696
+ const sessionFile = path.join(sessionsDir, 'cli-e2e-session.json');
697
+ const state = JSON.parse(fs.readFileSync(sessionFile, 'utf-8'));
698
+ expect(state.phase).toBe('ended');
699
+ expect(state.endedAt).toBeDefined();
700
+ });
701
+
702
+ it('should handle full hook lifecycle: start → prompt → tool use → stop → end', () => {
703
+ // 1. Session start
704
+ execSync(
705
+ `echo ${JSON.stringify(
706
+ JSON.stringify({
707
+ session_id: 'cli-e2e-session',
708
+ transcript_path: '/path/to/transcript.jsonl',
709
+ }),
710
+ )} | sessionlog hooks claude-code session-start`,
711
+ { cwd: tmpDir, timeout: 10_000, stdio: 'pipe' },
712
+ );
713
+
714
+ // 2. User prompt submit (turn start)
715
+ execSync(
716
+ `echo ${JSON.stringify(
717
+ JSON.stringify({
718
+ session_id: 'cli-e2e-session',
719
+ transcript_path: '/path/to/transcript.jsonl',
720
+ }),
721
+ )} | sessionlog hooks claude-code user-prompt-submit`,
722
+ { cwd: tmpDir, timeout: 10_000, stdio: 'pipe' },
723
+ );
724
+
725
+ // 3. Post tool use (Write tool)
726
+ execSync(
727
+ `echo ${JSON.stringify(
728
+ JSON.stringify({
729
+ session_id: 'cli-e2e-session',
730
+ transcript_path: '/path/to/transcript.jsonl',
731
+ tool_use_id: 'toolu_01',
732
+ tool_name: 'Write',
733
+ tool_input: { file_path: '/tmp/test/src/app.ts', content: 'console.log("hi")' },
734
+ }),
735
+ )} | sessionlog hooks claude-code post-tool-Write`,
736
+ { cwd: tmpDir, timeout: 10_000, stdio: 'pipe' },
737
+ );
738
+
739
+ // 4. Stop
740
+ execSync(
741
+ `echo ${JSON.stringify(
742
+ JSON.stringify({
743
+ session_id: 'cli-e2e-session',
744
+ transcript_path: '/path/to/transcript.jsonl',
745
+ }),
746
+ )} | sessionlog hooks claude-code stop`,
747
+ { cwd: tmpDir, timeout: 10_000, stdio: 'pipe' },
748
+ );
749
+
750
+ // 5. Session end
751
+ execSync(
752
+ `echo ${JSON.stringify(
753
+ JSON.stringify({
754
+ session_id: 'cli-e2e-session',
755
+ transcript_path: '/path/to/transcript.jsonl',
756
+ }),
757
+ )} | sessionlog hooks claude-code session-end`,
758
+ { cwd: tmpDir, timeout: 10_000, stdio: 'pipe' },
759
+ );
760
+
761
+ // Verify final state
762
+ const sessionFile = path.join(sessionsDir, 'cli-e2e-session.json');
763
+ const state = JSON.parse(fs.readFileSync(sessionFile, 'utf-8'));
764
+
765
+ expect(state.phase).toBe('ended');
766
+ expect(state.endedAt).toBeDefined();
767
+ });
768
+
769
+ it('should track tasks and plan mode through full CLI lifecycle', () => {
770
+ // 1. Enter plan mode
771
+ execSync(
772
+ `echo ${JSON.stringify(
773
+ JSON.stringify({
774
+ session_id: 'cli-e2e-session',
775
+ transcript_path: '/path/to/transcript.jsonl',
776
+ }),
777
+ )} | sessionlog hooks claude-code post-plan-enter`,
778
+ { cwd: tmpDir, timeout: 10_000, stdio: 'pipe' },
779
+ );
780
+
781
+ // 2. Exit plan mode with plan file
782
+ const planDir = path.join(tmpDir, '.claude', 'plans');
783
+ fs.mkdirSync(planDir, { recursive: true });
784
+ const planPath = path.join(planDir, 'e2e-plan.md');
785
+ fs.writeFileSync(planPath, '# E2E Plan\n\n1. Create files\n2. Run tests');
786
+
787
+ execSync(
788
+ `echo ${JSON.stringify(
789
+ JSON.stringify({
790
+ session_id: 'cli-e2e-session',
791
+ transcript_path: '/path/to/transcript.jsonl',
792
+ tool_input: {},
793
+ tool_response: { planFilePath: planPath },
794
+ }),
795
+ )} | sessionlog hooks claude-code post-plan-exit`,
796
+ { cwd: tmpDir, timeout: 10_000, stdio: 'pipe' },
797
+ );
798
+
799
+ // 3. Create task
800
+ execSync(
801
+ `echo ${JSON.stringify(
802
+ JSON.stringify({
803
+ session_id: 'cli-e2e-session',
804
+ transcript_path: '/path/to/transcript.jsonl',
805
+ tool_use_id: 'toolu_01',
806
+ tool_input: {
807
+ subject: 'Set up project',
808
+ description: 'Initialize project structure and dependencies',
809
+ },
810
+ tool_response: { taskId: '1' },
811
+ }),
812
+ )} | sessionlog hooks claude-code post-task-create`,
813
+ { cwd: tmpDir, timeout: 10_000, stdio: 'pipe' },
814
+ );
815
+
816
+ // 4. Create second task
817
+ execSync(
818
+ `echo ${JSON.stringify(
819
+ JSON.stringify({
820
+ session_id: 'cli-e2e-session',
821
+ transcript_path: '/path/to/transcript.jsonl',
822
+ tool_use_id: 'toolu_02',
823
+ tool_input: {
824
+ subject: 'Write tests',
825
+ description: 'Add unit and integration tests',
826
+ },
827
+ tool_response: { taskId: '2' },
828
+ }),
829
+ )} | sessionlog hooks claude-code post-task-create`,
830
+ { cwd: tmpDir, timeout: 10_000, stdio: 'pipe' },
831
+ );
832
+
833
+ // 5. Update first task to completed
834
+ execSync(
835
+ `echo ${JSON.stringify(
836
+ JSON.stringify({
837
+ session_id: 'cli-e2e-session',
838
+ transcript_path: '/path/to/transcript.jsonl',
839
+ tool_use_id: 'toolu_03',
840
+ tool_input: { taskId: '1', status: 'completed' },
841
+ }),
842
+ )} | sessionlog hooks claude-code post-task-update`,
843
+ { cwd: tmpDir, timeout: 10_000, stdio: 'pipe' },
844
+ );
845
+
846
+ // Verify final state
847
+ const sessionFile = path.join(sessionsDir, 'cli-e2e-session.json');
848
+ const state = JSON.parse(fs.readFileSync(sessionFile, 'utf-8'));
849
+
850
+ // Plan mode tracking
851
+ expect(state.inPlanMode).toBe(false);
852
+ expect(state.planModeEntries).toBe(1);
853
+ expect(state.planEntries).toHaveLength(1);
854
+ expect(state.planEntries[0].content).toBe('# E2E Plan\n\n1. Create files\n2. Run tests');
855
+ expect(state.planEntries[0].exitedAt).toBeDefined();
856
+
857
+ // Task tracking
858
+ expect(Object.keys(state.tasks)).toHaveLength(2);
859
+ expect(state.tasks['1'].subject).toBe('Set up project');
860
+ expect(state.tasks['1'].description).toBe('Initialize project structure and dependencies');
861
+ expect(state.tasks['1'].status).toBe('completed');
862
+ expect(state.tasks['2'].subject).toBe('Write tests');
863
+ expect(state.tasks['2'].description).toBe('Add unit and integration tests');
864
+ expect(state.tasks['2'].status).toBe('pending');
865
+ });
866
+
867
+ it('should verify status command reflects CLI-dispatched session state', () => {
868
+ // Dispatch some events
869
+ execSync(
870
+ `echo ${JSON.stringify(
871
+ JSON.stringify({
872
+ session_id: 'cli-e2e-session',
873
+ transcript_path: '/path/to/transcript.jsonl',
874
+ }),
875
+ )} | sessionlog hooks claude-code session-start`,
876
+ { cwd: tmpDir, timeout: 10_000, stdio: 'pipe' },
877
+ );
878
+
879
+ // Check status reflects the session
880
+ const status = getStatus(tmpDir);
881
+ const sessions = status.sessions as Record<string, unknown>[];
882
+
883
+ expect(sessions.length).toBeGreaterThanOrEqual(1);
884
+
885
+ const session = sessions.find((s) => s.sessionID === 'cli-e2e-session');
886
+ expect(session).toBeDefined();
887
+ expect(session!.agentType).toBe('Claude Code');
888
+ });
889
+ });
890
+ });