@pugi/cli 0.1.0-beta.7 → 0.1.0-beta.87

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 (402) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/THIRD_PARTY_NOTICES.md +40 -0
  3. package/assets/pugi-prozr2-mascot.ansi +9 -0
  4. package/bin/run.js +33 -1
  5. package/dist/commands/deploy.js +40 -40
  6. package/dist/commands/flatten.js +191 -0
  7. package/dist/commands/jobs-watch.js +201 -0
  8. package/dist/commands/jobs.js +42 -27
  9. package/dist/commands/smoke.js +133 -0
  10. package/dist/core/agent-progress/cleanup.js +134 -0
  11. package/dist/core/agent-progress/schema.js +144 -0
  12. package/dist/core/agent-progress/writer.js +101 -0
  13. package/dist/core/agents/adaptive-router.js +330 -0
  14. package/dist/core/agents/query-decomposer.js +297 -0
  15. package/dist/core/agents/registry.js +2 -2
  16. package/dist/core/approvals/shortcut-resolver.js +98 -0
  17. package/dist/core/artifact-chain/dispatcher.js +148 -0
  18. package/dist/core/artifact-chain/exporter.js +164 -0
  19. package/dist/core/artifact-chain/state.js +243 -0
  20. package/dist/core/artifact-chain/steps.js +169 -0
  21. package/dist/core/ask-user/question.js +92 -0
  22. package/dist/core/audit/audit-trail.js +275 -0
  23. package/dist/core/auth/ensure-authenticated.js +129 -0
  24. package/dist/core/auth/env-provider.js +238 -0
  25. package/dist/core/auto-open-browser.js +4 -4
  26. package/dist/core/auto-update/channels.js +122 -0
  27. package/dist/core/auto-update/checker.js +241 -0
  28. package/dist/core/auto-update/state.js +235 -0
  29. package/dist/core/bare-mode/index.js +107 -0
  30. package/dist/core/bash/redirect.js +281 -0
  31. package/dist/core/bash-classifier.js +436 -40
  32. package/dist/core/checkpoint/resumer.js +149 -0
  33. package/dist/core/checkpoint/rewinder.js +291 -0
  34. package/dist/core/checkpoints/shadow-git.js +670 -0
  35. package/dist/core/citations/parser.js +109 -0
  36. package/dist/core/classifier/yolo-classifier.js +88 -0
  37. package/dist/core/codegraph/decision-store.js +248 -0
  38. package/dist/core/codegraph/detect-repo.js +459 -0
  39. package/dist/core/codegraph/install.js +134 -0
  40. package/dist/core/codegraph/offer-hook.js +220 -0
  41. package/dist/core/compact/auto-trigger.js +96 -0
  42. package/dist/core/compact/buffer-rewriter.js +115 -0
  43. package/dist/core/compact/summarizer.js +208 -0
  44. package/dist/core/compact/token-counter.js +108 -0
  45. package/dist/core/consensus/anvil-fanout.js +25 -25
  46. package/dist/core/consensus/diff-capture.js +121 -12
  47. package/dist/core/consensus/rubric.js +21 -21
  48. package/dist/core/context/builder.js +6 -6
  49. package/dist/core/context/compaction-events.js +8 -8
  50. package/dist/core/context/compaction.js +31 -31
  51. package/dist/core/context/index.js +15 -8
  52. package/dist/core/context/invariants.js +51 -51
  53. package/dist/core/context/markdown-loader.js +28 -10
  54. package/dist/core/context/markdown-traverse.js +255 -0
  55. package/dist/core/context/pugiignore.js +41 -41
  56. package/dist/core/context/repo-skeleton.js +37 -37
  57. package/dist/core/context/tool-eviction.js +55 -0
  58. package/dist/core/context/watcher.js +32 -32
  59. package/dist/core/context/working-set.js +23 -23
  60. package/dist/core/coordinator/agent-tools.js +77 -0
  61. package/dist/core/coordinator/agent-toolset.js +65 -0
  62. package/dist/core/coordinator/fsm.js +73 -0
  63. package/dist/core/coordinator/mode-fsm.js +70 -0
  64. package/dist/core/cost/rate-card.js +129 -0
  65. package/dist/core/cost/tracker.js +221 -0
  66. package/dist/core/credentials.js +12 -12
  67. package/dist/core/cron/scheduler.js +138 -0
  68. package/dist/core/denial-tracking/index.js +8 -0
  69. package/dist/core/denial-tracking/state.js +264 -0
  70. package/dist/core/diagnostics/probe-runner.js +93 -0
  71. package/dist/core/diagnostics/probes/api.js +46 -0
  72. package/dist/core/diagnostics/probes/auth.js +93 -0
  73. package/dist/core/diagnostics/probes/bare-mode.js +42 -0
  74. package/dist/core/diagnostics/probes/cli-version.js +127 -0
  75. package/dist/core/diagnostics/probes/config.js +72 -0
  76. package/dist/core/diagnostics/probes/denial-tracking.js +57 -0
  77. package/dist/core/diagnostics/probes/disk.js +81 -0
  78. package/dist/core/diagnostics/probes/engine-live.js +46 -0
  79. package/dist/core/diagnostics/probes/git.js +65 -0
  80. package/dist/core/diagnostics/probes/hooks.js +118 -0
  81. package/dist/core/diagnostics/probes/mcp.js +75 -0
  82. package/dist/core/diagnostics/probes/node.js +59 -0
  83. package/dist/core/diagnostics/probes/pnpm.js +36 -0
  84. package/dist/core/diagnostics/probes/pugi-md.js +89 -0
  85. package/dist/core/diagnostics/probes/sandbox.js +40 -0
  86. package/dist/core/diagnostics/probes/session.js +74 -0
  87. package/dist/core/diagnostics/probes/status-snapshot.js +488 -0
  88. package/dist/core/diagnostics/probes/workspace.js +63 -0
  89. package/dist/core/diagnostics/types.js +70 -0
  90. package/dist/core/dispatch/cache-cleanup.js +197 -0
  91. package/dist/core/dispatch/cache-handoff.js +295 -0
  92. package/dist/core/edits/apply-patch-layer-e.js +189 -0
  93. package/dist/core/edits/dispatch.js +293 -7
  94. package/dist/core/edits/format-matrix.js +26 -0
  95. package/dist/core/edits/fuzzy-ladder.js +650 -0
  96. package/dist/core/edits/index.js +3 -1
  97. package/dist/core/edits/journal.js +199 -0
  98. package/dist/core/edits/layer-a-apply.js +15 -15
  99. package/dist/core/edits/layer-a-fuzzy-apply.js +198 -0
  100. package/dist/core/edits/layer-b-apply.js +9 -9
  101. package/dist/core/edits/layer-c-apply.js +6 -6
  102. package/dist/core/edits/layer-d-ast.js +557 -14
  103. package/dist/core/edits/marker-parser.js +12 -12
  104. package/dist/core/edits/security-gate.js +27 -27
  105. package/dist/core/edits/verify-hook.js +273 -0
  106. package/dist/core/edits/worktree.js +322 -0
  107. package/dist/core/engine/anvil-client.js +140 -26
  108. package/dist/core/engine/auto-compact.js +179 -0
  109. package/dist/core/engine/budgets.js +186 -0
  110. package/dist/core/engine/context-prefix.js +155 -0
  111. package/dist/core/engine/index.js +1 -1
  112. package/dist/core/engine/intensity.js +158 -0
  113. package/dist/core/engine/intent.js +260 -0
  114. package/dist/core/engine/native-pugi.js +1295 -227
  115. package/dist/core/engine/prompts.js +134 -16
  116. package/dist/core/engine/strip-internal-fields.js +124 -0
  117. package/dist/core/engine/tool-bridge.js +1295 -59
  118. package/dist/core/evaluation/golden-dataset.js +293 -0
  119. package/dist/core/feedback/queue.js +177 -0
  120. package/dist/core/feedback/submitter.js +145 -0
  121. package/dist/core/file-cache.js +113 -1
  122. package/dist/core/flatten/flatten-repo.js +439 -0
  123. package/dist/core/format/osc8-link.js +28 -0
  124. package/dist/core/hook-chains.js +392 -0
  125. package/dist/core/hooks/citation-verify-hook.js +138 -0
  126. package/dist/core/hooks/citation-verify.js +112 -0
  127. package/dist/core/hooks/events.js +44 -0
  128. package/dist/core/hooks/index.js +15 -0
  129. package/dist/core/hooks/registry.js +213 -0
  130. package/dist/core/hooks/runner.js +236 -0
  131. package/dist/core/hooks/v2/event-emitter.js +115 -0
  132. package/dist/core/hooks/v2/executor.js +282 -0
  133. package/dist/core/hooks/v2/index.js +25 -0
  134. package/dist/core/hooks/v2/lifecycle.js +104 -0
  135. package/dist/core/hooks/v2/loader.js +216 -0
  136. package/dist/core/hooks/v2/matcher.js +125 -0
  137. package/dist/core/hooks/v2/trust.js +143 -0
  138. package/dist/core/hooks/v2/types.js +86 -0
  139. package/dist/core/image/renderer.js +71 -0
  140. package/dist/core/init/detector.js +582 -0
  141. package/dist/core/init/template-renderer.js +242 -0
  142. package/dist/core/jobs/registry.js +18 -18
  143. package/dist/core/ledger/results-tsv.js +142 -0
  144. package/dist/core/log-discipline/stdout-redirect.js +51 -0
  145. package/dist/core/lsp/cache.js +105 -0
  146. package/dist/core/lsp/client.js +776 -0
  147. package/dist/core/lsp/language-detect.js +66 -0
  148. package/dist/core/lsp/post-edit-diagnostics.js +171 -0
  149. package/dist/core/lsp/symbol-tools.js +372 -0
  150. package/dist/core/mcp/client.js +97 -28
  151. package/dist/core/mcp/http-server.js +553 -0
  152. package/dist/core/mcp/orchestrator-tools.js +662 -0
  153. package/dist/core/mcp/permission.js +190 -0
  154. package/dist/core/mcp/registry.js +39 -17
  155. package/dist/core/mcp/server-tools.js +219 -0
  156. package/dist/core/mcp/server.js +397 -0
  157. package/dist/core/mcp/trust.js +10 -10
  158. package/dist/core/memory/dual-write.js +416 -0
  159. package/dist/core/memory/passive-extract.js +130 -0
  160. package/dist/core/memory/phase1-kinds.js +20 -0
  161. package/dist/core/memory/secret-scanner.js +304 -0
  162. package/dist/core/memory-sync/queue.js +170 -0
  163. package/dist/core/metrics/extract.js +113 -0
  164. package/dist/core/modes/roo-modes.js +68 -0
  165. package/dist/core/onboarding/ensure-initialized.js +133 -0
  166. package/dist/core/onboarding/marker.js +111 -0
  167. package/dist/core/onboarding/telemetry-state.js +108 -0
  168. package/dist/core/output-style/presets.js +176 -0
  169. package/dist/core/output-style/state.js +185 -0
  170. package/dist/core/path-security.js +287 -5
  171. package/dist/core/permission.js +82 -22
  172. package/dist/core/permissions/auto-classifier.js +124 -0
  173. package/dist/core/permissions/bash-parser.js +371 -0
  174. package/dist/core/permissions/circuit-breaker.js +83 -0
  175. package/dist/core/permissions/constrained-edit.js +91 -0
  176. package/dist/core/permissions/gate.js +278 -0
  177. package/dist/core/permissions/index.js +20 -0
  178. package/dist/core/permissions/mode.js +174 -0
  179. package/dist/core/permissions/network-egress.js +137 -0
  180. package/dist/core/permissions/state.js +241 -0
  181. package/dist/core/permissions/tool-class.js +93 -0
  182. package/dist/core/plan-mode/ui-state.js +51 -0
  183. package/dist/core/plans/plan-artifact.js +721 -0
  184. package/dist/core/policy-limits/etag-store.js +122 -0
  185. package/dist/core/prd-check/parser.js +215 -0
  186. package/dist/core/prd-check/reporter.js +127 -0
  187. package/dist/core/prd-check/session-review.js +557 -0
  188. package/dist/core/prd-check/verifiers.js +223 -0
  189. package/dist/core/prompt-cache/client-cache.js +99 -0
  190. package/dist/core/prompts/assembly.js +29 -0
  191. package/dist/core/prompts/registry.js +364 -0
  192. package/dist/core/pugi-md/cc-compat-rules.js +735 -0
  193. package/dist/core/pugi-md/context-injector.js +76 -0
  194. package/dist/core/pugi-md/walk-up.js +207 -0
  195. package/dist/core/python/uv-installer.js +270 -0
  196. package/dist/core/python/uv-resolver.js +83 -0
  197. package/dist/core/rate-limit/narrator.js +146 -0
  198. package/dist/core/recipes/cli-types.js +20 -0
  199. package/dist/core/recipes/loader.js +103 -0
  200. package/dist/core/recipes/runner.js +345 -0
  201. package/dist/core/recipes/schema.js +587 -0
  202. package/dist/core/release-notes/parser.js +241 -0
  203. package/dist/core/release-notes/state.js +116 -0
  204. package/dist/core/repl/ask.js +37 -37
  205. package/dist/core/repl/cancellation.js +26 -26
  206. package/dist/core/repl/cap-warning.js +4 -4
  207. package/dist/core/repl/clipboard-read.js +11 -11
  208. package/dist/core/repl/dispatch-fsm.js +12 -12
  209. package/dist/core/repl/history-search.js +15 -15
  210. package/dist/core/repl/history.js +28 -18
  211. package/dist/core/repl/kill-ring.js +5 -5
  212. package/dist/core/repl/model-pricing.js +135 -0
  213. package/dist/core/repl/privacy-banner.js +22 -22
  214. package/dist/core/repl/session.js +2157 -214
  215. package/dist/core/repl/slash-commands.js +533 -40
  216. package/dist/core/repl/store/index.js +1 -1
  217. package/dist/core/repl/store/jsonl-log.js +22 -22
  218. package/dist/core/repl/store/lockfile.js +10 -10
  219. package/dist/core/repl/store/session-store.js +136 -107
  220. package/dist/core/repl/store/types.js +15 -15
  221. package/dist/core/repl/store/uuid-v7.js +12 -12
  222. package/dist/core/repl/workspace-context.js +43 -21
  223. package/dist/core/repo-map/build.js +125 -0
  224. package/dist/core/repo-map/cache.js +185 -0
  225. package/dist/core/repo-map/extractor.js +254 -0
  226. package/dist/core/repo-map/formatter.js +145 -0
  227. package/dist/core/repo-map/page-rank.js +105 -0
  228. package/dist/core/repo-map/scanner.js +211 -0
  229. package/dist/core/retry-budget/budget.js +284 -0
  230. package/dist/core/retry-budget/index.js +5 -0
  231. package/dist/core/retry-budget/retry-cap.js +74 -0
  232. package/dist/core/routing/lead-worker.js +43 -0
  233. package/dist/core/routing/pre-flight-estimator.js +108 -0
  234. package/dist/core/runs/run-tree.js +103 -0
  235. package/dist/core/security/injection-scanner.js +367 -0
  236. package/dist/core/security/output-filter.js +418 -0
  237. package/dist/core/session/env-file.js +105 -0
  238. package/dist/core/session/section-budgets.js +140 -0
  239. package/dist/core/session.js +92 -0
  240. package/dist/core/settings.js +286 -5
  241. package/dist/core/share/formatter.js +271 -0
  242. package/dist/core/share/redactor.js +221 -0
  243. package/dist/core/share/uploader.js +267 -0
  244. package/dist/core/skills/defaults.js +457 -0
  245. package/dist/core/skills/loader.js +22 -22
  246. package/dist/core/skills/sources.js +27 -27
  247. package/dist/core/smoke/headless-driver.js +174 -0
  248. package/dist/core/smoke/orchestrator.js +194 -0
  249. package/dist/core/smoke/runner.js +238 -0
  250. package/dist/core/smoke/scenario-parser.js +316 -0
  251. package/dist/core/statusline.js +99 -0
  252. package/dist/core/subagents/dispatcher-real.js +600 -0
  253. package/dist/core/subagents/dispatcher.js +132 -43
  254. package/dist/core/subagents/index.js +19 -6
  255. package/dist/core/subagents/isolation-matrix.js +213 -0
  256. package/dist/core/subagents/spawn.js +19 -4
  257. package/dist/core/telemetry/emitter.js +229 -0
  258. package/dist/core/telemetry/queue.js +251 -0
  259. package/dist/core/theme/context.js +91 -0
  260. package/dist/core/theme/presets.js +228 -0
  261. package/dist/core/theme/state.js +181 -0
  262. package/dist/core/todos/invariant.js +10 -0
  263. package/dist/core/todos/state.js +177 -0
  264. package/dist/core/tool-schema/compressor.js +89 -0
  265. package/dist/core/transport/version-interceptor.js +166 -0
  266. package/dist/core/trust.js +2 -2
  267. package/dist/core/tui/thinking-block.js +64 -0
  268. package/dist/core/vim/keymap.js +288 -0
  269. package/dist/core/vim/state.js +92 -0
  270. package/dist/core/watch-markers/marker-watcher.js +133 -0
  271. package/dist/core/worktree-manager/cleanup.js +123 -0
  272. package/dist/core/worktree-manager/manager.js +303 -0
  273. package/dist/index.js +28 -0
  274. package/dist/runtime/bootstrap.js +190 -0
  275. package/dist/runtime/cli.js +4162 -488
  276. package/dist/runtime/commands/agents.js +30 -30
  277. package/dist/runtime/commands/budget.js +5 -5
  278. package/dist/runtime/commands/cancel.js +231 -0
  279. package/dist/runtime/commands/chain.js +489 -0
  280. package/dist/runtime/commands/codegraph-status.js +227 -0
  281. package/dist/runtime/commands/compact.js +297 -0
  282. package/dist/runtime/commands/config.js +32 -32
  283. package/dist/runtime/commands/cost.js +199 -0
  284. package/dist/runtime/commands/delegate.js +244 -13
  285. package/dist/runtime/commands/dispatch.js +126 -0
  286. package/dist/runtime/commands/doctor.js +579 -0
  287. package/dist/runtime/commands/feedback.js +184 -0
  288. package/dist/runtime/commands/hooks.js +184 -0
  289. package/dist/runtime/commands/init.js +254 -0
  290. package/dist/runtime/commands/lsp.js +368 -0
  291. package/dist/runtime/commands/mcp.js +879 -0
  292. package/dist/runtime/commands/memory.js +582 -0
  293. package/dist/runtime/commands/model.js +237 -0
  294. package/dist/runtime/commands/onboarding.js +275 -0
  295. package/dist/runtime/commands/patch.js +128 -0
  296. package/dist/runtime/commands/permissions.js +112 -0
  297. package/dist/runtime/commands/plan.js +143 -0
  298. package/dist/runtime/commands/prd-check.js +285 -0
  299. package/dist/runtime/commands/privacy.js +17 -17
  300. package/dist/runtime/commands/recipe.js +325 -0
  301. package/dist/runtime/commands/redo-blob-store.js +92 -0
  302. package/dist/runtime/commands/redo.js +361 -0
  303. package/dist/runtime/commands/release-notes.js +229 -0
  304. package/dist/runtime/commands/repo-map.js +95 -0
  305. package/dist/runtime/commands/report.js +299 -0
  306. package/dist/runtime/commands/resume.js +118 -0
  307. package/dist/runtime/commands/review-consensus.js +68 -53
  308. package/dist/runtime/commands/rewind.js +333 -0
  309. package/dist/runtime/commands/roster.js +14 -14
  310. package/dist/runtime/commands/sessions.js +163 -0
  311. package/dist/runtime/commands/share.js +316 -0
  312. package/dist/runtime/commands/skills.js +31 -31
  313. package/dist/runtime/commands/status.js +186 -0
  314. package/dist/runtime/commands/stickers.js +82 -0
  315. package/dist/runtime/commands/style.js +194 -0
  316. package/dist/runtime/commands/theme.js +196 -0
  317. package/dist/runtime/commands/undo.js +54 -22
  318. package/dist/runtime/commands/update.js +289 -0
  319. package/dist/runtime/commands/vim.js +140 -0
  320. package/dist/runtime/commands/worktree.js +177 -0
  321. package/dist/runtime/commands/worktrees.js +155 -0
  322. package/dist/runtime/headless-repl.js +195 -0
  323. package/dist/runtime/headless.js +543 -0
  324. package/dist/runtime/load-hooks-or-exit.js +71 -0
  325. package/dist/runtime/plan-decompose.js +531 -0
  326. package/dist/runtime/update-check.js +28 -28
  327. package/dist/runtime/version.js +65 -0
  328. package/dist/skills/bundled/batch.js +617 -0
  329. package/dist/skills/bundled/index.js +45 -0
  330. package/dist/skills/bundled/loop.js +358 -0
  331. package/dist/skills/bundled/remember.js +383 -0
  332. package/dist/skills/bundled/simplify.js +289 -0
  333. package/dist/skills/bundled/skillify.js +373 -0
  334. package/dist/skills/bundled/stuck.js +558 -0
  335. package/dist/skills/bundled/verify.js +439 -0
  336. package/dist/testing/vcr.js +486 -0
  337. package/dist/tools/agent-tool.js +229 -0
  338. package/dist/tools/apply-patch.js +556 -0
  339. package/dist/tools/ask-user-question.js +222 -0
  340. package/dist/tools/ask-user.js +115 -0
  341. package/dist/tools/bash.js +623 -45
  342. package/dist/tools/brief.js +224 -0
  343. package/dist/tools/enter-worktree.js +250 -0
  344. package/dist/tools/exit-worktree.js +147 -0
  345. package/dist/tools/file-tools.js +161 -44
  346. package/dist/tools/lsp-tools.js +189 -0
  347. package/dist/tools/mcp-tool.js +260 -0
  348. package/dist/tools/multi-edit.js +361 -0
  349. package/dist/tools/powershell.js +268 -0
  350. package/dist/tools/registry.js +85 -0
  351. package/dist/tools/skill-tool.js +96 -0
  352. package/dist/tools/sleep.js +99 -0
  353. package/dist/tools/synthetic-output.js +133 -0
  354. package/dist/tools/tasks.js +208 -0
  355. package/dist/tools/todo-write.js +184 -0
  356. package/dist/tools/verify-plan-execution.js +295 -0
  357. package/dist/tools/web-fetch-injection-scanner.js +207 -0
  358. package/dist/tools/web-fetch.js +195 -10
  359. package/dist/tools/web-search.js +458 -0
  360. package/dist/tui/agent-progress-card.js +111 -0
  361. package/dist/tui/agent-tree.js +11 -1
  362. package/dist/tui/ask-modal.js +14 -14
  363. package/dist/tui/ask-user-question-prompt.js +203 -0
  364. package/dist/tui/compact-banner.js +81 -0
  365. package/dist/tui/conversation-pane.js +85 -11
  366. package/dist/tui/cost-table.js +111 -0
  367. package/dist/tui/device-flow.js +2 -2
  368. package/dist/tui/doctor-table.js +46 -0
  369. package/dist/tui/feedback-prompt.js +156 -0
  370. package/dist/tui/input-box.js +247 -32
  371. package/dist/tui/login-picker.js +3 -3
  372. package/dist/tui/markdown-render.js +6 -6
  373. package/dist/tui/onboarding-wizard.js +240 -0
  374. package/dist/tui/permissions-picker.js +86 -0
  375. package/dist/tui/render.js +35 -0
  376. package/dist/tui/repl-render.js +332 -54
  377. package/dist/tui/repl-splash-art.js +16 -16
  378. package/dist/tui/repl-splash-mascot.js +48 -24
  379. package/dist/tui/repl-splash.js +22 -22
  380. package/dist/tui/repl.js +124 -44
  381. package/dist/tui/slash-palette.js +6 -6
  382. package/dist/tui/splash.js +2 -2
  383. package/dist/tui/status-bar.js +109 -31
  384. package/dist/tui/status-table.js +7 -0
  385. package/dist/tui/stickers-art.js +136 -0
  386. package/dist/tui/style-table.js +28 -0
  387. package/dist/tui/theme-table.js +29 -0
  388. package/dist/tui/thinking-spinner.js +123 -0
  389. package/dist/tui/tool-stream-pane.js +53 -4
  390. package/dist/tui/update-banner.js +27 -2
  391. package/dist/tui/vim-input.js +267 -0
  392. package/dist/tui/welcome-banner.js +107 -0
  393. package/dist/tui/welcome-data.js +293 -0
  394. package/dist/tui/workspace-context.js +2 -2
  395. package/docs/examples/codegraph.mcp.json +10 -0
  396. package/package.json +23 -6
  397. package/test/scenarios/codegen-create-file.scenario.txt +13 -0
  398. package/test/scenarios/compact-force.scenario.txt +11 -0
  399. package/test/scenarios/identity.scenario.txt +11 -0
  400. package/test/scenarios/persona-handoff.scenario.txt +11 -0
  401. package/test/scenarios/walkback.scenario.txt +12 -0
  402. package/dist/core/engine/compaction-hook.js +0 -154
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Public re-exports for the SessionStore module — Sprint α6.4.
2
+ * Public re-exports for the SessionStore module — Sprint .
3
3
  *
4
4
  * Consumers (`repl/session.ts`, `runtime/cli.ts`, the `/resume`
5
5
  * dispatcher) import from `./store/index.js` so the internal split
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Append-only JSONL event log — Sprint α6.4 (PR-PUGI-CLI-SESSION-STORE).
2
+ * Append-only JSONL event log — Sprint .
3
3
  *
4
4
  * Durable truth for the session. The SQLite index is rebuildable from
5
5
  * the JSONL; if the index is lost or corrupt, `pugi sessions --rebuild`
@@ -8,10 +8,10 @@
8
8
  *
9
9
  * File layout per session directory:
10
10
  *
11
- * <sessionDir>/events.0.jsonl active rotation file
12
- * <sessionDir>/events.1.jsonl previous rotation, oldest event first
13
- * <sessionDir>/events.2.jsonl older still
14
- * ...
11
+ * <sessionDir>/events.0.jsonl active rotation file
12
+ * <sessionDir>/events.1.jsonl previous rotation, oldest event first
13
+ * <sessionDir>/events.2.jsonl older still
14
+ * ...
15
15
  *
16
16
  * Rotation threshold is 50 MB per spec §4.2 must-ship #2. When the
17
17
  * active file exceeds the threshold AFTER a write, we close it, rename
@@ -21,23 +21,23 @@
21
21
  *
22
22
  * Crash safety:
23
23
  *
24
- * - Each write is a single `appendFileSync` of `JSON.stringify(event)\n`.
25
- * On Linux/macOS, append-mode writes of bytes < PIPE_BUF (4096) are
26
- * atomic with respect to other appends. Our events are well under
27
- * 4 KB so the OS guarantees per-line atomicity even if two
28
- * processes hold append fds (the lockfile already prevents that,
29
- * but defence-in-depth).
30
- * - After each write we call `fsync(fd)` so the bytes are durable
31
- * against power loss / kernel panic. Slow but correct — the
32
- * conversation-flow path is throughput-bound by the LLM, not by
33
- * the disk, so a few hundred extra microseconds per event is
34
- * invisible to the operator.
35
- * - On reopen we walk every line and drop any that fail JSON parse.
36
- * A crash mid-write leaves a truncated tail; we treat it as
37
- * "event was never written" and continue from there. The next
38
- * write may overlap with the truncated bytes; that is acceptable
39
- * because the truncated line is invalid JSON either way and the
40
- * reader is already designed to skip it.
24
+ * - Each write is a single `appendFileSync` of `JSON.stringify(event)\n`.
25
+ * On Linux/macOS, append-mode writes of bytes < PIPE_BUF (4096) are
26
+ * atomic with respect to other appends. Our events are well under
27
+ * 4 KB so the OS guarantees per-line atomicity even if two
28
+ * processes hold append fds (the lockfile already prevents that,
29
+ * but defence-in-depth).
30
+ * - After each write we call `fsync(fd)` so the bytes are durable
31
+ * against power loss / kernel panic. Slow but correct — the
32
+ * conversation-flow path is throughput-bound by the LLM, not by
33
+ * the disk, so a few hundred extra microseconds per event is
34
+ * invisible to the operator.
35
+ * - On reopen we walk every line and drop any that fail JSON parse.
36
+ * A crash mid-write leaves a truncated tail; we treat it as
37
+ * "event was never written" and continue from there. The next
38
+ * write may overlap with the truncated bytes; that is acceptable
39
+ * because the truncated line is invalid JSON either way and the
40
+ * reader is already designed to skip it.
41
41
  */
42
42
  import { closeSync, existsSync, fsyncSync, mkdirSync, openSync, readdirSync, readFileSync, renameSync, statSync, writeSync, } from 'node:fs';
43
43
  import { resolve } from 'node:path';
@@ -1,5 +1,5 @@
1
1
  /**
2
- * PID lockfile — Sprint α6.4 (PR-PUGI-CLI-SESSION-STORE).
2
+ * PID lockfile — Sprint .
3
3
  *
4
4
  * Prevents two REPL processes in the same project directory from
5
5
  * writing to the same `session.db` concurrently. SQLite's WAL handles
@@ -9,15 +9,15 @@
9
9
  *
10
10
  * Algorithm:
11
11
  *
12
- * 1. Try `O_CREAT | O_EXCL` open of `<dir>/session.lock`. Write the
13
- * caller's PID + process start time as the body. If the open
14
- * succeeds, we hold the lock; return.
15
- * 2. If `EEXIST`, read the existing PID. Probe with `kill(pid, 0)`
16
- * (signal 0 = "check liveness, do not deliver"). If the probe
17
- * returns ESRCH, the holder is dead — unlink the stale lock and
18
- * retry the exclusive create.
19
- * 3. If the probe says the PID is alive, throw `SessionLockBusyError`
20
- * so the caller surfaces a clean message to the operator.
12
+ * 1. Try `O_CREAT | O_EXCL` open of `<dir>/session.lock`. Write the
13
+ * caller's PID + process start time as the body. If the open
14
+ * succeeds, we hold the lock; return.
15
+ * 2. If `EEXIST`, read the existing PID. Probe with `kill(pid, 0)`
16
+ * (signal 0 = "check liveness, do not deliver"). If the probe
17
+ * returns ESRCH, the holder is dead — unlink the stale lock and
18
+ * retry the exclusive create.
19
+ * 3. If the probe says the PID is alive, throw `SessionLockBusyError`
20
+ * so the caller surfaces a clean message to the operator.
21
21
  *
22
22
  * Why not `proper-lockfile`: pulling a 14kB dependency for a 60-line
23
23
  * PID file is poor cost/benefit. The stale-detection loop is the only
@@ -1,15 +1,15 @@
1
1
  /**
2
- * SessionStore — Sprint α6.4 (PR-PUGI-CLI-SESSION-STORE).
2
+ * SessionStore — Sprint .
3
3
  *
4
4
  * SQLite-indexed, JSONL-durable session store. The JSONL log is the
5
5
  * source of truth; the SQLite tables are a queryable cache. Layout:
6
6
  *
7
- * ~/.pugi/projects/<project-slug>/
8
- * session.db SQLite index (sessions + FTS5)
9
- * session.lock PID lockfile
10
- * sessions/<session-id>/
11
- * events.0.jsonl active append log
12
- * events.1.jsonl older rotations (50 MB threshold)
7
+ * ~/.pugi/projects/<project-slug>/
8
+ * session.db SQLite index (sessions + FTS5)
9
+ * session.lock PID lockfile
10
+ * sessions/<session-id>/
11
+ * events.0.jsonl active append log
12
+ * events.1.jsonl older rotations (50 MB threshold)
13
13
  *
14
14
  * The store lives entirely under `$HOME/.pugi/` per the local-first
15
15
  * invariants memo (`feedback_no_landing_oes_secondary_2026_05_23.md`)
@@ -19,20 +19,20 @@
19
19
  *
20
20
  * Why node:sqlite over better-sqlite3:
21
21
  *
22
- * - Zero install-time native build. better-sqlite3 needs prebuilt
23
- * binaries for every Node ABI × platform; missing a wheel forces
24
- * a node-gyp compile that fails on bare-metal CI agents without
25
- * a C++ toolchain. Pugi CLI ships via npm to operators who almost
26
- * certainly do not have build-essential installed.
27
- * - Available since Node 22.5.0 (stable subset; LTS as of 2026). Our
28
- * `engines.node` is pinned to `>=22.5.0` in apps/pugi-cli +
29
- * packages/pugi-sdk so npm refuses to install the CLI on Node 20.x
30
- * instead of crash-on-import. CI runs Node 22 (matrix-free; see
31
- * `.github/workflows/ci.yml`).
32
- * - Marked Experimental by Node — silenced via process.emitWarning
33
- * suppression at boot. The API surface we use (DatabaseSync,
34
- * StatementSync, exec/prepare) is the stable subset that has
35
- * shipped unchanged since Node 22.5.
22
+ * - Zero install-time native build. better-sqlite3 needs prebuilt
23
+ * binaries for every Node ABI × platform; missing a wheel forces
24
+ * a node-gyp compile that fails on bare-metal CI agents without
25
+ * a C++ toolchain. Pugi CLI ships via npm to operators who almost
26
+ * certainly do not have build-essential installed.
27
+ * - Available since Node 22.5.0 (stable subset; LTS as of 2026). Our
28
+ * `engines.node` is pinned to `>=22.5.0` in apps/pugi-cli +
29
+ * packages/pugi-sdk so npm refuses to install the CLI on Node 20.x
30
+ * instead of crash-on-import. CI runs Node 22 (matrix-free; see
31
+ * `.github/workflows/ci.yml`).
32
+ * - Marked Experimental by Node — silenced via process.emitWarning
33
+ * suppression at boot. The API surface we use (DatabaseSync,
34
+ * StatementSync, exec/prepare) is the stable subset that has
35
+ * shipped unchanged since Node 22.5.
36
36
  *
37
37
  * Schema is created at first open. `schema_meta` carries a single row
38
38
  * `('version', '1')`; future migrations bump the version + run the
@@ -47,32 +47,32 @@ import { takeLock } from './lockfile.js';
47
47
  import { uuidV7 } from './uuid-v7.js';
48
48
  const SCHEMA_VERSION = '1';
49
49
  const SCHEMA_SQL = `
50
- CREATE TABLE IF NOT EXISTS sessions (
51
- id TEXT PRIMARY KEY,
52
- created_at INTEGER NOT NULL,
53
- updated_at INTEGER NOT NULL,
54
- workspace_root TEXT NOT NULL,
55
- branch TEXT,
56
- project_slug TEXT NOT NULL,
57
- title TEXT,
58
- turn_count INTEGER NOT NULL DEFAULT 0,
59
- event_count INTEGER NOT NULL DEFAULT 0,
60
- model TEXT,
61
- tenant_id TEXT,
62
- status TEXT NOT NULL DEFAULT 'active'
63
- );
64
- CREATE INDEX IF NOT EXISTS idx_sessions_updated ON sessions(updated_at DESC);
65
- CREATE INDEX IF NOT EXISTS idx_sessions_project ON sessions(project_slug, updated_at DESC);
66
- CREATE VIRTUAL TABLE IF NOT EXISTS sessions_fts USING fts5(
67
- id UNINDEXED,
68
- title,
69
- body,
70
- tokenize='unicode61'
71
- );
72
- CREATE TABLE IF NOT EXISTS schema_meta (
73
- key TEXT PRIMARY KEY,
74
- value TEXT NOT NULL
75
- );
50
+ CREATE TABLE IF NOT EXISTS sessions (
51
+ id TEXT PRIMARY KEY,
52
+ created_at INTEGER NOT NULL,
53
+ updated_at INTEGER NOT NULL,
54
+ workspace_root TEXT NOT NULL,
55
+ branch TEXT,
56
+ project_slug TEXT NOT NULL,
57
+ title TEXT,
58
+ turn_count INTEGER NOT NULL DEFAULT 0,
59
+ event_count INTEGER NOT NULL DEFAULT 0,
60
+ model TEXT,
61
+ tenant_id TEXT,
62
+ status TEXT NOT NULL DEFAULT 'active'
63
+ );
64
+ CREATE INDEX IF NOT EXISTS idx_sessions_updated ON sessions(updated_at DESC);
65
+ CREATE INDEX IF NOT EXISTS idx_sessions_project ON sessions(project_slug, updated_at DESC);
66
+ CREATE VIRTUAL TABLE IF NOT EXISTS sessions_fts USING fts5(
67
+ id UNINDEXED,
68
+ title,
69
+ body,
70
+ tokenize='unicode61'
71
+ );
72
+ CREATE TABLE IF NOT EXISTS schema_meta (
73
+ key TEXT PRIMARY KEY,
74
+ value TEXT NOT NULL
75
+ );
76
76
  `;
77
77
  /** Default list limit. Operators rarely scroll past the most recent 50. */
78
78
  const DEFAULT_LIST_LIMIT = 50;
@@ -180,13 +180,13 @@ export class SqliteSessionStore {
180
180
  // bump turn_count and set title. Splitting into multiple statements
181
181
  // would race the lockfile if a second process slipped through.
182
182
  const sql = `
183
- UPDATE sessions
184
- SET event_count = event_count + 1,
185
- updated_at = ?,
186
- turn_count = turn_count + ${isUserTurn ? 1 : 0},
187
- title = COALESCE(title, ?)
188
- WHERE id = ?
189
- `;
183
+ UPDATE sessions
184
+ SET event_count = event_count + 1,
185
+ updated_at = ?,
186
+ turn_count = turn_count + ${isUserTurn ? 1 : 0},
187
+ title = COALESCE(title, ?)
188
+ WHERE id = ?
189
+ `;
190
190
  db.prepare(sql).run(ts, titlePatch ?? null, sessionId);
191
191
  // Mirror the user-turn body into FTS so substring search hits
192
192
  // every previous user turn, not just the most recent one.
@@ -237,13 +237,13 @@ export class SqliteSessionStore {
237
237
  }
238
238
  const whereClause = where.length > 0 ? `WHERE ${where.join(' AND ')}` : '';
239
239
  const sql = `
240
- SELECT id, created_at, updated_at, workspace_root, branch, project_slug,
241
- title, turn_count, event_count, model, tenant_id, status
242
- FROM sessions
243
- ${whereClause}
244
- ORDER BY updated_at DESC
245
- LIMIT ?
246
- `;
240
+ SELECT id, created_at, updated_at, workspace_root, branch, project_slug,
241
+ title, turn_count, event_count, model, tenant_id, status
242
+ FROM sessions
243
+ ${whereClause}
244
+ ORDER BY updated_at DESC
245
+ LIMIT ?
246
+ `;
247
247
  const stmt = db.prepare(sql);
248
248
  const rows = stmt.all(...params, limit);
249
249
  return rows.map(rawToSession);
@@ -294,15 +294,15 @@ export class SqliteSessionStore {
294
294
  // `unable to use function MATCH in the requested context`. We
295
295
  // search title+body together by matching against `sessions_fts`.
296
296
  const sql = `
297
- SELECT s.id, s.created_at, s.updated_at, s.workspace_root, s.branch,
298
- s.project_slug, s.title, s.turn_count, s.event_count, s.model,
299
- s.tenant_id, s.status
300
- FROM sessions_fts f
301
- JOIN sessions s ON s.id = f.id
302
- WHERE sessions_fts MATCH ?
303
- ORDER BY s.updated_at DESC
304
- LIMIT ?
305
- `;
297
+ SELECT s.id, s.created_at, s.updated_at, s.workspace_root, s.branch,
298
+ s.project_slug, s.title, s.turn_count, s.event_count, s.model,
299
+ s.tenant_id, s.status
300
+ FROM sessions_fts f
301
+ JOIN sessions s ON s.id = f.id
302
+ WHERE sessions_fts MATCH ?
303
+ ORDER BY s.updated_at DESC
304
+ LIMIT ?
305
+ `;
306
306
  let rows;
307
307
  try {
308
308
  rows = db.prepare(sql).all(ftsQuery, limit);
@@ -361,10 +361,10 @@ export class SqliteSessionStore {
361
361
  // which maps to SQLITE_OPEN_READONLY. The option form is the
362
362
  // documented API; the file-URI form (file:...?mode=ro) also works.
363
363
  const db = new DatabaseSync(dbPath, { readOnly: true });
364
- return new SqliteSessionStoreReadOnlyView(db);
364
+ return new SqliteSessionStoreReadOnlyView(db, projectStoreDir);
365
365
  }
366
366
  /* ------------------------------------------------------------ */
367
- /* Internals */
367
+ /* Internals */
368
368
  /* ------------------------------------------------------------ */
369
369
  takeLockOrThrow() {
370
370
  const lockPath = resolve(this.projectDir, 'session.lock');
@@ -420,11 +420,11 @@ export class SqliteSessionStore {
420
420
  getSessionSync(sessionId) {
421
421
  const db = this.requireDb();
422
422
  const stmt = db.prepare(`
423
- SELECT id, created_at, updated_at, workspace_root, branch, project_slug,
424
- title, turn_count, event_count, model, tenant_id, status
425
- FROM sessions
426
- WHERE id = ?
427
- `);
423
+ SELECT id, created_at, updated_at, workspace_root, branch, project_slug,
424
+ title, turn_count, event_count, model, tenant_id, status
425
+ FROM sessions
426
+ WHERE id = ?
427
+ `);
428
428
  const row = stmt.get(sessionId);
429
429
  return row ? rawToSession(row) : null;
430
430
  }
@@ -432,11 +432,11 @@ export class SqliteSessionStore {
432
432
  const db = this.requireDb();
433
433
  const ts = this.now();
434
434
  db.prepare(`
435
- INSERT INTO sessions
436
- (id, created_at, updated_at, workspace_root, branch, project_slug,
437
- title, turn_count, event_count, model, tenant_id, status)
438
- VALUES (?, ?, ?, ?, ?, ?, NULL, 0, 0, ?, ?, 'active')
439
- `).run(input.id, ts, ts, input.workspaceRoot, input.branch, input.projectSlug, input.model, input.tenantId);
435
+ INSERT INTO sessions
436
+ (id, created_at, updated_at, workspace_root, branch, project_slug,
437
+ title, turn_count, event_count, model, tenant_id, status)
438
+ VALUES (?, ?, ?, ?, ?, ?, NULL, 0, 0, ?, ?, 'active')
439
+ `).run(input.id, ts, ts, input.workspaceRoot, input.branch, input.projectSlug, input.model, input.tenantId);
440
440
  // Seed an empty FTS row so the title patch path can rely on a
441
441
  // single UPDATE OR REPLACE without first checking for the row.
442
442
  this.upsertFtsRow(input.id, '', '');
@@ -584,8 +584,37 @@ export class SqliteSessionStore {
584
584
  */
585
585
  export class SqliteSessionStoreReadOnlyView {
586
586
  db;
587
- constructor(db) {
587
+ projectStoreDir;
588
+ constructor(db,
589
+ /**
590
+ * Project store directory — required for the JSONL event read path.
591
+ * L9 : `/rewind` + `/resume` need to walk events from
592
+ * inside the read-only view so the rewind picker + resume preview
593
+ * never take the writer lockfile.
594
+ */
595
+ projectStoreDir) {
588
596
  this.db = db;
597
+ this.projectStoreDir = projectStoreDir;
598
+ }
599
+ /**
600
+ * Read every event for a session via the durable JSONL log. The
601
+ * SQLite cache is NOT used here — JSONL is the source of truth and
602
+ * the cache only holds counters. The walk stitches across rotation
603
+ * files (`events.<n>.jsonl`) in the same order `JsonlEventLog.read`
604
+ * uses inside the writer path so consumers see one consistent stream
605
+ * whether they came in via the writer store OR the read-only view.
606
+ */
607
+ async events(sessionId, opts) {
608
+ const sessionDir = resolve(this.projectStoreDir, 'sessions', sessionId);
609
+ if (!existsSync(sessionDir))
610
+ return [];
611
+ const log = new JsonlEventLog({ sessionDir });
612
+ try {
613
+ return log.read(opts);
614
+ }
615
+ finally {
616
+ log.close();
617
+ }
589
618
  }
590
619
  async list(opts) {
591
620
  const limit = clampLimit(opts?.limit ?? DEFAULT_LIST_LIMIT, MAX_LIST_LIMIT);
@@ -613,13 +642,13 @@ export class SqliteSessionStoreReadOnlyView {
613
642
  }
614
643
  const whereClause = where.length > 0 ? `WHERE ${where.join(' AND ')}` : '';
615
644
  const sql = `
616
- SELECT id, created_at, updated_at, workspace_root, branch, project_slug,
617
- title, turn_count, event_count, model, tenant_id, status
618
- FROM sessions
619
- ${whereClause}
620
- ORDER BY updated_at DESC
621
- LIMIT ?
622
- `;
645
+ SELECT id, created_at, updated_at, workspace_root, branch, project_slug,
646
+ title, turn_count, event_count, model, tenant_id, status
647
+ FROM sessions
648
+ ${whereClause}
649
+ ORDER BY updated_at DESC
650
+ LIMIT ?
651
+ `;
623
652
  const rows = this.db
624
653
  .prepare(sql)
625
654
  .all(...params, limit);
@@ -633,15 +662,15 @@ export class SqliteSessionStoreReadOnlyView {
633
662
  const limit = clampLimit(opts?.limit ?? DEFAULT_SEARCH_LIMIT, MAX_SEARCH_LIMIT);
634
663
  const ftsQuery = sanitiseFtsQuery(trimmed);
635
664
  const sql = `
636
- SELECT s.id, s.created_at, s.updated_at, s.workspace_root, s.branch,
637
- s.project_slug, s.title, s.turn_count, s.event_count, s.model,
638
- s.tenant_id, s.status
639
- FROM sessions_fts f
640
- JOIN sessions s ON s.id = f.id
641
- WHERE sessions_fts MATCH ?
642
- ORDER BY s.updated_at DESC
643
- LIMIT ?
644
- `;
665
+ SELECT s.id, s.created_at, s.updated_at, s.workspace_root, s.branch,
666
+ s.project_slug, s.title, s.turn_count, s.event_count, s.model,
667
+ s.tenant_id, s.status
668
+ FROM sessions_fts f
669
+ JOIN sessions s ON s.id = f.id
670
+ WHERE sessions_fts MATCH ?
671
+ ORDER BY s.updated_at DESC
672
+ LIMIT ?
673
+ `;
645
674
  let rows;
646
675
  try {
647
676
  rows = this.db.prepare(sql).all(ftsQuery, limit);
@@ -656,11 +685,11 @@ export class SqliteSessionStoreReadOnlyView {
656
685
  }
657
686
  async get(sessionId) {
658
687
  const stmt = this.db.prepare(`
659
- SELECT id, created_at, updated_at, workspace_root, branch, project_slug,
660
- title, turn_count, event_count, model, tenant_id, status
661
- FROM sessions
662
- WHERE id = ?
663
- `);
688
+ SELECT id, created_at, updated_at, workspace_root, branch, project_slug,
689
+ title, turn_count, event_count, model, tenant_id, status
690
+ FROM sessions
691
+ WHERE id = ?
692
+ `);
664
693
  const row = stmt.get(sessionId);
665
694
  return row ? rawToSession(row) : null;
666
695
  }
@@ -722,9 +751,9 @@ function sanitiseSlugForFs(raw) {
722
751
  * Pull a human-readable text body out of an event payload. We support
723
752
  * three shapes the producer commonly emits:
724
753
  *
725
- * - `{ text: string }` — explicit text body.
726
- * - `{ brief: string }` — REPL `dispatch` brief.
727
- * - `string` — payload is the body itself.
754
+ * - `{ text: string }` — explicit text body.
755
+ * - `{ brief: string }` — REPL `dispatch` brief.
756
+ * - `string` — payload is the body itself.
728
757
  *
729
758
  * Anything else returns the empty string so a typo at the call site
730
759
  * silently degrades to "no FTS body" rather than crashing the writer.
@@ -1,26 +1,26 @@
1
1
  /**
2
- * Persistent REPL session store — Sprint α6.4 (PR-PUGI-CLI-SESSION-STORE).
2
+ * Persistent REPL session store — Sprint .
3
3
  *
4
4
  * Public types consumed by the REPL session module + the `pugi sessions`
5
5
  * / `pugi resume` dispatchers. Wire format is stable:
6
6
  *
7
- * - `SessionRow` mirrors the SQLite `sessions` table one-to-one and is
8
- * also the JSON shape returned by `pugi sessions --json`. Field names
9
- * are camelCase (PascalCase types, camelCase fields per CLAUDE.md
10
- * conventions). The SQL columns themselves stay snake_case because
11
- * they originate from raw SQL.
7
+ * - `SessionRow` mirrors the SQLite `sessions` table one-to-one and is
8
+ * also the JSON shape returned by `pugi sessions --json`. Field names
9
+ * are camelCase (PascalCase types, camelCase fields per CLAUDE.md
10
+ * conventions). The SQL columns themselves stay snake_case because
11
+ * they originate from raw SQL.
12
12
  *
13
- * - `SessionEvent` is the on-disk shape of one line in
14
- * `events.<n>.jsonl`. `kind` is a closed union; `payload` is an
15
- * opaque JSON value so the producer can attach whatever fields the
16
- * event type requires without forcing the store to change.
13
+ * - `SessionEvent` is the on-disk shape of one line in
14
+ * `events.<n>.jsonl`. `kind` is a closed union; `payload` is an
15
+ * opaque JSON value so the producer can attach whatever fields the
16
+ * event type requires without forcing the store to change.
17
17
  *
18
- * - `SessionListOptions` / `SessionLoadEventsOptions` /
19
- * `SessionSearchOptions` are inputs the store accepts. Defaults are
20
- * spec'd inline so the test plan can pin them without reading the
21
- * implementation.
18
+ * - `SessionListOptions` / `SessionLoadEventsOptions` /
19
+ * `SessionSearchOptions` are inputs the store accepts. Defaults are
20
+ * spec'd inline so the test plan can pin them without reading the
21
+ * implementation.
22
22
  *
23
- * The blob store + `pugi undo` + named checkpoints are α6.4b follow-ups
23
+ * The blob store + `pugi undo` + named checkpoints are follow-ups
24
24
  * — out of scope for THIS PR per spec. The types here intentionally do
25
25
  * NOT model blob refs so a future blob-store landing can extend without
26
26
  * a wire break.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * UUID v7 generator — Sprint α6.4 (PR-PUGI-CLI-SESSION-STORE).
2
+ * UUID v7 generator — Sprint .
3
3
  *
4
4
  * uuid v7 (RFC 9562 draft) is a time-sortable 128-bit identifier whose
5
5
  * first 48 bits are the unix-epoch milliseconds, the next 4 bits are
@@ -9,17 +9,17 @@
9
9
  *
10
10
  * Why v7 and not v4 (random) or v6 (gregorian time):
11
11
  *
12
- * - The session id IS the primary key of the SQLite table. We want
13
- * inserts to land at the end of the b-tree to keep page fanout
14
- * small. v4 fragments the tree (uniformly random keys); v7 sorts
15
- * in time order so inserts are append-only.
16
- * - `pugi sessions` sorts by `updated_at DESC` for display, but the
17
- * pagination cursor uses the session id directly — a v7 id IS the
18
- * creation timestamp, so the cursor is a single column compare
19
- * instead of (updated_at, id) tuple.
20
- * - Operators see ids in `/resume` picker; v7 prefix is monotonically
21
- * increasing so the most recent session lands at the bottom of an
22
- * id sort, matching the human expectation of "newest last".
12
+ * - The session id IS the primary key of the SQLite table. We want
13
+ * inserts to land at the end of the b-tree to keep page fanout
14
+ * small. v4 fragments the tree (uniformly random keys); v7 sorts
15
+ * in time order so inserts are append-only.
16
+ * - `pugi sessions` sorts by `updated_at DESC` for display, but the
17
+ * pagination cursor uses the session id directly — a v7 id IS the
18
+ * creation timestamp, so the cursor is a single column compare
19
+ * instead of (updated_at, id) tuple.
20
+ * - Operators see ids in `/resume` picker; v7 prefix is monotonically
21
+ * increasing so the most recent session lands at the bottom of an
22
+ * id sort, matching the human expectation of "newest last".
23
23
  *
24
24
  * Node 22 does not ship a v7 generator (`crypto.randomUUID()` is v4
25
25
  * only). We implement it inline with `crypto.randomBytes(10)` for the