cognitive-core 0.2.1 → 0.2.2

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