praxis-agent 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (395) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +534 -0
  3. package/dist/application/background-agent-manager.d.ts +66 -0
  4. package/dist/application/background-agent-manager.d.ts.map +1 -0
  5. package/dist/application/background-agent-manager.js +362 -0
  6. package/dist/application/background-agent-manager.js.map +1 -0
  7. package/dist/application/background-bash-manager.d.ts +54 -0
  8. package/dist/application/background-bash-manager.d.ts.map +1 -0
  9. package/dist/application/background-bash-manager.js +354 -0
  10. package/dist/application/background-bash-manager.js.map +1 -0
  11. package/dist/application/background-task-id.d.ts +5 -0
  12. package/dist/application/background-task-id.d.ts.map +1 -0
  13. package/dist/application/background-task-id.js +25 -0
  14. package/dist/application/background-task-id.js.map +1 -0
  15. package/dist/application/claude-project-purge.d.ts +50 -0
  16. package/dist/application/claude-project-purge.d.ts.map +1 -0
  17. package/dist/application/claude-project-purge.js +459 -0
  18. package/dist/application/claude-project-purge.js.map +1 -0
  19. package/dist/application/managed-worktree.d.ts +15 -0
  20. package/dist/application/managed-worktree.d.ts.map +1 -0
  21. package/dist/application/managed-worktree.js +127 -0
  22. package/dist/application/managed-worktree.js.map +1 -0
  23. package/dist/application/model-compactor.d.ts +8 -0
  24. package/dist/application/model-compactor.d.ts.map +1 -0
  25. package/dist/application/model-compactor.js +70 -0
  26. package/dist/application/model-compactor.js.map +1 -0
  27. package/dist/application/scheduled-prompt-manager.d.ts +69 -0
  28. package/dist/application/scheduled-prompt-manager.d.ts.map +1 -0
  29. package/dist/application/scheduled-prompt-manager.js +387 -0
  30. package/dist/application/scheduled-prompt-manager.js.map +1 -0
  31. package/dist/application/session-service.d.ts +142 -0
  32. package/dist/application/session-service.d.ts.map +1 -0
  33. package/dist/application/session-service.js +1690 -0
  34. package/dist/application/session-service.js.map +1 -0
  35. package/dist/application/session-worktree.d.ts +55 -0
  36. package/dist/application/session-worktree.d.ts.map +1 -0
  37. package/dist/application/session-worktree.js +311 -0
  38. package/dist/application/session-worktree.js.map +1 -0
  39. package/dist/application/subagent-service.d.ts +98 -0
  40. package/dist/application/subagent-service.d.ts.map +1 -0
  41. package/dist/application/subagent-service.js +1305 -0
  42. package/dist/application/subagent-service.js.map +1 -0
  43. package/dist/application/tool-use-summary.d.ts +8 -0
  44. package/dist/application/tool-use-summary.d.ts.map +1 -0
  45. package/dist/application/tool-use-summary.js +53 -0
  46. package/dist/application/tool-use-summary.js.map +1 -0
  47. package/dist/application/top-level-agent-manager.d.ts +58 -0
  48. package/dist/application/top-level-agent-manager.d.ts.map +1 -0
  49. package/dist/application/top-level-agent-manager.js +907 -0
  50. package/dist/application/top-level-agent-manager.js.map +1 -0
  51. package/dist/application/workflow-manager.d.ts +61 -0
  52. package/dist/application/workflow-manager.d.ts.map +1 -0
  53. package/dist/application/workflow-manager.js +582 -0
  54. package/dist/application/workflow-manager.js.map +1 -0
  55. package/dist/application/workflow-meta.d.ts +18 -0
  56. package/dist/application/workflow-meta.d.ts.map +1 -0
  57. package/dist/application/workflow-meta.js +146 -0
  58. package/dist/application/workflow-meta.js.map +1 -0
  59. package/dist/application/workflow-runtime.d.ts +29 -0
  60. package/dist/application/workflow-runtime.d.ts.map +1 -0
  61. package/dist/application/workflow-runtime.js +176 -0
  62. package/dist/application/workflow-runtime.js.map +1 -0
  63. package/dist/application/workflow-worktree.d.ts +9 -0
  64. package/dist/application/workflow-worktree.d.ts.map +1 -0
  65. package/dist/application/workflow-worktree.js +11 -0
  66. package/dist/application/workflow-worktree.js.map +1 -0
  67. package/dist/cli/agents-dashboard.d.ts +37 -0
  68. package/dist/cli/agents-dashboard.d.ts.map +1 -0
  69. package/dist/cli/agents-dashboard.js +408 -0
  70. package/dist/cli/agents-dashboard.js.map +1 -0
  71. package/dist/cli/controls.d.ts +15 -0
  72. package/dist/cli/controls.d.ts.map +1 -0
  73. package/dist/cli/controls.js +219 -0
  74. package/dist/cli/controls.js.map +1 -0
  75. package/dist/cli/debug.d.ts +13 -0
  76. package/dist/cli/debug.d.ts.map +1 -0
  77. package/dist/cli/debug.js +37 -0
  78. package/dist/cli/debug.js.map +1 -0
  79. package/dist/cli/interactive.d.ts +63 -0
  80. package/dist/cli/interactive.d.ts.map +1 -0
  81. package/dist/cli/interactive.js +600 -0
  82. package/dist/cli/interactive.js.map +1 -0
  83. package/dist/cli/protocol.d.ts +251 -0
  84. package/dist/cli/protocol.d.ts.map +1 -0
  85. package/dist/cli/protocol.js +2146 -0
  86. package/dist/cli/protocol.js.map +1 -0
  87. package/dist/cli.d.ts +116 -0
  88. package/dist/cli.d.ts.map +1 -0
  89. package/dist/cli.js +3901 -0
  90. package/dist/cli.js.map +1 -0
  91. package/dist/compatibility/claude/compaction.d.ts +19 -0
  92. package/dist/compatibility/claude/compaction.d.ts.map +1 -0
  93. package/dist/compatibility/claude/compaction.js +82 -0
  94. package/dist/compatibility/claude/compaction.js.map +1 -0
  95. package/dist/compatibility/claude/context.d.ts +24 -0
  96. package/dist/compatibility/claude/context.d.ts.map +1 -0
  97. package/dist/compatibility/claude/context.js +92 -0
  98. package/dist/compatibility/claude/context.js.map +1 -0
  99. package/dist/compatibility/claude/dynamic-context.d.ts +20 -0
  100. package/dist/compatibility/claude/dynamic-context.d.ts.map +1 -0
  101. package/dist/compatibility/claude/dynamic-context.js +168 -0
  102. package/dist/compatibility/claude/dynamic-context.js.map +1 -0
  103. package/dist/compatibility/claude/file-history.d.ts +14 -0
  104. package/dist/compatibility/claude/file-history.d.ts.map +1 -0
  105. package/dist/compatibility/claude/file-history.js +340 -0
  106. package/dist/compatibility/claude/file-history.js.map +1 -0
  107. package/dist/compatibility/claude/file-resources.d.ts +28 -0
  108. package/dist/compatibility/claude/file-resources.d.ts.map +1 -0
  109. package/dist/compatibility/claude/file-resources.js +168 -0
  110. package/dist/compatibility/claude/file-resources.js.map +1 -0
  111. package/dist/compatibility/claude/fork.d.ts +9 -0
  112. package/dist/compatibility/claude/fork.d.ts.map +1 -0
  113. package/dist/compatibility/claude/fork.js +225 -0
  114. package/dist/compatibility/claude/fork.js.map +1 -0
  115. package/dist/compatibility/claude/history.d.ts +4 -0
  116. package/dist/compatibility/claude/history.d.ts.map +1 -0
  117. package/dist/compatibility/claude/history.js +86 -0
  118. package/dist/compatibility/claude/history.js.map +1 -0
  119. package/dist/compatibility/claude/ownership.d.ts +87 -0
  120. package/dist/compatibility/claude/ownership.d.ts.map +1 -0
  121. package/dist/compatibility/claude/ownership.js +100 -0
  122. package/dist/compatibility/claude/ownership.js.map +1 -0
  123. package/dist/compatibility/claude/paths.d.ts +17 -0
  124. package/dist/compatibility/claude/paths.d.ts.map +1 -0
  125. package/dist/compatibility/claude/paths.js +54 -0
  126. package/dist/compatibility/claude/paths.js.map +1 -0
  127. package/dist/compatibility/claude/pr-links.d.ts +25 -0
  128. package/dist/compatibility/claude/pr-links.d.ts.map +1 -0
  129. package/dist/compatibility/claude/pr-links.js +80 -0
  130. package/dist/compatibility/claude/pr-links.js.map +1 -0
  131. package/dist/compatibility/claude/projection.d.ts +11 -0
  132. package/dist/compatibility/claude/projection.d.ts.map +1 -0
  133. package/dist/compatibility/claude/projection.js +325 -0
  134. package/dist/compatibility/claude/projection.js.map +1 -0
  135. package/dist/compatibility/claude/schema.d.ts +18 -0
  136. package/dist/compatibility/claude/schema.d.ts.map +1 -0
  137. package/dist/compatibility/claude/schema.js +983 -0
  138. package/dist/compatibility/claude/schema.js.map +1 -0
  139. package/dist/compatibility/claude/shared-resources.d.ts +51 -0
  140. package/dist/compatibility/claude/shared-resources.d.ts.map +1 -0
  141. package/dist/compatibility/claude/shared-resources.js +382 -0
  142. package/dist/compatibility/claude/shared-resources.js.map +1 -0
  143. package/dist/compatibility/claude/sidechain.d.ts +50 -0
  144. package/dist/compatibility/claude/sidechain.d.ts.map +1 -0
  145. package/dist/compatibility/claude/sidechain.js +90 -0
  146. package/dist/compatibility/claude/sidechain.js.map +1 -0
  147. package/dist/compatibility/claude/tool-links.d.ts +13 -0
  148. package/dist/compatibility/claude/tool-links.d.ts.map +1 -0
  149. package/dist/compatibility/claude/tool-links.js +61 -0
  150. package/dist/compatibility/claude/tool-links.js.map +1 -0
  151. package/dist/compatibility/claude/translation.d.ts +71 -0
  152. package/dist/compatibility/claude/translation.d.ts.map +1 -0
  153. package/dist/compatibility/claude/translation.js +443 -0
  154. package/dist/compatibility/claude/translation.js.map +1 -0
  155. package/dist/compatibility/claude/workflow-replay.d.ts +10 -0
  156. package/dist/compatibility/claude/workflow-replay.d.ts.map +1 -0
  157. package/dist/compatibility/claude/workflow-replay.js +66 -0
  158. package/dist/compatibility/claude/workflow-replay.js.map +1 -0
  159. package/dist/compatibility/claude/workflow.d.ts +33 -0
  160. package/dist/compatibility/claude/workflow.d.ts.map +1 -0
  161. package/dist/compatibility/claude/workflow.js +76 -0
  162. package/dist/compatibility/claude/workflow.js.map +1 -0
  163. package/dist/core/compaction.d.ts +16 -0
  164. package/dist/core/compaction.d.ts.map +1 -0
  165. package/dist/core/compaction.js +2 -0
  166. package/dist/core/compaction.js.map +1 -0
  167. package/dist/core/context-budget.d.ts +28 -0
  168. package/dist/core/context-budget.d.ts.map +1 -0
  169. package/dist/core/context-budget.js +108 -0
  170. package/dist/core/context-budget.js.map +1 -0
  171. package/dist/core/context.d.ts +16 -0
  172. package/dist/core/context.d.ts.map +1 -0
  173. package/dist/core/context.js +13 -0
  174. package/dist/core/context.js.map +1 -0
  175. package/dist/core/runtime.d.ts +394 -0
  176. package/dist/core/runtime.d.ts.map +1 -0
  177. package/dist/core/runtime.js +507 -0
  178. package/dist/core/runtime.js.map +1 -0
  179. package/dist/core/usage.d.ts +26 -0
  180. package/dist/core/usage.d.ts.map +1 -0
  181. package/dist/core/usage.js +133 -0
  182. package/dist/core/usage.js.map +1 -0
  183. package/dist/extensions/claude-extension-tools.d.ts +16 -0
  184. package/dist/extensions/claude-extension-tools.d.ts.map +1 -0
  185. package/dist/extensions/claude-extension-tools.js +78 -0
  186. package/dist/extensions/claude-extension-tools.js.map +1 -0
  187. package/dist/extensions/claude-extensions.d.ts +41 -0
  188. package/dist/extensions/claude-extensions.d.ts.map +1 -0
  189. package/dist/extensions/claude-extensions.js +270 -0
  190. package/dist/extensions/claude-extensions.js.map +1 -0
  191. package/dist/hooks/claude-hook-tools.d.ts +26 -0
  192. package/dist/hooks/claude-hook-tools.d.ts.map +1 -0
  193. package/dist/hooks/claude-hook-tools.js +129 -0
  194. package/dist/hooks/claude-hook-tools.js.map +1 -0
  195. package/dist/hooks/claude-hooks.d.ts +87 -0
  196. package/dist/hooks/claude-hooks.d.ts.map +1 -0
  197. package/dist/hooks/claude-hooks.js +411 -0
  198. package/dist/hooks/claude-hooks.js.map +1 -0
  199. package/dist/maintenance/doctor.d.ts +33 -0
  200. package/dist/maintenance/doctor.d.ts.map +1 -0
  201. package/dist/maintenance/doctor.js +391 -0
  202. package/dist/maintenance/doctor.js.map +1 -0
  203. package/dist/maintenance/self-update.d.ts +31 -0
  204. package/dist/maintenance/self-update.d.ts.map +1 -0
  205. package/dist/maintenance/self-update.js +81 -0
  206. package/dist/maintenance/self-update.js.map +1 -0
  207. package/dist/mcp/claude-mcp-management.d.ts +28 -0
  208. package/dist/mcp/claude-mcp-management.d.ts.map +1 -0
  209. package/dist/mcp/claude-mcp-management.js +169 -0
  210. package/dist/mcp/claude-mcp-management.js.map +1 -0
  211. package/dist/mcp/claude-mcp-oauth.d.ts +113 -0
  212. package/dist/mcp/claude-mcp-oauth.d.ts.map +1 -0
  213. package/dist/mcp/claude-mcp-oauth.js +1053 -0
  214. package/dist/mcp/claude-mcp-oauth.js.map +1 -0
  215. package/dist/mcp/claude-mcp-tools.d.ts +98 -0
  216. package/dist/mcp/claude-mcp-tools.d.ts.map +1 -0
  217. package/dist/mcp/claude-mcp-tools.js +1246 -0
  218. package/dist/mcp/claude-mcp-tools.js.map +1 -0
  219. package/dist/mcp/praxis-mcp-server.d.ts +35 -0
  220. package/dist/mcp/praxis-mcp-server.d.ts.map +1 -0
  221. package/dist/mcp/praxis-mcp-server.js +520 -0
  222. package/dist/mcp/praxis-mcp-server.js.map +1 -0
  223. package/dist/permissions/claude-auto-classifier.d.ts +20 -0
  224. package/dist/permissions/claude-auto-classifier.d.ts.map +1 -0
  225. package/dist/permissions/claude-auto-classifier.js +140 -0
  226. package/dist/permissions/claude-auto-classifier.js.map +1 -0
  227. package/dist/permissions/claude-permission-resolver.d.ts +30 -0
  228. package/dist/permissions/claude-permission-resolver.d.ts.map +1 -0
  229. package/dist/permissions/claude-permission-resolver.js +334 -0
  230. package/dist/permissions/claude-permission-resolver.js.map +1 -0
  231. package/dist/persistence/claude-job-store.d.ts +68 -0
  232. package/dist/persistence/claude-job-store.d.ts.map +1 -0
  233. package/dist/persistence/claude-job-store.js +311 -0
  234. package/dist/persistence/claude-job-store.js.map +1 -0
  235. package/dist/persistence/claude-scheduled-task-store.d.ts +29 -0
  236. package/dist/persistence/claude-scheduled-task-store.d.ts.map +1 -0
  237. package/dist/persistence/claude-scheduled-task-store.js +163 -0
  238. package/dist/persistence/claude-scheduled-task-store.js.map +1 -0
  239. package/dist/persistence/claude-sidechain-store.d.ts +18 -0
  240. package/dist/persistence/claude-sidechain-store.d.ts.map +1 -0
  241. package/dist/persistence/claude-sidechain-store.js +107 -0
  242. package/dist/persistence/claude-sidechain-store.js.map +1 -0
  243. package/dist/persistence/claude-task-store.d.ts +72 -0
  244. package/dist/persistence/claude-task-store.d.ts.map +1 -0
  245. package/dist/persistence/claude-task-store.js +440 -0
  246. package/dist/persistence/claude-task-store.js.map +1 -0
  247. package/dist/persistence/claude-transcript-store.d.ts +85 -0
  248. package/dist/persistence/claude-transcript-store.d.ts.map +1 -0
  249. package/dist/persistence/claude-transcript-store.js +385 -0
  250. package/dist/persistence/claude-transcript-store.js.map +1 -0
  251. package/dist/persistence/claude-workflow-store.d.ts +41 -0
  252. package/dist/persistence/claude-workflow-store.d.ts.map +1 -0
  253. package/dist/persistence/claude-workflow-store.js +263 -0
  254. package/dist/persistence/claude-workflow-store.js.map +1 -0
  255. package/dist/persistence/in-memory-sidechain-store.d.ts +12 -0
  256. package/dist/persistence/in-memory-sidechain-store.d.ts.map +1 -0
  257. package/dist/persistence/in-memory-sidechain-store.js +30 -0
  258. package/dist/persistence/in-memory-sidechain-store.js.map +1 -0
  259. package/dist/persistence/in-memory-transcript-store.d.ts +15 -0
  260. package/dist/persistence/in-memory-transcript-store.d.ts.map +1 -0
  261. package/dist/persistence/in-memory-transcript-store.js +95 -0
  262. package/dist/persistence/in-memory-transcript-store.js.map +1 -0
  263. package/dist/platform/atomic-write.d.ts +5 -0
  264. package/dist/platform/atomic-write.d.ts.map +1 -0
  265. package/dist/platform/atomic-write.js +25 -0
  266. package/dist/platform/atomic-write.js.map +1 -0
  267. package/dist/platform/bounded-process-runner.d.ts +28 -0
  268. package/dist/platform/bounded-process-runner.d.ts.map +1 -0
  269. package/dist/platform/bounded-process-runner.js +209 -0
  270. package/dist/platform/bounded-process-runner.js.map +1 -0
  271. package/dist/platform/claude-version.d.ts +5 -0
  272. package/dist/platform/claude-version.d.ts.map +1 -0
  273. package/dist/platform/claude-version.js +17 -0
  274. package/dist/platform/claude-version.js.map +1 -0
  275. package/dist/platform/command-shell.d.ts +3 -0
  276. package/dist/platform/command-shell.d.ts.map +1 -0
  277. package/dist/platform/command-shell.js +15 -0
  278. package/dist/platform/command-shell.js.map +1 -0
  279. package/dist/platform/exclusive-file-lease.d.ts +15 -0
  280. package/dist/platform/exclusive-file-lease.d.ts.map +1 -0
  281. package/dist/platform/exclusive-file-lease.js +265 -0
  282. package/dist/platform/exclusive-file-lease.js.map +1 -0
  283. package/dist/platform/sensitive-data.d.ts +8 -0
  284. package/dist/platform/sensitive-data.d.ts.map +1 -0
  285. package/dist/platform/sensitive-data.js +138 -0
  286. package/dist/platform/sensitive-data.js.map +1 -0
  287. package/dist/platform/tmux-worktree.d.ts +30 -0
  288. package/dist/platform/tmux-worktree.d.ts.map +1 -0
  289. package/dist/platform/tmux-worktree.js +138 -0
  290. package/dist/platform/tmux-worktree.js.map +1 -0
  291. package/dist/plugins/claude-plugin-eval-discovery.d.ts +20 -0
  292. package/dist/plugins/claude-plugin-eval-discovery.d.ts.map +1 -0
  293. package/dist/plugins/claude-plugin-eval-discovery.js +128 -0
  294. package/dist/plugins/claude-plugin-eval-discovery.js.map +1 -0
  295. package/dist/plugins/claude-plugin-eval-graders.d.ts +49 -0
  296. package/dist/plugins/claude-plugin-eval-graders.d.ts.map +1 -0
  297. package/dist/plugins/claude-plugin-eval-graders.js +137 -0
  298. package/dist/plugins/claude-plugin-eval-graders.js.map +1 -0
  299. package/dist/plugins/claude-plugin-eval-runner.d.ts +50 -0
  300. package/dist/plugins/claude-plugin-eval-runner.d.ts.map +1 -0
  301. package/dist/plugins/claude-plugin-eval-runner.js +189 -0
  302. package/dist/plugins/claude-plugin-eval-runner.js.map +1 -0
  303. package/dist/plugins/claude-plugin-eval-schema.d.ts +80 -0
  304. package/dist/plugins/claude-plugin-eval-schema.d.ts.map +1 -0
  305. package/dist/plugins/claude-plugin-eval-schema.js +436 -0
  306. package/dist/plugins/claude-plugin-eval-schema.js.map +1 -0
  307. package/dist/plugins/claude-plugin-eval.d.ts +66 -0
  308. package/dist/plugins/claude-plugin-eval.d.ts.map +1 -0
  309. package/dist/plugins/claude-plugin-eval.js +438 -0
  310. package/dist/plugins/claude-plugin-eval.js.map +1 -0
  311. package/dist/plugins/claude-plugin-maintenance.d.ts +39 -0
  312. package/dist/plugins/claude-plugin-maintenance.d.ts.map +1 -0
  313. package/dist/plugins/claude-plugin-maintenance.js +336 -0
  314. package/dist/plugins/claude-plugin-maintenance.js.map +1 -0
  315. package/dist/plugins/claude-plugin-marketplace.d.ts +97 -0
  316. package/dist/plugins/claude-plugin-marketplace.d.ts.map +1 -0
  317. package/dist/plugins/claude-plugin-marketplace.js +1433 -0
  318. package/dist/plugins/claude-plugin-marketplace.js.map +1 -0
  319. package/dist/plugins/claude-plugin-mcpb.d.ts +71 -0
  320. package/dist/plugins/claude-plugin-mcpb.d.ts.map +1 -0
  321. package/dist/plugins/claude-plugin-mcpb.js +885 -0
  322. package/dist/plugins/claude-plugin-mcpb.js.map +1 -0
  323. package/dist/plugins/claude-plugin-runtime.d.ts +120 -0
  324. package/dist/plugins/claude-plugin-runtime.d.ts.map +1 -0
  325. package/dist/plugins/claude-plugin-runtime.js +1263 -0
  326. package/dist/plugins/claude-plugin-runtime.js.map +1 -0
  327. package/dist/providers/anthropic-compatible.d.ts +35 -0
  328. package/dist/providers/anthropic-compatible.d.ts.map +1 -0
  329. package/dist/providers/anthropic-compatible.js +733 -0
  330. package/dist/providers/anthropic-compatible.js.map +1 -0
  331. package/dist/providers/environment.d.ts +14 -0
  332. package/dist/providers/environment.d.ts.map +1 -0
  333. package/dist/providers/environment.js +67 -0
  334. package/dist/providers/environment.js.map +1 -0
  335. package/dist/providers/fallback-provider.d.ts +17 -0
  336. package/dist/providers/fallback-provider.d.ts.map +1 -0
  337. package/dist/providers/fallback-provider.js +70 -0
  338. package/dist/providers/fallback-provider.js.map +1 -0
  339. package/dist/providers/openai-compatible.d.ts +30 -0
  340. package/dist/providers/openai-compatible.d.ts.map +1 -0
  341. package/dist/providers/openai-compatible.js +409 -0
  342. package/dist/providers/openai-compatible.js.map +1 -0
  343. package/dist/tools/claude-interactive-tools.d.ts +58 -0
  344. package/dist/tools/claude-interactive-tools.d.ts.map +1 -0
  345. package/dist/tools/claude-interactive-tools.js +390 -0
  346. package/dist/tools/claude-interactive-tools.js.map +1 -0
  347. package/dist/tools/claude-lsp-formatters.d.ts +2 -0
  348. package/dist/tools/claude-lsp-formatters.d.ts.map +1 -0
  349. package/dist/tools/claude-lsp-formatters.js +291 -0
  350. package/dist/tools/claude-lsp-formatters.js.map +1 -0
  351. package/dist/tools/claude-lsp-tool.d.ts +22 -0
  352. package/dist/tools/claude-lsp-tool.d.ts.map +1 -0
  353. package/dist/tools/claude-lsp-tool.js +744 -0
  354. package/dist/tools/claude-lsp-tool.js.map +1 -0
  355. package/dist/tools/claude-scheduled-tools.d.ts +20 -0
  356. package/dist/tools/claude-scheduled-tools.d.ts.map +1 -0
  357. package/dist/tools/claude-scheduled-tools.js +344 -0
  358. package/dist/tools/claude-scheduled-tools.js.map +1 -0
  359. package/dist/tools/claude-task-tools.d.ts +30 -0
  360. package/dist/tools/claude-task-tools.d.ts.map +1 -0
  361. package/dist/tools/claude-task-tools.js +503 -0
  362. package/dist/tools/claude-task-tools.js.map +1 -0
  363. package/dist/tools/claude-user-message.d.ts +16 -0
  364. package/dist/tools/claude-user-message.d.ts.map +1 -0
  365. package/dist/tools/claude-user-message.js +98 -0
  366. package/dist/tools/claude-user-message.js.map +1 -0
  367. package/dist/tools/claude-workflow-tools.d.ts +27 -0
  368. package/dist/tools/claude-workflow-tools.d.ts.map +1 -0
  369. package/dist/tools/claude-workflow-tools.js +257 -0
  370. package/dist/tools/claude-workflow-tools.js.map +1 -0
  371. package/dist/tools/claude-worktree-tools.d.ts +17 -0
  372. package/dist/tools/claude-worktree-tools.d.ts.map +1 -0
  373. package/dist/tools/claude-worktree-tools.js +135 -0
  374. package/dist/tools/claude-worktree-tools.js.map +1 -0
  375. package/dist/tools/filtered-tool-registry.d.ts +16 -0
  376. package/dist/tools/filtered-tool-registry.d.ts.map +1 -0
  377. package/dist/tools/filtered-tool-registry.js +51 -0
  378. package/dist/tools/filtered-tool-registry.js.map +1 -0
  379. package/dist/tools/glob.d.ts +9 -0
  380. package/dist/tools/glob.d.ts.map +1 -0
  381. package/dist/tools/glob.js +88 -0
  382. package/dist/tools/glob.js.map +1 -0
  383. package/dist/tools/local-tools.d.ts +47 -0
  384. package/dist/tools/local-tools.d.ts.map +1 -0
  385. package/dist/tools/local-tools.js +1082 -0
  386. package/dist/tools/local-tools.js.map +1 -0
  387. package/dist/tools/notebook.d.ts +22 -0
  388. package/dist/tools/notebook.d.ts.map +1 -0
  389. package/dist/tools/notebook.js +154 -0
  390. package/dist/tools/notebook.js.map +1 -0
  391. package/dist/tools/web.d.ts +48 -0
  392. package/dist/tools/web.d.ts.map +1 -0
  393. package/dist/tools/web.js +726 -0
  394. package/dist/tools/web.js.map +1 -0
  395. package/package.json +145 -0
@@ -0,0 +1,1690 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { lstat, readdir, stat } from 'node:fs/promises';
3
+ import { basename, extname, isAbsolute, join, relative } from 'node:path';
4
+ import { createClaudeCompactEntries, formatClaudeCompactSummary, getCumulativeDroppedTokens, } from '../compatibility/claude/compaction.js';
5
+ import { isClaudeSessionId, resolveClaudePaths, resolveClaudeScheduledTaskFile, } from '../compatibility/claude/paths.js';
6
+ import { downloadClaudeFileResources, } from '../compatibility/claude/file-resources.js';
7
+ import { createClaudeNativeFork } from '../compatibility/claude/fork.js';
8
+ import { selectClaudeTranscriptAtMessage } from '../compatibility/claude/history.js';
9
+ import { ClaudeFileHistory } from '../compatibility/claude/file-history.js';
10
+ import { getClaudePrLink } from '../compatibility/claude/pr-links.js';
11
+ import { getClaudeAgentSetting, getClaudeLastPrompt, projectClaudeModelMessages, } from '../compatibility/claude/projection.js';
12
+ import { selectClaudeSchemaAdapter, } from '../compatibility/claude/schema.js';
13
+ import { findUnresolvedClaudeToolCalls } from '../compatibility/claude/tool-links.js';
14
+ import { createClaudeAgentSettingEntry, createClaudeHookAttachmentEntries, createClaudeLastPromptEntry, createClaudeRuleAttachmentEntry, translateProviderEvents, } from '../compatibility/claude/translation.js';
15
+ import { AgentRunCancelledError, AgentRuntime, } from '../core/runtime.js';
16
+ import { usageCostUsd } from '../core/usage.js';
17
+ import { ContextBudget } from '../core/context-budget.js';
18
+ import { injectFirstUserMessageContext, } from '../core/context.js';
19
+ import { ClaudeHookToolCoordinator } from '../hooks/claude-hook-tools.js';
20
+ import { ClaudeTranscriptStore, } from '../persistence/claude-transcript-store.js';
21
+ import { InMemoryTranscriptStore } from '../persistence/in-memory-transcript-store.js';
22
+ import { ModelCompactor } from './model-compactor.js';
23
+ import { ClaudeSubagentExecutor, StructuredOutputRegistry, } from './subagent-service.js';
24
+ import { ScheduledPromptManager } from './scheduled-prompt-manager.js';
25
+ import { ClaudeScheduledToolRegistry } from '../tools/claude-scheduled-tools.js';
26
+ import { ClaudeTaskToolRegistry } from '../tools/claude-task-tools.js';
27
+ import { ClaudeWorkflowToolRegistry } from '../tools/claude-workflow-tools.js';
28
+ import { WorkflowManager } from './workflow-manager.js';
29
+ import { SessionWorktreeManager } from './session-worktree.js';
30
+ import { ClaudeWorktreeToolRegistry } from '../tools/claude-worktree-tools.js';
31
+ import { generateToolUseSummary } from './tool-use-summary.js';
32
+ import { ClaudeUserMessageToolRegistry, CLAUDE_USER_MESSAGE_PROMPT, } from '../tools/claude-user-message.js';
33
+ const emptyToolRegistry = {
34
+ definitions: () => [],
35
+ prepare: async (call) => call,
36
+ execute: async () => ({ content: '', isError: false }),
37
+ };
38
+ function mergeUsage(left, right) {
39
+ const cacheReadInputTokens = (left.cacheReadInputTokens ?? 0) + (right.cacheReadInputTokens ?? 0);
40
+ const cacheCreationInputTokens = (left.cacheCreationInputTokens ?? 0) + (right.cacheCreationInputTokens ?? 0);
41
+ return {
42
+ inputTokens: left.inputTokens + right.inputTokens,
43
+ outputTokens: left.outputTokens + right.outputTokens,
44
+ ...(cacheReadInputTokens === 0 ? {} : { cacheReadInputTokens }),
45
+ ...(cacheCreationInputTokens === 0 ? {} : { cacheCreationInputTokens }),
46
+ };
47
+ }
48
+ export function workflowTokenTarget(prompt) {
49
+ const match = /(?:^|\s)\+(\d+(?:\.\d+)?)([km])\b/iu.exec(prompt);
50
+ if (!match)
51
+ return null;
52
+ const value = Number(match[1]);
53
+ if (!Number.isFinite(value) || value <= 0)
54
+ return null;
55
+ return Math.floor(value * (match[2]?.toLowerCase() === 'm' ? 1_000_000 : 1_000));
56
+ }
57
+ const PROMPT_SUGGESTION_INSTRUCTION = `[SUGGESTION MODE: Suggest what the user might naturally type next into Claude Code.]
58
+
59
+ FIRST: Look at the user's recent messages and original request.
60
+
61
+ Your job is to predict what THEY would type - not what you think they should do.
62
+
63
+ Reply with ONLY the suggestion, no quotes or explanation.
64
+ Use 2-12 words. Do not ask a question, evaluate the prior response, introduce a new idea, or use a Claude voice. If the topic is unsafe or sensitive, reply with an empty string.`;
65
+ function validPromptSuggestion(value) {
66
+ const suggestion = value.trim();
67
+ if (!suggestion)
68
+ return null;
69
+ const words = suggestion.split(/\s+/u);
70
+ if (words.length < 2 || words.length > 12)
71
+ return null;
72
+ if (/[??\n\r]/u.test(suggestion) || /[.!。!]/u.test(suggestion))
73
+ return null;
74
+ return suggestion;
75
+ }
76
+ export class ClaudeSessionService {
77
+ options;
78
+ schema;
79
+ inMemoryStores = new Map();
80
+ scheduledPrompts;
81
+ workflowManager;
82
+ worktreeManager;
83
+ sessionCwds = new Map();
84
+ hostedSubagents = new Set();
85
+ downloadedFileResourceSessions = new Set();
86
+ constructor(options) {
87
+ this.options = options;
88
+ this.schema = selectClaudeSchemaAdapter(options.claudeVersion);
89
+ this.scheduledPrompts =
90
+ options.tools && (options.scheduledToolNames?.length ?? 0) > 0
91
+ ? new ScheduledPromptManager({
92
+ filePath: resolveClaudeScheduledTaskFile(options.cwd),
93
+ lockFile: join(options.configRoot, 'praxis', 'locks', 'scheduled-tasks.lock'),
94
+ ...(options.enableDynamicWakeups === undefined
95
+ ? {}
96
+ : { dynamicWakeupsEnabled: options.enableDynamicWakeups }),
97
+ })
98
+ : null;
99
+ this.workflowManager = options.enableWorkflows
100
+ ? new WorkflowManager(options.configRoot, options.cwd, () => this.activeCwd())
101
+ : null;
102
+ this.worktreeManager =
103
+ options.enableWorktrees && options.workspace
104
+ ? new SessionWorktreeManager({
105
+ workspace: options.workspace,
106
+ sessionId: '',
107
+ })
108
+ : null;
109
+ }
110
+ nextScheduledPrompt(signal) {
111
+ return this.scheduledPrompts?.next(signal) ?? Promise.resolve(null);
112
+ }
113
+ workflows() {
114
+ return this.workflowManager?.list() ?? [];
115
+ }
116
+ async close() {
117
+ this.scheduledPrompts?.close();
118
+ await Promise.all([...this.hostedSubagents].map((executor) => executor.close()));
119
+ this.hostedSubagents.clear();
120
+ await this.workflowManager?.close();
121
+ }
122
+ createHostedToolRegistry(sessionId) {
123
+ const baseTools = this.options.tools;
124
+ if (!baseTools)
125
+ throw new Error('Hosted tool registry requires base tools');
126
+ const paths = this.paths(sessionId);
127
+ const taskTools = (this.options.taskToolNames?.length ?? 0) > 0
128
+ ? new ClaudeTaskToolRegistry({
129
+ base: baseTools,
130
+ cwd: this.activeCwd(),
131
+ cwdProvider: () => this.activeCwd(),
132
+ praxisRoot: paths.praxisRoot,
133
+ sessionId,
134
+ taskRoot: paths.taskRoot,
135
+ ...(this.options.eventSink
136
+ ? { eventSink: this.options.eventSink }
137
+ : {}),
138
+ ...(this.options.taskToolNames
139
+ ? { enabledTools: this.options.taskToolNames }
140
+ : {}),
141
+ })
142
+ : null;
143
+ const scheduledTools = this.scheduledPrompts &&
144
+ (this.options.scheduledToolNames?.length ?? 0) > 0
145
+ ? new ClaudeScheduledToolRegistry({
146
+ base: taskTools ?? baseTools,
147
+ manager: this.scheduledPrompts,
148
+ sessionId,
149
+ ...(this.options.scheduledToolNames
150
+ ? { enabledTools: this.options.scheduledToolNames }
151
+ : {}),
152
+ })
153
+ : null;
154
+ const wrappedBase = scheduledTools ?? taskTools ?? baseTools;
155
+ const subagentExecutor = (this.options.enableSubagents || this.options.enableWorkflows) &&
156
+ this.options.permissions
157
+ ? new ClaudeSubagentExecutor({
158
+ configRoot: this.options.configRoot,
159
+ cwd: this.activeCwd(),
160
+ cwdProvider: () => this.activeCwd(),
161
+ claudeVersion: this.options.claudeVersion,
162
+ provider: this.options.provider ??
163
+ (() => {
164
+ throw new Error('A model provider is required to execute hosted Agent tools');
165
+ })(),
166
+ persistence: this.options.sessionPersistence === false ? 'memory' : 'disk',
167
+ ...(this.options.providerForModel
168
+ ? { providerForModel: this.options.providerForModel }
169
+ : {}),
170
+ baseTools: wrappedBase,
171
+ permissions: this.options.permissions,
172
+ ...(this.options.permissionResolverForMode
173
+ ? {
174
+ permissionResolverForMode: this.options.permissionResolverForMode,
175
+ }
176
+ : {}),
177
+ ...(this.options.subagentToolNames
178
+ ? { toolNames: this.options.subagentToolNames }
179
+ : {}),
180
+ ...(this.options.extensions
181
+ ? { extensions: this.options.extensions }
182
+ : {}),
183
+ ...(this.options.hooks ? { hooks: this.options.hooks } : {}),
184
+ ...(this.options.contextAssembler
185
+ ? { contextAssembler: this.options.contextAssembler }
186
+ : {}),
187
+ ...((this.options.contextBudget?.reserveTokens ??
188
+ this.options.contextReserveTokens) === undefined
189
+ ? {}
190
+ : {
191
+ contextReserveTokens: this.options.contextBudget?.reserveTokens ??
192
+ this.options.contextReserveTokens,
193
+ }),
194
+ ...(this.options.approveTool
195
+ ? { approveTool: this.options.approveTool }
196
+ : {}),
197
+ ...(this.options.eventSink
198
+ ? { eventSink: this.options.eventSink }
199
+ : {}),
200
+ ...(taskTools
201
+ ? {
202
+ backgroundTaskNotifications: (waitForRunning) => taskTools.notifications(waitForRunning),
203
+ }
204
+ : {}),
205
+ })
206
+ : null;
207
+ if (subagentExecutor)
208
+ this.hostedSubagents.add(subagentExecutor);
209
+ const agentTools = subagentExecutor
210
+ ? subagentExecutor.registry(sessionId, 0, (callId) => callId)
211
+ : wrappedBase;
212
+ const workflowTools = this.workflowManager && subagentExecutor
213
+ ? new ClaudeWorkflowToolRegistry({
214
+ base: agentTools,
215
+ manager: this.workflowManager,
216
+ executor: subagentExecutor,
217
+ cwd: this.activeCwd(),
218
+ cwdProvider: () => this.activeCwd(),
219
+ configRoot: this.options.configRoot,
220
+ sessionId,
221
+ promptIdForCall: (callId) => callId,
222
+ defaultModel: this.options.provider?.model ?? 'praxis/provider',
223
+ tokenBudget: null,
224
+ enabled: true,
225
+ })
226
+ : agentTools;
227
+ if (this.worktreeManager)
228
+ this.worktreeManager.bindSession(sessionId);
229
+ const registry = this.worktreeManager && this.options.workspace
230
+ ? new ClaudeWorktreeToolRegistry({
231
+ base: workflowTools,
232
+ manager: this.worktreeManager,
233
+ workspace: this.options.workspace,
234
+ ...(this.options.worktreeToolNames
235
+ ? { enabledTools: this.options.worktreeToolNames }
236
+ : {}),
237
+ })
238
+ : workflowTools;
239
+ const messageRegistry = this.options.brief
240
+ ? new ClaudeUserMessageToolRegistry(registry, (message) => this.options.eventSink?.({
241
+ type: 'user-message',
242
+ message: message.message,
243
+ status: message.status,
244
+ ...(message.attachments.length
245
+ ? { attachments: message.attachments }
246
+ : {}),
247
+ }))
248
+ : registry;
249
+ const interactiveRegistry = this.options.interactiveTools
250
+ ? this.options.interactiveTools.registry(messageRegistry, sessionId)
251
+ : messageRegistry;
252
+ const preferredOrder = [
253
+ 'Agent',
254
+ 'AskUserQuestion',
255
+ 'TaskOutput',
256
+ 'Bash',
257
+ 'EnterPlanMode',
258
+ 'Read',
259
+ 'LSP',
260
+ 'Edit',
261
+ 'Write',
262
+ 'NotebookEdit',
263
+ 'WebFetch',
264
+ 'ReportFindings',
265
+ 'WebSearch',
266
+ 'TaskStop',
267
+ 'Skill',
268
+ 'DesignSync',
269
+ 'TaskCreate',
270
+ 'TaskGet',
271
+ 'TaskUpdate',
272
+ 'ExitPlanMode',
273
+ 'EnterWorktree',
274
+ 'ExitWorktree',
275
+ 'SendMessage',
276
+ 'SendUserMessage',
277
+ 'Workflow',
278
+ 'CronCreate',
279
+ 'CronDelete',
280
+ 'CronList',
281
+ 'ScheduleWakeup',
282
+ 'Monitor',
283
+ 'PushNotification',
284
+ ];
285
+ return {
286
+ definitions: () => {
287
+ const definitions = interactiveRegistry.definitions();
288
+ return [...definitions].sort((left, right) => {
289
+ const leftIndex = preferredOrder.indexOf(left.name);
290
+ const rightIndex = preferredOrder.indexOf(right.name);
291
+ return ((leftIndex < 0 ? preferredOrder.length : leftIndex) -
292
+ (rightIndex < 0 ? preferredOrder.length : rightIndex));
293
+ });
294
+ },
295
+ prepare: (call, context) => interactiveRegistry.prepare(call, context),
296
+ execute: (call, context) => interactiveRegistry.execute(call, context),
297
+ };
298
+ }
299
+ async run(prompt, signal, sessionId = randomUUID(), name, images, documents) {
300
+ this.worktreeManager?.bindSession(sessionId);
301
+ return this.executeTurn(sessionId, prompt, false, signal, name, images, documents);
302
+ }
303
+ async resume(sessionId, prompt, signal, name, images, documents, resumeSessionAt) {
304
+ this.worktreeManager?.bindSession(sessionId);
305
+ return this.executeTurn(sessionId, prompt, true, signal, name, images, documents, resumeSessionAt);
306
+ }
307
+ async promptSuggestion(sessionId, signal) {
308
+ const provider = this.provider();
309
+ const loaded = this.options.sessionPersistence === false
310
+ ? await this.turnStore(sessionId).withLease((lease) => lease.load())
311
+ : {
312
+ status: 'completed',
313
+ value: await this.store(sessionId).loadReadOnly(),
314
+ };
315
+ if (loaded.status === 'conflict')
316
+ return null;
317
+ const entries = loaded.value;
318
+ this.restoreWorktree(entries.entries);
319
+ const agentName = this.options.agent ?? getClaudeAgentSetting(entries.entries);
320
+ const agent = agentName ? this.options.extensions?.agent(agentName) : null;
321
+ const assembledContext = await this.options.contextAssembler?.assemble({
322
+ cwd: this.activeCwd(),
323
+ });
324
+ const contextMessages = [
325
+ ...(assembledContext?.systemMessages ?? []),
326
+ ...(agent
327
+ ? [
328
+ {
329
+ role: 'system',
330
+ content: `# Agent definition: ${agent.name}\n\n${agent.body}`,
331
+ },
332
+ ]
333
+ : []),
334
+ ];
335
+ const messages = [
336
+ ...contextMessages,
337
+ ...injectFirstUserMessageContext([
338
+ ...projectClaudeModelMessages(entries.entries),
339
+ { role: 'user', content: PROMPT_SUGGESTION_INSTRUCTION },
340
+ ], assembledContext?.firstUserMessageContext),
341
+ ];
342
+ let suggestion = '';
343
+ for await (const event of provider.complete({
344
+ messages,
345
+ ...(provider.capabilities.tools
346
+ ? { tools: this.options.tools?.definitions() ?? [] }
347
+ : {}),
348
+ ...(this.options.effort ? { effort: this.options.effort } : {}),
349
+ ...(signal ? { signal } : {}),
350
+ })) {
351
+ if (event.type === 'text-delta')
352
+ suggestion += event.delta;
353
+ if (event.type === 'tool-call')
354
+ return null;
355
+ }
356
+ return validPromptSuggestion(suggestion);
357
+ }
358
+ async sessions() {
359
+ const paths = this.paths(randomUUID());
360
+ let names;
361
+ try {
362
+ names = await readdir(paths.projectRoot);
363
+ }
364
+ catch (error) {
365
+ if (error.code === 'ENOENT')
366
+ return [];
367
+ throw error;
368
+ }
369
+ const summaries = await Promise.all(names
370
+ .filter((name) => extname(name) === '.jsonl')
371
+ .map(async (name) => {
372
+ const sessionId = basename(name, '.jsonl');
373
+ if (!isClaudeSessionId(sessionId))
374
+ return null;
375
+ const sessionFile = join(paths.projectRoot, name);
376
+ try {
377
+ const metadata = await lstat(sessionFile);
378
+ if (!metadata.isFile())
379
+ return null;
380
+ const recovery = await this.store(sessionId).loadReadOnly();
381
+ if (!(await lstat(sessionFile)).isFile())
382
+ return null;
383
+ const name = this.sessionName(recovery.entries);
384
+ const prLink = getClaudePrLink(recovery.entries, sessionId);
385
+ return {
386
+ sessionId,
387
+ ...(name === null ? {} : { name }),
388
+ lastPrompt: getClaudeLastPrompt(recovery.entries),
389
+ updatedAt: metadata.mtime.toISOString(),
390
+ status: this.sessionStatus(recovery.issue, recovery.entries.length),
391
+ issue: recovery.issue,
392
+ ...(prLink
393
+ ? {
394
+ prNumber: prLink.prNumber,
395
+ prUrl: prLink.prUrl,
396
+ prRepository: prLink.prRepository,
397
+ }
398
+ : {}),
399
+ };
400
+ }
401
+ catch (error) {
402
+ if (typeof error.code === 'string') {
403
+ return null;
404
+ }
405
+ throw error;
406
+ }
407
+ }));
408
+ return summaries
409
+ .filter((summary) => summary !== null)
410
+ .sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
411
+ }
412
+ async inspect(sessionId) {
413
+ this.assertSessionPersistence();
414
+ const paths = this.paths(sessionId);
415
+ let metadata;
416
+ try {
417
+ metadata = await stat(paths.sessionFile);
418
+ }
419
+ catch (error) {
420
+ if (error.code === 'ENOENT') {
421
+ throw new Error(`Claude session not found: ${sessionId}`);
422
+ }
423
+ throw error;
424
+ }
425
+ const recovery = await this.store(sessionId).loadReadOnly();
426
+ const prLink = getClaudePrLink(recovery.entries, sessionId);
427
+ return {
428
+ sessionId,
429
+ lastPrompt: getClaudeLastPrompt(recovery.entries),
430
+ updatedAt: metadata.mtime.toISOString(),
431
+ status: this.sessionStatus(recovery.issue, recovery.entries.length),
432
+ issue: recovery.issue,
433
+ claudeVersion: this.options.claudeVersion,
434
+ writeMode: this.schema.writeMode,
435
+ entryCount: recovery.entries.length,
436
+ byteLength: recovery.tail.byteLength,
437
+ newlineTerminated: recovery.tail.newlineTerminated,
438
+ ...(prLink
439
+ ? {
440
+ prNumber: prLink.prNumber,
441
+ prUrl: prLink.prUrl,
442
+ prRepository: prLink.prRepository,
443
+ }
444
+ : {}),
445
+ };
446
+ }
447
+ async export(sessionId) {
448
+ this.assertSessionPersistence();
449
+ try {
450
+ return await this.store(sessionId).exportReadOnly();
451
+ }
452
+ catch (error) {
453
+ if (error.code === 'ENOENT') {
454
+ throw new Error(`Claude session not found: ${sessionId}`);
455
+ }
456
+ throw error;
457
+ }
458
+ }
459
+ async fork(parentSessionId, sessionId = randomUUID(), resumeSessionAt) {
460
+ this.assertSessionPersistence();
461
+ this.assertWritable();
462
+ const sourceResult = await this.store(parentSessionId).withLease((lease) => lease.load());
463
+ if (sourceResult.status === 'conflict') {
464
+ throw new Error(`Claude transcript fork conflict: ${sourceResult.reason}`);
465
+ }
466
+ const source = sourceResult.value;
467
+ if (source.entries.length === 0) {
468
+ throw new Error(`Claude session not found: ${parentSessionId}`);
469
+ }
470
+ const target = this.store(sessionId);
471
+ const result = await target.create(createClaudeNativeFork({
472
+ source: source.entries,
473
+ sourceSessionId: parentSessionId,
474
+ sessionId,
475
+ ...(resumeSessionAt === undefined ? {} : { resumeSessionAt }),
476
+ }));
477
+ if (result.status === 'conflict') {
478
+ throw new Error('Generated Claude fork session already exists');
479
+ }
480
+ return { sessionId, parentSessionId };
481
+ }
482
+ async rewindFiles(sessionId, userMessageId) {
483
+ const result = await this.store(sessionId).withLease(async (lease) => {
484
+ const snapshot = await lease.load();
485
+ if (snapshot.entries.length === 0) {
486
+ throw new Error(`Claude session not found: ${sessionId}`);
487
+ }
488
+ this.restoreWorktree(snapshot.entries);
489
+ this.options.interactiveTools?.restore(sessionId, snapshot.entries);
490
+ await new ClaudeFileHistory(this.options.configRoot, sessionId, [
491
+ this.activeCwd(),
492
+ ...(this.options.fileRewindRoots ?? []),
493
+ ]).rewind(snapshot.entries, userMessageId);
494
+ });
495
+ if (result.status === 'conflict') {
496
+ throw new Error(`Claude file rewind conflict: ${result.reason}`);
497
+ }
498
+ }
499
+ async executeTurn(sessionId, prompt, requireExisting, signal, name, images = [], documents = [], resumeSessionAt) {
500
+ this.assertWritable();
501
+ if (prompt.length === 0 && images.length === 0 && documents.length === 0)
502
+ throw new Error('Prompt must not be empty');
503
+ if (name !== undefined && name.length === 0) {
504
+ throw new Error('Session name must not be empty');
505
+ }
506
+ await this.ensureFileResources(sessionId, signal);
507
+ this.worktreeManager?.bindSession(sessionId);
508
+ if (this.options.initialWorktree) {
509
+ await this.worktreeManager?.ensureInitial(this.options.initialWorktreeName);
510
+ }
511
+ const pinnedCwd = this.sessionCwds.get(sessionId) ?? this.activeCwd();
512
+ this.sessionCwds.set(sessionId, pinnedCwd);
513
+ const sessionPaths = this.paths(sessionId);
514
+ const toolResultDirectory = join(sessionPaths.projectRoot, sessionId, 'tool-results');
515
+ const store = this.turnStore(sessionId);
516
+ const leaseResult = await store.withLease(async (lease) => {
517
+ if (!requireExisting) {
518
+ const initialization = name === undefined
519
+ ? await store.reserve()
520
+ : await store.create(this.sessionNameEntries(sessionId, name));
521
+ if (initialization.status === 'conflict') {
522
+ throw new Error(`Session ID ${sessionId} is already in use`);
523
+ }
524
+ }
525
+ let snapshot = await lease.load();
526
+ if (requireExisting &&
527
+ this.options.sessionPersistence === false &&
528
+ snapshot.entries.length === 0) {
529
+ const persisted = await this.store(sessionId).load();
530
+ if (persisted.entries.length > 0) {
531
+ const imported = await store.create(persisted.entries);
532
+ if (imported.status === 'created')
533
+ snapshot = await lease.load();
534
+ }
535
+ }
536
+ if (requireExisting && snapshot.entries.length === 0) {
537
+ throw new Error(`Claude session not found: ${sessionId}`);
538
+ }
539
+ if (resumeSessionAt !== undefined) {
540
+ snapshot = {
541
+ entries: selectClaudeTranscriptAtMessage(snapshot.entries, resumeSessionAt),
542
+ tail: { ...snapshot.tail, branchParentUuid: resumeSessionAt },
543
+ };
544
+ }
545
+ const initialTransition = this.worktreeManager?.consumeTransition('__initial__');
546
+ if (initialTransition && snapshot.entries.length === 0) {
547
+ const stateEntry = {
548
+ type: 'worktree-state',
549
+ worktreeSession: initialTransition.state,
550
+ sessionId,
551
+ };
552
+ const stateTail = await this.append(lease, snapshot.tail, stateEntry);
553
+ snapshot = {
554
+ entries: [...snapshot.entries, stateEntry],
555
+ tail: stateTail,
556
+ };
557
+ }
558
+ this.restoreWorktree(snapshot.entries);
559
+ this.options.interactiveTools?.restore(sessionId, snapshot.entries);
560
+ if (requireExisting &&
561
+ name !== undefined &&
562
+ !this.hasSessionName(snapshot.entries, name)) {
563
+ const entries = this.sessionNameEntries(sessionId, name);
564
+ const appendResult = await lease.appendMany(snapshot.tail, entries);
565
+ if (appendResult.status === 'conflict') {
566
+ throw new Error(`Claude transcript append conflict: ${appendResult.reason}`);
567
+ }
568
+ snapshot = {
569
+ entries: [...snapshot.entries, ...entries],
570
+ tail: appendResult.tail,
571
+ };
572
+ }
573
+ const provider = this.provider();
574
+ const initialPricing = this.options.pricing?.resolve(provider.model ?? 'praxis/provider');
575
+ if (this.options.maxBudgetUsd !== undefined && !initialPricing) {
576
+ throw new Error(`Cannot enforce --max-budget-usd: no pricing is configured for model ${provider.model ?? 'praxis/provider'}`);
577
+ }
578
+ let currentPromptId = null;
579
+ let lastAssistantUuid = null;
580
+ const fileHistory = this.options.fileCheckpointing &&
581
+ this.options.sessionPersistence !== false
582
+ ? new ClaudeFileHistory(this.options.configRoot, sessionId, [
583
+ this.activeCwd(),
584
+ ...(this.options.fileRewindRoots ?? []),
585
+ ])
586
+ : null;
587
+ const unresolvedToolCalls = findUnresolvedClaudeToolCalls(snapshot.entries);
588
+ const pendingRecoveryToolCallIds = new Set(unresolvedToolCalls.map((call) => call.id));
589
+ const pendingRecoveryHookOutcomes = [];
590
+ const currentHookCwd = () => this.activeCwd();
591
+ const hookSession = {
592
+ session_id: sessionId,
593
+ transcript_path: sessionPaths.sessionFile,
594
+ get cwd() {
595
+ return currentHookCwd();
596
+ },
597
+ permission_mode: 'default',
598
+ };
599
+ const appendHookOutcome = async (outcome) => {
600
+ for (const entry of createClaudeHookAttachmentEntries(outcome, this.translationContext(sessionId, snapshot))) {
601
+ const tail = await this.append(lease, snapshot.tail, entry);
602
+ snapshot = { entries: [...snapshot.entries, entry], tail };
603
+ }
604
+ };
605
+ const recordHookOutcome = async (outcome, deferUntilApproval = false) => {
606
+ if (deferUntilApproval) {
607
+ pendingRecoveryHookOutcomes.push(outcome);
608
+ return;
609
+ }
610
+ await appendHookOutcome(outcome);
611
+ };
612
+ const flushRecoveryHookOutcomes = async () => {
613
+ const entries = [];
614
+ let history = snapshot.entries;
615
+ let parentUuid = this.logicalTailUuid(snapshot.tail);
616
+ for (const outcome of pendingRecoveryHookOutcomes) {
617
+ const outcomeEntries = createClaudeHookAttachmentEntries(outcome, {
618
+ ...this.translationContext(sessionId, snapshot),
619
+ parentUuid,
620
+ history,
621
+ });
622
+ entries.push(...outcomeEntries);
623
+ history = [...history, ...outcomeEntries];
624
+ const lastEntry = outcomeEntries.at(-1);
625
+ if (typeof lastEntry?.uuid === 'string')
626
+ parentUuid = lastEntry.uuid;
627
+ }
628
+ if (entries.length === 0) {
629
+ pendingRecoveryHookOutcomes.length = 0;
630
+ return;
631
+ }
632
+ const appendResult = await lease.appendMany(snapshot.tail, entries);
633
+ if (appendResult.status === 'conflict') {
634
+ throw new Error(`Claude transcript append conflict: ${appendResult.reason}`);
635
+ }
636
+ snapshot = { entries: history, tail: appendResult.tail };
637
+ pendingRecoveryHookOutcomes.length = 0;
638
+ };
639
+ const taskTools = this.options.tools && (this.options.taskToolNames?.length ?? 0) > 0
640
+ ? new ClaudeTaskToolRegistry({
641
+ base: this.options.tools,
642
+ cwd: this.activeCwd(),
643
+ cwdProvider: () => this.activeCwd(),
644
+ praxisRoot: sessionPaths.praxisRoot,
645
+ sessionId,
646
+ taskRoot: sessionPaths.taskRoot,
647
+ ...(this.options.eventSink
648
+ ? { eventSink: this.options.eventSink }
649
+ : {}),
650
+ ...(this.options.taskToolNames
651
+ ? { enabledTools: this.options.taskToolNames }
652
+ : {}),
653
+ })
654
+ : null;
655
+ const scheduledTools = this.scheduledPrompts &&
656
+ this.options.tools &&
657
+ (this.options.scheduledToolNames?.length ?? 0) > 0
658
+ ? new ClaudeScheduledToolRegistry({
659
+ base: taskTools ?? this.options.tools,
660
+ manager: this.scheduledPrompts,
661
+ sessionId,
662
+ ...(this.options.scheduledToolNames
663
+ ? { enabledTools: this.options.scheduledToolNames }
664
+ : {}),
665
+ })
666
+ : null;
667
+ const baseTools = scheduledTools ?? taskTools ?? this.options.tools;
668
+ const turnPermissions = this.options.interactiveTools?.permissions(sessionId) ??
669
+ this.options.permissions;
670
+ const subagentExecutor = (this.options.enableSubagents || this.options.enableWorkflows) &&
671
+ baseTools &&
672
+ turnPermissions
673
+ ? new ClaudeSubagentExecutor({
674
+ configRoot: this.options.configRoot,
675
+ cwd: this.activeCwd(),
676
+ cwdProvider: () => this.activeCwd(),
677
+ claudeVersion: this.options.claudeVersion,
678
+ provider,
679
+ persistence: this.options.sessionPersistence === false ? 'memory' : 'disk',
680
+ ...(this.options.providerForModel
681
+ ? { providerForModel: this.options.providerForModel }
682
+ : {}),
683
+ baseTools,
684
+ permissions: turnPermissions,
685
+ ...(this.options.permissionResolverForMode
686
+ ? {
687
+ permissionResolverForMode: this.options.permissionResolverForMode,
688
+ }
689
+ : {}),
690
+ ...(this.options.subagentToolNames
691
+ ? { toolNames: this.options.subagentToolNames }
692
+ : {}),
693
+ ...(this.options.extensions
694
+ ? { extensions: this.options.extensions }
695
+ : {}),
696
+ ...(this.options.hooks ? { hooks: this.options.hooks } : {}),
697
+ ...(this.options.contextAssembler
698
+ ? { contextAssembler: this.options.contextAssembler }
699
+ : {}),
700
+ ...((this.options.contextBudget?.reserveTokens ??
701
+ this.options.contextReserveTokens) === undefined
702
+ ? {}
703
+ : {
704
+ contextReserveTokens: this.options.contextBudget?.reserveTokens ??
705
+ this.options.contextReserveTokens,
706
+ }),
707
+ ...(this.options.approveTool
708
+ ? { approveTool: this.options.approveTool }
709
+ : {}),
710
+ ...(this.options.eventSink
711
+ ? { eventSink: this.options.eventSink }
712
+ : {}),
713
+ ...(taskTools
714
+ ? {
715
+ backgroundTaskNotifications: (waitForRunning) => taskTools.notifications(waitForRunning),
716
+ }
717
+ : {}),
718
+ })
719
+ : null;
720
+ const agentTools = subagentExecutor
721
+ ? subagentExecutor.registry(sessionId, 0, (callId) => currentPromptId ??
722
+ this.promptIdForToolCall(snapshot.entries, callId))
723
+ : baseTools;
724
+ const turnTools = this.workflowManager && subagentExecutor && agentTools
725
+ ? new ClaudeWorkflowToolRegistry({
726
+ base: agentTools,
727
+ manager: this.workflowManager,
728
+ executor: subagentExecutor,
729
+ cwd: this.activeCwd(),
730
+ cwdProvider: () => this.activeCwd(),
731
+ configRoot: this.options.configRoot,
732
+ sessionId,
733
+ promptIdForCall: (callId) => currentPromptId ??
734
+ this.promptIdForToolCall(snapshot.entries, callId),
735
+ defaultModel: provider.model ?? 'praxis/provider',
736
+ tokenBudget: workflowTokenTarget(prompt),
737
+ enabled: true,
738
+ })
739
+ : agentTools;
740
+ const workspaceTools = this.worktreeManager &&
741
+ turnTools &&
742
+ this.options.workspace &&
743
+ (this.options.worktreeToolNames?.length ?? 0) > 0
744
+ ? new ClaudeWorktreeToolRegistry({
745
+ base: turnTools,
746
+ manager: this.worktreeManager,
747
+ workspace: this.options.workspace,
748
+ enabledTools: this.options.worktreeToolNames ?? [],
749
+ })
750
+ : turnTools;
751
+ const messageTools = this.options.brief && workspaceTools
752
+ ? new ClaudeUserMessageToolRegistry(workspaceTools, (message) => this.options.eventSink?.({
753
+ type: 'user-message',
754
+ message: message.message,
755
+ status: message.status,
756
+ ...(message.attachments.length
757
+ ? { attachments: message.attachments }
758
+ : {}),
759
+ }))
760
+ : workspaceTools;
761
+ const interactiveMessageTools = this.options.interactiveTools && messageTools
762
+ ? this.options.interactiveTools.registry(messageTools, sessionId)
763
+ : messageTools;
764
+ const fileHistoryTools = fileHistory && interactiveMessageTools
765
+ ? {
766
+ definitions: () => interactiveMessageTools.definitions(),
767
+ prepare: (call, context) => interactiveMessageTools.prepare(call, context),
768
+ execute: async (call, context) => {
769
+ const path = call.name === 'Write' || call.name === 'Edit'
770
+ ? call.input.file_path
771
+ : call.name === 'NotebookEdit'
772
+ ? call.input.notebook_path
773
+ : undefined;
774
+ if (typeof path !== 'string') {
775
+ return interactiveMessageTools.execute(call, context);
776
+ }
777
+ const snapshotMessageId = currentPromptId ??
778
+ this.promptIdForToolCall(snapshot.entries, call.id);
779
+ const assistantMessageId = lastAssistantUuid ??
780
+ this.assistantIdForToolCall(snapshot.entries, call.id);
781
+ if (!snapshotMessageId || !assistantMessageId) {
782
+ throw new Error('Claude file history could not link tool call');
783
+ }
784
+ const prepared = await fileHistory.prepareMutation(snapshot.entries, snapshotMessageId, path);
785
+ let result;
786
+ try {
787
+ result = await interactiveMessageTools.execute(call, context);
788
+ }
789
+ catch (error) {
790
+ await prepared.rollback();
791
+ throw error;
792
+ }
793
+ if (result.isError) {
794
+ await prepared.rollback();
795
+ return result;
796
+ }
797
+ const entry = prepared.commit(assistantMessageId);
798
+ if (entry) {
799
+ const tail = await this.append(lease, snapshot.tail, entry);
800
+ snapshot = { entries: [...snapshot.entries, entry], tail };
801
+ }
802
+ return result;
803
+ },
804
+ }
805
+ : interactiveMessageTools;
806
+ const structuredCapture = this.options.structuredOutputSchema
807
+ ? { calls: 0, value: undefined }
808
+ : undefined;
809
+ const structuredTools = this.options.structuredOutputSchema && structuredCapture
810
+ ? new StructuredOutputRegistry(fileHistoryTools ?? this.options.tools ?? emptyToolRegistry, this.options.structuredOutputSchema, structuredCapture)
811
+ : fileHistoryTools;
812
+ const hookTools = this.options.hooks && structuredTools && turnPermissions
813
+ ? new ClaudeHookToolCoordinator({
814
+ tools: structuredTools,
815
+ permissions: turnPermissions,
816
+ hooks: this.options.hooks,
817
+ session: hookSession,
818
+ recordOutcome: recordHookOutcome,
819
+ deferPreToolUseOutcome: (call) => pendingRecoveryToolCallIds.has(call.id),
820
+ })
821
+ : null;
822
+ const runtime = new AgentRuntime(provider, this.options.eventSink, {
823
+ emitInitialContextState: false,
824
+ ...(this.options.emitToolUseSummaries
825
+ ? {
826
+ generateToolUseSummary: ({ tools, lastAssistantText, signal }) => generateToolUseSummary(provider, tools, signal, lastAssistantText),
827
+ }
828
+ : {}),
829
+ ...(this.options.pricing
830
+ ? {
831
+ costUsd: (usage) => {
832
+ const pricing = this.options.pricing?.resolve(provider.model ?? 'praxis/provider');
833
+ return pricing ? usageCostUsd(usage, pricing) : undefined;
834
+ },
835
+ }
836
+ : {}),
837
+ ...(this.options.maxBudgetUsd === undefined
838
+ ? {}
839
+ : { maxBudgetUsd: this.options.maxBudgetUsd }),
840
+ ...(hookTools
841
+ ? { tools: hookTools, permissions: hookTools }
842
+ : {
843
+ ...(structuredTools ? { tools: structuredTools } : {}),
844
+ ...(turnPermissions ? { permissions: turnPermissions } : {}),
845
+ }),
846
+ });
847
+ let currentTurnUserMessages = null;
848
+ const observer = {
849
+ assistantCompleted: async (message) => {
850
+ const [entry] = translateProviderEvents([
851
+ {
852
+ type: 'assistant-message',
853
+ text: message.content,
854
+ ...(message.thinkingBlocks
855
+ ? { thinkingBlocks: message.thinkingBlocks }
856
+ : {}),
857
+ toolCalls: message.toolCalls ?? [],
858
+ providerMessageId: `msg_${randomUUID().replaceAll('-', '')}`,
859
+ model: provider.model ?? 'praxis/provider',
860
+ },
861
+ ], this.translationContext(sessionId, snapshot));
862
+ if (!entry)
863
+ throw new Error('Could not translate assistant response');
864
+ const tail = await this.append(lease, snapshot.tail, entry);
865
+ snapshot = { entries: [...snapshot.entries, entry], tail };
866
+ lastAssistantUuid =
867
+ typeof entry.uuid === 'string' ? entry.uuid : lastAssistantUuid;
868
+ },
869
+ toolCompleted: async (call, toolResult) => {
870
+ const transition = this.worktreeManager?.consumeTransition(call.id);
871
+ if (transition) {
872
+ const stateEntry = {
873
+ type: 'worktree-state',
874
+ worktreeSession: transition.state,
875
+ sessionId,
876
+ };
877
+ const stateTail = await this.append(lease, snapshot.tail, stateEntry);
878
+ snapshot = {
879
+ entries: [...snapshot.entries, stateEntry],
880
+ tail: stateTail,
881
+ };
882
+ }
883
+ const permissionMode = this.options.interactiveTools?.consumeTransition(call.id);
884
+ if (permissionMode) {
885
+ const modeEntry = {
886
+ type: 'permission-mode',
887
+ permissionMode,
888
+ sessionId,
889
+ };
890
+ const modeTail = await this.append(lease, snapshot.tail, modeEntry);
891
+ snapshot = {
892
+ entries: [...snapshot.entries, modeEntry],
893
+ tail: modeTail,
894
+ };
895
+ }
896
+ const [entry] = translateProviderEvents([
897
+ {
898
+ type: 'tool-result',
899
+ toolCallId: call.id,
900
+ content: toolResult.content,
901
+ ...(toolResult.contentBlocks
902
+ ? { contentBlocks: toolResult.contentBlocks }
903
+ : {}),
904
+ ...(toolResult.images ? { images: toolResult.images } : {}),
905
+ ...(toolResult.documents
906
+ ? { documents: toolResult.documents }
907
+ : {}),
908
+ isError: toolResult.isError,
909
+ ...(toolResult.nativeToolUseResult
910
+ ? { nativeToolUseResult: toolResult.nativeToolUseResult }
911
+ : {}),
912
+ ...(toolResult.nativeMcpMeta
913
+ ? { nativeMcpMeta: toolResult.nativeMcpMeta }
914
+ : {}),
915
+ },
916
+ ], this.translationContext(sessionId, snapshot));
917
+ if (!entry)
918
+ throw new Error('Could not translate tool result');
919
+ const tail = await this.append(lease, snapshot.tail, entry);
920
+ snapshot = { entries: [...snapshot.entries, entry], tail };
921
+ if (toolResult.isError ||
922
+ call.name !== 'Read' ||
923
+ !this.options.conditionalRuleResolver ||
924
+ !toolResult.accessedPaths) {
925
+ return;
926
+ }
927
+ const attachedRulePaths = this.attachedRulePaths(snapshot.entries);
928
+ for (const filePath of toolResult.accessedPaths) {
929
+ const rules = await this.options.conditionalRuleResolver.resolve(filePath, [...attachedRulePaths]);
930
+ for (const rule of rules) {
931
+ const attachment = createClaudeRuleAttachmentEntry(rule, this.displayRulePath(rule.path), this.translationContext(sessionId, snapshot));
932
+ const attachmentTail = await this.append(lease, snapshot.tail, attachment);
933
+ snapshot = {
934
+ entries: [...snapshot.entries, attachment],
935
+ tail: attachmentTail,
936
+ };
937
+ attachedRulePaths.add(rule.path);
938
+ }
939
+ }
940
+ },
941
+ followUpUserMessagesCompleted: async (messages) => {
942
+ for (const content of messages) {
943
+ const [followUpEntry] = translateProviderEvents([{ type: 'user-text-block', text: content }], this.translationContext(sessionId, snapshot));
944
+ if (!followUpEntry) {
945
+ throw new Error('Could not translate tool follow-up message');
946
+ }
947
+ const followUpTail = await this.append(lease, snapshot.tail, followUpEntry);
948
+ snapshot = {
949
+ entries: [...snapshot.entries, followUpEntry],
950
+ tail: followUpTail,
951
+ };
952
+ currentTurnUserMessages?.push(content);
953
+ }
954
+ },
955
+ };
956
+ try {
957
+ if (this.options.hooks) {
958
+ const outcome = await this.options.hooks.run({
959
+ ...hookSession,
960
+ hook_event_name: 'SessionStart',
961
+ source: requireExisting ? 'resume' : 'startup',
962
+ }, requireExisting ? 'resume' : 'startup', signal);
963
+ await recordHookOutcome(outcome, pendingRecoveryToolCallIds.size > 0);
964
+ if (outcome.blockedReason) {
965
+ throw new Error(`SessionStart hook error: ${outcome.blockedReason}`);
966
+ }
967
+ }
968
+ const approveRecovery = this.options.approveRecovery;
969
+ const recoveryRequest = {
970
+ cwd: this.activeCwd(),
971
+ toolResultDirectory,
972
+ messages: projectClaudeModelMessages(snapshot.entries),
973
+ observer,
974
+ ...(signal ? { signal } : {}),
975
+ ...(approveRecovery
976
+ ? {
977
+ approveRecovery: async (call) => {
978
+ if (!(await approveRecovery(call))) {
979
+ throw new Error(`Claude session tool call ${call.id} recovery was declined`);
980
+ }
981
+ if (signal?.aborted)
982
+ throw new AgentRunCancelledError();
983
+ await flushRecoveryHookOutcomes();
984
+ pendingRecoveryToolCallIds.delete(call.id);
985
+ return true;
986
+ },
987
+ approveTool: () => true,
988
+ }
989
+ : {}),
990
+ };
991
+ const unresolvedToolCall = unresolvedToolCalls[0];
992
+ if (unresolvedToolCall && !approveRecovery) {
993
+ throw new Error(`Claude session tool call ${unresolvedToolCall.id} requires explicit recovery approval`);
994
+ }
995
+ const recoveryResults = await runtime.recoverToolCalls(unresolvedToolCalls, recoveryRequest);
996
+ const recoveryUsage = recoveryResults.reduce((usage, result) => ({
997
+ inputTokens: usage.inputTokens + (result.usage?.inputTokens ?? 0),
998
+ outputTokens: usage.outputTokens + (result.usage?.outputTokens ?? 0),
999
+ }), { inputTokens: 0, outputTokens: 0 });
1000
+ const agentName = this.options.agent ?? getClaudeAgentSetting(snapshot.entries);
1001
+ const agent = agentName
1002
+ ? this.options.extensions?.agent(agentName)
1003
+ : null;
1004
+ if (agentName && !agent) {
1005
+ throw new Error(`Unknown Claude agent ${agentName}`);
1006
+ }
1007
+ if (this.options.agent &&
1008
+ getClaudeAgentSetting(snapshot.entries) !== this.options.agent) {
1009
+ const agentSetting = createClaudeAgentSettingEntry(sessionId, this.options.agent);
1010
+ const settingTail = await this.append(lease, snapshot.tail, agentSetting);
1011
+ snapshot = {
1012
+ entries: [...snapshot.entries, agentSetting],
1013
+ tail: settingTail,
1014
+ };
1015
+ }
1016
+ const assembledContext = await this.options.contextAssembler?.assemble({
1017
+ cwd: this.activeCwd(),
1018
+ });
1019
+ const planModeMessage = this.options.interactiveTools?.contextMessage(sessionId);
1020
+ const contextMessages = [
1021
+ ...(assembledContext?.systemMessages ?? []),
1022
+ ...(planModeMessage
1023
+ ? [{ role: 'system', content: planModeMessage }]
1024
+ : []),
1025
+ ...(this.options.brief
1026
+ ? [
1027
+ {
1028
+ role: 'system',
1029
+ content: CLAUDE_USER_MESSAGE_PROMPT,
1030
+ },
1031
+ ]
1032
+ : []),
1033
+ ...(agent
1034
+ ? [
1035
+ {
1036
+ role: 'system',
1037
+ content: `# Agent definition: ${agent.name}\n\n${agent.body}`,
1038
+ },
1039
+ ]
1040
+ : []),
1041
+ ...(this.options.structuredOutputSchema
1042
+ ? [
1043
+ {
1044
+ role: 'system',
1045
+ content: 'You MUST call StructuredOutput exactly once at the end with a value matching the requested JSON Schema.',
1046
+ },
1047
+ ]
1048
+ : []),
1049
+ ];
1050
+ const expansion = this.options.extensions
1051
+ ? await this.options.extensions.expandPromptAsync(prompt, signal, toolResultDirectory)
1052
+ : { userMessages: [prompt] };
1053
+ const expandedMessages = expansion.messages ?? expansion.userMessages.map((text) => ({ text }));
1054
+ const attachmentIndex = expansion.messages
1055
+ ? expandedMessages.length - 1
1056
+ : 0;
1057
+ currentTurnUserMessages = [...expansion.userMessages];
1058
+ this.options.eventSink?.({
1059
+ type: 'state',
1060
+ state: 'assembling-context',
1061
+ });
1062
+ let compactionUsage = {
1063
+ inputTokens: 0,
1064
+ outputTokens: 0,
1065
+ };
1066
+ const definitions = provider.capabilities.tools
1067
+ ? (structuredTools?.definitions() ?? [])
1068
+ : [];
1069
+ const budget = this.contextBudget(provider);
1070
+ const pendingUserMessages = expandedMessages.map((message, index) => ({
1071
+ role: 'user',
1072
+ content: message.text,
1073
+ ...(message.contentBlocks?.length
1074
+ ? { contentBlocks: message.contentBlocks }
1075
+ : {}),
1076
+ ...((index === attachmentIndex && images.length > 0) ||
1077
+ message.images?.length
1078
+ ? {
1079
+ images: [
1080
+ ...(index === attachmentIndex ? images : []),
1081
+ ...(message.images ?? []),
1082
+ ],
1083
+ }
1084
+ : {}),
1085
+ ...(index === attachmentIndex && documents.length > 0
1086
+ ? { documents }
1087
+ : {}),
1088
+ }));
1089
+ const injectDynamicContext = (messages) => injectFirstUserMessageContext(messages, assembledContext?.firstUserMessageContext);
1090
+ let compactionAnchorUuid = this.lastMessageUuid(snapshot.entries);
1091
+ const compactIfNeeded = async (pendingMessages = [], preservedUserMessages = []) => {
1092
+ if (!budget)
1093
+ return;
1094
+ const historyMessages = projectClaudeModelMessages(snapshot.entries);
1095
+ const predicted = budget.evaluate([
1096
+ ...contextMessages,
1097
+ ...injectDynamicContext([...historyMessages, ...pendingMessages]),
1098
+ ], definitions);
1099
+ if (!predicted.shouldCompact)
1100
+ return;
1101
+ const irreducibleMessages = [
1102
+ ...contextMessages,
1103
+ ...injectDynamicContext([
1104
+ ...pendingMessages,
1105
+ ...preservedUserMessages.map((content) => ({
1106
+ role: 'user',
1107
+ content,
1108
+ })),
1109
+ ]),
1110
+ ];
1111
+ const irreducible = budget.evaluate(irreducibleMessages, definitions);
1112
+ budget.assertFits(irreducible);
1113
+ const logicalParentUuid = compactionAnchorUuid;
1114
+ if (!logicalParentUuid || historyMessages.length === 0) {
1115
+ budget.assertFits(predicted);
1116
+ throw new Error('Cannot compact an empty Claude transcript');
1117
+ }
1118
+ if (findUnresolvedClaudeToolCalls(snapshot.entries).length > 0) {
1119
+ throw new Error('Cannot compact a Claude session with unresolved tool calls');
1120
+ }
1121
+ this.options.eventSink?.({ type: 'state', state: 'compacting' });
1122
+ const compactEnvelope = budget.evaluate([
1123
+ ...irreducibleMessages,
1124
+ {
1125
+ role: 'user',
1126
+ content: formatClaudeCompactSummary(''),
1127
+ },
1128
+ ], definitions);
1129
+ let targetTokens = Math.min(8192, compactEnvelope.availableTokens - compactEnvelope.estimatedTokens);
1130
+ if (targetTokens < 1) {
1131
+ budget.assertFits(budget.evaluate([
1132
+ ...irreducibleMessages,
1133
+ {
1134
+ role: 'user',
1135
+ content: formatClaudeCompactSummary('a'),
1136
+ },
1137
+ ], definitions));
1138
+ targetTokens = 1;
1139
+ }
1140
+ const compacted = await (this.options.compactor ?? new ModelCompactor(provider)).compact({
1141
+ messages: historyMessages,
1142
+ targetTokens,
1143
+ contextWindowTokens: budget.contextWindowTokens,
1144
+ ...(signal ? { signal } : {}),
1145
+ });
1146
+ const boundaryUuid = randomUUID();
1147
+ const summaryUuid = randomUUID();
1148
+ const timestamp = new Date().toISOString();
1149
+ const preTokens = budget.evaluate([...contextMessages, ...injectDynamicContext(historyMessages)], definitions).estimatedTokens;
1150
+ const compactEntries = (postTokens) => {
1151
+ const uuids = [boundaryUuid, summaryUuid];
1152
+ return createClaudeCompactEntries({
1153
+ sessionId,
1154
+ logicalParentUuid,
1155
+ summary: compacted.summary,
1156
+ preTokens,
1157
+ postTokens,
1158
+ previousCumulativeDroppedTokens: getCumulativeDroppedTokens(snapshot.entries),
1159
+ durationMs: compacted.durationMs,
1160
+ cwd: this.activeCwd(),
1161
+ claudeVersion: this.options.claudeVersion,
1162
+ gitBranch: null,
1163
+ createUuid: () => uuids.shift() ?? randomUUID(),
1164
+ now: () => timestamp,
1165
+ });
1166
+ };
1167
+ const provisionalEntries = compactEntries(0);
1168
+ const compactSummaryUuid = provisionalEntries.at(-1)?.uuid;
1169
+ if (typeof compactSummaryUuid !== 'string') {
1170
+ throw new Error('Could not create Claude compact summary');
1171
+ }
1172
+ const replayUuids = preservedUserMessages.map(() => randomUUID());
1173
+ const replayEntries = translateProviderEvents(preservedUserMessages.map((text, index) => index === 0
1174
+ ? { type: 'user-text', text }
1175
+ : { type: 'user-text-block', text }), {
1176
+ sessionId,
1177
+ parentUuid: compactSummaryUuid,
1178
+ cwd: this.activeCwd(),
1179
+ claudeVersion: this.options.claudeVersion,
1180
+ gitBranch: null,
1181
+ history: [...snapshot.entries, ...provisionalEntries],
1182
+ createUuid: () => replayUuids.shift() ?? randomUUID(),
1183
+ now: () => timestamp,
1184
+ });
1185
+ const compactedHistory = projectClaudeModelMessages([
1186
+ ...snapshot.entries,
1187
+ ...provisionalEntries,
1188
+ ...replayEntries,
1189
+ ]);
1190
+ const afterHistory = budget.evaluate([...contextMessages, ...injectDynamicContext(compactedHistory)], definitions);
1191
+ const afterPending = budget.evaluate([
1192
+ ...contextMessages,
1193
+ ...injectDynamicContext([
1194
+ ...compactedHistory,
1195
+ ...pendingMessages,
1196
+ ]),
1197
+ ], definitions);
1198
+ budget.assertFits(afterPending);
1199
+ const entries = [
1200
+ ...compactEntries(afterHistory.estimatedTokens),
1201
+ ...replayEntries,
1202
+ ];
1203
+ if (signal?.aborted)
1204
+ throw new AgentRunCancelledError();
1205
+ const appendResult = await lease.appendMany(snapshot.tail, entries);
1206
+ if (appendResult.status === 'conflict') {
1207
+ throw new Error(`Claude transcript append conflict: ${appendResult.reason}`);
1208
+ }
1209
+ snapshot = {
1210
+ entries: [...snapshot.entries, ...entries],
1211
+ tail: appendResult.tail,
1212
+ };
1213
+ this.options.eventSink?.({
1214
+ type: 'compact-boundary',
1215
+ trigger: 'auto',
1216
+ preTokens,
1217
+ uuid: boundaryUuid,
1218
+ });
1219
+ compactionAnchorUuid = compactSummaryUuid;
1220
+ compactionUsage = {
1221
+ inputTokens: compactionUsage.inputTokens + compacted.usage.inputTokens,
1222
+ outputTokens: compactionUsage.outputTokens + compacted.usage.outputTokens,
1223
+ };
1224
+ };
1225
+ await compactIfNeeded(pendingUserMessages);
1226
+ for (const [index, message] of expandedMessages.entries()) {
1227
+ const messageImages = [
1228
+ ...(index === attachmentIndex ? images : []),
1229
+ ...(message.images ?? []),
1230
+ ];
1231
+ const [userEntry] = translateProviderEvents([
1232
+ messageImages.length > 0 ||
1233
+ (index === attachmentIndex && documents.length > 0)
1234
+ ? {
1235
+ type: 'user-message',
1236
+ text: message.text,
1237
+ images: messageImages,
1238
+ ...(index === attachmentIndex && documents.length > 0
1239
+ ? { documents }
1240
+ : {}),
1241
+ }
1242
+ : index === 0
1243
+ ? { type: 'user-text', text: message.text }
1244
+ : { type: 'user-text-block', text: message.text },
1245
+ ], this.translationContext(sessionId, snapshot));
1246
+ if (!userEntry)
1247
+ throw new Error('Could not translate user prompt');
1248
+ if (currentPromptId === null && typeof userEntry.uuid === 'string') {
1249
+ currentPromptId = userEntry.uuid;
1250
+ compactionAnchorUuid ??= userEntry.uuid;
1251
+ }
1252
+ const userTail = await this.append(lease, snapshot.tail, userEntry);
1253
+ snapshot = {
1254
+ entries: [...snapshot.entries, userEntry],
1255
+ tail: userTail,
1256
+ };
1257
+ }
1258
+ if (fileHistory && currentPromptId) {
1259
+ const historySnapshot = await fileHistory.snapshot(snapshot.entries, currentPromptId);
1260
+ const historyTail = await this.append(lease, snapshot.tail, historySnapshot);
1261
+ snapshot = {
1262
+ entries: [...snapshot.entries, historySnapshot],
1263
+ tail: historyTail,
1264
+ };
1265
+ }
1266
+ if (this.options.hooks) {
1267
+ const outcome = await this.options.hooks.run({
1268
+ ...hookSession,
1269
+ hook_event_name: 'UserPromptSubmit',
1270
+ prompt_id: currentPromptId ?? randomUUID(),
1271
+ prompt,
1272
+ }, undefined, signal);
1273
+ await recordHookOutcome(outcome);
1274
+ if (outcome.blockedReason) {
1275
+ throw new Error(`UserPromptSubmit hook error: ${outcome.blockedReason}`);
1276
+ }
1277
+ }
1278
+ if (budget) {
1279
+ await compactIfNeeded([], currentTurnUserMessages ?? []);
1280
+ budget.assertFits(budget.evaluate([
1281
+ ...contextMessages,
1282
+ ...injectDynamicContext(projectClaudeModelMessages(snapshot.entries)),
1283
+ ], definitions));
1284
+ }
1285
+ let stopHookActive = false;
1286
+ const runtimeRequest = {
1287
+ messages: [
1288
+ ...contextMessages,
1289
+ ...injectDynamicContext(projectClaudeModelMessages(snapshot.entries)),
1290
+ ],
1291
+ cwd: this.activeCwd(),
1292
+ toolResultDirectory,
1293
+ observer,
1294
+ ...(this.options.effort ? { effort: this.options.effort } : {}),
1295
+ ...(this.options.maxModelTurns
1296
+ ? { maxModelTurns: this.options.maxModelTurns }
1297
+ : {}),
1298
+ ...(this.options.betas?.length ? { betas: this.options.betas } : {}),
1299
+ ...(this.options.collectMetrics ? { collectMetrics: true } : {}),
1300
+ reloadMessages: async () => {
1301
+ await compactIfNeeded([], currentTurnUserMessages ?? []);
1302
+ return [
1303
+ ...contextMessages,
1304
+ ...injectDynamicContext(projectClaudeModelMessages(snapshot.entries)),
1305
+ ];
1306
+ },
1307
+ ...(this.options.hooks ||
1308
+ subagentExecutor ||
1309
+ taskTools ||
1310
+ this.scheduledPrompts ||
1311
+ this.workflowManager
1312
+ ? {
1313
+ onStop: async (text) => {
1314
+ const messages = [];
1315
+ const outcome = await this.options.hooks?.run({
1316
+ ...hookSession,
1317
+ hook_event_name: 'Stop',
1318
+ stop_hook_active: stopHookActive,
1319
+ last_assistant_message: text,
1320
+ }, undefined, signal);
1321
+ if (outcome) {
1322
+ await recordHookOutcome(outcome);
1323
+ if (outcome.blockedReason) {
1324
+ stopHookActive = true;
1325
+ messages.push(`Stop hook error: ${outcome.blockedReason}`);
1326
+ }
1327
+ }
1328
+ const background = await subagentExecutor?.notifications(true);
1329
+ if (background)
1330
+ messages.push(...background.messages);
1331
+ const workflow = await this.workflowManager?.notifications(true);
1332
+ if (workflow)
1333
+ messages.push(...workflow.messages);
1334
+ const bashMessages = await taskTools?.notifications(true);
1335
+ if (bashMessages)
1336
+ messages.push(...bashMessages);
1337
+ const scheduled = await this.scheduledPrompts?.drainDue();
1338
+ if (scheduled) {
1339
+ messages.push(...scheduled.map(({ prompt }) => prompt));
1340
+ }
1341
+ return {
1342
+ messages,
1343
+ ...(background || workflow
1344
+ ? {
1345
+ usage: {
1346
+ inputTokens: (background?.usage.inputTokens ?? 0) +
1347
+ (workflow?.usage.inputTokens ?? 0),
1348
+ outputTokens: (background?.usage.outputTokens ?? 0) +
1349
+ (workflow?.usage.outputTokens ?? 0),
1350
+ },
1351
+ }
1352
+ : {}),
1353
+ };
1354
+ },
1355
+ }
1356
+ : {}),
1357
+ ...(this.options.approveTool
1358
+ ? { approveTool: this.options.approveTool }
1359
+ : {}),
1360
+ };
1361
+ const result = signal
1362
+ ? await runtime.run({ ...runtimeRequest, signal })
1363
+ : await runtime.run(runtimeRequest);
1364
+ if (structuredCapture && structuredCapture.calls !== 1) {
1365
+ throw new Error(`StructuredOutput must be called exactly once (received ${structuredCapture.calls})`);
1366
+ }
1367
+ const finalLeafUuid = lastAssistantUuid;
1368
+ if (!finalLeafUuid) {
1369
+ throw new Error('Could not locate final assistant response');
1370
+ }
1371
+ await this.append(lease, snapshot.tail, createClaudeLastPromptEntry({
1372
+ sessionId,
1373
+ lastPrompt: prompt,
1374
+ leafUuid: finalLeafUuid,
1375
+ }));
1376
+ const totalUsage = mergeUsage(mergeUsage(recoveryUsage, compactionUsage), result.usage);
1377
+ return {
1378
+ sessionId,
1379
+ text: structuredCapture && structuredCapture.calls === 1
1380
+ ? JSON.stringify(structuredCapture.value)
1381
+ : result.text,
1382
+ usage: totalUsage,
1383
+ ...(result.durationApiMs === undefined
1384
+ ? {}
1385
+ : { durationApiMs: result.durationApiMs }),
1386
+ ...(this.options.pricing
1387
+ ? (() => {
1388
+ const pricing = this.options.pricing?.resolve(provider.model ?? 'praxis/provider');
1389
+ return pricing
1390
+ ? { costUsd: usageCostUsd(result.usage, pricing) }
1391
+ : {};
1392
+ })()
1393
+ : {}),
1394
+ ...(provider.model
1395
+ ? { modelUsage: { [provider.model]: result.usage } }
1396
+ : {}),
1397
+ ...(structuredCapture && structuredCapture.calls === 1
1398
+ ? { structuredOutput: structuredCapture.value }
1399
+ : {}),
1400
+ };
1401
+ }
1402
+ finally {
1403
+ try {
1404
+ const outcome = await this.options.hooks?.run({
1405
+ ...hookSession,
1406
+ hook_event_name: 'SessionEnd',
1407
+ reason: 'other',
1408
+ }, 'other');
1409
+ const failedExecutions = outcome?.executions.filter((execution) => execution.exitCode !== 0) ?? [];
1410
+ for (const execution of failedExecutions) {
1411
+ const detail = execution.stderr.trim() ||
1412
+ execution.stdout.trim() ||
1413
+ `exit code ${execution.exitCode}`;
1414
+ this.options.eventSink?.({
1415
+ type: 'warning',
1416
+ message: `SessionEnd hook failed: ${detail}`,
1417
+ });
1418
+ }
1419
+ if (outcome?.blockedReason &&
1420
+ outcome.executions.at(-1)?.exitCode === 0) {
1421
+ this.options.eventSink?.({
1422
+ type: 'warning',
1423
+ message: `SessionEnd hook failed: ${outcome.blockedReason}`,
1424
+ });
1425
+ }
1426
+ }
1427
+ catch (error) {
1428
+ this.options.eventSink?.({
1429
+ type: 'warning',
1430
+ message: `SessionEnd hook failed: ${error instanceof Error ? error.message : String(error)}`,
1431
+ });
1432
+ }
1433
+ }
1434
+ });
1435
+ if (leaseResult.status === 'conflict') {
1436
+ throw new Error(`Claude transcript append conflict: ${leaseResult.reason}`);
1437
+ }
1438
+ return leaseResult.value;
1439
+ }
1440
+ async ensureFileResources(sessionId, signal) {
1441
+ const resources = this.options.fileResources ?? [];
1442
+ if (resources.length === 0 ||
1443
+ this.downloadedFileResourceSessions.has(sessionId)) {
1444
+ return;
1445
+ }
1446
+ const config = this.options.fileResourceConfig;
1447
+ if (!config) {
1448
+ throw new Error('--file requires PRAXIS_FILES_BEARER_TOKEN, PRAXIS_FILES_API_KEY, or PRAXIS_API_KEY');
1449
+ }
1450
+ const downloads = await downloadClaudeFileResources(resources, {
1451
+ ...config,
1452
+ sessionId,
1453
+ ...(signal ? { signal } : {}),
1454
+ });
1455
+ this.downloadedFileResourceSessions.add(sessionId);
1456
+ for (const download of downloads) {
1457
+ if (download.success)
1458
+ continue;
1459
+ this.options.eventSink?.({
1460
+ type: 'warning',
1461
+ message: `File ${download.fileId} failed to download: ${download.error ?? 'unknown error'}`,
1462
+ });
1463
+ }
1464
+ }
1465
+ translationContext(sessionId, snapshot) {
1466
+ return {
1467
+ sessionId,
1468
+ parentUuid: this.logicalTailUuid(snapshot.tail),
1469
+ cwd: this.activeCwd(),
1470
+ claudeVersion: this.options.claudeVersion,
1471
+ gitBranch: null,
1472
+ ...(this.options.sessionKind === undefined
1473
+ ? {}
1474
+ : { sessionKind: this.options.sessionKind }),
1475
+ history: snapshot.entries,
1476
+ };
1477
+ }
1478
+ attachedRulePaths(entries) {
1479
+ const paths = new Set();
1480
+ for (const entry of entries) {
1481
+ if (entry.type !== 'attachment')
1482
+ continue;
1483
+ const attachment = entry.attachment;
1484
+ if (typeof attachment !== 'object' ||
1485
+ attachment === null ||
1486
+ Array.isArray(attachment)) {
1487
+ continue;
1488
+ }
1489
+ const path = attachment.path;
1490
+ if (typeof path === 'string')
1491
+ paths.add(path);
1492
+ }
1493
+ return paths;
1494
+ }
1495
+ sessionNameEntries(sessionId, name) {
1496
+ return [
1497
+ { type: 'custom-title', customTitle: name, sessionId },
1498
+ { type: 'agent-name', agentName: name, sessionId },
1499
+ ];
1500
+ }
1501
+ hasSessionName(entries, name) {
1502
+ return this.sessionName(entries) === name;
1503
+ }
1504
+ sessionName(entries) {
1505
+ let customTitle;
1506
+ let agentName;
1507
+ for (let index = entries.length - 1; index >= 0; index -= 1) {
1508
+ const entry = entries[index];
1509
+ if (customTitle === undefined && entry?.type === 'custom-title') {
1510
+ customTitle = entry.customTitle;
1511
+ }
1512
+ if (agentName === undefined && entry?.type === 'agent-name') {
1513
+ agentName = entry.agentName;
1514
+ }
1515
+ if (customTitle !== undefined && agentName !== undefined)
1516
+ break;
1517
+ }
1518
+ if (typeof customTitle === 'string' && customTitle === agentName) {
1519
+ return customTitle;
1520
+ }
1521
+ if (typeof customTitle === 'string')
1522
+ return customTitle;
1523
+ if (typeof agentName === 'string')
1524
+ return agentName;
1525
+ return null;
1526
+ }
1527
+ lastMessageUuid(entries) {
1528
+ for (let index = entries.length - 1; index >= 0; index -= 1) {
1529
+ const entry = entries[index];
1530
+ if (entry &&
1531
+ typeof entry.uuid === 'string' &&
1532
+ typeof entry.message === 'object' &&
1533
+ entry.message !== null &&
1534
+ !Array.isArray(entry.message)) {
1535
+ return entry.uuid;
1536
+ }
1537
+ }
1538
+ return null;
1539
+ }
1540
+ promptIdForToolCall(entries, callId) {
1541
+ const byUuid = new Map();
1542
+ let source;
1543
+ for (const entry of entries) {
1544
+ if (typeof entry.uuid === 'string')
1545
+ byUuid.set(entry.uuid, entry);
1546
+ if (entry.type !== 'assistant' ||
1547
+ typeof entry.message !== 'object' ||
1548
+ entry.message === null ||
1549
+ Array.isArray(entry.message)) {
1550
+ continue;
1551
+ }
1552
+ const message = entry.message;
1553
+ if (typeof message !== 'object' ||
1554
+ message === null ||
1555
+ !Array.isArray(message.content)) {
1556
+ continue;
1557
+ }
1558
+ const content = message.content;
1559
+ if (content.some((block) => typeof block === 'object' &&
1560
+ block !== null &&
1561
+ block.type === 'tool_use' &&
1562
+ block.id === callId)) {
1563
+ source = entry;
1564
+ }
1565
+ }
1566
+ let candidate = source;
1567
+ while (candidate) {
1568
+ if (candidate.type === 'user' &&
1569
+ typeof candidate.promptId === 'string' &&
1570
+ (candidate.promptSource === 'interactive' ||
1571
+ candidate.promptSource === 'sdk')) {
1572
+ return candidate.promptId;
1573
+ }
1574
+ candidate =
1575
+ typeof candidate.parentUuid === 'string'
1576
+ ? byUuid.get(candidate.parentUuid)
1577
+ : undefined;
1578
+ }
1579
+ return null;
1580
+ }
1581
+ assistantIdForToolCall(entries, callId) {
1582
+ for (let index = entries.length - 1; index >= 0; index -= 1) {
1583
+ const entry = entries[index];
1584
+ if (entry?.type !== 'assistant' ||
1585
+ typeof entry.uuid !== 'string' ||
1586
+ typeof entry.message !== 'object' ||
1587
+ entry.message === null ||
1588
+ !Array.isArray(entry.message.content)) {
1589
+ continue;
1590
+ }
1591
+ if (entry.message.content.some((block) => typeof block === 'object' &&
1592
+ block !== null &&
1593
+ block.type === 'tool_use' &&
1594
+ block.id === callId)) {
1595
+ return entry.uuid;
1596
+ }
1597
+ }
1598
+ return null;
1599
+ }
1600
+ displayRulePath(rulePath) {
1601
+ const pathFromCwd = relative(this.activeCwd(), rulePath);
1602
+ return pathFromCwd.startsWith('..') || isAbsolute(pathFromCwd)
1603
+ ? rulePath
1604
+ : pathFromCwd;
1605
+ }
1606
+ activeCwd() {
1607
+ return this.options.workspace?.cwd() ?? this.options.cwd;
1608
+ }
1609
+ restoreWorktree(entries) {
1610
+ const latest = [...entries]
1611
+ .reverse()
1612
+ .find((entry) => entry.type === 'worktree-state');
1613
+ if (!latest || !this.worktreeManager)
1614
+ return;
1615
+ const state = latest.worktreeSession;
1616
+ if (!state || typeof state !== 'object' || Array.isArray(state))
1617
+ return;
1618
+ this.worktreeManager.restore(state);
1619
+ }
1620
+ paths(sessionId) {
1621
+ return resolveClaudePaths({
1622
+ configDir: this.options.configRoot,
1623
+ cwd: this.sessionCwds.get(sessionId) ?? this.options.cwd,
1624
+ sessionId,
1625
+ });
1626
+ }
1627
+ store(sessionId) {
1628
+ const paths = this.paths(sessionId);
1629
+ return new ClaudeTranscriptStore({
1630
+ sessionFile: paths.sessionFile,
1631
+ lockFile: join(paths.praxisRoot, 'locks', `${sessionId}.lock`),
1632
+ schema: this.schema,
1633
+ });
1634
+ }
1635
+ turnStore(sessionId) {
1636
+ if (this.options.sessionPersistence !== false)
1637
+ return this.store(sessionId);
1638
+ let store = this.inMemoryStores.get(sessionId);
1639
+ if (!store) {
1640
+ store = new InMemoryTranscriptStore();
1641
+ this.inMemoryStores.set(sessionId, store);
1642
+ }
1643
+ return store;
1644
+ }
1645
+ assertSessionPersistence() {
1646
+ if (this.options.sessionPersistence === false) {
1647
+ throw new Error('Session persistence is disabled');
1648
+ }
1649
+ }
1650
+ assertWritable() {
1651
+ if (this.schema.writeMode !== 'read-write') {
1652
+ throw new Error(`Claude ${this.options.claudeVersion} session is read-only`);
1653
+ }
1654
+ }
1655
+ sessionStatus(issue, entryCount) {
1656
+ if (issue || entryCount === 0)
1657
+ return 'corrupt';
1658
+ return this.schema.writeMode === 'read-write' ? 'ready' : 'read-only';
1659
+ }
1660
+ provider() {
1661
+ if (!this.options.provider) {
1662
+ throw new Error('A model provider is required for run and resume');
1663
+ }
1664
+ return this.options.provider;
1665
+ }
1666
+ contextBudget(provider) {
1667
+ if (this.options.contextBudget)
1668
+ return this.options.contextBudget;
1669
+ const contextWindowTokens = provider.capabilities.contextWindowTokens;
1670
+ if (contextWindowTokens === undefined)
1671
+ return null;
1672
+ return new ContextBudget({
1673
+ contextWindowTokens,
1674
+ ...(this.options.contextReserveTokens === undefined
1675
+ ? {}
1676
+ : { reserveTokens: this.options.contextReserveTokens }),
1677
+ });
1678
+ }
1679
+ async append(lease, tail, entry) {
1680
+ const result = await lease.append(tail, entry);
1681
+ if (result.status === 'conflict') {
1682
+ throw new Error(`Claude transcript append conflict: ${result.reason}`);
1683
+ }
1684
+ return result.tail;
1685
+ }
1686
+ logicalTailUuid(tail) {
1687
+ return tail.branchParentUuid ?? tail.lastUuid;
1688
+ }
1689
+ }
1690
+ //# sourceMappingURL=session-service.js.map