cognitive-core 0.2.1 → 0.2.3

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 (332) hide show
  1. package/dist/atlas.d.ts +10 -0
  2. package/dist/atlas.d.ts.map +1 -1
  3. package/dist/atlas.js +65 -0
  4. package/dist/atlas.js.map +1 -1
  5. package/dist/bin/cognitive-core.js +0 -0
  6. package/dist/memory/curated-loader.d.ts +21 -4
  7. package/dist/memory/curated-loader.d.ts.map +1 -1
  8. package/dist/memory/curated-loader.js +53 -16
  9. package/dist/memory/curated-loader.js.map +1 -1
  10. package/dist/memory/index.d.ts +2 -1
  11. package/dist/memory/index.d.ts.map +1 -1
  12. package/dist/memory/index.js +3 -1
  13. package/dist/memory/index.js.map +1 -1
  14. package/dist/memory/playbook.d.ts +6 -0
  15. package/dist/memory/playbook.d.ts.map +1 -1
  16. package/dist/memory/playbook.js +15 -0
  17. package/dist/memory/playbook.js.map +1 -1
  18. package/dist/memory/source-resolver.d.ts +120 -0
  19. package/dist/memory/source-resolver.d.ts.map +1 -0
  20. package/dist/memory/source-resolver.js +300 -0
  21. package/dist/memory/source-resolver.js.map +1 -0
  22. package/dist/types/config.d.ts +141 -0
  23. package/dist/types/config.d.ts.map +1 -1
  24. package/dist/types/config.js +40 -0
  25. package/dist/types/config.js.map +1 -1
  26. package/dist/types/index.d.ts +1 -1
  27. package/dist/types/index.d.ts.map +1 -1
  28. package/dist/types/index.js +1 -1
  29. package/dist/types/index.js.map +1 -1
  30. package/dist/workspace/types.d.ts +12 -54
  31. package/dist/workspace/types.d.ts.map +1 -1
  32. package/dist/workspace/types.js.map +1 -1
  33. package/package.json +3 -3
  34. package/playbooks/compound-engineering/adversarial-review.json +51 -0
  35. package/playbooks/compound-engineering/agent-native-architecture.json +59 -0
  36. package/playbooks/compound-engineering/agent-native-review.json +54 -0
  37. package/playbooks/compound-engineering/api-contract-review.json +52 -0
  38. package/playbooks/compound-engineering/brainstorm-requirements.json +55 -0
  39. package/playbooks/compound-engineering/bug-reproduction.json +62 -0
  40. package/playbooks/compound-engineering/confidence-calibration.json +49 -0
  41. package/playbooks/compound-engineering/correctness-review.json +49 -0
  42. package/playbooks/compound-engineering/data-migration-safety.json +59 -0
  43. package/playbooks/compound-engineering/deployment-verification.json +63 -0
  44. package/playbooks/compound-engineering/error-recovery-patterns.json +53 -0
  45. package/playbooks/compound-engineering/implementation-planning.json +64 -0
  46. package/playbooks/compound-engineering/issue-pattern-analysis.json +53 -0
  47. package/playbooks/compound-engineering/knowledge-compounding.json +63 -0
  48. package/playbooks/compound-engineering/learnings-research.json +54 -0
  49. package/playbooks/compound-engineering/maintainability-review.json +49 -0
  50. package/playbooks/compound-engineering/performance-review.json +54 -0
  51. package/playbooks/compound-engineering/plan-adversarial-review.json +56 -0
  52. package/playbooks/compound-engineering/plan-feasibility-review.json +56 -0
  53. package/playbooks/compound-engineering/project-standards-review.json +52 -0
  54. package/playbooks/compound-engineering/reliability-review.json +53 -0
  55. package/playbooks/compound-engineering/review-orchestration.json +64 -0
  56. package/playbooks/compound-engineering/security-review.json +54 -0
  57. package/playbooks/compound-engineering/systematic-execution.json +64 -0
  58. package/playbooks/compound-engineering/testing-review.json +50 -0
  59. package/src/atlas.ts +96 -0
  60. package/src/memory/curated-loader.ts +69 -16
  61. package/src/memory/index.ts +16 -0
  62. package/src/memory/playbook.ts +19 -0
  63. package/src/memory/source-resolver.ts +422 -0
  64. package/src/types/config.ts +46 -0
  65. package/src/types/index.ts +4 -0
  66. package/src/workspace/types.ts +22 -78
  67. package/tests/integration/curated-sources-e2e.test.ts +502 -0
  68. package/tests/memory/compound-engineering-seed.test.ts +338 -0
  69. package/tests/memory/curated-loader-extended.test.ts +225 -0
  70. package/tests/memory/playbook-quality-validation.test.ts +430 -0
  71. package/tests/memory/source-resolver.test.ts +700 -0
  72. package/.claude/settings.local.json +0 -11
  73. package/dist/learning/llm-extractor.d.ts +0 -88
  74. package/dist/learning/llm-extractor.d.ts.map +0 -1
  75. package/dist/learning/llm-extractor.js +0 -372
  76. package/dist/learning/llm-extractor.js.map +0 -1
  77. package/dist/learning/loop-coordinator.d.ts +0 -61
  78. package/dist/learning/loop-coordinator.d.ts.map +0 -1
  79. package/dist/learning/loop-coordinator.js +0 -96
  80. package/dist/learning/loop-coordinator.js.map +0 -1
  81. package/dist/learning/pipeline.d.ts +0 -116
  82. package/dist/learning/pipeline.d.ts.map +0 -1
  83. package/dist/learning/pipeline.js +0 -288
  84. package/dist/learning/pipeline.js.map +0 -1
  85. package/references/agent-workspace/CLAUDE.md +0 -74
  86. package/references/agent-workspace/README.md +0 -587
  87. package/references/agent-workspace/media/banner.png +0 -0
  88. package/references/agent-workspace/package-lock.json +0 -2061
  89. package/references/agent-workspace/package.json +0 -54
  90. package/references/agent-workspace/src/handle.ts +0 -122
  91. package/references/agent-workspace/src/index.ts +0 -32
  92. package/references/agent-workspace/src/manager.ts +0 -102
  93. package/references/agent-workspace/src/readers/json.ts +0 -71
  94. package/references/agent-workspace/src/readers/markdown.ts +0 -37
  95. package/references/agent-workspace/src/readers/raw.ts +0 -27
  96. package/references/agent-workspace/src/types.ts +0 -68
  97. package/references/agent-workspace/src/validation.ts +0 -93
  98. package/references/agent-workspace/src/writers/json.ts +0 -17
  99. package/references/agent-workspace/src/writers/markdown.ts +0 -27
  100. package/references/agent-workspace/src/writers/raw.ts +0 -22
  101. package/references/agent-workspace/tests/errors.test.ts +0 -652
  102. package/references/agent-workspace/tests/handle.test.ts +0 -144
  103. package/references/agent-workspace/tests/manager.test.ts +0 -124
  104. package/references/agent-workspace/tests/readers.test.ts +0 -205
  105. package/references/agent-workspace/tests/validation.test.ts +0 -196
  106. package/references/agent-workspace/tests/writers.test.ts +0 -108
  107. package/references/agent-workspace/tsconfig.json +0 -20
  108. package/references/agent-workspace/tsup.config.ts +0 -9
  109. package/references/minimem/.claude/settings.json +0 -7
  110. package/references/minimem/.sudocode/issues.jsonl +0 -18
  111. package/references/minimem/.sudocode/specs.jsonl +0 -1
  112. package/references/minimem/CLAUDE.md +0 -310
  113. package/references/minimem/README.md +0 -556
  114. package/references/minimem/claude-plugin/.claude-plugin/plugin.json +0 -10
  115. package/references/minimem/claude-plugin/.mcp.json +0 -7
  116. package/references/minimem/claude-plugin/README.md +0 -158
  117. package/references/minimem/claude-plugin/commands/recall.md +0 -47
  118. package/references/minimem/claude-plugin/commands/remember.md +0 -41
  119. package/references/minimem/claude-plugin/hooks/__tests__/hooks.test.ts +0 -272
  120. package/references/minimem/claude-plugin/hooks/hooks.json +0 -27
  121. package/references/minimem/claude-plugin/hooks/session-end.sh +0 -86
  122. package/references/minimem/claude-plugin/hooks/session-start.sh +0 -85
  123. package/references/minimem/claude-plugin/skills/memory/SKILL.md +0 -108
  124. package/references/minimem/package-lock.json +0 -5373
  125. package/references/minimem/package.json +0 -60
  126. package/references/minimem/scripts/postbuild.js +0 -35
  127. package/references/minimem/src/__tests__/edge-cases.test.ts +0 -371
  128. package/references/minimem/src/__tests__/errors.test.ts +0 -265
  129. package/references/minimem/src/__tests__/helpers.ts +0 -199
  130. package/references/minimem/src/__tests__/internal.test.ts +0 -407
  131. package/references/minimem/src/__tests__/knowledge.test.ts +0 -287
  132. package/references/minimem/src/__tests__/minimem.integration.test.ts +0 -1127
  133. package/references/minimem/src/__tests__/session.test.ts +0 -190
  134. package/references/minimem/src/cli/__tests__/commands.test.ts +0 -759
  135. package/references/minimem/src/cli/commands/__tests__/conflicts.test.ts +0 -141
  136. package/references/minimem/src/cli/commands/append.ts +0 -76
  137. package/references/minimem/src/cli/commands/config.ts +0 -262
  138. package/references/minimem/src/cli/commands/conflicts.ts +0 -413
  139. package/references/minimem/src/cli/commands/daemon.ts +0 -169
  140. package/references/minimem/src/cli/commands/index.ts +0 -12
  141. package/references/minimem/src/cli/commands/init.ts +0 -88
  142. package/references/minimem/src/cli/commands/mcp.ts +0 -177
  143. package/references/minimem/src/cli/commands/push-pull.ts +0 -213
  144. package/references/minimem/src/cli/commands/search.ts +0 -158
  145. package/references/minimem/src/cli/commands/status.ts +0 -84
  146. package/references/minimem/src/cli/commands/sync-init.ts +0 -290
  147. package/references/minimem/src/cli/commands/sync.ts +0 -70
  148. package/references/minimem/src/cli/commands/upsert.ts +0 -197
  149. package/references/minimem/src/cli/config.ts +0 -584
  150. package/references/minimem/src/cli/index.ts +0 -264
  151. package/references/minimem/src/cli/shared.ts +0 -161
  152. package/references/minimem/src/cli/sync/__tests__/central.test.ts +0 -152
  153. package/references/minimem/src/cli/sync/__tests__/conflicts.test.ts +0 -209
  154. package/references/minimem/src/cli/sync/__tests__/daemon.test.ts +0 -118
  155. package/references/minimem/src/cli/sync/__tests__/detection.test.ts +0 -207
  156. package/references/minimem/src/cli/sync/__tests__/integration.test.ts +0 -476
  157. package/references/minimem/src/cli/sync/__tests__/registry.test.ts +0 -363
  158. package/references/minimem/src/cli/sync/__tests__/state.test.ts +0 -255
  159. package/references/minimem/src/cli/sync/__tests__/validation.test.ts +0 -193
  160. package/references/minimem/src/cli/sync/__tests__/watcher.test.ts +0 -178
  161. package/references/minimem/src/cli/sync/central.ts +0 -292
  162. package/references/minimem/src/cli/sync/conflicts.ts +0 -204
  163. package/references/minimem/src/cli/sync/daemon.ts +0 -407
  164. package/references/minimem/src/cli/sync/detection.ts +0 -138
  165. package/references/minimem/src/cli/sync/index.ts +0 -107
  166. package/references/minimem/src/cli/sync/operations.ts +0 -373
  167. package/references/minimem/src/cli/sync/registry.ts +0 -279
  168. package/references/minimem/src/cli/sync/state.ts +0 -355
  169. package/references/minimem/src/cli/sync/validation.ts +0 -206
  170. package/references/minimem/src/cli/sync/watcher.ts +0 -234
  171. package/references/minimem/src/cli/version.ts +0 -34
  172. package/references/minimem/src/core/index.ts +0 -9
  173. package/references/minimem/src/core/indexer.ts +0 -628
  174. package/references/minimem/src/core/searcher.ts +0 -221
  175. package/references/minimem/src/db/schema.ts +0 -183
  176. package/references/minimem/src/db/sqlite-vec.ts +0 -24
  177. package/references/minimem/src/embeddings/__tests__/embeddings.test.ts +0 -431
  178. package/references/minimem/src/embeddings/batch-gemini.ts +0 -392
  179. package/references/minimem/src/embeddings/batch-openai.ts +0 -409
  180. package/references/minimem/src/embeddings/embeddings.ts +0 -434
  181. package/references/minimem/src/index.ts +0 -109
  182. package/references/minimem/src/internal.ts +0 -299
  183. package/references/minimem/src/minimem.ts +0 -1276
  184. package/references/minimem/src/search/__tests__/hybrid.test.ts +0 -247
  185. package/references/minimem/src/search/graph.ts +0 -234
  186. package/references/minimem/src/search/hybrid.ts +0 -151
  187. package/references/minimem/src/search/search.ts +0 -256
  188. package/references/minimem/src/server/__tests__/mcp.test.ts +0 -341
  189. package/references/minimem/src/server/__tests__/tools.test.ts +0 -364
  190. package/references/minimem/src/server/mcp.ts +0 -326
  191. package/references/minimem/src/server/tools.ts +0 -720
  192. package/references/minimem/src/session.ts +0 -460
  193. package/references/minimem/tsconfig.json +0 -19
  194. package/references/minimem/tsup.config.ts +0 -26
  195. package/references/minimem/vitest.config.ts +0 -24
  196. package/references/sessionlog/.husky/pre-commit +0 -1
  197. package/references/sessionlog/.lintstagedrc.json +0 -4
  198. package/references/sessionlog/.prettierignore +0 -4
  199. package/references/sessionlog/.prettierrc.json +0 -11
  200. package/references/sessionlog/LICENSE +0 -21
  201. package/references/sessionlog/README.md +0 -453
  202. package/references/sessionlog/eslint.config.js +0 -58
  203. package/references/sessionlog/package-lock.json +0 -3672
  204. package/references/sessionlog/package.json +0 -65
  205. package/references/sessionlog/src/__tests__/agent-hooks.test.ts +0 -570
  206. package/references/sessionlog/src/__tests__/agent-registry.test.ts +0 -127
  207. package/references/sessionlog/src/__tests__/claude-code-hooks.test.ts +0 -225
  208. package/references/sessionlog/src/__tests__/claude-generator.test.ts +0 -46
  209. package/references/sessionlog/src/__tests__/commit-msg.test.ts +0 -86
  210. package/references/sessionlog/src/__tests__/cursor-agent.test.ts +0 -224
  211. package/references/sessionlog/src/__tests__/e2e-live.test.ts +0 -890
  212. package/references/sessionlog/src/__tests__/event-log.test.ts +0 -183
  213. package/references/sessionlog/src/__tests__/flush-sentinel.test.ts +0 -105
  214. package/references/sessionlog/src/__tests__/gemini-agent.test.ts +0 -375
  215. package/references/sessionlog/src/__tests__/git-hooks.test.ts +0 -78
  216. package/references/sessionlog/src/__tests__/hook-managers.test.ts +0 -121
  217. package/references/sessionlog/src/__tests__/lifecycle-tasks.test.ts +0 -759
  218. package/references/sessionlog/src/__tests__/opencode-agent.test.ts +0 -338
  219. package/references/sessionlog/src/__tests__/redaction.test.ts +0 -136
  220. package/references/sessionlog/src/__tests__/session-repo.test.ts +0 -353
  221. package/references/sessionlog/src/__tests__/session-store.test.ts +0 -166
  222. package/references/sessionlog/src/__tests__/setup-ccweb.test.ts +0 -466
  223. package/references/sessionlog/src/__tests__/skill-live.test.ts +0 -461
  224. package/references/sessionlog/src/__tests__/summarize.test.ts +0 -348
  225. package/references/sessionlog/src/__tests__/task-plan-e2e.test.ts +0 -610
  226. package/references/sessionlog/src/__tests__/task-plan-live.test.ts +0 -632
  227. package/references/sessionlog/src/__tests__/transcript-timestamp.test.ts +0 -121
  228. package/references/sessionlog/src/__tests__/types.test.ts +0 -166
  229. package/references/sessionlog/src/__tests__/utils.test.ts +0 -333
  230. package/references/sessionlog/src/__tests__/validation.test.ts +0 -103
  231. package/references/sessionlog/src/__tests__/worktree.test.ts +0 -57
  232. package/references/sessionlog/src/agent/agents/claude-code.ts +0 -1089
  233. package/references/sessionlog/src/agent/agents/cursor.ts +0 -361
  234. package/references/sessionlog/src/agent/agents/gemini-cli.ts +0 -632
  235. package/references/sessionlog/src/agent/agents/opencode.ts +0 -540
  236. package/references/sessionlog/src/agent/registry.ts +0 -143
  237. package/references/sessionlog/src/agent/session-types.ts +0 -113
  238. package/references/sessionlog/src/agent/types.ts +0 -220
  239. package/references/sessionlog/src/cli.ts +0 -597
  240. package/references/sessionlog/src/commands/clean.ts +0 -133
  241. package/references/sessionlog/src/commands/disable.ts +0 -84
  242. package/references/sessionlog/src/commands/doctor.ts +0 -145
  243. package/references/sessionlog/src/commands/enable.ts +0 -202
  244. package/references/sessionlog/src/commands/explain.ts +0 -261
  245. package/references/sessionlog/src/commands/reset.ts +0 -105
  246. package/references/sessionlog/src/commands/resume.ts +0 -180
  247. package/references/sessionlog/src/commands/rewind.ts +0 -195
  248. package/references/sessionlog/src/commands/setup-ccweb.ts +0 -275
  249. package/references/sessionlog/src/commands/status.ts +0 -172
  250. package/references/sessionlog/src/config.ts +0 -165
  251. package/references/sessionlog/src/events/event-log.ts +0 -126
  252. package/references/sessionlog/src/git-operations.ts +0 -558
  253. package/references/sessionlog/src/hooks/git-hooks.ts +0 -165
  254. package/references/sessionlog/src/hooks/lifecycle.ts +0 -391
  255. package/references/sessionlog/src/index.ts +0 -650
  256. package/references/sessionlog/src/security/redaction.ts +0 -283
  257. package/references/sessionlog/src/session/state-machine.ts +0 -452
  258. package/references/sessionlog/src/store/checkpoint-store.ts +0 -509
  259. package/references/sessionlog/src/store/native-store.ts +0 -173
  260. package/references/sessionlog/src/store/provider-types.ts +0 -99
  261. package/references/sessionlog/src/store/session-store.ts +0 -266
  262. package/references/sessionlog/src/strategy/attribution.ts +0 -296
  263. package/references/sessionlog/src/strategy/common.ts +0 -207
  264. package/references/sessionlog/src/strategy/content-overlap.ts +0 -228
  265. package/references/sessionlog/src/strategy/manual-commit.ts +0 -988
  266. package/references/sessionlog/src/strategy/types.ts +0 -279
  267. package/references/sessionlog/src/summarize/claude-generator.ts +0 -115
  268. package/references/sessionlog/src/summarize/summarize.ts +0 -432
  269. package/references/sessionlog/src/types.ts +0 -508
  270. package/references/sessionlog/src/utils/chunk-files.ts +0 -49
  271. package/references/sessionlog/src/utils/commit-message.ts +0 -65
  272. package/references/sessionlog/src/utils/detect-agent.ts +0 -36
  273. package/references/sessionlog/src/utils/hook-managers.ts +0 -125
  274. package/references/sessionlog/src/utils/ide-tags.ts +0 -32
  275. package/references/sessionlog/src/utils/paths.ts +0 -79
  276. package/references/sessionlog/src/utils/preview-rewind.ts +0 -80
  277. package/references/sessionlog/src/utils/rewind-conflict.ts +0 -121
  278. package/references/sessionlog/src/utils/shadow-branch.ts +0 -109
  279. package/references/sessionlog/src/utils/string-utils.ts +0 -46
  280. package/references/sessionlog/src/utils/todo-extract.ts +0 -188
  281. package/references/sessionlog/src/utils/trailers.ts +0 -187
  282. package/references/sessionlog/src/utils/transcript-parse.ts +0 -177
  283. package/references/sessionlog/src/utils/transcript-timestamp.ts +0 -59
  284. package/references/sessionlog/src/utils/tree-ops.ts +0 -219
  285. package/references/sessionlog/src/utils/tty.ts +0 -72
  286. package/references/sessionlog/src/utils/validation.ts +0 -65
  287. package/references/sessionlog/src/utils/worktree.ts +0 -58
  288. package/references/sessionlog/src/wire-types.ts +0 -59
  289. package/references/sessionlog/templates/setup-env.sh +0 -153
  290. package/references/sessionlog/tsconfig.json +0 -18
  291. package/references/sessionlog/vitest.config.ts +0 -12
  292. package/references/skill-tree/.claude/settings.json +0 -6
  293. package/references/skill-tree/.sudocode/issues.jsonl +0 -19
  294. package/references/skill-tree/.sudocode/specs.jsonl +0 -3
  295. package/references/skill-tree/CLAUDE.md +0 -126
  296. package/references/skill-tree/README.md +0 -372
  297. package/references/skill-tree/docs/GAPS_v1.md +0 -221
  298. package/references/skill-tree/docs/INTEGRATION_PLAN.md +0 -467
  299. package/references/skill-tree/docs/TODOS.md +0 -91
  300. package/references/skill-tree/docs/anthropic_skill_guide.md +0 -1364
  301. package/references/skill-tree/docs/design/federated-skill-trees.md +0 -524
  302. package/references/skill-tree/docs/design/multi-agent-sync.md +0 -759
  303. package/references/skill-tree/docs/scraper/BRAINSTORM.md +0 -583
  304. package/references/skill-tree/docs/scraper/POC_PLAN.md +0 -420
  305. package/references/skill-tree/docs/scraper/README.md +0 -170
  306. package/references/skill-tree/examples/basic-usage.ts +0 -164
  307. package/references/skill-tree/package-lock.json +0 -1852
  308. package/references/skill-tree/package.json +0 -66
  309. package/references/skill-tree/scraper/README.md +0 -123
  310. package/references/skill-tree/scraper/docs/DESIGN.md +0 -683
  311. package/references/skill-tree/scraper/docs/PLAN.md +0 -336
  312. package/references/skill-tree/scraper/drizzle.config.ts +0 -10
  313. package/references/skill-tree/scraper/package-lock.json +0 -6329
  314. package/references/skill-tree/scraper/package.json +0 -68
  315. package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-description.md +0 -7
  316. package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-name.md +0 -7
  317. package/references/skill-tree/scraper/test/fixtures/minimal-skill/SKILL.md +0 -27
  318. package/references/skill-tree/scraper/test/fixtures/skill-json/SKILL.json +0 -21
  319. package/references/skill-tree/scraper/test/fixtures/skill-with-meta/SKILL.md +0 -54
  320. package/references/skill-tree/scraper/test/fixtures/skill-with-meta/_meta.json +0 -24
  321. package/references/skill-tree/scraper/test/fixtures/valid-skill/SKILL.md +0 -93
  322. package/references/skill-tree/scraper/test/fixtures/valid-skill/_meta.json +0 -22
  323. package/references/skill-tree/scraper/tsup.config.ts +0 -14
  324. package/references/skill-tree/scraper/vitest.config.ts +0 -17
  325. package/references/skill-tree/scripts/convert-to-vitest.ts +0 -166
  326. package/references/skill-tree/skills/skill-writer/SKILL.md +0 -339
  327. package/references/skill-tree/skills/skill-writer/references/examples.md +0 -326
  328. package/references/skill-tree/skills/skill-writer/references/patterns.md +0 -210
  329. package/references/skill-tree/skills/skill-writer/references/quality-checklist.md +0 -123
  330. package/references/skill-tree/test/run-all.ts +0 -106
  331. package/references/skill-tree/test/utils.ts +0 -128
  332. package/references/skill-tree/vitest.config.ts +0 -16
@@ -1,890 +0,0 @@
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
- });