@evalops/maestro 0.10.23 → 0.10.24

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 (376) hide show
  1. package/README.md +4 -4
  2. package/dist/agent/agent.d.ts +2 -2
  3. package/dist/agent/agent.d.ts.map +1 -1
  4. package/dist/agent/agent.js +1 -1
  5. package/dist/agent/agent.js.map +1 -1
  6. package/dist/agent/keys.d.ts +2 -5
  7. package/dist/agent/keys.d.ts.map +1 -1
  8. package/dist/agent/keys.js +4 -5
  9. package/dist/agent/keys.js.map +1 -1
  10. package/dist/agent/modes.d.ts +2 -2
  11. package/dist/agent/modes.d.ts.map +1 -1
  12. package/dist/agent/modes.js +6 -7
  13. package/dist/agent/modes.js.map +1 -1
  14. package/dist/agent/providers/anthropic.d.ts.map +1 -1
  15. package/dist/agent/providers/anthropic.js +4 -4
  16. package/dist/agent/providers/anthropic.js.map +1 -1
  17. package/dist/agent/providers/google.js +1 -1
  18. package/dist/agent/swarm/executor.d.ts +2 -0
  19. package/dist/agent/swarm/executor.d.ts.map +1 -1
  20. package/dist/agent/swarm/executor.js +208 -35
  21. package/dist/agent/swarm/executor.js.map +1 -1
  22. package/dist/agent/swarm/types.d.ts +2 -0
  23. package/dist/agent/swarm/types.d.ts.map +1 -1
  24. package/dist/agent/swarm/types.js.map +1 -1
  25. package/dist/agent/tool-capability-types.d.ts +36 -0
  26. package/dist/agent/tool-capability-types.d.ts.map +1 -0
  27. package/dist/agent/tool-capability-types.js +2 -0
  28. package/dist/agent/tool-capability-types.js.map +1 -0
  29. package/dist/agent/transport/tool-execution-bridge.d.ts +13 -0
  30. package/dist/agent/transport/tool-execution-bridge.d.ts.map +1 -1
  31. package/dist/agent/transport/tool-execution-bridge.js +28 -15
  32. package/dist/agent/transport/tool-execution-bridge.js.map +1 -1
  33. package/dist/agent/transport/transport-utils.d.ts.map +1 -1
  34. package/dist/agent/transport/transport-utils.js +2 -3
  35. package/dist/agent/transport/transport-utils.js.map +1 -1
  36. package/dist/agent/transport.js +1 -1
  37. package/dist/agent/transport.js.map +1 -1
  38. package/dist/agent/type-guards.d.ts +1 -1
  39. package/dist/agent/type-guards.js +1 -1
  40. package/dist/agent/type-guards.js.map +1 -1
  41. package/dist/agent/types.d.ts +5 -3
  42. package/dist/agent/types.d.ts.map +1 -1
  43. package/dist/agent/types.js +2 -2
  44. package/dist/agent/types.js.map +1 -1
  45. package/dist/app-server/daemon-lifecycle-api.d.ts +31 -0
  46. package/dist/app-server/daemon-lifecycle-api.d.ts.map +1 -0
  47. package/dist/app-server/daemon-lifecycle-api.js +259 -0
  48. package/dist/app-server/daemon-lifecycle-api.js.map +1 -0
  49. package/dist/app-server/external-agent-import-api.d.ts +30 -0
  50. package/dist/app-server/external-agent-import-api.d.ts.map +1 -0
  51. package/dist/app-server/external-agent-import-api.js +553 -0
  52. package/dist/app-server/external-agent-import-api.js.map +1 -0
  53. package/dist/app-server/host-control-api.d.ts +30 -0
  54. package/dist/app-server/host-control-api.d.ts.map +1 -0
  55. package/dist/app-server/host-control-api.js +343 -0
  56. package/dist/app-server/host-control-api.js.map +1 -0
  57. package/dist/app-server/in-process-client.d.ts +2 -2
  58. package/dist/app-server/in-process-client.d.ts.map +1 -1
  59. package/dist/app-server/in-process-client.js.map +1 -1
  60. package/dist/app-server/network-governance-api.d.ts +26 -0
  61. package/dist/app-server/network-governance-api.d.ts.map +1 -0
  62. package/dist/app-server/network-governance-api.js +476 -0
  63. package/dist/app-server/network-governance-api.js.map +1 -0
  64. package/dist/app-server/plugin-bundle-api.d.ts +17 -0
  65. package/dist/app-server/plugin-bundle-api.d.ts.map +1 -0
  66. package/dist/app-server/plugin-bundle-api.js +219 -0
  67. package/dist/app-server/plugin-bundle-api.js.map +1 -0
  68. package/dist/app-server/policy-control-api.d.ts +14 -0
  69. package/dist/app-server/policy-control-api.d.ts.map +1 -0
  70. package/dist/app-server/policy-control-api.js +200 -0
  71. package/dist/app-server/policy-control-api.js.map +1 -0
  72. package/dist/app-server/protocol-modes-api.d.ts +22 -0
  73. package/dist/app-server/protocol-modes-api.d.ts.map +1 -0
  74. package/dist/app-server/protocol-modes-api.js +124 -0
  75. package/dist/app-server/protocol-modes-api.js.map +1 -0
  76. package/dist/app-server/sandbox-proof-api.d.ts +21 -0
  77. package/dist/app-server/sandbox-proof-api.d.ts.map +1 -0
  78. package/dist/app-server/sandbox-proof-api.js +127 -0
  79. package/dist/app-server/sandbox-proof-api.js.map +1 -0
  80. package/dist/app-server/session-api.d.ts +93 -3
  81. package/dist/app-server/session-api.d.ts.map +1 -1
  82. package/dist/app-server/session-api.js +706 -18
  83. package/dist/app-server/session-api.js.map +1 -1
  84. package/dist/audit/logger.d.ts +1 -1
  85. package/dist/bootstrap/auth-setup.d.ts.map +1 -1
  86. package/dist/bootstrap/auth-setup.js +17 -2
  87. package/dist/bootstrap/auth-setup.js.map +1 -1
  88. package/dist/bootstrap/model-resolution-setup.d.ts.map +1 -1
  89. package/dist/bootstrap/model-resolution-setup.js +19 -4
  90. package/dist/bootstrap/model-resolution-setup.js.map +1 -1
  91. package/dist/cli/args.d.ts +2 -2
  92. package/dist/cli/args.d.ts.map +1 -1
  93. package/dist/cli/args.js +2 -2
  94. package/dist/cli/args.js.map +1 -1
  95. package/dist/cli/commands/a2a.d.ts.map +1 -1
  96. package/dist/cli/commands/a2a.js +226 -14
  97. package/dist/cli/commands/a2a.js.map +1 -1
  98. package/dist/cli/commands/anthropic.d.ts +1 -1
  99. package/dist/cli/commands/anthropic.d.ts.map +1 -1
  100. package/dist/cli/commands/anthropic.js +3 -68
  101. package/dist/cli/commands/anthropic.js.map +1 -1
  102. package/dist/cli/commands/modes.js +1 -1
  103. package/dist/cli/commands/modes.js.map +1 -1
  104. package/dist/cli/help.d.ts.map +1 -1
  105. package/dist/cli/help.js +5 -7
  106. package/dist/cli/help.js.map +1 -1
  107. package/dist/cli/rpc-mode.d.ts +1 -1
  108. package/dist/cli/rpc-mode.js +1 -1
  109. package/dist/cli/rpc-mode.js.map +1 -1
  110. package/dist/cli/session.js +1 -1
  111. package/dist/cli/session.js.map +1 -1
  112. package/dist/cli-tui/commands/command-catalog.d.ts.map +1 -1
  113. package/dist/cli-tui/commands/command-catalog.js +7 -12
  114. package/dist/cli-tui/commands/command-catalog.js.map +1 -1
  115. package/dist/cli-tui/commands/subcommands/auth-commands.d.ts +1 -1
  116. package/dist/cli-tui/commands/subcommands/auth-commands.d.ts.map +1 -1
  117. package/dist/cli-tui/commands/subcommands/auth-commands.js +4 -12
  118. package/dist/cli-tui/commands/subcommands/auth-commands.js.map +1 -1
  119. package/dist/cli-tui/custom-editor.d.ts +1 -1
  120. package/dist/cli-tui/custom-editor.js +2 -2
  121. package/dist/cli-tui/custom-editor.js.map +1 -1
  122. package/dist/cli-tui/oauth/oauth-flow-controller.d.ts.map +1 -1
  123. package/dist/cli-tui/oauth/oauth-flow-controller.js +19 -23
  124. package/dist/cli-tui/oauth/oauth-flow-controller.js.map +1 -1
  125. package/dist/cli-tui/selectors/model-selector.d.ts.map +1 -1
  126. package/dist/cli-tui/selectors/model-selector.js +0 -1
  127. package/dist/cli-tui/selectors/model-selector.js.map +1 -1
  128. package/dist/cli-tui/selectors/oauth-selector-view.d.ts +2 -2
  129. package/dist/cli-tui/selectors/oauth-selector-view.d.ts.map +1 -1
  130. package/dist/cli-tui/selectors/oauth-selector-view.js.map +1 -1
  131. package/dist/cli-tui/selectors/oauth-selector.d.ts +2 -2
  132. package/dist/cli-tui/selectors/oauth-selector.d.ts.map +1 -1
  133. package/dist/cli-tui/selectors/oauth-selector.js +3 -4
  134. package/dist/cli-tui/selectors/oauth-selector.js.map +1 -1
  135. package/dist/cli-tui/tui-renderer/mcp-events-setup.js +1 -1
  136. package/dist/cli-tui/tui-renderer/mcp-events-setup.js.map +1 -1
  137. package/dist/cli-tui/tui-renderer.js +2 -2
  138. package/dist/cli-tui/tui-renderer.js.map +1 -1
  139. package/dist/cli-tui/utils/footer-utils.d.ts +1 -1
  140. package/dist/cli-tui/utils/footer-utils.js +1 -1
  141. package/dist/cli-tui/utils/footer-utils.js.map +1 -1
  142. package/dist/cli.js +15156 -14232
  143. package/dist/commands/prompts.d.ts +1 -1
  144. package/dist/commands/prompts.js +1 -1
  145. package/dist/commands/prompts.js.map +1 -1
  146. package/dist/config/constants.d.ts +2 -2
  147. package/dist/config/constants.d.ts.map +1 -1
  148. package/dist/config/constants.js +2 -2
  149. package/dist/config/constants.js.map +1 -1
  150. package/dist/config/index.d.ts +1 -1
  151. package/dist/config/index.js +1 -1
  152. package/dist/config/index.js.map +1 -1
  153. package/dist/config/toml-config.js +3 -3
  154. package/dist/config/toml-config.js.map +1 -1
  155. package/dist/db/client.d.ts +2 -2
  156. package/dist/db/client.js +2 -2
  157. package/dist/db/client.js.map +1 -1
  158. package/dist/db/migrate.d.ts +1 -1
  159. package/dist/db/migrate.js +1 -1
  160. package/dist/db/migrate.js.map +1 -1
  161. package/dist/db/schema.d.ts +2 -2
  162. package/dist/db/schema.js +1 -1
  163. package/dist/db/schema.js.map +1 -1
  164. package/dist/errors/index.d.ts +2 -2
  165. package/dist/errors/index.js +2 -2
  166. package/dist/errors/index.js.map +1 -1
  167. package/dist/main.d.ts +4 -5
  168. package/dist/main.d.ts.map +1 -1
  169. package/dist/main.js +17 -14
  170. package/dist/main.js.map +1 -1
  171. package/dist/mcp/config.d.ts +15 -2
  172. package/dist/mcp/config.d.ts.map +1 -1
  173. package/dist/mcp/config.js +50 -26
  174. package/dist/mcp/config.js.map +1 -1
  175. package/dist/mcp/fathom-cua.d.ts.map +1 -1
  176. package/dist/mcp/fathom-cua.js +10 -0
  177. package/dist/mcp/fathom-cua.js.map +1 -1
  178. package/dist/mcp/manager.d.ts.map +1 -1
  179. package/dist/mcp/manager.js +32 -1
  180. package/dist/mcp/manager.js.map +1 -1
  181. package/dist/mcp/tool-bridge.d.ts.map +1 -1
  182. package/dist/mcp/tool-bridge.js +12 -3
  183. package/dist/mcp/tool-bridge.js.map +1 -1
  184. package/dist/mcp/tool-capabilities.d.ts +5 -0
  185. package/dist/mcp/tool-capabilities.d.ts.map +1 -0
  186. package/dist/mcp/tool-capabilities.js +271 -0
  187. package/dist/mcp/tool-capabilities.js.map +1 -0
  188. package/dist/mcp/types.d.ts +6 -1
  189. package/dist/mcp/types.d.ts.map +1 -1
  190. package/dist/mcp/types.js.map +1 -1
  191. package/dist/models/config-loader.d.ts +1 -1
  192. package/dist/models/factory-integration.d.ts +1 -1
  193. package/dist/models/factory-integration.js +1 -1
  194. package/dist/models/factory-integration.js.map +1 -1
  195. package/dist/node_modules/@evalops/contracts/dist/index.d.ts +3 -3
  196. package/dist/node_modules/@evalops/contracts/dist/index.js +2 -2
  197. package/dist/node_modules/@evalops/contracts/dist/index.js.map +1 -1
  198. package/dist/node_modules/@evalops/contracts/dist/maestro-app-server.d.ts +1182 -14
  199. package/dist/node_modules/@evalops/contracts/dist/maestro-app-server.d.ts.map +1 -1
  200. package/dist/node_modules/@evalops/contracts/dist/maestro-app-server.js +450 -1
  201. package/dist/node_modules/@evalops/contracts/dist/maestro-app-server.js.map +1 -1
  202. package/dist/node_modules/@evalops/contracts/package.json +1 -1
  203. package/dist/node_modules/@evalops/tui/package.json +1 -1
  204. package/dist/oauth/connectors.d.ts +2 -2
  205. package/dist/oauth/connectors.d.ts.map +1 -1
  206. package/dist/oauth/connectors.js +3 -5
  207. package/dist/oauth/connectors.js.map +1 -1
  208. package/dist/oauth/github-copilot.d.ts +1 -1
  209. package/dist/oauth/github-copilot.js +1 -1
  210. package/dist/oauth/github-copilot.js.map +1 -1
  211. package/dist/oauth/index.d.ts +10 -8
  212. package/dist/oauth/index.d.ts.map +1 -1
  213. package/dist/oauth/index.js +54 -31
  214. package/dist/oauth/index.js.map +1 -1
  215. package/dist/oauth/openai.d.ts +1 -1
  216. package/dist/oauth/openai.js +2 -2
  217. package/dist/oauth/openai.js.map +1 -1
  218. package/dist/platform/a2a-completion-audit.d.ts +41 -0
  219. package/dist/platform/a2a-completion-audit.d.ts.map +1 -0
  220. package/dist/platform/a2a-completion-audit.js +177 -0
  221. package/dist/platform/a2a-completion-audit.js.map +1 -0
  222. package/dist/platform/a2a-task-ledger.d.ts.map +1 -1
  223. package/dist/platform/a2a-task-ledger.js +17 -0
  224. package/dist/platform/a2a-task-ledger.js.map +1 -1
  225. package/dist/platform/a2a-telemetry-inspect.d.ts +58 -0
  226. package/dist/platform/a2a-telemetry-inspect.d.ts.map +1 -0
  227. package/dist/platform/a2a-telemetry-inspect.js +224 -0
  228. package/dist/platform/a2a-telemetry-inspect.js.map +1 -0
  229. package/dist/platform/agent-registry-client.d.ts +8 -0
  230. package/dist/platform/agent-registry-client.d.ts.map +1 -1
  231. package/dist/platform/agent-registry-client.js +9 -1
  232. package/dist/platform/agent-registry-client.js.map +1 -1
  233. package/dist/providers/api-keys.d.ts +2 -2
  234. package/dist/providers/api-keys.js +2 -2
  235. package/dist/providers/api-keys.js.map +1 -1
  236. package/dist/providers/auth.d.ts +3 -6
  237. package/dist/providers/auth.d.ts.map +1 -1
  238. package/dist/providers/auth.js +1 -40
  239. package/dist/providers/auth.js.map +1 -1
  240. package/dist/rpc/index.d.ts +2 -2
  241. package/dist/rpc/index.js +2 -2
  242. package/dist/rpc/index.js.map +1 -1
  243. package/dist/rpc/rpc-types.d.ts +1 -1
  244. package/dist/rpc/rpc-types.js +1 -1
  245. package/dist/rpc/rpc-types.js.map +1 -1
  246. package/dist/safety/nested-agent-guard.js +1 -1
  247. package/dist/safety/nested-agent-guard.js.map +1 -1
  248. package/dist/safety/policy.d.ts +2 -2
  249. package/dist/safety/policy.js +2 -2
  250. package/dist/safety/policy.js.map +1 -1
  251. package/dist/safety/validators/network-policy-validator.d.ts +8 -0
  252. package/dist/safety/validators/network-policy-validator.d.ts.map +1 -1
  253. package/dist/safety/validators/network-policy-validator.js +29 -4
  254. package/dist/safety/validators/network-policy-validator.js.map +1 -1
  255. package/dist/sandbox/local-sandbox.d.ts +1 -1
  256. package/dist/sandbox/local-sandbox.js +1 -1
  257. package/dist/sandbox/local-sandbox.js.map +1 -1
  258. package/dist/server/app-context.d.ts +2 -0
  259. package/dist/server/app-context.d.ts.map +1 -1
  260. package/dist/server/app-context.js.map +1 -1
  261. package/dist/server/handlers/attachments.d.ts.map +1 -1
  262. package/dist/server/handlers/attachments.js +1 -0
  263. package/dist/server/handlers/attachments.js.map +1 -1
  264. package/dist/server/handlers/models.d.ts.map +1 -1
  265. package/dist/server/handlers/models.js +3 -1
  266. package/dist/server/handlers/models.js.map +1 -1
  267. package/dist/server/handlers/session-attachments.d.ts.map +1 -1
  268. package/dist/server/handlers/session-attachments.js +2 -0
  269. package/dist/server/handlers/session-attachments.js.map +1 -1
  270. package/dist/server/handlers/sessions.js +1 -1
  271. package/dist/server/handlers/sessions.js.map +1 -1
  272. package/dist/server/handlers/status.d.ts +2 -0
  273. package/dist/server/handlers/status.d.ts.map +1 -1
  274. package/dist/server/handlers/status.js +3 -2
  275. package/dist/server/handlers/status.js.map +1 -1
  276. package/dist/server/headless-runtime-service.d.ts.map +1 -1
  277. package/dist/server/headless-runtime-service.js +32 -3
  278. package/dist/server/headless-runtime-service.js.map +1 -1
  279. package/dist/server/hosted-session-manager.d.ts +2 -0
  280. package/dist/server/hosted-session-manager.d.ts.map +1 -1
  281. package/dist/server/hosted-session-manager.js +9 -0
  282. package/dist/server/hosted-session-manager.js.map +1 -1
  283. package/dist/server/model-selection.d.ts.map +1 -1
  284. package/dist/server/model-selection.js +9 -1
  285. package/dist/server/model-selection.js.map +1 -1
  286. package/dist/server/rate-limiter.d.ts +1 -1
  287. package/dist/server/rate-limiter.js +1 -1
  288. package/dist/server/rate-limiter.js.map +1 -1
  289. package/dist/server/router.d.ts +2 -2
  290. package/dist/server/router.js.map +1 -1
  291. package/dist/server/session-serialization.d.ts +9 -9
  292. package/dist/server/session-serialization.js +15 -15
  293. package/dist/server/session-serialization.js.map +1 -1
  294. package/dist/session/manager.d.ts +5 -0
  295. package/dist/session/manager.d.ts.map +1 -1
  296. package/dist/session/manager.js +56 -8
  297. package/dist/session/manager.js.map +1 -1
  298. package/dist/session/session-catalog.d.ts +2 -0
  299. package/dist/session/session-catalog.d.ts.map +1 -1
  300. package/dist/session/session-catalog.js +6 -0
  301. package/dist/session/session-catalog.js.map +1 -1
  302. package/dist/session/session-context.d.ts +2 -0
  303. package/dist/session/session-context.d.ts.map +1 -1
  304. package/dist/session/session-context.js +15 -0
  305. package/dist/session/session-context.js.map +1 -1
  306. package/dist/session/types.d.ts +7 -0
  307. package/dist/session/types.d.ts.map +1 -1
  308. package/dist/session/types.js.map +1 -1
  309. package/dist/session/wire-format.generated.d.ts +1 -0
  310. package/dist/session/wire-format.generated.d.ts.map +1 -1
  311. package/dist/session/wire-format.generated.js +1 -0
  312. package/dist/session/wire-format.generated.js.map +1 -1
  313. package/dist/shared-memory/contract.d.ts +4 -4
  314. package/dist/shared-memory/contract.js +2 -2
  315. package/dist/shared-memory/contract.js.map +1 -1
  316. package/dist/telemetry/index.d.ts +2 -2
  317. package/dist/telemetry/index.d.ts.map +1 -1
  318. package/dist/telemetry/index.js +2 -2
  319. package/dist/telemetry/index.js.map +1 -1
  320. package/dist/telemetry/maestro-event-bus.d.ts +57 -0
  321. package/dist/telemetry/maestro-event-bus.d.ts.map +1 -1
  322. package/dist/telemetry/maestro-event-bus.js +59 -1
  323. package/dist/telemetry/maestro-event-bus.js.map +1 -1
  324. package/dist/telemetry/maestro-event-catalog.d.ts +17 -1
  325. package/dist/telemetry/maestro-event-catalog.d.ts.map +1 -1
  326. package/dist/telemetry/maestro-event-catalog.js +24 -0
  327. package/dist/telemetry/maestro-event-catalog.js.map +1 -1
  328. package/dist/telemetry/mcp-beacon.d.ts +2 -0
  329. package/dist/telemetry/mcp-beacon.d.ts.map +1 -1
  330. package/dist/telemetry/mcp-beacon.js +15 -0
  331. package/dist/telemetry/mcp-beacon.js.map +1 -1
  332. package/dist/telemetry/metrics.d.ts +62 -0
  333. package/dist/telemetry/metrics.d.ts.map +1 -1
  334. package/dist/telemetry/metrics.js +84 -0
  335. package/dist/telemetry/metrics.js.map +1 -1
  336. package/dist/telemetry.d.ts +44 -0
  337. package/dist/telemetry.d.ts.map +1 -1
  338. package/dist/telemetry.js +84 -2
  339. package/dist/telemetry.js.map +1 -1
  340. package/dist/theme/theme-loader.js +2 -2
  341. package/dist/theme/theme-loader.js.map +1 -1
  342. package/dist/theme/theme-schema.json +2 -2
  343. package/dist/theme/theme.d.ts +1 -1
  344. package/dist/theme/theme.js.map +1 -1
  345. package/dist/tools/background/task-types.d.ts +1 -1
  346. package/dist/tools/extract-document.d.ts +1 -0
  347. package/dist/tools/extract-document.d.ts.map +1 -1
  348. package/dist/tools/extract-document.js +2 -1
  349. package/dist/tools/extract-document.js.map +1 -1
  350. package/dist/tools/index.d.ts +55 -55
  351. package/dist/tools/index.js +1 -1
  352. package/dist/tools/index.js.map +1 -1
  353. package/dist/tools/tool-dsl.d.ts +1 -1
  354. package/dist/tools/tool-dsl.js +1 -1
  355. package/dist/tools/tool-dsl.js.map +1 -1
  356. package/dist/utils/document-extractor.d.ts +1 -0
  357. package/dist/utils/document-extractor.d.ts.map +1 -1
  358. package/dist/utils/document-extractor.js +320 -40
  359. package/dist/utils/document-extractor.js.map +1 -1
  360. package/dist/utils/logger.d.ts +1 -1
  361. package/dist/utils/logger.js +1 -1
  362. package/dist/utils/logger.js.map +1 -1
  363. package/dist/version.json +2 -2
  364. package/dist/web-server.d.ts +1 -1
  365. package/dist/web-server.d.ts.map +1 -1
  366. package/dist/web-server.js +12 -8
  367. package/dist/web-server.js.map +1 -1
  368. package/package.json +4 -2
  369. package/dist/oauth/anthropic.d.ts +0 -17
  370. package/dist/oauth/anthropic.d.ts.map +0 -1
  371. package/dist/oauth/anthropic.js +0 -81
  372. package/dist/oauth/anthropic.js.map +0 -1
  373. package/dist/providers/anthropic-auth.d.ts +0 -75
  374. package/dist/providers/anthropic-auth.d.ts.map +0 -1
  375. package/dist/providers/anthropic-auth.js +0 -221
  376. package/dist/providers/anthropic-auth.js.map +0 -1
@@ -95,6 +95,8 @@ export declare class HostedSessionManager {
95
95
  setSessionAppServerGoal(sessionRef: string, goal: NonNullable<SessionMetaEntry["appServerGoal"]> | null): void;
96
96
  getSessionId(): string;
97
97
  getSessionFile(): string;
98
+ getCurrentLeafId(): string | null;
99
+ branch(branchFromId: string): void;
98
100
  getSessionFileById(sessionId: string): string | null;
99
101
  setSessionFile(sessionRef: string): void;
100
102
  isInitialized(): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"hosted-session-manager.d.ts","sourceRoot":"","sources":["../../src/server/hosted-session-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hosted-session-manager.d.ts","sourceRoot":"","sources":["../../src/server/hosted-session-manager.ts"],"names":[],"mappings":"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"}
@@ -589,6 +589,15 @@ export class HostedSessionManager {
589
589
  getSessionFile() {
590
590
  return `db:${this.sessionId}`;
591
591
  }
592
+ getCurrentLeafId() {
593
+ return this.leafId;
594
+ }
595
+ branch(branchFromId) {
596
+ if (!this.byId.has(branchFromId)) {
597
+ throw new Error(`Entry ${branchFromId} not found`);
598
+ }
599
+ this.leafId = branchFromId;
600
+ }
592
601
  getSessionFileById(sessionId) {
593
602
  return `db:${sessionId}`;
594
603
  }
@@ -1 +1 @@
1
- {"version":3,"file":"hosted-session-manager.js","sourceRoot":"","sources":["../../src/server/hosted-session-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAEnE,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAEN,8BAA8B,EAC9B,eAAe,EACf,4BAA4B,GAC5B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACN,uBAAuB,EACvB,yBAAyB,GACzB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAEN,uBAAuB,EASvB,wCAAwC,EACxC,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,GACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,kCAAkC,EAAE,MAAM,mCAAmC,CAAC;AAIvF,SAAS,sBAAsB,CAAC,KAAc;IAC7C,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjE,OAAO,IAAI,CAAC;IACb,CAAC;IACD,IAAI,OAAQ,KAA4B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC5D,OAAO,IAAI,CAAC;IACb,CAAC;IACD,OAAO,qBAAqB,CAAC,KAAK,CAAC,CAAC;AACrC,CAAC;AAQD,MAAM,OAAO,oBAAoB;IAgBhC,YAAY,OAA4C;QAf/C,gBAAW,GAAG,UAAmB,CAAC;QAInC,cAAS,GAAW,UAAU,EAAE,CAAC;QACjC,YAAO,GAAmB,EAAE,CAAC;QAC7B,SAAI,GAAkC,IAAI,GAAG,EAAE,CAAC;QAChD,WAAM,GAAkB,IAAI,CAAC;QAC7B,uBAAkB,GAAG,KAAK,CAAC;QAC3B,eAAU,GAAqB,OAAO,CAAC,OAAO,EAAE,CAAC;QACjD,kBAAa,GAAG,KAAK,CAAC;QAM7B,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAChC,CAAC;IAEO,eAAe,CAAC,KAA0B;QACjD,MAAM,QAAQ,GAAG,KAC8C,CAAC;QAChE,OAAO;YACN,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,OAAO,EAAE,KAAK,CAAC,EAAE;YACjB,YAAY,EAAE,QAAQ,CAAC,YAAY;YACnC,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,MAAM,EAAE,QAAQ,CAAC,MAAM;SACvB,CAAC;IACH,CAAC;IAEO,OAAO,CAAC,SAA8B;QAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QAC1D,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,IAAI,CAC5B,GAAG,EAAE,CAAC,SAAS,EACf,CAAC,KAAK,EAAE,EAAE;YACT,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;gBACzB,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;gBACxB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;YAC3B,CAAC;QACF,CAAC,CACD,CAAC;IACH,CAAC;IAEO,YAAY,CAAC,OAAuB;QAC3C,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAChC,SAAS;YACV,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC/B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,EAAE,CAAC;QACxB,CAAC;QACD,IAAI,CAAC,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAC9D,CAAC;IAEO,mBAAmB;QAC1B,OAAO,IAAI,CAAC,mBAAmB,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC;IACnD,CAAC;IAEO,gBAAgB,CAAC,UAAmB;QAC3C,IAAI,CAAC,UAAU,EAAE,CAAC;YACjB,OAAO,IAAI,CAAC,SAAS,CAAC;QACvB,CAAC;QACD,OAAO,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC;YAClC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC;YAChC,CAAC,CAAC,UAAU,CAAC;IACf,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAC7B,SAAiB,EACjB,SAAsD,EAAE;QAExD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,KAAK,EAAE;aACX,MAAM,CAAC,cAAc,CAAC;aACtB,MAAM,CAAC;YACP,SAAS;YACT,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,IAAI;YAC7B,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;YAClB,YAAY,EAAE,IAAI,CAAC,mBAAmB,EAAE;YACxC,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;YACd,GAAG,MAAM;SACT,CAAC;aACD,kBAAkB,CAAC;YACnB,MAAM,EAAE,cAAc,CAAC,SAAS;YAChC,GAAG,EAAE;gBACJ,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI;gBAC/C,GAAG,EAAE,MAAM,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE;gBAChC,SAAS,EAAE,GAAG;gBACd,SAAS,EAAE,IAAI;gBACf,GAAG,MAAM;aACT;SACD,CAAC,CAAC;IACL,CAAC;IAEO,WAAW,CAAC,KAAmB;QACtC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC/B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,EAAE,CAAC;QACxB,CAAC;QACD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;QACjC,MAAM,OAAO,GACZ,IAAI,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACtE,MAAM,YAAY,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAEhD,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE;YACvB,MAAM,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC;YACzD,MAAM,KAAK,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,MAAM,CAAC;gBACjD,SAAS;gBACT,SAAS,EAAE,KAAK,CAAC,IAAI;gBACrB,OAAO;gBACP,KAAK;aACL,CAAC,CAAC;YACH,MAAM,KAAK,EAAE;iBACX,MAAM,CAAC,cAAc,CAAC;iBACtB,GAAG,CAAC;gBACJ,YAAY;gBACZ,SAAS,EAAE,IAAI,IAAI,EAAE;aACrB,CAAC;iBACD,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;IACJ,CAAC;IAEO,sBAAsB,CAC7B,SAAiB,EACjB,MAAoD,EACpD,aAA0D,EAAE;QAE5D,MAAM,KAAK,GAAqB;YAC/B,IAAI,EAAE,cAAc;YACpB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,GAAG,MAAM;SACT,CAAC;QACF,IAAI,SAAS,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;YAClC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;QACD,MAAM,YAAY,GACjB,SAAS,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACvE,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE;YACvB,IAAI,SAAS,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;gBAClC,MAAM,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC;YAC1D,CAAC;YACD,MAAM,KAAK,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,MAAM,CAAC;gBACjD,SAAS;gBACT,SAAS,EAAE,KAAK,CAAC,IAAI;gBACrB,KAAK;aACL,CAAC,CAAC;YACH,MAAM,KAAK,EAAE;iBACX,MAAM,CAAC,cAAc,CAAC;iBACtB,GAAG,CAAC;gBACJ,GAAG,UAAU;gBACb,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvD,SAAS,EAAE,IAAI,IAAI,EAAE;aACrB,CAAC;iBACD,KAAK,CACL,GAAG,CACF,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,EACvC,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,EACpC,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAChC,CACD,CAAC;QACJ,CAAC,CAAC,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,OAAO,CAAC,SAAiB;QACtC,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,KAAK,EAAE;aACzB,MAAM,EAAE;aACR,IAAI,CAAC,cAAc,CAAC;aACpB,KAAK,CACL,GAAG,CACF,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,EACvC,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,EACpC,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAChC,CACD;aACA,KAAK,CAAC,CAAC,CAAC,CAAC;QACX,OAAO,GAAG,IAAI,IAAI,CAAC;IACpB,CAAC;IAEO,KAAK,CAAC,qBAAqB,CAClC,SAAiB;QAEjB,MAAM,IAAI,GAAG,MAAM,KAAK,EAAE;aACxB,MAAM,CAAC,EAAE,KAAK,EAAE,oBAAoB,CAAC,KAAK,EAAE,CAAC;aAC7C,IAAI,CAAC,oBAAoB,CAAC;aAC1B,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;aACpD,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC,CAAC;QAE9C,MAAM,OAAO,GAAmB,EAAE,CAAC;QACnC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACxB,MAAM,KAAK,GAAG,sBAAsB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAChD,IAAI,KAAK,EAAE,CAAC;gBACX,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrB,CAAC;QACF,CAAC;QACD,OAAO,OAAO,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,SAAiB;QAClC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC1C,IAAI,CAAC,GAAG,EAAE,CAAC;YACV,OAAO,IAAI,CAAC;QACb,CAAC;QACD,OAAO,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,SAAiB;QACpC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACnB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC1C,IAAI,CAAC,GAAG,EAAE,CAAC;YACV,OAAO,KAAK,CAAC;QACd,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;QAC5D,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC;QAC/B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAC3B,OAAO,IAAI,CAAC;IACb,CAAC;IAED,eAAe;QACd,OAAO,EAAE,CAAC;IACX,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,KAAW;QACpC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACnB,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,KAAK,EAAE;aACzB,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,CAAQ,eAAe,EAAE,CAAC;aAC7C,IAAI,CAAC,cAAc,CAAC;aACpB,KAAK,CACL,GAAG,CACF,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,EACpC,GAAG,CAAC,cAAc,CAAC,SAAS,EAAE,KAAK,CAAC,EACpC,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAChC,CACD,CAAC;QACH,OAAO,MAAM,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAGlB;QACA,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,KAAK,GAAG,KAAK,EAAE;aACjB,MAAM,EAAE;aACR,IAAI,CAAC,cAAc,CAAC;aACpB,KAAK,CACL,GAAG,CACF,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,EACpC,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAChC,CACD;aACA,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;aACvC,QAAQ,EAAE,CAAC;QACb,IAAI,OAAO,OAAO,EAAE,KAAK,KAAK,QAAQ,EAAE,CAAC;YACxC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;QACD,IAAI,OAAO,OAAO,EAAE,MAAM,KAAK,QAAQ,EAAE,CAAC;YACzC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACtC,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC;QAEzB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACzB,EAAE,EAAE,GAAG,CAAC,SAAS;YACjB,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,SAAS;YACjC,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,SAAS;YAC7B,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,SAAS;YACjC,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,SAAS;YAC7C,oBAAoB,EAAE,GAAG,CAAC,oBAAoB,IAAI,SAAS;YAC3D,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,WAAW,EAAE;YACtC,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,WAAW,EAAE;YACtC,YAAY,EAAE,GAAG,CAAC,YAAY;YAC9B,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,SAAS;SAC3B,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,WAAW,CAChB,SAAiB,EACjB,UAAkD,EAAE;QAgBpD,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACnB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC1C,IAAI,CAAC,GAAG,EAAE,CAAC;YACV,OAAO,IAAI,CAAC;QACb,CAAC;QACD,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,MAAM,CAAC;QACpD,IAAI,YAAY,KAAK,WAAW,EAAE,CAAC;YAClC,OAAO;gBACN,EAAE,EAAE,GAAG,CAAC,SAAS;gBACjB,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,SAAS;gBACjC,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,SAAS;gBAC7B,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,SAAS;gBACjC,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,SAAS;gBAC7C,oBAAoB,EAAE,GAAG,CAAC,oBAAoB,IAAI,SAAS;gBAC3D,QAAQ,EAAE,EAAE;gBACZ,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,WAAW,EAAE;gBACtC,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,WAAW,EAAE;gBACtC,YAAY,EAAE,GAAG,CAAC,YAAY;gBAC9B,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,SAAS;gBAC3B,YAAY;aACZ,CAAC;QACH,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;QAC5D,MAAM,OAAO,GAAG,8BAA8B,CAAC,OAAO,CAAC,CAAC;QACxD,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;QAChD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC7B,IACC,KAAK,CAAC,IAAI,KAAK,oBAAoB;gBACnC,KAAK,CAAC,YAAY;gBAClB,KAAK,CAAC,aAAa,EAClB,CAAC;gBACF,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;YAC5D,CAAC;QACF,CAAC;QACD,MAAM,QAAQ,GACb,aAAa,CAAC,IAAI,KAAK,CAAC;YACvB,CAAC,CAAC,OAAO,CAAC,QAAQ;YAClB,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CACjC,uBAAuB,CAAC,OAAO,EAAE,aAAa,CAAC,CAC/C,CAAC;QACL,MAAM,YAAY,GAAG,GAAG,CAAC,YAAY,IAAI,QAAQ,CAAC,MAAM,CAAC;QACzD,MAAM,gBAAgB,GAAG,4BAA4B,CACpD,QAAQ,EACR,YAAY,CACZ,CAAC;QAEF,OAAO;YACN,EAAE,EAAE,GAAG,CAAC,SAAS;YACjB,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,SAAS;YACjC,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,SAAS;YAC7B,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,SAAS;YACjC,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,SAAS;YAC7C,oBAAoB,EAAE,GAAG,CAAC,oBAAoB,IAAI,SAAS;YAC3D,QAAQ,EAAE,gBAAgB;YAC1B,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,WAAW,EAAE;YACtC,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,WAAW,EAAE;YACtC,YAAY;YACZ,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,SAAS;YAC3B,YAAY;SACZ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAA4B;QAW/C,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,SAAS,GAAG,UAAU,EAAE,CAAC;QAC9B,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;QAClB,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;QACtB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,SAAS,EAAE;YAC3C,KAAK,EAAE,OAAO,EAAE,KAAK;YACrB,QAAQ,EAAE,KAAK;YACf,YAAY,EAAE,CAAC;YACf,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;SACd,CAAC,CAAC;QACH,OAAO;YACN,EAAE,EAAE,IAAI,CAAC,SAAS;YAClB,KAAK,EAAE,OAAO,EAAE,KAAK;YACrB,QAAQ,EAAE,EAAE;YACZ,SAAS,EAAE,GAAG,CAAC,WAAW,EAAE;YAC5B,SAAS,EAAE,GAAG,CAAC,WAAW,EAAE;YAC5B,YAAY,EAAE,CAAC;YACf,QAAQ,EAAE,KAAK;SACf,CAAC;IACH,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,SAAiB;QACpC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACnB,MAAM,KAAK,EAAE;aACX,MAAM,CAAC,cAAc,CAAC;aACtB,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;aACrD,KAAK,CACL,GAAG,CACF,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,EACvC,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CACpC,CACD,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,8BAA8B,CACnC,KAAiB,EACjB,eAAuB;QAEvB,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACnB,MAAM,YAAY,GAAG,UAAU,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC3C,MAAM,QAAQ,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;QAC7D,MAAM,aAAa,GAAmB;YACrC;gBACC,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,uBAAuB;gBAChC,EAAE,EAAE,YAAY;gBAChB,SAAS;gBACT,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;gBAClB,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,KAAK,EAAE,QAAQ;gBACf,aAAa,EAAE,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC;gBAChD,aAAa,EAAE,KAAK,CAAC,aAAa;gBAClC,YAAY,EAAE,KAAK,CAAC,YAAY;gBAChC,cAAc,EAAE,KAAK,CAAC,cAAc;gBACpC,qBAAqB,EAAE,wCAAwC,CAAC,KAAK,CAAC;gBACtE,sBAAsB,EAAE,KAAK,CAAC,sBAAsB;gBACpD,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;oBACjC,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,WAAW,EAAE,IAAI,CAAC,WAAW;iBAC7B,CAAC,CAAC;gBACH,YAAY,EAAE,IAAI,CAAC,SAAS;gBAC5B,aAAa,EAAE,IAAI,CAAC,SAAS;aACA;SAC9B,CAAC;QACF,MAAM,SAAS,GAAG,IAAI,GAAG,EAA4B,CAAC;QACtD,IAAI,QAAQ,GAAkB,IAAI,CAAC;QACnC,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,EAAE,CAAC;YAChE,MAAM,KAAK,GAAqB;gBAC/B,IAAI,EAAE,SAAS;gBACf,EAAE,EAAE,eAAe,CAAC,SAAS,CAAC;gBAC9B,QAAQ;gBACR,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,OAAO,EAAE,yBAAyB,CAAC,OAAO,CAAC;aAC3C,CAAC;YACF,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC/B,QAAQ,GAAG,KAAK,CAAC,EAAE,CAAC;YACpB,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,KAAK,EAAE;aACX,MAAM,CAAC,cAAc,CAAC;aACtB,MAAM,CAAC;YACP,SAAS,EAAE,YAAY;YACvB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;YAClB,KAAK,EAAE,QAAQ;YACf,aAAa,EAAE,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC;YAChD,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,YAAY,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC;iBACrE,MAAM;YACR,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;SACd,CAAC,CAAC;QACJ,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;YACnC,MAAM,KAAK,EAAE;iBACX,MAAM,CAAC,oBAAoB,CAAC;iBAC5B,MAAM,CAAC;gBACP,SAAS,EAAE,YAAY;gBACvB,SAAS,EAAE,KAAK,CAAC,IAAI;gBACrB,OAAO,EACN,IAAI,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ;oBAC5C,CAAC,CAAC,KAAK,CAAC,EAAE;oBACV,CAAC,CAAC,SAAS;gBACb,KAAK;aACL,CAAC,CAAC;QACL,CAAC;QACD,OAAO,YAAY,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,qBAAqB,CAC1B,SAAiB,EACjB,OAAoC;QAEpC,MAAM,GAAG,GAAgD,EAAE,CAAC;QAC5D,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;YAAE,GAAG,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3D,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS;YAAE,GAAG,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACpE,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS;YAAE,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QACxD,IAAI,CAAC,sBAAsB,CAC1B,SAAS,EACT;YACC,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChE,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS;gBACjC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE;gBAChC,CAAC,CAAC,EAAE,CAAC;YACN,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC7D,EACD,GAAG,CACH,CAAC;QACF,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;IAED,YAAY,CAAC,KAAiB,EAAE,OAA8B;QAC7D,IAAI,IAAI,CAAC,kBAAkB;YAAE,OAAO;QAEpC,MAAM,QAAQ,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;QAC7D,MAAM,KAAK,GAAuB;YACjC,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,uBAAuB;YAChC,EAAE,EAAE,IAAI,CAAC,SAAS;YAClB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;YAClB,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,IAAI,CAAC,OAAO;YACzC,KAAK,EAAE,QAAQ;YACf,aAAa,EAAE,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC;YAChD,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,qBAAqB,EAAE,wCAAwC,CAAC,KAAK,CAAC;YACtE,sBAAsB,EAAE,KAAK,CAAC,sBAAsB;YACpD,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBACjC,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,WAAW,EAAE,IAAI,CAAC,WAAW;aAC7B,CAAC,CAAC;SACH,CAAC;QACF,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;QAC/B,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAExB,uBAAuB,CAAC;YACvB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,KAAK,EAAE;gBACN,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;gBAClB,KAAK,EAAE,QAAQ;gBACf,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,MAAM,EAAE,SAAS;aACjB;YACD,KAAK,EAAE;gBACN,IAAI,EAAE,yBAAyB;gBAC/B,OAAO,EAAE;oBACR,SAAS,EAAE,IAAI,CAAC,SAAS;oBACzB,KAAK,EAAE,QAAQ;oBACf,SAAS,EAAE,KAAK,CAAC,SAAS;iBAC1B;aACD;SACD,CAAC,CAAC;QAEH,IAAI,KAAK,CAAC,cAAc,EAAE,CAAC;YAC1B,kCAAkC,CAAC;gBAClC,eAAe,EAAE,KAAK,CAAC,cAAc;gBACrC,WAAW,EAAE;oBACZ,UAAU,EAAE,IAAI,CAAC,SAAS;iBAC1B;gBACD,WAAW,EAAE,KAAK,CAAC,SAAS;aAC5B,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;IAED,WAAW,CAAC,OAAmB;QAC9B,MAAM,gBAAgB,GAAG,yBAAyB,CAAC,OAAO,CAAC,CAAC;QAC5D,MAAM,KAAK,GAAqB;YAC/B,IAAI,EAAE,SAAS;YACf,EAAE,EAAE,IAAI,CAAC,iBAAiB,EAAE;YAC5B,QAAQ,EAAE,IAAI,CAAC,MAAM;YACrB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,OAAO,EAAE,gBAAgB;SACzB,CAAC;QACF,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAExB,uBAAuB,CAAC;YACvB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,KAAK,EAAE;gBACN,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,aAAa,EAAE,KAAK,CAAC,EAAE;gBACvB,eAAe,EAAE,OAAO,CAAC,IAAI;gBAC7B,MAAM,EAAE,SAAS;aACjB;YACD,KAAK,EAAE;gBACN,IAAI,EAAE,uBAAuB;gBAC7B,OAAO,EAAE;oBACR,SAAS,EAAE,IAAI,CAAC,SAAS;oBACzB,SAAS,EAAE,KAAK,CAAC,EAAE;oBACnB,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,SAAS,EAAE,KAAK,CAAC,SAAS;iBAC1B;aACD;SACD,CAAC,CAAC;IACJ,CAAC;IAED,cAAc,CACb,OAAe,EACf,mBAA2B,EAC3B,YAAoB,EACpB,OAIC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3C,MAAM,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC;QAClE,MAAM,gBAAgB,GACrB,OAAO,EAAE,gBAAgB,IAAI,aAAa,EAAE,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC;QAC/D,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACvB,OAAO;QACR,CAAC;QACD,MAAM,KAAK,GAAoB;YAC9B,IAAI,EAAE,YAAY;YAClB,EAAE,EAAE,IAAI,CAAC,iBAAiB,EAAE;YAC5B,QAAQ,EAAE,IAAI,CAAC,MAAM;YACrB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,OAAO;YACP,gBAAgB;YAChB,YAAY;YACZ,IAAI,EAAE,OAAO,EAAE,IAAI;YACnB,kBAAkB,EAAE,OAAO,EAAE,kBAAkB;SAC/C,CAAC;QACF,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IAED,wBAAwB,CACvB,UAAkB,EAClB,YAAoB,EACpB,IAAY;QAEZ,IAAI,CAAC,YAAY,IAAI,CAAC,IAAI;YAAE,OAAO;QACnC,MAAM,KAAK,GAA6B;YACvC,IAAI,EAAE,oBAAoB;YAC1B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,YAAY;YACZ,aAAa,EAAE,IAAI;SACnB,CAAC;QACF,MAAM,eAAe,GAAG,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC;YACnD,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC;YAChC,CAAC,CAAC,UAAU,CAAC;QACd,IAAI,eAAe,IAAI,eAAe,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;YAC3D,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE;gBACvB,MAAM,KAAK,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,MAAM,CAAC;oBACjD,SAAS,EAAE,eAAe;oBAC1B,SAAS,EAAE,KAAK,CAAC,IAAI;oBACrB,KAAK;iBACL,CAAC,CAAC;gBACH,MAAM,KAAK,EAAE;qBACX,MAAM,CAAC,cAAc,CAAC;qBACtB,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;qBAC9B,KAAK,CACL,GAAG,CACF,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,eAAe,CAAC,EAC7C,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,EACpC,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAChC,CACD,CAAC;YACJ,CAAC,CAAC,CAAC;YACH,OAAO;QACR,CAAC;QACD,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IAED,kBAAkB,CAAC,OAAe,EAAE,UAAmB;QACtD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QACpD,IAAI,CAAC,sBAAsB,CAC1B,SAAS,EACT,EAAE,OAAO,EAAE,OAAO,EAAE,EACpB,EAAE,OAAO,EAAE,OAAO,EAAE,CACpB,CAAC;IACH,CAAC;IAED,wBAAwB,CAAC,OAAe,EAAE,UAAmB;QAC5D,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QACpD,IAAI,CAAC,sBAAsB,CAC1B,SAAS,EACT,EAAE,aAAa,EAAE,OAAO,EAAE,EAC1B,EAAE,aAAa,EAAE,OAAO,EAAE,CAC1B,CAAC;IACH,CAAC;IAED,+BAA+B,CAAC,IAAY,EAAE,UAAmB;QAChE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QACpD,IAAI,CAAC,sBAAsB,CAC1B,SAAS,EACT,EAAE,oBAAoB,EAAE,OAAO,EAAE,EACjC,EAAE,oBAAoB,EAAE,OAAO,EAAE,CACjC,CAAC;IACH,CAAC;IAED,kBAAkB,CAAC,UAAkB,EAAE,QAAiB;QACvD,IAAI,CAAC,sBAAsB,CAC1B,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,EACjC,EAAE,QAAQ,EAAE,EACZ,EAAE,QAAQ,EAAE,CACZ,CAAC;IACH,CAAC;IAED,eAAe,CAAC,UAAkB,EAAE,KAAa;QAChD,IAAI,CAAC,sBAAsB,CAC1B,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,EACjC,EAAE,KAAK,EAAE,EACT,EAAE,KAAK,EAAE,CACT,CAAC;IACH,CAAC;IAED,cAAc,CAAC,UAAkB,EAAE,IAAc;QAChD,IAAI,CAAC,sBAAsB,CAC1B,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,EACjC,EAAE,IAAI,EAAE,EACR,EAAE,IAAI,EAAE,CACR,CAAC;IACH,CAAC;IAED,uBAAuB,CACtB,UAAkB,EAClB,IAA2D;QAE3D,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,EAAE;YAC9D,aAAa,EAAE,IAAI;SACnB,CAAC,CAAC;IACJ,CAAC;IAED,YAAY;QACX,OAAO,IAAI,CAAC,SAAS,CAAC;IACvB,CAAC;IAED,cAAc;QACb,OAAO,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;IAC/B,CAAC;IAED,kBAAkB,CAAC,SAAiB;QACnC,OAAO,MAAM,SAAS,EAAE,CAAC;IAC1B,CAAC;IAED,cAAc,CAAC,UAAkB;QAChC,MAAM,SAAS,GAAG,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC;YAC7C,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC;YAChC,CAAC,CAAC,UAAU,CAAC;QACd,IAAI,SAAS,EAAE,CAAC;YACf,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC5B,CAAC;IACF,CAAC;IAED,aAAa;QACZ,OAAO,IAAI,CAAC,kBAAkB,CAAC;IAChC,CAAC;IAED,uBAAuB,CAAC,QAAsB;QAC7C,OAAO,CACN,CAAC,IAAI,CAAC,kBAAkB;YACxB,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC,CACnD,CAAC;IACH,CAAC;IAED,cAAc,CAAC,KAAiB,EAAE,QAA+B;QAChE,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,QAAQ,EAAE,CAAC;YACd,IAAI,CAAC,iBAAiB,GAAG,QAAQ,CAAC;QACnC,CAAC;IACF,CAAC;IAED,mBAAmB,CAClB,SAAwB,IAAI,CAAC,MAAM;QAEnC,OAAO,8BAA8B,CAAC,IAAI,CAAC,OAAO,EAAE;YACnD,MAAM;YACN,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE;SACxB,CAAC,CAAC;IACJ,CAAC;IAED,SAAS;QACR,OAAO,IAAI,CAAC,mBAAmB,EAAE,CAAC,KAAK,CAAC;IACzC,CAAC;IAED,iBAAiB;QAChB,OAAO,IAAI,CAAC,mBAAmB,EAAE,CAAC,aAAa,CAAC;IACjD,CAAC;IAED,SAAS;QACR,OAAO,CACL,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAEzC,IAAI,IAAI,CACrB,CAAC;IACH,CAAC;IAEO,iBAAiB;QACxB,OAAO,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,KAAK;QACV,MAAM,IAAI,CAAC,UAAU,CAAC;QACtB,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC;YAC9B,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;YAC5B,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;YAC3B,MAAM,KAAK,CAAC;QACb,CAAC;IACF,CAAC;CACD;AAED,MAAM,UAAU,sBAAsB,CACrC,OAAgB;IAEhB,OAAO,CACN,OAAO,OAAO,KAAK,QAAQ;QAC3B,OAAO,KAAK,IAAI;QAChB,aAAa,IAAI,OAAO;QACvB,OAAqC,CAAC,WAAW,KAAK,UAAU,CACjE,CAAC;AACH,CAAC","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { and, asc, desc, eq, gte, isNull, sql } from \"drizzle-orm\";\nimport type { AgentState, AppMessage } from \"../agent/types.js\";\nimport { getDb } from \"../db/client.js\";\nimport { hostedSessionEntries, hostedSessions } from \"../db/schema.js\";\nimport {\n\ttype SessionContextSnapshot,\n\tbuildSessionContextFromEntries,\n\tgenerateEntryId,\n\tselectSessionMessagesForView,\n} from \"../session/session-context.js\";\nimport {\n\tapplyAttachmentExtracts,\n\tsanitizeMessageForSession,\n} from \"../session/session-sanitize.js\";\nimport type { SessionMetadata } from \"../session/types.js\";\nimport {\n\ttype AttachmentExtractedEntry,\n\tCURRENT_SESSION_VERSION,\n\ttype CompactionEntry,\n\ttype SessionEntry,\n\ttype SessionHeaderEntry,\n\ttype SessionMessagesView,\n\ttype SessionMetaEntry,\n\ttype SessionModelMetadata,\n\ttype SessionSummary,\n\ttype SessionTreeEntry,\n\tgetPersistedSessionPromptContextManifest,\n\tisSessionHeaderEntry,\n\tisSessionTreeEntry,\n\tnormalizeSessionEntry,\n} from \"../session/types.js\";\nimport { queueSharedMemoryUpdate } from \"../shared-memory/client.js\";\nimport { recordMaestroPromptVariantSelected } from \"../telemetry/maestro-event-bus.js\";\n\ntype SessionRow = typeof hostedSessions.$inferSelect;\n\nfunction parseSessionEntryValue(value: unknown): SessionEntry | null {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\treturn null;\n\t}\n\tif (typeof (value as { type?: unknown }).type !== \"string\") {\n\t\treturn null;\n\t}\n\treturn normalizeSessionEntry(value);\n}\n\nexport interface HostedSessionMetadataUpdate {\n\ttitle?: string;\n\tfavorite?: boolean;\n\ttags?: string[];\n}\n\nexport class HostedSessionManager {\n\treadonly storageKind = \"database\" as const;\n\n\tprivate readonly scope: string;\n\tprivate readonly subject?: string;\n\tprivate sessionId: string = randomUUID();\n\tprivate entries: SessionEntry[] = [];\n\tprivate byId: Map<string, SessionTreeEntry> = new Map();\n\tprivate leafId: string | null = null;\n\tprivate sessionInitialized = false;\n\tprivate writeChain: Promise<unknown> = Promise.resolve();\n\tprivate hasWriteError = false;\n\tprivate writeError: unknown;\n\tprivate snapshot?: AgentState;\n\tprivate lastModelMetadata?: SessionModelMetadata;\n\n\tconstructor(options: { scope: string; subject?: string }) {\n\t\tthis.scope = options.scope;\n\t\tthis.subject = options.subject;\n\t}\n\n\tprivate toModelMetadata(model: AgentState[\"model\"]): SessionModelMetadata {\n\t\tconst optional = model as AgentState[\"model\"] &\n\t\t\tPartial<Pick<SessionModelMetadata, \"providerName\" | \"source\">>;\n\t\treturn {\n\t\t\tprovider: model.provider,\n\t\t\tmodelId: model.id,\n\t\t\tproviderName: optional.providerName,\n\t\t\tname: model.name,\n\t\t\tbaseUrl: model.baseUrl,\n\t\t\treasoning: model.reasoning,\n\t\t\tcontextWindow: model.contextWindow,\n\t\t\tmaxTokens: model.maxTokens,\n\t\t\tsource: optional.source,\n\t\t};\n\t}\n\n\tprivate enqueue(operation: () => Promise<void>): void {\n\t\tconst result = this.writeChain.then(operation, operation);\n\t\tthis.writeChain = result.then(\n\t\t\t() => undefined,\n\t\t\t(error) => {\n\t\t\t\tif (!this.hasWriteError) {\n\t\t\t\t\tthis.writeError = error;\n\t\t\t\t\tthis.hasWriteError = true;\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\t}\n\n\tprivate rebuildIndex(entries: SessionEntry[]): void {\n\t\tthis.byId.clear();\n\t\tthis.leafId = null;\n\t\tfor (const entry of entries) {\n\t\t\tif (!isSessionTreeEntry(entry)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis.byId.set(entry.id, entry);\n\t\t\tthis.leafId = entry.id;\n\t\t}\n\t\tthis.sessionInitialized = entries.some(isSessionHeaderEntry);\n\t}\n\n\tprivate currentMessageCount(): number {\n\t\treturn this.buildSessionContext().messages.length;\n\t}\n\n\tprivate resolveSessionId(sessionRef?: string): string {\n\t\tif (!sessionRef) {\n\t\t\treturn this.sessionId;\n\t\t}\n\t\treturn sessionRef.startsWith(\"db:\")\n\t\t\t? sessionRef.slice(\"db:\".length)\n\t\t\t: sessionRef;\n\t}\n\n\tprivate async ensureSessionRow(\n\t\tsessionId: string,\n\t\tvalues: Partial<typeof hostedSessions.$inferInsert> = {},\n\t): Promise<void> {\n\t\tconst now = new Date();\n\t\tawait getDb()\n\t\t\t.insert(hostedSessions)\n\t\t\t.values({\n\t\t\t\tsessionId,\n\t\t\t\tscope: this.scope,\n\t\t\t\tsubject: this.subject ?? null,\n\t\t\t\tcwd: process.cwd(),\n\t\t\t\tmessageCount: this.currentMessageCount(),\n\t\t\t\tcreatedAt: now,\n\t\t\t\tupdatedAt: now,\n\t\t\t\t...values,\n\t\t\t})\n\t\t\t.onConflictDoUpdate({\n\t\t\t\ttarget: hostedSessions.sessionId,\n\t\t\t\tset: {\n\t\t\t\t\tscope: this.scope,\n\t\t\t\t\tsubject: values.subject ?? this.subject ?? null,\n\t\t\t\t\tcwd: values.cwd ?? process.cwd(),\n\t\t\t\t\tupdatedAt: now,\n\t\t\t\t\tdeletedAt: null,\n\t\t\t\t\t...values,\n\t\t\t\t},\n\t\t\t});\n\t}\n\n\tprivate appendEntry(entry: SessionEntry): void {\n\t\tthis.entries.push(entry);\n\t\tif (isSessionTreeEntry(entry)) {\n\t\t\tthis.byId.set(entry.id, entry);\n\t\t\tthis.leafId = entry.id;\n\t\t}\n\t\tconst sessionId = this.sessionId;\n\t\tconst entryId =\n\t\t\t\"id\" in entry && typeof entry.id === \"string\" ? entry.id : undefined;\n\t\tconst messageCount = this.currentMessageCount();\n\n\t\tthis.enqueue(async () => {\n\t\t\tawait this.ensureSessionRow(sessionId, { messageCount });\n\t\t\tawait getDb().insert(hostedSessionEntries).values({\n\t\t\t\tsessionId,\n\t\t\t\tentryType: entry.type,\n\t\t\t\tentryId,\n\t\t\t\tentry,\n\t\t\t});\n\t\t\tawait getDb()\n\t\t\t\t.update(hostedSessions)\n\t\t\t\t.set({\n\t\t\t\t\tmessageCount,\n\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t})\n\t\t\t\t.where(eq(hostedSessions.sessionId, sessionId));\n\t\t});\n\t}\n\n\tprivate appendSessionMetaEntry(\n\t\tsessionId: string,\n\t\tfields: Omit<SessionMetaEntry, \"type\" | \"timestamp\">,\n\t\trowUpdates: Partial<typeof hostedSessions.$inferInsert> = {},\n\t): void {\n\t\tconst entry: SessionMetaEntry = {\n\t\t\ttype: \"session_meta\",\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t...fields,\n\t\t};\n\t\tif (sessionId === this.sessionId) {\n\t\t\tthis.entries.push(entry);\n\t\t}\n\t\tconst messageCount =\n\t\t\tsessionId === this.sessionId ? this.currentMessageCount() : undefined;\n\t\tthis.enqueue(async () => {\n\t\t\tif (sessionId === this.sessionId) {\n\t\t\t\tawait this.ensureSessionRow(sessionId, { messageCount });\n\t\t\t}\n\t\t\tawait getDb().insert(hostedSessionEntries).values({\n\t\t\t\tsessionId,\n\t\t\t\tentryType: entry.type,\n\t\t\t\tentry,\n\t\t\t});\n\t\t\tawait getDb()\n\t\t\t\t.update(hostedSessions)\n\t\t\t\t.set({\n\t\t\t\t\t...rowUpdates,\n\t\t\t\t\t...(messageCount !== undefined ? { messageCount } : {}),\n\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t})\n\t\t\t\t.where(\n\t\t\t\t\tand(\n\t\t\t\t\t\teq(hostedSessions.sessionId, sessionId),\n\t\t\t\t\t\teq(hostedSessions.scope, this.scope),\n\t\t\t\t\t\tisNull(hostedSessions.deletedAt),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t});\n\t}\n\n\tprivate async loadRow(sessionId: string): Promise<SessionRow | null> {\n\t\tconst [row] = await getDb()\n\t\t\t.select()\n\t\t\t.from(hostedSessions)\n\t\t\t.where(\n\t\t\t\tand(\n\t\t\t\t\teq(hostedSessions.sessionId, sessionId),\n\t\t\t\t\teq(hostedSessions.scope, this.scope),\n\t\t\t\t\tisNull(hostedSessions.deletedAt),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.limit(1);\n\t\treturn row ?? null;\n\t}\n\n\tprivate async loadEntriesForSession(\n\t\tsessionId: string,\n\t): Promise<SessionEntry[]> {\n\t\tconst rows = await getDb()\n\t\t\t.select({ entry: hostedSessionEntries.entry })\n\t\t\t.from(hostedSessionEntries)\n\t\t\t.where(eq(hostedSessionEntries.sessionId, sessionId))\n\t\t\t.orderBy(asc(hostedSessionEntries.sequence));\n\n\t\tconst entries: SessionEntry[] = [];\n\t\tfor (const row of rows) {\n\t\t\tconst entry = parseSessionEntryValue(row.entry);\n\t\t\tif (entry) {\n\t\t\t\tentries.push(entry);\n\t\t\t}\n\t\t}\n\t\treturn entries;\n\t}\n\n\tasync loadEntries(sessionId: string): Promise<SessionEntry[] | null> {\n\t\tconst row = await this.loadRow(sessionId);\n\t\tif (!row) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this.loadEntriesForSession(sessionId);\n\t}\n\n\tasync resumeSession(sessionId: string): Promise<boolean> {\n\t\tawait this.flush();\n\t\tconst row = await this.loadRow(sessionId);\n\t\tif (!row) {\n\t\t\treturn false;\n\t\t}\n\t\tconst entries = await this.loadEntriesForSession(sessionId);\n\t\tthis.sessionId = row.sessionId;\n\t\tthis.entries = entries;\n\t\tthis.rebuildIndex(entries);\n\t\treturn true;\n\t}\n\n\tloadAllSessions(): SessionMetadata[] {\n\t\treturn [];\n\t}\n\n\tasync countActiveSessions(since: Date): Promise<number> {\n\t\tawait this.flush();\n\t\tconst [row] = await getDb()\n\t\t\t.select({ count: sql<number>`count(*)::int` })\n\t\t\t.from(hostedSessions)\n\t\t\t.where(\n\t\t\t\tand(\n\t\t\t\t\teq(hostedSessions.scope, this.scope),\n\t\t\t\t\tgte(hostedSessions.updatedAt, since),\n\t\t\t\t\tisNull(hostedSessions.deletedAt),\n\t\t\t\t),\n\t\t\t);\n\t\treturn Number(row?.count ?? 0);\n\t}\n\n\tasync listSessions(options?: {\n\t\tlimit?: number;\n\t\toffset?: number;\n\t}): Promise<SessionSummary[]> {\n\t\tawait this.flush();\n\t\tlet query = getDb()\n\t\t\t.select()\n\t\t\t.from(hostedSessions)\n\t\t\t.where(\n\t\t\t\tand(\n\t\t\t\t\teq(hostedSessions.scope, this.scope),\n\t\t\t\t\tisNull(hostedSessions.deletedAt),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.orderBy(desc(hostedSessions.updatedAt))\n\t\t\t.$dynamic();\n\t\tif (typeof options?.limit === \"number\") {\n\t\t\tquery = query.limit(options.limit);\n\t\t}\n\t\tif (typeof options?.offset === \"number\") {\n\t\t\tquery = query.offset(options.offset);\n\t\t}\n\t\tconst rows = await query;\n\n\t\treturn rows.map((row) => ({\n\t\t\tid: row.sessionId,\n\t\t\tsubject: row.subject ?? undefined,\n\t\t\ttitle: row.title ?? undefined,\n\t\t\tsummary: row.summary ?? undefined,\n\t\t\tresumeSummary: row.resumeSummary ?? undefined,\n\t\t\tmemoryExtractionHash: row.memoryExtractionHash ?? undefined,\n\t\t\tcreatedAt: row.createdAt.toISOString(),\n\t\t\tupdatedAt: row.updatedAt.toISOString(),\n\t\t\tmessageCount: row.messageCount,\n\t\t\tfavorite: row.favorite,\n\t\t\ttags: row.tags ?? undefined,\n\t\t}));\n\t}\n\n\tasync loadSession(\n\t\tsessionId: string,\n\t\toptions: { messagesView?: SessionMessagesView } = {},\n\t): Promise<{\n\t\tid: string;\n\t\tsubject?: string;\n\t\ttitle?: string;\n\t\tsummary?: string;\n\t\tresumeSummary?: string;\n\t\tmemoryExtractionHash?: string;\n\t\tmessages: AppMessage[];\n\t\tcreatedAt: string;\n\t\tupdatedAt: string;\n\t\tmessageCount: number;\n\t\tfavorite: boolean;\n\t\ttags?: string[];\n\t\tmessagesView: SessionMessagesView;\n\t} | null> {\n\t\tawait this.flush();\n\t\tconst row = await this.loadRow(sessionId);\n\t\tif (!row) {\n\t\t\treturn null;\n\t\t}\n\t\tconst messagesView = options.messagesView ?? \"full\";\n\t\tif (messagesView === \"notLoaded\") {\n\t\t\treturn {\n\t\t\t\tid: row.sessionId,\n\t\t\t\tsubject: row.subject ?? undefined,\n\t\t\t\ttitle: row.title ?? undefined,\n\t\t\t\tsummary: row.summary ?? undefined,\n\t\t\t\tresumeSummary: row.resumeSummary ?? undefined,\n\t\t\t\tmemoryExtractionHash: row.memoryExtractionHash ?? undefined,\n\t\t\t\tmessages: [],\n\t\t\t\tcreatedAt: row.createdAt.toISOString(),\n\t\t\t\tupdatedAt: row.updatedAt.toISOString(),\n\t\t\t\tmessageCount: row.messageCount,\n\t\t\t\tfavorite: row.favorite,\n\t\t\t\ttags: row.tags ?? undefined,\n\t\t\t\tmessagesView,\n\t\t\t};\n\t\t}\n\t\tconst entries = await this.loadEntriesForSession(sessionId);\n\t\tconst context = buildSessionContextFromEntries(entries);\n\t\tconst extractedById = new Map<string, string>();\n\t\tfor (const entry of entries) {\n\t\t\tif (\n\t\t\t\tentry.type === \"attachment_extract\" &&\n\t\t\t\tentry.attachmentId &&\n\t\t\t\tentry.extractedText\n\t\t\t) {\n\t\t\t\textractedById.set(entry.attachmentId, entry.extractedText);\n\t\t\t}\n\t\t}\n\t\tconst messages =\n\t\t\textractedById.size === 0\n\t\t\t\t? context.messages\n\t\t\t\t: context.messages.map((message) =>\n\t\t\t\t\t\tapplyAttachmentExtracts(message, extractedById),\n\t\t\t\t\t);\n\t\tconst messageCount = row.messageCount || messages.length;\n\t\tconst selectedMessages = selectSessionMessagesForView(\n\t\t\tmessages,\n\t\t\tmessagesView,\n\t\t);\n\n\t\treturn {\n\t\t\tid: row.sessionId,\n\t\t\tsubject: row.subject ?? undefined,\n\t\t\ttitle: row.title ?? undefined,\n\t\t\tsummary: row.summary ?? undefined,\n\t\t\tresumeSummary: row.resumeSummary ?? undefined,\n\t\t\tmemoryExtractionHash: row.memoryExtractionHash ?? undefined,\n\t\t\tmessages: selectedMessages,\n\t\t\tcreatedAt: row.createdAt.toISOString(),\n\t\t\tupdatedAt: row.updatedAt.toISOString(),\n\t\t\tmessageCount,\n\t\t\tfavorite: row.favorite,\n\t\t\ttags: row.tags ?? undefined,\n\t\t\tmessagesView,\n\t\t};\n\t}\n\n\tasync createSession(options?: { title?: string }): Promise<{\n\t\tid: string;\n\t\ttitle?: string;\n\t\tresumeSummary?: string;\n\t\tmessages: AppMessage[];\n\t\tcreatedAt: string;\n\t\tupdatedAt: string;\n\t\tmessageCount: number;\n\t\tfavorite: boolean;\n\t\ttags?: string[];\n\t}> {\n\t\tawait this.flush();\n\t\tthis.sessionId = randomUUID();\n\t\tthis.entries = [];\n\t\tthis.rebuildIndex([]);\n\t\tconst now = new Date();\n\t\tawait this.ensureSessionRow(this.sessionId, {\n\t\t\ttitle: options?.title,\n\t\t\tfavorite: false,\n\t\t\tmessageCount: 0,\n\t\t\tcreatedAt: now,\n\t\t\tupdatedAt: now,\n\t\t});\n\t\treturn {\n\t\t\tid: this.sessionId,\n\t\t\ttitle: options?.title,\n\t\t\tmessages: [],\n\t\t\tcreatedAt: now.toISOString(),\n\t\t\tupdatedAt: now.toISOString(),\n\t\t\tmessageCount: 0,\n\t\t\tfavorite: false,\n\t\t};\n\t}\n\n\tasync deleteSession(sessionId: string): Promise<void> {\n\t\tawait this.flush();\n\t\tawait getDb()\n\t\t\t.update(hostedSessions)\n\t\t\t.set({ deletedAt: new Date(), updatedAt: new Date() })\n\t\t\t.where(\n\t\t\t\tand(\n\t\t\t\t\teq(hostedSessions.sessionId, sessionId),\n\t\t\t\t\teq(hostedSessions.scope, this.scope),\n\t\t\t\t),\n\t\t\t);\n\t}\n\n\tasync createBranchedSessionFromState(\n\t\tstate: AgentState,\n\t\tbranchFromIndex: number,\n\t): Promise<string> {\n\t\tawait this.flush();\n\t\tconst newSessionId = randomUUID();\n\t\tconst timestamp = new Date().toISOString();\n\t\tconst modelKey = `${state.model.provider}/${state.model.id}`;\n\t\tconst branchEntries: SessionEntry[] = [\n\t\t\t{\n\t\t\t\ttype: \"session\",\n\t\t\t\tversion: CURRENT_SESSION_VERSION,\n\t\t\t\tid: newSessionId,\n\t\t\t\ttimestamp,\n\t\t\t\tcwd: process.cwd(),\n\t\t\t\tsubject: this.subject,\n\t\t\t\tmodel: modelKey,\n\t\t\t\tmodelMetadata: this.toModelMetadata(state.model),\n\t\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t\t\tsystemPrompt: state.systemPrompt,\n\t\t\t\tpromptMetadata: state.promptMetadata,\n\t\t\t\tpromptContextManifest: getPersistedSessionPromptContextManifest(state),\n\t\t\t\tunifiedContextManifest: state.unifiedContextManifest,\n\t\t\t\ttools: state.tools.map((tool) => ({\n\t\t\t\t\tname: tool.name,\n\t\t\t\t\tlabel: tool.label,\n\t\t\t\t\tdescription: tool.description,\n\t\t\t\t})),\n\t\t\t\tbranchedFrom: this.sessionId,\n\t\t\t\tparentSession: this.sessionId,\n\t\t\t} satisfies SessionHeaderEntry,\n\t\t];\n\t\tconst branchIds = new Map<string, SessionTreeEntry>();\n\t\tlet parentId: string | null = null;\n\t\tfor (const message of state.messages.slice(0, branchFromIndex)) {\n\t\t\tconst entry: SessionTreeEntry = {\n\t\t\t\ttype: \"message\",\n\t\t\t\tid: generateEntryId(branchIds),\n\t\t\t\tparentId,\n\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\tmessage: sanitizeMessageForSession(message),\n\t\t\t};\n\t\t\tbranchIds.set(entry.id, entry);\n\t\t\tparentId = entry.id;\n\t\t\tbranchEntries.push(entry);\n\t\t}\n\t\tconst now = new Date();\n\t\tawait getDb()\n\t\t\t.insert(hostedSessions)\n\t\t\t.values({\n\t\t\t\tsessionId: newSessionId,\n\t\t\t\tscope: this.scope,\n\t\t\t\tsubject: this.subject,\n\t\t\t\tcwd: process.cwd(),\n\t\t\t\tmodel: modelKey,\n\t\t\t\tmodelMetadata: this.toModelMetadata(state.model),\n\t\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t\t\tsystemPrompt: state.systemPrompt,\n\t\t\t\tpromptMetadata: state.promptMetadata,\n\t\t\t\ttools: state.tools,\n\t\t\t\tmessageCount: branchEntries.filter((entry) => entry.type === \"message\")\n\t\t\t\t\t.length,\n\t\t\t\tcreatedAt: now,\n\t\t\t\tupdatedAt: now,\n\t\t\t});\n\t\tfor (const entry of branchEntries) {\n\t\t\tawait getDb()\n\t\t\t\t.insert(hostedSessionEntries)\n\t\t\t\t.values({\n\t\t\t\t\tsessionId: newSessionId,\n\t\t\t\t\tentryType: entry.type,\n\t\t\t\t\tentryId:\n\t\t\t\t\t\t\"id\" in entry && typeof entry.id === \"string\"\n\t\t\t\t\t\t\t? entry.id\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\tentry,\n\t\t\t\t});\n\t\t}\n\t\treturn newSessionId;\n\t}\n\n\tasync updateSessionMetadata(\n\t\tsessionId: string,\n\t\tupdates: HostedSessionMetadataUpdate,\n\t): Promise<void> {\n\t\tconst set: Partial<typeof hostedSessions.$inferInsert> = {};\n\t\tif (updates.title !== undefined) set.title = updates.title;\n\t\tif (updates.favorite !== undefined) set.favorite = updates.favorite;\n\t\tif (updates.tags !== undefined) set.tags = updates.tags;\n\t\tthis.appendSessionMetaEntry(\n\t\t\tsessionId,\n\t\t\t{\n\t\t\t\t...(updates.title !== undefined ? { title: updates.title } : {}),\n\t\t\t\t...(updates.favorite !== undefined\n\t\t\t\t\t? { favorite: updates.favorite }\n\t\t\t\t\t: {}),\n\t\t\t\t...(updates.tags !== undefined ? { tags: updates.tags } : {}),\n\t\t\t},\n\t\t\tset,\n\t\t);\n\t\tawait this.flush();\n\t}\n\n\tstartSession(state: AgentState, options?: { subject?: string }): void {\n\t\tif (this.sessionInitialized) return;\n\n\t\tconst modelKey = `${state.model.provider}/${state.model.id}`;\n\t\tconst entry: SessionHeaderEntry = {\n\t\t\ttype: \"session\",\n\t\t\tversion: CURRENT_SESSION_VERSION,\n\t\t\tid: this.sessionId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcwd: process.cwd(),\n\t\t\tsubject: options?.subject ?? this.subject,\n\t\t\tmodel: modelKey,\n\t\t\tmodelMetadata: this.toModelMetadata(state.model),\n\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t\tsystemPrompt: state.systemPrompt,\n\t\t\tpromptMetadata: state.promptMetadata,\n\t\t\tpromptContextManifest: getPersistedSessionPromptContextManifest(state),\n\t\t\tunifiedContextManifest: state.unifiedContextManifest,\n\t\t\ttools: state.tools.map((tool) => ({\n\t\t\t\tname: tool.name,\n\t\t\t\tlabel: tool.label,\n\t\t\t\tdescription: tool.description,\n\t\t\t})),\n\t\t};\n\t\tthis.sessionInitialized = true;\n\t\tthis.appendEntry(entry);\n\n\t\tqueueSharedMemoryUpdate({\n\t\t\tsessionId: this.sessionId,\n\t\t\tstate: {\n\t\t\t\tsessionId: this.sessionId,\n\t\t\t\tcwd: process.cwd(),\n\t\t\t\tmodel: modelKey,\n\t\t\t\tupdatedAt: entry.timestamp,\n\t\t\t\tsource: \"maestro\",\n\t\t\t},\n\t\t\tevent: {\n\t\t\t\ttype: \"maestro.session.started\",\n\t\t\t\tpayload: {\n\t\t\t\t\tsessionId: this.sessionId,\n\t\t\t\t\tmodel: modelKey,\n\t\t\t\t\ttimestamp: entry.timestamp,\n\t\t\t\t},\n\t\t\t},\n\t\t});\n\n\t\tif (state.promptMetadata) {\n\t\t\trecordMaestroPromptVariantSelected({\n\t\t\t\tprompt_metadata: state.promptMetadata,\n\t\t\t\tcorrelation: {\n\t\t\t\t\tsession_id: this.sessionId,\n\t\t\t\t},\n\t\t\t\tselected_at: entry.timestamp,\n\t\t\t});\n\t\t}\n\t}\n\n\tsaveMessage(message: AppMessage): void {\n\t\tconst sanitizedMessage = sanitizeMessageForSession(message);\n\t\tconst entry: SessionTreeEntry = {\n\t\t\ttype: \"message\",\n\t\t\tid: this.createTreeEntryId(),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tmessage: sanitizedMessage,\n\t\t};\n\t\tthis.appendEntry(entry);\n\n\t\tqueueSharedMemoryUpdate({\n\t\t\tsessionId: this.sessionId,\n\t\t\tstate: {\n\t\t\t\tsessionId: this.sessionId,\n\t\t\t\tupdatedAt: entry.timestamp,\n\t\t\t\tlastMessageId: entry.id,\n\t\t\t\tlastMessageRole: message.role,\n\t\t\t\tsource: \"maestro\",\n\t\t\t},\n\t\t\tevent: {\n\t\t\t\ttype: \"maestro.message.saved\",\n\t\t\t\tpayload: {\n\t\t\t\t\tsessionId: this.sessionId,\n\t\t\t\t\tmessageId: entry.id,\n\t\t\t\t\trole: message.role,\n\t\t\t\t\ttimestamp: entry.timestamp,\n\t\t\t\t},\n\t\t\t},\n\t\t});\n\t}\n\n\tsaveCompaction(\n\t\tsummary: string,\n\t\tfirstKeptEntryIndex: number,\n\t\ttokensBefore: number,\n\t\toptions?: {\n\t\t\tauto?: boolean;\n\t\t\tcustomInstructions?: string;\n\t\t\tfirstKeptEntryId?: string;\n\t\t},\n\t): void {\n\t\tconst context = this.buildSessionContext();\n\t\tconst fallbackEntry = context.messageEntries[firstKeptEntryIndex];\n\t\tconst firstKeptEntryId =\n\t\t\toptions?.firstKeptEntryId ?? fallbackEntry?.id ?? this.leafId;\n\t\tif (!firstKeptEntryId) {\n\t\t\treturn;\n\t\t}\n\t\tconst entry: CompactionEntry = {\n\t\t\ttype: \"compaction\",\n\t\t\tid: this.createTreeEntryId(),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tsummary,\n\t\t\tfirstKeptEntryId,\n\t\t\ttokensBefore,\n\t\t\tauto: options?.auto,\n\t\t\tcustomInstructions: options?.customInstructions,\n\t\t};\n\t\tthis.appendEntry(entry);\n\t}\n\n\tsaveAttachmentExtraction(\n\t\tsessionRef: string,\n\t\tattachmentId: string,\n\t\ttext: string,\n\t): void {\n\t\tif (!attachmentId || !text) return;\n\t\tconst entry: AttachmentExtractedEntry = {\n\t\t\ttype: \"attachment_extract\",\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tattachmentId,\n\t\t\textractedText: text,\n\t\t};\n\t\tconst targetSessionId = sessionRef.startsWith(\"db:\")\n\t\t\t? sessionRef.slice(\"db:\".length)\n\t\t\t: sessionRef;\n\t\tif (targetSessionId && targetSessionId !== this.sessionId) {\n\t\t\tthis.enqueue(async () => {\n\t\t\t\tawait getDb().insert(hostedSessionEntries).values({\n\t\t\t\t\tsessionId: targetSessionId,\n\t\t\t\t\tentryType: entry.type,\n\t\t\t\t\tentry,\n\t\t\t\t});\n\t\t\t\tawait getDb()\n\t\t\t\t\t.update(hostedSessions)\n\t\t\t\t\t.set({ updatedAt: new Date() })\n\t\t\t\t\t.where(\n\t\t\t\t\t\tand(\n\t\t\t\t\t\t\teq(hostedSessions.sessionId, targetSessionId),\n\t\t\t\t\t\t\teq(hostedSessions.scope, this.scope),\n\t\t\t\t\t\t\tisNull(hostedSessions.deletedAt),\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tthis.appendEntry(entry);\n\t}\n\n\tsaveSessionSummary(summary: string, sessionRef?: string): void {\n\t\tconst trimmed = summary.trim();\n\t\tif (!trimmed) return;\n\t\tconst sessionId = this.resolveSessionId(sessionRef);\n\t\tthis.appendSessionMetaEntry(\n\t\t\tsessionId,\n\t\t\t{ summary: trimmed },\n\t\t\t{ summary: trimmed },\n\t\t);\n\t}\n\n\tsaveSessionResumeSummary(summary: string, sessionRef?: string): void {\n\t\tconst trimmed = summary.trim();\n\t\tif (!trimmed) return;\n\t\tconst sessionId = this.resolveSessionId(sessionRef);\n\t\tthis.appendSessionMetaEntry(\n\t\t\tsessionId,\n\t\t\t{ resumeSummary: trimmed },\n\t\t\t{ resumeSummary: trimmed },\n\t\t);\n\t}\n\n\tsaveSessionMemoryExtractionHash(hash: string, sessionRef?: string): void {\n\t\tconst trimmed = hash.trim();\n\t\tif (!trimmed) return;\n\t\tconst sessionId = this.resolveSessionId(sessionRef);\n\t\tthis.appendSessionMetaEntry(\n\t\t\tsessionId,\n\t\t\t{ memoryExtractionHash: trimmed },\n\t\t\t{ memoryExtractionHash: trimmed },\n\t\t);\n\t}\n\n\tsetSessionFavorite(sessionRef: string, favorite: boolean): void {\n\t\tthis.appendSessionMetaEntry(\n\t\t\tthis.resolveSessionId(sessionRef),\n\t\t\t{ favorite },\n\t\t\t{ favorite },\n\t\t);\n\t}\n\n\tsetSessionTitle(sessionRef: string, title: string): void {\n\t\tthis.appendSessionMetaEntry(\n\t\t\tthis.resolveSessionId(sessionRef),\n\t\t\t{ title },\n\t\t\t{ title },\n\t\t);\n\t}\n\n\tsetSessionTags(sessionRef: string, tags: string[]): void {\n\t\tthis.appendSessionMetaEntry(\n\t\t\tthis.resolveSessionId(sessionRef),\n\t\t\t{ tags },\n\t\t\t{ tags },\n\t\t);\n\t}\n\n\tsetSessionAppServerGoal(\n\t\tsessionRef: string,\n\t\tgoal: NonNullable<SessionMetaEntry[\"appServerGoal\"]> | null,\n\t): void {\n\t\tthis.appendSessionMetaEntry(this.resolveSessionId(sessionRef), {\n\t\t\tappServerGoal: goal,\n\t\t});\n\t}\n\n\tgetSessionId(): string {\n\t\treturn this.sessionId;\n\t}\n\n\tgetSessionFile(): string {\n\t\treturn `db:${this.sessionId}`;\n\t}\n\n\tgetSessionFileById(sessionId: string): string | null {\n\t\treturn `db:${sessionId}`;\n\t}\n\n\tsetSessionFile(sessionRef: string): void {\n\t\tconst sessionId = sessionRef.startsWith(\"db:\")\n\t\t\t? sessionRef.slice(\"db:\".length)\n\t\t\t: sessionRef;\n\t\tif (sessionId) {\n\t\t\tthis.sessionId = sessionId;\n\t\t}\n\t}\n\n\tisInitialized(): boolean {\n\t\treturn this.sessionInitialized;\n\t}\n\n\tshouldInitializeSession(messages: AppMessage[]): boolean {\n\t\treturn (\n\t\t\t!this.sessionInitialized &&\n\t\t\tmessages.some((message) => message.role === \"user\")\n\t\t);\n\t}\n\n\tupdateSnapshot(state: AgentState, metadata?: SessionModelMetadata): void {\n\t\tthis.snapshot = state;\n\t\tif (metadata) {\n\t\t\tthis.lastModelMetadata = metadata;\n\t\t}\n\t}\n\n\tbuildSessionContext(\n\t\tleafId: string | null = this.leafId,\n\t): SessionContextSnapshot {\n\t\treturn buildSessionContextFromEntries(this.entries, {\n\t\t\tleafId,\n\t\t\tbyId: this.byId,\n\t\t\theader: this.getHeader(),\n\t\t});\n\t}\n\n\tloadModel(): string | null {\n\t\treturn this.buildSessionContext().model;\n\t}\n\n\tloadThinkingLevel(): string {\n\t\treturn this.buildSessionContext().thinkingLevel;\n\t}\n\n\tgetHeader(): SessionHeaderEntry | null {\n\t\treturn (\n\t\t\t(this.entries.find((entry) => entry.type === \"session\") as\n\t\t\t\t| SessionHeaderEntry\n\t\t\t\t| undefined) ?? null\n\t\t);\n\t}\n\n\tprivate createTreeEntryId(): string {\n\t\treturn generateEntryId(this.byId);\n\t}\n\n\tasync flush(): Promise<void> {\n\t\tawait this.writeChain;\n\t\tif (this.hasWriteError) {\n\t\t\tconst error = this.writeError;\n\t\t\tthis.writeError = undefined;\n\t\t\tthis.hasWriteError = false;\n\t\t\tthrow error;\n\t\t}\n\t}\n}\n\nexport function isHostedSessionManager(\n\tmanager: unknown,\n): manager is HostedSessionManager {\n\treturn (\n\t\ttypeof manager === \"object\" &&\n\t\tmanager !== null &&\n\t\t\"storageKind\" in manager &&\n\t\t(manager as { storageKind?: unknown }).storageKind === \"database\"\n\t);\n}\n"]}
1
+ {"version":3,"file":"hosted-session-manager.js","sourceRoot":"","sources":["../../src/server/hosted-session-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAEnE,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAEN,8BAA8B,EAC9B,eAAe,EACf,4BAA4B,GAC5B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACN,uBAAuB,EACvB,yBAAyB,GACzB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAEN,uBAAuB,EASvB,wCAAwC,EACxC,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,GACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,kCAAkC,EAAE,MAAM,mCAAmC,CAAC;AAIvF,SAAS,sBAAsB,CAAC,KAAc;IAC7C,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjE,OAAO,IAAI,CAAC;IACb,CAAC;IACD,IAAI,OAAQ,KAA4B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC5D,OAAO,IAAI,CAAC;IACb,CAAC;IACD,OAAO,qBAAqB,CAAC,KAAK,CAAC,CAAC;AACrC,CAAC;AAQD,MAAM,OAAO,oBAAoB;IAgBhC,YAAY,OAA4C;QAf/C,gBAAW,GAAG,UAAmB,CAAC;QAInC,cAAS,GAAW,UAAU,EAAE,CAAC;QACjC,YAAO,GAAmB,EAAE,CAAC;QAC7B,SAAI,GAAkC,IAAI,GAAG,EAAE,CAAC;QAChD,WAAM,GAAkB,IAAI,CAAC;QAC7B,uBAAkB,GAAG,KAAK,CAAC;QAC3B,eAAU,GAAqB,OAAO,CAAC,OAAO,EAAE,CAAC;QACjD,kBAAa,GAAG,KAAK,CAAC;QAM7B,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAChC,CAAC;IAEO,eAAe,CAAC,KAA0B;QACjD,MAAM,QAAQ,GAAG,KAC8C,CAAC;QAChE,OAAO;YACN,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,OAAO,EAAE,KAAK,CAAC,EAAE;YACjB,YAAY,EAAE,QAAQ,CAAC,YAAY;YACnC,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,MAAM,EAAE,QAAQ,CAAC,MAAM;SACvB,CAAC;IACH,CAAC;IAEO,OAAO,CAAC,SAA8B;QAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QAC1D,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,IAAI,CAC5B,GAAG,EAAE,CAAC,SAAS,EACf,CAAC,KAAK,EAAE,EAAE;YACT,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;gBACzB,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;gBACxB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;YAC3B,CAAC;QACF,CAAC,CACD,CAAC;IACH,CAAC;IAEO,YAAY,CAAC,OAAuB;QAC3C,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAChC,SAAS;YACV,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC/B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,EAAE,CAAC;QACxB,CAAC;QACD,IAAI,CAAC,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAC9D,CAAC;IAEO,mBAAmB;QAC1B,OAAO,IAAI,CAAC,mBAAmB,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC;IACnD,CAAC;IAEO,gBAAgB,CAAC,UAAmB;QAC3C,IAAI,CAAC,UAAU,EAAE,CAAC;YACjB,OAAO,IAAI,CAAC,SAAS,CAAC;QACvB,CAAC;QACD,OAAO,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC;YAClC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC;YAChC,CAAC,CAAC,UAAU,CAAC;IACf,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAC7B,SAAiB,EACjB,SAAsD,EAAE;QAExD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,KAAK,EAAE;aACX,MAAM,CAAC,cAAc,CAAC;aACtB,MAAM,CAAC;YACP,SAAS;YACT,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,IAAI;YAC7B,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;YAClB,YAAY,EAAE,IAAI,CAAC,mBAAmB,EAAE;YACxC,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;YACd,GAAG,MAAM;SACT,CAAC;aACD,kBAAkB,CAAC;YACnB,MAAM,EAAE,cAAc,CAAC,SAAS;YAChC,GAAG,EAAE;gBACJ,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI;gBAC/C,GAAG,EAAE,MAAM,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE;gBAChC,SAAS,EAAE,GAAG;gBACd,SAAS,EAAE,IAAI;gBACf,GAAG,MAAM;aACT;SACD,CAAC,CAAC;IACL,CAAC;IAEO,WAAW,CAAC,KAAmB;QACtC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC/B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,EAAE,CAAC;QACxB,CAAC;QACD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;QACjC,MAAM,OAAO,GACZ,IAAI,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACtE,MAAM,YAAY,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAEhD,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE;YACvB,MAAM,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC;YACzD,MAAM,KAAK,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,MAAM,CAAC;gBACjD,SAAS;gBACT,SAAS,EAAE,KAAK,CAAC,IAAI;gBACrB,OAAO;gBACP,KAAK;aACL,CAAC,CAAC;YACH,MAAM,KAAK,EAAE;iBACX,MAAM,CAAC,cAAc,CAAC;iBACtB,GAAG,CAAC;gBACJ,YAAY;gBACZ,SAAS,EAAE,IAAI,IAAI,EAAE;aACrB,CAAC;iBACD,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;IACJ,CAAC;IAEO,sBAAsB,CAC7B,SAAiB,EACjB,MAAoD,EACpD,aAA0D,EAAE;QAE5D,MAAM,KAAK,GAAqB;YAC/B,IAAI,EAAE,cAAc;YACpB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,GAAG,MAAM;SACT,CAAC;QACF,IAAI,SAAS,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;YAClC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;QACD,MAAM,YAAY,GACjB,SAAS,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACvE,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE;YACvB,IAAI,SAAS,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;gBAClC,MAAM,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC;YAC1D,CAAC;YACD,MAAM,KAAK,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,MAAM,CAAC;gBACjD,SAAS;gBACT,SAAS,EAAE,KAAK,CAAC,IAAI;gBACrB,KAAK;aACL,CAAC,CAAC;YACH,MAAM,KAAK,EAAE;iBACX,MAAM,CAAC,cAAc,CAAC;iBACtB,GAAG,CAAC;gBACJ,GAAG,UAAU;gBACb,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvD,SAAS,EAAE,IAAI,IAAI,EAAE;aACrB,CAAC;iBACD,KAAK,CACL,GAAG,CACF,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,EACvC,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,EACpC,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAChC,CACD,CAAC;QACJ,CAAC,CAAC,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,OAAO,CAAC,SAAiB;QACtC,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,KAAK,EAAE;aACzB,MAAM,EAAE;aACR,IAAI,CAAC,cAAc,CAAC;aACpB,KAAK,CACL,GAAG,CACF,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,EACvC,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,EACpC,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAChC,CACD;aACA,KAAK,CAAC,CAAC,CAAC,CAAC;QACX,OAAO,GAAG,IAAI,IAAI,CAAC;IACpB,CAAC;IAEO,KAAK,CAAC,qBAAqB,CAClC,SAAiB;QAEjB,MAAM,IAAI,GAAG,MAAM,KAAK,EAAE;aACxB,MAAM,CAAC,EAAE,KAAK,EAAE,oBAAoB,CAAC,KAAK,EAAE,CAAC;aAC7C,IAAI,CAAC,oBAAoB,CAAC;aAC1B,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;aACpD,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC,CAAC;QAE9C,MAAM,OAAO,GAAmB,EAAE,CAAC;QACnC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACxB,MAAM,KAAK,GAAG,sBAAsB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAChD,IAAI,KAAK,EAAE,CAAC;gBACX,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrB,CAAC;QACF,CAAC;QACD,OAAO,OAAO,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,SAAiB;QAClC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC1C,IAAI,CAAC,GAAG,EAAE,CAAC;YACV,OAAO,IAAI,CAAC;QACb,CAAC;QACD,OAAO,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,SAAiB;QACpC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACnB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC1C,IAAI,CAAC,GAAG,EAAE,CAAC;YACV,OAAO,KAAK,CAAC;QACd,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;QAC5D,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC;QAC/B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAC3B,OAAO,IAAI,CAAC;IACb,CAAC;IAED,eAAe;QACd,OAAO,EAAE,CAAC;IACX,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,KAAW;QACpC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACnB,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,KAAK,EAAE;aACzB,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,CAAQ,eAAe,EAAE,CAAC;aAC7C,IAAI,CAAC,cAAc,CAAC;aACpB,KAAK,CACL,GAAG,CACF,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,EACpC,GAAG,CAAC,cAAc,CAAC,SAAS,EAAE,KAAK,CAAC,EACpC,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAChC,CACD,CAAC;QACH,OAAO,MAAM,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAGlB;QACA,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,KAAK,GAAG,KAAK,EAAE;aACjB,MAAM,EAAE;aACR,IAAI,CAAC,cAAc,CAAC;aACpB,KAAK,CACL,GAAG,CACF,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,EACpC,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAChC,CACD;aACA,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;aACvC,QAAQ,EAAE,CAAC;QACb,IAAI,OAAO,OAAO,EAAE,KAAK,KAAK,QAAQ,EAAE,CAAC;YACxC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;QACD,IAAI,OAAO,OAAO,EAAE,MAAM,KAAK,QAAQ,EAAE,CAAC;YACzC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACtC,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC;QAEzB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACzB,EAAE,EAAE,GAAG,CAAC,SAAS;YACjB,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,SAAS;YACjC,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,SAAS;YAC7B,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,SAAS;YACjC,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,SAAS;YAC7C,oBAAoB,EAAE,GAAG,CAAC,oBAAoB,IAAI,SAAS;YAC3D,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,WAAW,EAAE;YACtC,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,WAAW,EAAE;YACtC,YAAY,EAAE,GAAG,CAAC,YAAY;YAC9B,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,SAAS;SAC3B,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,WAAW,CAChB,SAAiB,EACjB,UAAkD,EAAE;QAgBpD,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACnB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC1C,IAAI,CAAC,GAAG,EAAE,CAAC;YACV,OAAO,IAAI,CAAC;QACb,CAAC;QACD,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,MAAM,CAAC;QACpD,IAAI,YAAY,KAAK,WAAW,EAAE,CAAC;YAClC,OAAO;gBACN,EAAE,EAAE,GAAG,CAAC,SAAS;gBACjB,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,SAAS;gBACjC,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,SAAS;gBAC7B,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,SAAS;gBACjC,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,SAAS;gBAC7C,oBAAoB,EAAE,GAAG,CAAC,oBAAoB,IAAI,SAAS;gBAC3D,QAAQ,EAAE,EAAE;gBACZ,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,WAAW,EAAE;gBACtC,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,WAAW,EAAE;gBACtC,YAAY,EAAE,GAAG,CAAC,YAAY;gBAC9B,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,SAAS;gBAC3B,YAAY;aACZ,CAAC;QACH,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;QAC5D,MAAM,OAAO,GAAG,8BAA8B,CAAC,OAAO,CAAC,CAAC;QACxD,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;QAChD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC7B,IACC,KAAK,CAAC,IAAI,KAAK,oBAAoB;gBACnC,KAAK,CAAC,YAAY;gBAClB,KAAK,CAAC,aAAa,EAClB,CAAC;gBACF,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;YAC5D,CAAC;QACF,CAAC;QACD,MAAM,QAAQ,GACb,aAAa,CAAC,IAAI,KAAK,CAAC;YACvB,CAAC,CAAC,OAAO,CAAC,QAAQ;YAClB,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CACjC,uBAAuB,CAAC,OAAO,EAAE,aAAa,CAAC,CAC/C,CAAC;QACL,MAAM,YAAY,GAAG,GAAG,CAAC,YAAY,IAAI,QAAQ,CAAC,MAAM,CAAC;QACzD,MAAM,gBAAgB,GAAG,4BAA4B,CACpD,QAAQ,EACR,YAAY,CACZ,CAAC;QAEF,OAAO;YACN,EAAE,EAAE,GAAG,CAAC,SAAS;YACjB,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,SAAS;YACjC,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,SAAS;YAC7B,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,SAAS;YACjC,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,SAAS;YAC7C,oBAAoB,EAAE,GAAG,CAAC,oBAAoB,IAAI,SAAS;YAC3D,QAAQ,EAAE,gBAAgB;YAC1B,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,WAAW,EAAE;YACtC,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,WAAW,EAAE;YACtC,YAAY;YACZ,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,SAAS;YAC3B,YAAY;SACZ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAA4B;QAW/C,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,SAAS,GAAG,UAAU,EAAE,CAAC;QAC9B,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;QAClB,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;QACtB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,SAAS,EAAE;YAC3C,KAAK,EAAE,OAAO,EAAE,KAAK;YACrB,QAAQ,EAAE,KAAK;YACf,YAAY,EAAE,CAAC;YACf,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;SACd,CAAC,CAAC;QACH,OAAO;YACN,EAAE,EAAE,IAAI,CAAC,SAAS;YAClB,KAAK,EAAE,OAAO,EAAE,KAAK;YACrB,QAAQ,EAAE,EAAE;YACZ,SAAS,EAAE,GAAG,CAAC,WAAW,EAAE;YAC5B,SAAS,EAAE,GAAG,CAAC,WAAW,EAAE;YAC5B,YAAY,EAAE,CAAC;YACf,QAAQ,EAAE,KAAK;SACf,CAAC;IACH,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,SAAiB;QACpC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACnB,MAAM,KAAK,EAAE;aACX,MAAM,CAAC,cAAc,CAAC;aACtB,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;aACrD,KAAK,CACL,GAAG,CACF,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,EACvC,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CACpC,CACD,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,8BAA8B,CACnC,KAAiB,EACjB,eAAuB;QAEvB,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACnB,MAAM,YAAY,GAAG,UAAU,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC3C,MAAM,QAAQ,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;QAC7D,MAAM,aAAa,GAAmB;YACrC;gBACC,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,uBAAuB;gBAChC,EAAE,EAAE,YAAY;gBAChB,SAAS;gBACT,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;gBAClB,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,KAAK,EAAE,QAAQ;gBACf,aAAa,EAAE,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC;gBAChD,aAAa,EAAE,KAAK,CAAC,aAAa;gBAClC,YAAY,EAAE,KAAK,CAAC,YAAY;gBAChC,cAAc,EAAE,KAAK,CAAC,cAAc;gBACpC,qBAAqB,EAAE,wCAAwC,CAAC,KAAK,CAAC;gBACtE,sBAAsB,EAAE,KAAK,CAAC,sBAAsB;gBACpD,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;oBACjC,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,WAAW,EAAE,IAAI,CAAC,WAAW;iBAC7B,CAAC,CAAC;gBACH,YAAY,EAAE,IAAI,CAAC,SAAS;gBAC5B,aAAa,EAAE,IAAI,CAAC,SAAS;aACA;SAC9B,CAAC;QACF,MAAM,SAAS,GAAG,IAAI,GAAG,EAA4B,CAAC;QACtD,IAAI,QAAQ,GAAkB,IAAI,CAAC;QACnC,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,EAAE,CAAC;YAChE,MAAM,KAAK,GAAqB;gBAC/B,IAAI,EAAE,SAAS;gBACf,EAAE,EAAE,eAAe,CAAC,SAAS,CAAC;gBAC9B,QAAQ;gBACR,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,OAAO,EAAE,yBAAyB,CAAC,OAAO,CAAC;aAC3C,CAAC;YACF,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC/B,QAAQ,GAAG,KAAK,CAAC,EAAE,CAAC;YACpB,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,KAAK,EAAE;aACX,MAAM,CAAC,cAAc,CAAC;aACtB,MAAM,CAAC;YACP,SAAS,EAAE,YAAY;YACvB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;YAClB,KAAK,EAAE,QAAQ;YACf,aAAa,EAAE,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC;YAChD,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,YAAY,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC;iBACrE,MAAM;YACR,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;SACd,CAAC,CAAC;QACJ,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;YACnC,MAAM,KAAK,EAAE;iBACX,MAAM,CAAC,oBAAoB,CAAC;iBAC5B,MAAM,CAAC;gBACP,SAAS,EAAE,YAAY;gBACvB,SAAS,EAAE,KAAK,CAAC,IAAI;gBACrB,OAAO,EACN,IAAI,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ;oBAC5C,CAAC,CAAC,KAAK,CAAC,EAAE;oBACV,CAAC,CAAC,SAAS;gBACb,KAAK;aACL,CAAC,CAAC;QACL,CAAC;QACD,OAAO,YAAY,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,qBAAqB,CAC1B,SAAiB,EACjB,OAAoC;QAEpC,MAAM,GAAG,GAAgD,EAAE,CAAC;QAC5D,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;YAAE,GAAG,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3D,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS;YAAE,GAAG,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACpE,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS;YAAE,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QACxD,IAAI,CAAC,sBAAsB,CAC1B,SAAS,EACT;YACC,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChE,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS;gBACjC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE;gBAChC,CAAC,CAAC,EAAE,CAAC;YACN,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC7D,EACD,GAAG,CACH,CAAC;QACF,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;IAED,YAAY,CAAC,KAAiB,EAAE,OAA8B;QAC7D,IAAI,IAAI,CAAC,kBAAkB;YAAE,OAAO;QAEpC,MAAM,QAAQ,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;QAC7D,MAAM,KAAK,GAAuB;YACjC,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,uBAAuB;YAChC,EAAE,EAAE,IAAI,CAAC,SAAS;YAClB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;YAClB,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,IAAI,CAAC,OAAO;YACzC,KAAK,EAAE,QAAQ;YACf,aAAa,EAAE,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC;YAChD,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,qBAAqB,EAAE,wCAAwC,CAAC,KAAK,CAAC;YACtE,sBAAsB,EAAE,KAAK,CAAC,sBAAsB;YACpD,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBACjC,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,WAAW,EAAE,IAAI,CAAC,WAAW;aAC7B,CAAC,CAAC;SACH,CAAC;QACF,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;QAC/B,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAExB,uBAAuB,CAAC;YACvB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,KAAK,EAAE;gBACN,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;gBAClB,KAAK,EAAE,QAAQ;gBACf,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,MAAM,EAAE,SAAS;aACjB;YACD,KAAK,EAAE;gBACN,IAAI,EAAE,yBAAyB;gBAC/B,OAAO,EAAE;oBACR,SAAS,EAAE,IAAI,CAAC,SAAS;oBACzB,KAAK,EAAE,QAAQ;oBACf,SAAS,EAAE,KAAK,CAAC,SAAS;iBAC1B;aACD;SACD,CAAC,CAAC;QAEH,IAAI,KAAK,CAAC,cAAc,EAAE,CAAC;YAC1B,kCAAkC,CAAC;gBAClC,eAAe,EAAE,KAAK,CAAC,cAAc;gBACrC,WAAW,EAAE;oBACZ,UAAU,EAAE,IAAI,CAAC,SAAS;iBAC1B;gBACD,WAAW,EAAE,KAAK,CAAC,SAAS;aAC5B,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;IAED,WAAW,CAAC,OAAmB;QAC9B,MAAM,gBAAgB,GAAG,yBAAyB,CAAC,OAAO,CAAC,CAAC;QAC5D,MAAM,KAAK,GAAqB;YAC/B,IAAI,EAAE,SAAS;YACf,EAAE,EAAE,IAAI,CAAC,iBAAiB,EAAE;YAC5B,QAAQ,EAAE,IAAI,CAAC,MAAM;YACrB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,OAAO,EAAE,gBAAgB;SACzB,CAAC;QACF,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAExB,uBAAuB,CAAC;YACvB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,KAAK,EAAE;gBACN,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,aAAa,EAAE,KAAK,CAAC,EAAE;gBACvB,eAAe,EAAE,OAAO,CAAC,IAAI;gBAC7B,MAAM,EAAE,SAAS;aACjB;YACD,KAAK,EAAE;gBACN,IAAI,EAAE,uBAAuB;gBAC7B,OAAO,EAAE;oBACR,SAAS,EAAE,IAAI,CAAC,SAAS;oBACzB,SAAS,EAAE,KAAK,CAAC,EAAE;oBACnB,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,SAAS,EAAE,KAAK,CAAC,SAAS;iBAC1B;aACD;SACD,CAAC,CAAC;IACJ,CAAC;IAED,cAAc,CACb,OAAe,EACf,mBAA2B,EAC3B,YAAoB,EACpB,OAIC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3C,MAAM,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC;QAClE,MAAM,gBAAgB,GACrB,OAAO,EAAE,gBAAgB,IAAI,aAAa,EAAE,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC;QAC/D,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACvB,OAAO;QACR,CAAC;QACD,MAAM,KAAK,GAAoB;YAC9B,IAAI,EAAE,YAAY;YAClB,EAAE,EAAE,IAAI,CAAC,iBAAiB,EAAE;YAC5B,QAAQ,EAAE,IAAI,CAAC,MAAM;YACrB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,OAAO;YACP,gBAAgB;YAChB,YAAY;YACZ,IAAI,EAAE,OAAO,EAAE,IAAI;YACnB,kBAAkB,EAAE,OAAO,EAAE,kBAAkB;SAC/C,CAAC;QACF,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IAED,wBAAwB,CACvB,UAAkB,EAClB,YAAoB,EACpB,IAAY;QAEZ,IAAI,CAAC,YAAY,IAAI,CAAC,IAAI;YAAE,OAAO;QACnC,MAAM,KAAK,GAA6B;YACvC,IAAI,EAAE,oBAAoB;YAC1B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,YAAY;YACZ,aAAa,EAAE,IAAI;SACnB,CAAC;QACF,MAAM,eAAe,GAAG,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC;YACnD,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC;YAChC,CAAC,CAAC,UAAU,CAAC;QACd,IAAI,eAAe,IAAI,eAAe,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;YAC3D,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE;gBACvB,MAAM,KAAK,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,MAAM,CAAC;oBACjD,SAAS,EAAE,eAAe;oBAC1B,SAAS,EAAE,KAAK,CAAC,IAAI;oBACrB,KAAK;iBACL,CAAC,CAAC;gBACH,MAAM,KAAK,EAAE;qBACX,MAAM,CAAC,cAAc,CAAC;qBACtB,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;qBAC9B,KAAK,CACL,GAAG,CACF,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,eAAe,CAAC,EAC7C,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,EACpC,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAChC,CACD,CAAC;YACJ,CAAC,CAAC,CAAC;YACH,OAAO;QACR,CAAC;QACD,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IAED,kBAAkB,CAAC,OAAe,EAAE,UAAmB;QACtD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QACpD,IAAI,CAAC,sBAAsB,CAC1B,SAAS,EACT,EAAE,OAAO,EAAE,OAAO,EAAE,EACpB,EAAE,OAAO,EAAE,OAAO,EAAE,CACpB,CAAC;IACH,CAAC;IAED,wBAAwB,CAAC,OAAe,EAAE,UAAmB;QAC5D,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QACpD,IAAI,CAAC,sBAAsB,CAC1B,SAAS,EACT,EAAE,aAAa,EAAE,OAAO,EAAE,EAC1B,EAAE,aAAa,EAAE,OAAO,EAAE,CAC1B,CAAC;IACH,CAAC;IAED,+BAA+B,CAAC,IAAY,EAAE,UAAmB;QAChE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QACpD,IAAI,CAAC,sBAAsB,CAC1B,SAAS,EACT,EAAE,oBAAoB,EAAE,OAAO,EAAE,EACjC,EAAE,oBAAoB,EAAE,OAAO,EAAE,CACjC,CAAC;IACH,CAAC;IAED,kBAAkB,CAAC,UAAkB,EAAE,QAAiB;QACvD,IAAI,CAAC,sBAAsB,CAC1B,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,EACjC,EAAE,QAAQ,EAAE,EACZ,EAAE,QAAQ,EAAE,CACZ,CAAC;IACH,CAAC;IAED,eAAe,CAAC,UAAkB,EAAE,KAAa;QAChD,IAAI,CAAC,sBAAsB,CAC1B,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,EACjC,EAAE,KAAK,EAAE,EACT,EAAE,KAAK,EAAE,CACT,CAAC;IACH,CAAC;IAED,cAAc,CAAC,UAAkB,EAAE,IAAc;QAChD,IAAI,CAAC,sBAAsB,CAC1B,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,EACjC,EAAE,IAAI,EAAE,EACR,EAAE,IAAI,EAAE,CACR,CAAC;IACH,CAAC;IAED,uBAAuB,CACtB,UAAkB,EAClB,IAA2D;QAE3D,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,EAAE;YAC9D,aAAa,EAAE,IAAI;SACnB,CAAC,CAAC;IACJ,CAAC;IAED,YAAY;QACX,OAAO,IAAI,CAAC,SAAS,CAAC;IACvB,CAAC;IAED,cAAc;QACb,OAAO,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;IAC/B,CAAC;IAED,gBAAgB;QACf,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;IAED,MAAM,CAAC,YAAoB;QAC1B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,SAAS,YAAY,YAAY,CAAC,CAAC;QACpD,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,YAAY,CAAC;IAC5B,CAAC;IAED,kBAAkB,CAAC,SAAiB;QACnC,OAAO,MAAM,SAAS,EAAE,CAAC;IAC1B,CAAC;IAED,cAAc,CAAC,UAAkB;QAChC,MAAM,SAAS,GAAG,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC;YAC7C,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC;YAChC,CAAC,CAAC,UAAU,CAAC;QACd,IAAI,SAAS,EAAE,CAAC;YACf,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC5B,CAAC;IACF,CAAC;IAED,aAAa;QACZ,OAAO,IAAI,CAAC,kBAAkB,CAAC;IAChC,CAAC;IAED,uBAAuB,CAAC,QAAsB;QAC7C,OAAO,CACN,CAAC,IAAI,CAAC,kBAAkB;YACxB,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC,CACnD,CAAC;IACH,CAAC;IAED,cAAc,CAAC,KAAiB,EAAE,QAA+B;QAChE,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,QAAQ,EAAE,CAAC;YACd,IAAI,CAAC,iBAAiB,GAAG,QAAQ,CAAC;QACnC,CAAC;IACF,CAAC;IAED,mBAAmB,CAClB,SAAwB,IAAI,CAAC,MAAM;QAEnC,OAAO,8BAA8B,CAAC,IAAI,CAAC,OAAO,EAAE;YACnD,MAAM;YACN,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE;SACxB,CAAC,CAAC;IACJ,CAAC;IAED,SAAS;QACR,OAAO,IAAI,CAAC,mBAAmB,EAAE,CAAC,KAAK,CAAC;IACzC,CAAC;IAED,iBAAiB;QAChB,OAAO,IAAI,CAAC,mBAAmB,EAAE,CAAC,aAAa,CAAC;IACjD,CAAC;IAED,SAAS;QACR,OAAO,CACL,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAEzC,IAAI,IAAI,CACrB,CAAC;IACH,CAAC;IAEO,iBAAiB;QACxB,OAAO,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,KAAK;QACV,MAAM,IAAI,CAAC,UAAU,CAAC;QACtB,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC;YAC9B,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;YAC5B,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;YAC3B,MAAM,KAAK,CAAC;QACb,CAAC;IACF,CAAC;CACD;AAED,MAAM,UAAU,sBAAsB,CACrC,OAAgB;IAEhB,OAAO,CACN,OAAO,OAAO,KAAK,QAAQ;QAC3B,OAAO,KAAK,IAAI;QAChB,aAAa,IAAI,OAAO;QACvB,OAAqC,CAAC,WAAW,KAAK,UAAU,CACjE,CAAC;AACH,CAAC","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { and, asc, desc, eq, gte, isNull, sql } from \"drizzle-orm\";\nimport type { AgentState, AppMessage } from \"../agent/types.js\";\nimport { getDb } from \"../db/client.js\";\nimport { hostedSessionEntries, hostedSessions } from \"../db/schema.js\";\nimport {\n\ttype SessionContextSnapshot,\n\tbuildSessionContextFromEntries,\n\tgenerateEntryId,\n\tselectSessionMessagesForView,\n} from \"../session/session-context.js\";\nimport {\n\tapplyAttachmentExtracts,\n\tsanitizeMessageForSession,\n} from \"../session/session-sanitize.js\";\nimport type { SessionMetadata } from \"../session/types.js\";\nimport {\n\ttype AttachmentExtractedEntry,\n\tCURRENT_SESSION_VERSION,\n\ttype CompactionEntry,\n\ttype SessionEntry,\n\ttype SessionHeaderEntry,\n\ttype SessionMessagesView,\n\ttype SessionMetaEntry,\n\ttype SessionModelMetadata,\n\ttype SessionSummary,\n\ttype SessionTreeEntry,\n\tgetPersistedSessionPromptContextManifest,\n\tisSessionHeaderEntry,\n\tisSessionTreeEntry,\n\tnormalizeSessionEntry,\n} from \"../session/types.js\";\nimport { queueSharedMemoryUpdate } from \"../shared-memory/client.js\";\nimport { recordMaestroPromptVariantSelected } from \"../telemetry/maestro-event-bus.js\";\n\ntype SessionRow = typeof hostedSessions.$inferSelect;\n\nfunction parseSessionEntryValue(value: unknown): SessionEntry | null {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\treturn null;\n\t}\n\tif (typeof (value as { type?: unknown }).type !== \"string\") {\n\t\treturn null;\n\t}\n\treturn normalizeSessionEntry(value);\n}\n\nexport interface HostedSessionMetadataUpdate {\n\ttitle?: string;\n\tfavorite?: boolean;\n\ttags?: string[];\n}\n\nexport class HostedSessionManager {\n\treadonly storageKind = \"database\" as const;\n\n\tprivate readonly scope: string;\n\tprivate readonly subject?: string;\n\tprivate sessionId: string = randomUUID();\n\tprivate entries: SessionEntry[] = [];\n\tprivate byId: Map<string, SessionTreeEntry> = new Map();\n\tprivate leafId: string | null = null;\n\tprivate sessionInitialized = false;\n\tprivate writeChain: Promise<unknown> = Promise.resolve();\n\tprivate hasWriteError = false;\n\tprivate writeError: unknown;\n\tprivate snapshot?: AgentState;\n\tprivate lastModelMetadata?: SessionModelMetadata;\n\n\tconstructor(options: { scope: string; subject?: string }) {\n\t\tthis.scope = options.scope;\n\t\tthis.subject = options.subject;\n\t}\n\n\tprivate toModelMetadata(model: AgentState[\"model\"]): SessionModelMetadata {\n\t\tconst optional = model as AgentState[\"model\"] &\n\t\t\tPartial<Pick<SessionModelMetadata, \"providerName\" | \"source\">>;\n\t\treturn {\n\t\t\tprovider: model.provider,\n\t\t\tmodelId: model.id,\n\t\t\tproviderName: optional.providerName,\n\t\t\tname: model.name,\n\t\t\tbaseUrl: model.baseUrl,\n\t\t\treasoning: model.reasoning,\n\t\t\tcontextWindow: model.contextWindow,\n\t\t\tmaxTokens: model.maxTokens,\n\t\t\tsource: optional.source,\n\t\t};\n\t}\n\n\tprivate enqueue(operation: () => Promise<void>): void {\n\t\tconst result = this.writeChain.then(operation, operation);\n\t\tthis.writeChain = result.then(\n\t\t\t() => undefined,\n\t\t\t(error) => {\n\t\t\t\tif (!this.hasWriteError) {\n\t\t\t\t\tthis.writeError = error;\n\t\t\t\t\tthis.hasWriteError = true;\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\t}\n\n\tprivate rebuildIndex(entries: SessionEntry[]): void {\n\t\tthis.byId.clear();\n\t\tthis.leafId = null;\n\t\tfor (const entry of entries) {\n\t\t\tif (!isSessionTreeEntry(entry)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis.byId.set(entry.id, entry);\n\t\t\tthis.leafId = entry.id;\n\t\t}\n\t\tthis.sessionInitialized = entries.some(isSessionHeaderEntry);\n\t}\n\n\tprivate currentMessageCount(): number {\n\t\treturn this.buildSessionContext().messages.length;\n\t}\n\n\tprivate resolveSessionId(sessionRef?: string): string {\n\t\tif (!sessionRef) {\n\t\t\treturn this.sessionId;\n\t\t}\n\t\treturn sessionRef.startsWith(\"db:\")\n\t\t\t? sessionRef.slice(\"db:\".length)\n\t\t\t: sessionRef;\n\t}\n\n\tprivate async ensureSessionRow(\n\t\tsessionId: string,\n\t\tvalues: Partial<typeof hostedSessions.$inferInsert> = {},\n\t): Promise<void> {\n\t\tconst now = new Date();\n\t\tawait getDb()\n\t\t\t.insert(hostedSessions)\n\t\t\t.values({\n\t\t\t\tsessionId,\n\t\t\t\tscope: this.scope,\n\t\t\t\tsubject: this.subject ?? null,\n\t\t\t\tcwd: process.cwd(),\n\t\t\t\tmessageCount: this.currentMessageCount(),\n\t\t\t\tcreatedAt: now,\n\t\t\t\tupdatedAt: now,\n\t\t\t\t...values,\n\t\t\t})\n\t\t\t.onConflictDoUpdate({\n\t\t\t\ttarget: hostedSessions.sessionId,\n\t\t\t\tset: {\n\t\t\t\t\tscope: this.scope,\n\t\t\t\t\tsubject: values.subject ?? this.subject ?? null,\n\t\t\t\t\tcwd: values.cwd ?? process.cwd(),\n\t\t\t\t\tupdatedAt: now,\n\t\t\t\t\tdeletedAt: null,\n\t\t\t\t\t...values,\n\t\t\t\t},\n\t\t\t});\n\t}\n\n\tprivate appendEntry(entry: SessionEntry): void {\n\t\tthis.entries.push(entry);\n\t\tif (isSessionTreeEntry(entry)) {\n\t\t\tthis.byId.set(entry.id, entry);\n\t\t\tthis.leafId = entry.id;\n\t\t}\n\t\tconst sessionId = this.sessionId;\n\t\tconst entryId =\n\t\t\t\"id\" in entry && typeof entry.id === \"string\" ? entry.id : undefined;\n\t\tconst messageCount = this.currentMessageCount();\n\n\t\tthis.enqueue(async () => {\n\t\t\tawait this.ensureSessionRow(sessionId, { messageCount });\n\t\t\tawait getDb().insert(hostedSessionEntries).values({\n\t\t\t\tsessionId,\n\t\t\t\tentryType: entry.type,\n\t\t\t\tentryId,\n\t\t\t\tentry,\n\t\t\t});\n\t\t\tawait getDb()\n\t\t\t\t.update(hostedSessions)\n\t\t\t\t.set({\n\t\t\t\t\tmessageCount,\n\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t})\n\t\t\t\t.where(eq(hostedSessions.sessionId, sessionId));\n\t\t});\n\t}\n\n\tprivate appendSessionMetaEntry(\n\t\tsessionId: string,\n\t\tfields: Omit<SessionMetaEntry, \"type\" | \"timestamp\">,\n\t\trowUpdates: Partial<typeof hostedSessions.$inferInsert> = {},\n\t): void {\n\t\tconst entry: SessionMetaEntry = {\n\t\t\ttype: \"session_meta\",\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t...fields,\n\t\t};\n\t\tif (sessionId === this.sessionId) {\n\t\t\tthis.entries.push(entry);\n\t\t}\n\t\tconst messageCount =\n\t\t\tsessionId === this.sessionId ? this.currentMessageCount() : undefined;\n\t\tthis.enqueue(async () => {\n\t\t\tif (sessionId === this.sessionId) {\n\t\t\t\tawait this.ensureSessionRow(sessionId, { messageCount });\n\t\t\t}\n\t\t\tawait getDb().insert(hostedSessionEntries).values({\n\t\t\t\tsessionId,\n\t\t\t\tentryType: entry.type,\n\t\t\t\tentry,\n\t\t\t});\n\t\t\tawait getDb()\n\t\t\t\t.update(hostedSessions)\n\t\t\t\t.set({\n\t\t\t\t\t...rowUpdates,\n\t\t\t\t\t...(messageCount !== undefined ? { messageCount } : {}),\n\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t})\n\t\t\t\t.where(\n\t\t\t\t\tand(\n\t\t\t\t\t\teq(hostedSessions.sessionId, sessionId),\n\t\t\t\t\t\teq(hostedSessions.scope, this.scope),\n\t\t\t\t\t\tisNull(hostedSessions.deletedAt),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t});\n\t}\n\n\tprivate async loadRow(sessionId: string): Promise<SessionRow | null> {\n\t\tconst [row] = await getDb()\n\t\t\t.select()\n\t\t\t.from(hostedSessions)\n\t\t\t.where(\n\t\t\t\tand(\n\t\t\t\t\teq(hostedSessions.sessionId, sessionId),\n\t\t\t\t\teq(hostedSessions.scope, this.scope),\n\t\t\t\t\tisNull(hostedSessions.deletedAt),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.limit(1);\n\t\treturn row ?? null;\n\t}\n\n\tprivate async loadEntriesForSession(\n\t\tsessionId: string,\n\t): Promise<SessionEntry[]> {\n\t\tconst rows = await getDb()\n\t\t\t.select({ entry: hostedSessionEntries.entry })\n\t\t\t.from(hostedSessionEntries)\n\t\t\t.where(eq(hostedSessionEntries.sessionId, sessionId))\n\t\t\t.orderBy(asc(hostedSessionEntries.sequence));\n\n\t\tconst entries: SessionEntry[] = [];\n\t\tfor (const row of rows) {\n\t\t\tconst entry = parseSessionEntryValue(row.entry);\n\t\t\tif (entry) {\n\t\t\t\tentries.push(entry);\n\t\t\t}\n\t\t}\n\t\treturn entries;\n\t}\n\n\tasync loadEntries(sessionId: string): Promise<SessionEntry[] | null> {\n\t\tconst row = await this.loadRow(sessionId);\n\t\tif (!row) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this.loadEntriesForSession(sessionId);\n\t}\n\n\tasync resumeSession(sessionId: string): Promise<boolean> {\n\t\tawait this.flush();\n\t\tconst row = await this.loadRow(sessionId);\n\t\tif (!row) {\n\t\t\treturn false;\n\t\t}\n\t\tconst entries = await this.loadEntriesForSession(sessionId);\n\t\tthis.sessionId = row.sessionId;\n\t\tthis.entries = entries;\n\t\tthis.rebuildIndex(entries);\n\t\treturn true;\n\t}\n\n\tloadAllSessions(): SessionMetadata[] {\n\t\treturn [];\n\t}\n\n\tasync countActiveSessions(since: Date): Promise<number> {\n\t\tawait this.flush();\n\t\tconst [row] = await getDb()\n\t\t\t.select({ count: sql<number>`count(*)::int` })\n\t\t\t.from(hostedSessions)\n\t\t\t.where(\n\t\t\t\tand(\n\t\t\t\t\teq(hostedSessions.scope, this.scope),\n\t\t\t\t\tgte(hostedSessions.updatedAt, since),\n\t\t\t\t\tisNull(hostedSessions.deletedAt),\n\t\t\t\t),\n\t\t\t);\n\t\treturn Number(row?.count ?? 0);\n\t}\n\n\tasync listSessions(options?: {\n\t\tlimit?: number;\n\t\toffset?: number;\n\t}): Promise<SessionSummary[]> {\n\t\tawait this.flush();\n\t\tlet query = getDb()\n\t\t\t.select()\n\t\t\t.from(hostedSessions)\n\t\t\t.where(\n\t\t\t\tand(\n\t\t\t\t\teq(hostedSessions.scope, this.scope),\n\t\t\t\t\tisNull(hostedSessions.deletedAt),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.orderBy(desc(hostedSessions.updatedAt))\n\t\t\t.$dynamic();\n\t\tif (typeof options?.limit === \"number\") {\n\t\t\tquery = query.limit(options.limit);\n\t\t}\n\t\tif (typeof options?.offset === \"number\") {\n\t\t\tquery = query.offset(options.offset);\n\t\t}\n\t\tconst rows = await query;\n\n\t\treturn rows.map((row) => ({\n\t\t\tid: row.sessionId,\n\t\t\tsubject: row.subject ?? undefined,\n\t\t\ttitle: row.title ?? undefined,\n\t\t\tsummary: row.summary ?? undefined,\n\t\t\tresumeSummary: row.resumeSummary ?? undefined,\n\t\t\tmemoryExtractionHash: row.memoryExtractionHash ?? undefined,\n\t\t\tcreatedAt: row.createdAt.toISOString(),\n\t\t\tupdatedAt: row.updatedAt.toISOString(),\n\t\t\tmessageCount: row.messageCount,\n\t\t\tfavorite: row.favorite,\n\t\t\ttags: row.tags ?? undefined,\n\t\t}));\n\t}\n\n\tasync loadSession(\n\t\tsessionId: string,\n\t\toptions: { messagesView?: SessionMessagesView } = {},\n\t): Promise<{\n\t\tid: string;\n\t\tsubject?: string;\n\t\ttitle?: string;\n\t\tsummary?: string;\n\t\tresumeSummary?: string;\n\t\tmemoryExtractionHash?: string;\n\t\tmessages: AppMessage[];\n\t\tcreatedAt: string;\n\t\tupdatedAt: string;\n\t\tmessageCount: number;\n\t\tfavorite: boolean;\n\t\ttags?: string[];\n\t\tmessagesView: SessionMessagesView;\n\t} | null> {\n\t\tawait this.flush();\n\t\tconst row = await this.loadRow(sessionId);\n\t\tif (!row) {\n\t\t\treturn null;\n\t\t}\n\t\tconst messagesView = options.messagesView ?? \"full\";\n\t\tif (messagesView === \"notLoaded\") {\n\t\t\treturn {\n\t\t\t\tid: row.sessionId,\n\t\t\t\tsubject: row.subject ?? undefined,\n\t\t\t\ttitle: row.title ?? undefined,\n\t\t\t\tsummary: row.summary ?? undefined,\n\t\t\t\tresumeSummary: row.resumeSummary ?? undefined,\n\t\t\t\tmemoryExtractionHash: row.memoryExtractionHash ?? undefined,\n\t\t\t\tmessages: [],\n\t\t\t\tcreatedAt: row.createdAt.toISOString(),\n\t\t\t\tupdatedAt: row.updatedAt.toISOString(),\n\t\t\t\tmessageCount: row.messageCount,\n\t\t\t\tfavorite: row.favorite,\n\t\t\t\ttags: row.tags ?? undefined,\n\t\t\t\tmessagesView,\n\t\t\t};\n\t\t}\n\t\tconst entries = await this.loadEntriesForSession(sessionId);\n\t\tconst context = buildSessionContextFromEntries(entries);\n\t\tconst extractedById = new Map<string, string>();\n\t\tfor (const entry of entries) {\n\t\t\tif (\n\t\t\t\tentry.type === \"attachment_extract\" &&\n\t\t\t\tentry.attachmentId &&\n\t\t\t\tentry.extractedText\n\t\t\t) {\n\t\t\t\textractedById.set(entry.attachmentId, entry.extractedText);\n\t\t\t}\n\t\t}\n\t\tconst messages =\n\t\t\textractedById.size === 0\n\t\t\t\t? context.messages\n\t\t\t\t: context.messages.map((message) =>\n\t\t\t\t\t\tapplyAttachmentExtracts(message, extractedById),\n\t\t\t\t\t);\n\t\tconst messageCount = row.messageCount || messages.length;\n\t\tconst selectedMessages = selectSessionMessagesForView(\n\t\t\tmessages,\n\t\t\tmessagesView,\n\t\t);\n\n\t\treturn {\n\t\t\tid: row.sessionId,\n\t\t\tsubject: row.subject ?? undefined,\n\t\t\ttitle: row.title ?? undefined,\n\t\t\tsummary: row.summary ?? undefined,\n\t\t\tresumeSummary: row.resumeSummary ?? undefined,\n\t\t\tmemoryExtractionHash: row.memoryExtractionHash ?? undefined,\n\t\t\tmessages: selectedMessages,\n\t\t\tcreatedAt: row.createdAt.toISOString(),\n\t\t\tupdatedAt: row.updatedAt.toISOString(),\n\t\t\tmessageCount,\n\t\t\tfavorite: row.favorite,\n\t\t\ttags: row.tags ?? undefined,\n\t\t\tmessagesView,\n\t\t};\n\t}\n\n\tasync createSession(options?: { title?: string }): Promise<{\n\t\tid: string;\n\t\ttitle?: string;\n\t\tresumeSummary?: string;\n\t\tmessages: AppMessage[];\n\t\tcreatedAt: string;\n\t\tupdatedAt: string;\n\t\tmessageCount: number;\n\t\tfavorite: boolean;\n\t\ttags?: string[];\n\t}> {\n\t\tawait this.flush();\n\t\tthis.sessionId = randomUUID();\n\t\tthis.entries = [];\n\t\tthis.rebuildIndex([]);\n\t\tconst now = new Date();\n\t\tawait this.ensureSessionRow(this.sessionId, {\n\t\t\ttitle: options?.title,\n\t\t\tfavorite: false,\n\t\t\tmessageCount: 0,\n\t\t\tcreatedAt: now,\n\t\t\tupdatedAt: now,\n\t\t});\n\t\treturn {\n\t\t\tid: this.sessionId,\n\t\t\ttitle: options?.title,\n\t\t\tmessages: [],\n\t\t\tcreatedAt: now.toISOString(),\n\t\t\tupdatedAt: now.toISOString(),\n\t\t\tmessageCount: 0,\n\t\t\tfavorite: false,\n\t\t};\n\t}\n\n\tasync deleteSession(sessionId: string): Promise<void> {\n\t\tawait this.flush();\n\t\tawait getDb()\n\t\t\t.update(hostedSessions)\n\t\t\t.set({ deletedAt: new Date(), updatedAt: new Date() })\n\t\t\t.where(\n\t\t\t\tand(\n\t\t\t\t\teq(hostedSessions.sessionId, sessionId),\n\t\t\t\t\teq(hostedSessions.scope, this.scope),\n\t\t\t\t),\n\t\t\t);\n\t}\n\n\tasync createBranchedSessionFromState(\n\t\tstate: AgentState,\n\t\tbranchFromIndex: number,\n\t): Promise<string> {\n\t\tawait this.flush();\n\t\tconst newSessionId = randomUUID();\n\t\tconst timestamp = new Date().toISOString();\n\t\tconst modelKey = `${state.model.provider}/${state.model.id}`;\n\t\tconst branchEntries: SessionEntry[] = [\n\t\t\t{\n\t\t\t\ttype: \"session\",\n\t\t\t\tversion: CURRENT_SESSION_VERSION,\n\t\t\t\tid: newSessionId,\n\t\t\t\ttimestamp,\n\t\t\t\tcwd: process.cwd(),\n\t\t\t\tsubject: this.subject,\n\t\t\t\tmodel: modelKey,\n\t\t\t\tmodelMetadata: this.toModelMetadata(state.model),\n\t\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t\t\tsystemPrompt: state.systemPrompt,\n\t\t\t\tpromptMetadata: state.promptMetadata,\n\t\t\t\tpromptContextManifest: getPersistedSessionPromptContextManifest(state),\n\t\t\t\tunifiedContextManifest: state.unifiedContextManifest,\n\t\t\t\ttools: state.tools.map((tool) => ({\n\t\t\t\t\tname: tool.name,\n\t\t\t\t\tlabel: tool.label,\n\t\t\t\t\tdescription: tool.description,\n\t\t\t\t})),\n\t\t\t\tbranchedFrom: this.sessionId,\n\t\t\t\tparentSession: this.sessionId,\n\t\t\t} satisfies SessionHeaderEntry,\n\t\t];\n\t\tconst branchIds = new Map<string, SessionTreeEntry>();\n\t\tlet parentId: string | null = null;\n\t\tfor (const message of state.messages.slice(0, branchFromIndex)) {\n\t\t\tconst entry: SessionTreeEntry = {\n\t\t\t\ttype: \"message\",\n\t\t\t\tid: generateEntryId(branchIds),\n\t\t\t\tparentId,\n\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\tmessage: sanitizeMessageForSession(message),\n\t\t\t};\n\t\t\tbranchIds.set(entry.id, entry);\n\t\t\tparentId = entry.id;\n\t\t\tbranchEntries.push(entry);\n\t\t}\n\t\tconst now = new Date();\n\t\tawait getDb()\n\t\t\t.insert(hostedSessions)\n\t\t\t.values({\n\t\t\t\tsessionId: newSessionId,\n\t\t\t\tscope: this.scope,\n\t\t\t\tsubject: this.subject,\n\t\t\t\tcwd: process.cwd(),\n\t\t\t\tmodel: modelKey,\n\t\t\t\tmodelMetadata: this.toModelMetadata(state.model),\n\t\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t\t\tsystemPrompt: state.systemPrompt,\n\t\t\t\tpromptMetadata: state.promptMetadata,\n\t\t\t\ttools: state.tools,\n\t\t\t\tmessageCount: branchEntries.filter((entry) => entry.type === \"message\")\n\t\t\t\t\t.length,\n\t\t\t\tcreatedAt: now,\n\t\t\t\tupdatedAt: now,\n\t\t\t});\n\t\tfor (const entry of branchEntries) {\n\t\t\tawait getDb()\n\t\t\t\t.insert(hostedSessionEntries)\n\t\t\t\t.values({\n\t\t\t\t\tsessionId: newSessionId,\n\t\t\t\t\tentryType: entry.type,\n\t\t\t\t\tentryId:\n\t\t\t\t\t\t\"id\" in entry && typeof entry.id === \"string\"\n\t\t\t\t\t\t\t? entry.id\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\tentry,\n\t\t\t\t});\n\t\t}\n\t\treturn newSessionId;\n\t}\n\n\tasync updateSessionMetadata(\n\t\tsessionId: string,\n\t\tupdates: HostedSessionMetadataUpdate,\n\t): Promise<void> {\n\t\tconst set: Partial<typeof hostedSessions.$inferInsert> = {};\n\t\tif (updates.title !== undefined) set.title = updates.title;\n\t\tif (updates.favorite !== undefined) set.favorite = updates.favorite;\n\t\tif (updates.tags !== undefined) set.tags = updates.tags;\n\t\tthis.appendSessionMetaEntry(\n\t\t\tsessionId,\n\t\t\t{\n\t\t\t\t...(updates.title !== undefined ? { title: updates.title } : {}),\n\t\t\t\t...(updates.favorite !== undefined\n\t\t\t\t\t? { favorite: updates.favorite }\n\t\t\t\t\t: {}),\n\t\t\t\t...(updates.tags !== undefined ? { tags: updates.tags } : {}),\n\t\t\t},\n\t\t\tset,\n\t\t);\n\t\tawait this.flush();\n\t}\n\n\tstartSession(state: AgentState, options?: { subject?: string }): void {\n\t\tif (this.sessionInitialized) return;\n\n\t\tconst modelKey = `${state.model.provider}/${state.model.id}`;\n\t\tconst entry: SessionHeaderEntry = {\n\t\t\ttype: \"session\",\n\t\t\tversion: CURRENT_SESSION_VERSION,\n\t\t\tid: this.sessionId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcwd: process.cwd(),\n\t\t\tsubject: options?.subject ?? this.subject,\n\t\t\tmodel: modelKey,\n\t\t\tmodelMetadata: this.toModelMetadata(state.model),\n\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t\tsystemPrompt: state.systemPrompt,\n\t\t\tpromptMetadata: state.promptMetadata,\n\t\t\tpromptContextManifest: getPersistedSessionPromptContextManifest(state),\n\t\t\tunifiedContextManifest: state.unifiedContextManifest,\n\t\t\ttools: state.tools.map((tool) => ({\n\t\t\t\tname: tool.name,\n\t\t\t\tlabel: tool.label,\n\t\t\t\tdescription: tool.description,\n\t\t\t})),\n\t\t};\n\t\tthis.sessionInitialized = true;\n\t\tthis.appendEntry(entry);\n\n\t\tqueueSharedMemoryUpdate({\n\t\t\tsessionId: this.sessionId,\n\t\t\tstate: {\n\t\t\t\tsessionId: this.sessionId,\n\t\t\t\tcwd: process.cwd(),\n\t\t\t\tmodel: modelKey,\n\t\t\t\tupdatedAt: entry.timestamp,\n\t\t\t\tsource: \"maestro\",\n\t\t\t},\n\t\t\tevent: {\n\t\t\t\ttype: \"maestro.session.started\",\n\t\t\t\tpayload: {\n\t\t\t\t\tsessionId: this.sessionId,\n\t\t\t\t\tmodel: modelKey,\n\t\t\t\t\ttimestamp: entry.timestamp,\n\t\t\t\t},\n\t\t\t},\n\t\t});\n\n\t\tif (state.promptMetadata) {\n\t\t\trecordMaestroPromptVariantSelected({\n\t\t\t\tprompt_metadata: state.promptMetadata,\n\t\t\t\tcorrelation: {\n\t\t\t\t\tsession_id: this.sessionId,\n\t\t\t\t},\n\t\t\t\tselected_at: entry.timestamp,\n\t\t\t});\n\t\t}\n\t}\n\n\tsaveMessage(message: AppMessage): void {\n\t\tconst sanitizedMessage = sanitizeMessageForSession(message);\n\t\tconst entry: SessionTreeEntry = {\n\t\t\ttype: \"message\",\n\t\t\tid: this.createTreeEntryId(),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tmessage: sanitizedMessage,\n\t\t};\n\t\tthis.appendEntry(entry);\n\n\t\tqueueSharedMemoryUpdate({\n\t\t\tsessionId: this.sessionId,\n\t\t\tstate: {\n\t\t\t\tsessionId: this.sessionId,\n\t\t\t\tupdatedAt: entry.timestamp,\n\t\t\t\tlastMessageId: entry.id,\n\t\t\t\tlastMessageRole: message.role,\n\t\t\t\tsource: \"maestro\",\n\t\t\t},\n\t\t\tevent: {\n\t\t\t\ttype: \"maestro.message.saved\",\n\t\t\t\tpayload: {\n\t\t\t\t\tsessionId: this.sessionId,\n\t\t\t\t\tmessageId: entry.id,\n\t\t\t\t\trole: message.role,\n\t\t\t\t\ttimestamp: entry.timestamp,\n\t\t\t\t},\n\t\t\t},\n\t\t});\n\t}\n\n\tsaveCompaction(\n\t\tsummary: string,\n\t\tfirstKeptEntryIndex: number,\n\t\ttokensBefore: number,\n\t\toptions?: {\n\t\t\tauto?: boolean;\n\t\t\tcustomInstructions?: string;\n\t\t\tfirstKeptEntryId?: string;\n\t\t},\n\t): void {\n\t\tconst context = this.buildSessionContext();\n\t\tconst fallbackEntry = context.messageEntries[firstKeptEntryIndex];\n\t\tconst firstKeptEntryId =\n\t\t\toptions?.firstKeptEntryId ?? fallbackEntry?.id ?? this.leafId;\n\t\tif (!firstKeptEntryId) {\n\t\t\treturn;\n\t\t}\n\t\tconst entry: CompactionEntry = {\n\t\t\ttype: \"compaction\",\n\t\t\tid: this.createTreeEntryId(),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tsummary,\n\t\t\tfirstKeptEntryId,\n\t\t\ttokensBefore,\n\t\t\tauto: options?.auto,\n\t\t\tcustomInstructions: options?.customInstructions,\n\t\t};\n\t\tthis.appendEntry(entry);\n\t}\n\n\tsaveAttachmentExtraction(\n\t\tsessionRef: string,\n\t\tattachmentId: string,\n\t\ttext: string,\n\t): void {\n\t\tif (!attachmentId || !text) return;\n\t\tconst entry: AttachmentExtractedEntry = {\n\t\t\ttype: \"attachment_extract\",\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tattachmentId,\n\t\t\textractedText: text,\n\t\t};\n\t\tconst targetSessionId = sessionRef.startsWith(\"db:\")\n\t\t\t? sessionRef.slice(\"db:\".length)\n\t\t\t: sessionRef;\n\t\tif (targetSessionId && targetSessionId !== this.sessionId) {\n\t\t\tthis.enqueue(async () => {\n\t\t\t\tawait getDb().insert(hostedSessionEntries).values({\n\t\t\t\t\tsessionId: targetSessionId,\n\t\t\t\t\tentryType: entry.type,\n\t\t\t\t\tentry,\n\t\t\t\t});\n\t\t\t\tawait getDb()\n\t\t\t\t\t.update(hostedSessions)\n\t\t\t\t\t.set({ updatedAt: new Date() })\n\t\t\t\t\t.where(\n\t\t\t\t\t\tand(\n\t\t\t\t\t\t\teq(hostedSessions.sessionId, targetSessionId),\n\t\t\t\t\t\t\teq(hostedSessions.scope, this.scope),\n\t\t\t\t\t\t\tisNull(hostedSessions.deletedAt),\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tthis.appendEntry(entry);\n\t}\n\n\tsaveSessionSummary(summary: string, sessionRef?: string): void {\n\t\tconst trimmed = summary.trim();\n\t\tif (!trimmed) return;\n\t\tconst sessionId = this.resolveSessionId(sessionRef);\n\t\tthis.appendSessionMetaEntry(\n\t\t\tsessionId,\n\t\t\t{ summary: trimmed },\n\t\t\t{ summary: trimmed },\n\t\t);\n\t}\n\n\tsaveSessionResumeSummary(summary: string, sessionRef?: string): void {\n\t\tconst trimmed = summary.trim();\n\t\tif (!trimmed) return;\n\t\tconst sessionId = this.resolveSessionId(sessionRef);\n\t\tthis.appendSessionMetaEntry(\n\t\t\tsessionId,\n\t\t\t{ resumeSummary: trimmed },\n\t\t\t{ resumeSummary: trimmed },\n\t\t);\n\t}\n\n\tsaveSessionMemoryExtractionHash(hash: string, sessionRef?: string): void {\n\t\tconst trimmed = hash.trim();\n\t\tif (!trimmed) return;\n\t\tconst sessionId = this.resolveSessionId(sessionRef);\n\t\tthis.appendSessionMetaEntry(\n\t\t\tsessionId,\n\t\t\t{ memoryExtractionHash: trimmed },\n\t\t\t{ memoryExtractionHash: trimmed },\n\t\t);\n\t}\n\n\tsetSessionFavorite(sessionRef: string, favorite: boolean): void {\n\t\tthis.appendSessionMetaEntry(\n\t\t\tthis.resolveSessionId(sessionRef),\n\t\t\t{ favorite },\n\t\t\t{ favorite },\n\t\t);\n\t}\n\n\tsetSessionTitle(sessionRef: string, title: string): void {\n\t\tthis.appendSessionMetaEntry(\n\t\t\tthis.resolveSessionId(sessionRef),\n\t\t\t{ title },\n\t\t\t{ title },\n\t\t);\n\t}\n\n\tsetSessionTags(sessionRef: string, tags: string[]): void {\n\t\tthis.appendSessionMetaEntry(\n\t\t\tthis.resolveSessionId(sessionRef),\n\t\t\t{ tags },\n\t\t\t{ tags },\n\t\t);\n\t}\n\n\tsetSessionAppServerGoal(\n\t\tsessionRef: string,\n\t\tgoal: NonNullable<SessionMetaEntry[\"appServerGoal\"]> | null,\n\t): void {\n\t\tthis.appendSessionMetaEntry(this.resolveSessionId(sessionRef), {\n\t\t\tappServerGoal: goal,\n\t\t});\n\t}\n\n\tgetSessionId(): string {\n\t\treturn this.sessionId;\n\t}\n\n\tgetSessionFile(): string {\n\t\treturn `db:${this.sessionId}`;\n\t}\n\n\tgetCurrentLeafId(): string | null {\n\t\treturn this.leafId;\n\t}\n\n\tbranch(branchFromId: string): void {\n\t\tif (!this.byId.has(branchFromId)) {\n\t\t\tthrow new Error(`Entry ${branchFromId} not found`);\n\t\t}\n\t\tthis.leafId = branchFromId;\n\t}\n\n\tgetSessionFileById(sessionId: string): string | null {\n\t\treturn `db:${sessionId}`;\n\t}\n\n\tsetSessionFile(sessionRef: string): void {\n\t\tconst sessionId = sessionRef.startsWith(\"db:\")\n\t\t\t? sessionRef.slice(\"db:\".length)\n\t\t\t: sessionRef;\n\t\tif (sessionId) {\n\t\t\tthis.sessionId = sessionId;\n\t\t}\n\t}\n\n\tisInitialized(): boolean {\n\t\treturn this.sessionInitialized;\n\t}\n\n\tshouldInitializeSession(messages: AppMessage[]): boolean {\n\t\treturn (\n\t\t\t!this.sessionInitialized &&\n\t\t\tmessages.some((message) => message.role === \"user\")\n\t\t);\n\t}\n\n\tupdateSnapshot(state: AgentState, metadata?: SessionModelMetadata): void {\n\t\tthis.snapshot = state;\n\t\tif (metadata) {\n\t\t\tthis.lastModelMetadata = metadata;\n\t\t}\n\t}\n\n\tbuildSessionContext(\n\t\tleafId: string | null = this.leafId,\n\t): SessionContextSnapshot {\n\t\treturn buildSessionContextFromEntries(this.entries, {\n\t\t\tleafId,\n\t\t\tbyId: this.byId,\n\t\t\theader: this.getHeader(),\n\t\t});\n\t}\n\n\tloadModel(): string | null {\n\t\treturn this.buildSessionContext().model;\n\t}\n\n\tloadThinkingLevel(): string {\n\t\treturn this.buildSessionContext().thinkingLevel;\n\t}\n\n\tgetHeader(): SessionHeaderEntry | null {\n\t\treturn (\n\t\t\t(this.entries.find((entry) => entry.type === \"session\") as\n\t\t\t\t| SessionHeaderEntry\n\t\t\t\t| undefined) ?? null\n\t\t);\n\t}\n\n\tprivate createTreeEntryId(): string {\n\t\treturn generateEntryId(this.byId);\n\t}\n\n\tasync flush(): Promise<void> {\n\t\tawait this.writeChain;\n\t\tif (this.hasWriteError) {\n\t\t\tconst error = this.writeError;\n\t\t\tthis.writeError = undefined;\n\t\t\tthis.hasWriteError = false;\n\t\t\tthrow error;\n\t\t}\n\t}\n}\n\nexport function isHostedSessionManager(\n\tmanager: unknown,\n): manager is HostedSessionManager {\n\treturn (\n\t\ttypeof manager === \"object\" &&\n\t\tmanager !== null &&\n\t\t\"storageKind\" in manager &&\n\t\t(manager as { storageKind?: unknown }).storageKind === \"database\"\n\t);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"model-selection.d.ts","sourceRoot":"","sources":["../../src/server/model-selection.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,eAAe,EAIpB,MAAM,uBAAuB,CAAC;AAG/B,MAAM,WAAW,cAAc;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,gBAAgB;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,eAAe,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,gBAAgB,CAiC5E;AA0BD,wBAAgB,uBAAuB,CACtC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACrC,eAAe,EAAE,MAAM,EACvB,cAAc,EAAE,MAAM,GACpB,cAAc,CAoChB;AAED,wBAAgB,yBAAyB,CACxC,SAAS,EAAE,cAAc,GACvB,eAAe,CAYjB"}
1
+ {"version":3,"file":"model-selection.d.ts","sourceRoot":"","sources":["../../src/server/model-selection.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,eAAe,EAIpB,MAAM,uBAAuB,CAAC;AAG/B,MAAM,WAAW,cAAc;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,gBAAgB;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,eAAe,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,gBAAgB,CAiC5E;AAsCD,wBAAgB,uBAAuB,CACtC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACrC,eAAe,EAAE,MAAM,EACvB,cAAc,EAAE,MAAM,GACpB,cAAc,CAqChB;AAED,wBAAgB,yBAAyB,CACxC,SAAS,EAAE,cAAc,GACvB,eAAe,CAYjB"}
@@ -52,6 +52,13 @@ function providerExists(name) {
52
52
  return false;
53
53
  return getRegisteredModels().some((m) => m.provider === trimmed);
54
54
  }
55
+ function providerForBareModelId(modelId, defaultProvider) {
56
+ if (!modelId)
57
+ return undefined;
58
+ const matches = getRegisteredModels().filter((model) => model.id === modelId);
59
+ return (matches.find((model) => model.provider === defaultProvider)?.provider ??
60
+ matches[0]?.provider);
61
+ }
55
62
  export function determineModelSelection(modelInput, defaultProvider, defaultModelId) {
56
63
  let parts = parseModelInput(modelInput);
57
64
  parts = resolveModelAlias(parts);
@@ -59,7 +66,8 @@ export function determineModelSelection(modelInput, defaultProvider, defaultMode
59
66
  throw new ApiError(400, "Model id is required when specifying a provider");
60
67
  }
61
68
  if (!parts.provider && parts.modelId) {
62
- parts.provider = defaultProvider;
69
+ parts.provider =
70
+ providerForBareModelId(parts.modelId, defaultProvider) ?? defaultProvider;
63
71
  }
64
72
  if (!parts.provider && !parts.modelId) {
65
73
  const factoryDefault = getFactoryDefaultModelSelection();
@@ -1 +1 @@
1
- {"version":3,"file":"model-selection.js","sourceRoot":"","sources":["../../src/server/model-selection.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype RegisteredModel,\n\tgetFactoryDefaultModelSelection,\n\tgetRegisteredModels,\n\tresolveAlias,\n} from \"../models/registry.js\";\nimport { ApiError } from \"./server-utils.js\";\n\nexport interface ModelSelection {\n\tprovider: string;\n\tmodelId: string;\n}\n\ninterface ParsedModelInput {\n\tprovider?: string;\n\tmodelId?: string;\n}\n\nexport function parseModelInput(modelInput?: string | null): ParsedModelInput {\n\tconst normalized = modelInput?.trim();\n\tif (!normalized) {\n\t\treturn {};\n\t}\n\n\t// Prefer explicit provider delimiter \":\"\n\tif (normalized.includes(\":\")) {\n\t\tconst parts = normalized.split(\":\");\n\t\tif (parts.length !== 2) {\n\t\t\tthrow new ApiError(400, `Invalid model format: \"${normalized}\"`);\n\t\t}\n\t\tconst [providerPart, modelPart] = parts;\n\t\treturn {\n\t\t\tprovider: providerPart?.trim() || undefined,\n\t\t\tmodelId: modelPart?.trim() || undefined,\n\t\t};\n\t}\n\n\t// Only treat \"/\" as provider delimiter when the prefix matches a known provider.\n\tif (normalized.includes(\"/\")) {\n\t\tconst [possibleProvider, ...rest] = normalized.split(\"/\");\n\t\tif (possibleProvider && providerExists(possibleProvider)) {\n\t\t\tconst modelId = rest.join(\"/\").trim();\n\t\t\treturn {\n\t\t\t\tprovider: possibleProvider.trim() || undefined,\n\t\t\t\tmodelId: modelId || undefined,\n\t\t\t};\n\t\t}\n\t}\n\n\t// Otherwise it's a bare model id (which may itself contain \"/\")\n\treturn { modelId: normalized };\n}\n\nfunction resolveModelAlias(parts: ParsedModelInput): ParsedModelInput {\n\tif (!parts.modelId) {\n\t\treturn parts;\n\t}\n\tconst alias = resolveAlias(parts.modelId);\n\tif (!alias) {\n\t\treturn parts;\n\t}\n\tif (parts.provider && parts.provider !== alias.provider) {\n\t\tthrow new ApiError(\n\t\t\t400,\n\t\t\t`Alias \"${parts.modelId}\" maps to ${alias.provider}/${alias.modelId}, but provider \"${parts.provider}\" was requested`,\n\t\t);\n\t}\n\treturn { provider: alias.provider, modelId: alias.modelId };\n}\n\nfunction providerExists(name: string | undefined): boolean {\n\tif (!name) return false;\n\tconst trimmed = name.trim();\n\tif (!trimmed) return false;\n\treturn getRegisteredModels().some((m) => m.provider === trimmed);\n}\n\nexport function determineModelSelection(\n\tmodelInput: string | null | undefined,\n\tdefaultProvider: string,\n\tdefaultModelId: string,\n): ModelSelection {\n\tlet parts = parseModelInput(modelInput);\n\tparts = resolveModelAlias(parts);\n\n\tif (parts.provider && !parts.modelId) {\n\t\tthrow new ApiError(400, \"Model id is required when specifying a provider\");\n\t}\n\n\tif (!parts.provider && parts.modelId) {\n\t\tparts.provider = defaultProvider;\n\t}\n\n\tif (!parts.provider && !parts.modelId) {\n\t\tconst factoryDefault = getFactoryDefaultModelSelection();\n\t\tif (factoryDefault) {\n\t\t\treturn {\n\t\t\t\tprovider: factoryDefault.provider,\n\t\t\t\tmodelId: factoryDefault.modelId,\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tprovider: defaultProvider,\n\t\t\tmodelId: defaultModelId,\n\t\t};\n\t}\n\n\tconst finalProvider = parts.provider;\n\tconst finalModelId = parts.modelId;\n\tif (!finalProvider || !finalModelId) {\n\t\tthrow new ApiError(400, \"Model selection is incomplete\");\n\t}\n\n\treturn {\n\t\tprovider: finalProvider,\n\t\tmodelId: finalModelId,\n\t};\n}\n\nexport function getRegisteredModelOrThrow(\n\tselection: ModelSelection,\n): RegisteredModel {\n\tconst registeredModel = getRegisteredModels().find(\n\t\t(entry) =>\n\t\t\tentry.provider === selection.provider && entry.id === selection.modelId,\n\t);\n\tif (!registeredModel) {\n\t\tthrow new ApiError(\n\t\t\t404,\n\t\t\t`Model ${selection.provider}/${selection.modelId} not found in registry`,\n\t\t);\n\t}\n\treturn registeredModel;\n}\n"]}
1
+ {"version":3,"file":"model-selection.js","sourceRoot":"","sources":["../../src/server/model-selection.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype RegisteredModel,\n\tgetFactoryDefaultModelSelection,\n\tgetRegisteredModels,\n\tresolveAlias,\n} from \"../models/registry.js\";\nimport { ApiError } from \"./server-utils.js\";\n\nexport interface ModelSelection {\n\tprovider: string;\n\tmodelId: string;\n}\n\ninterface ParsedModelInput {\n\tprovider?: string;\n\tmodelId?: string;\n}\n\nexport function parseModelInput(modelInput?: string | null): ParsedModelInput {\n\tconst normalized = modelInput?.trim();\n\tif (!normalized) {\n\t\treturn {};\n\t}\n\n\t// Prefer explicit provider delimiter \":\"\n\tif (normalized.includes(\":\")) {\n\t\tconst parts = normalized.split(\":\");\n\t\tif (parts.length !== 2) {\n\t\t\tthrow new ApiError(400, `Invalid model format: \"${normalized}\"`);\n\t\t}\n\t\tconst [providerPart, modelPart] = parts;\n\t\treturn {\n\t\t\tprovider: providerPart?.trim() || undefined,\n\t\t\tmodelId: modelPart?.trim() || undefined,\n\t\t};\n\t}\n\n\t// Only treat \"/\" as provider delimiter when the prefix matches a known provider.\n\tif (normalized.includes(\"/\")) {\n\t\tconst [possibleProvider, ...rest] = normalized.split(\"/\");\n\t\tif (possibleProvider && providerExists(possibleProvider)) {\n\t\t\tconst modelId = rest.join(\"/\").trim();\n\t\t\treturn {\n\t\t\t\tprovider: possibleProvider.trim() || undefined,\n\t\t\t\tmodelId: modelId || undefined,\n\t\t\t};\n\t\t}\n\t}\n\n\t// Otherwise it's a bare model id (which may itself contain \"/\")\n\treturn { modelId: normalized };\n}\n\nfunction resolveModelAlias(parts: ParsedModelInput): ParsedModelInput {\n\tif (!parts.modelId) {\n\t\treturn parts;\n\t}\n\tconst alias = resolveAlias(parts.modelId);\n\tif (!alias) {\n\t\treturn parts;\n\t}\n\tif (parts.provider && parts.provider !== alias.provider) {\n\t\tthrow new ApiError(\n\t\t\t400,\n\t\t\t`Alias \"${parts.modelId}\" maps to ${alias.provider}/${alias.modelId}, but provider \"${parts.provider}\" was requested`,\n\t\t);\n\t}\n\treturn { provider: alias.provider, modelId: alias.modelId };\n}\n\nfunction providerExists(name: string | undefined): boolean {\n\tif (!name) return false;\n\tconst trimmed = name.trim();\n\tif (!trimmed) return false;\n\treturn getRegisteredModels().some((m) => m.provider === trimmed);\n}\n\nfunction providerForBareModelId(\n\tmodelId: string | undefined,\n\tdefaultProvider: string,\n): string | undefined {\n\tif (!modelId) return undefined;\n\tconst matches = getRegisteredModels().filter((model) => model.id === modelId);\n\treturn (\n\t\tmatches.find((model) => model.provider === defaultProvider)?.provider ??\n\t\tmatches[0]?.provider\n\t);\n}\n\nexport function determineModelSelection(\n\tmodelInput: string | null | undefined,\n\tdefaultProvider: string,\n\tdefaultModelId: string,\n): ModelSelection {\n\tlet parts = parseModelInput(modelInput);\n\tparts = resolveModelAlias(parts);\n\n\tif (parts.provider && !parts.modelId) {\n\t\tthrow new ApiError(400, \"Model id is required when specifying a provider\");\n\t}\n\n\tif (!parts.provider && parts.modelId) {\n\t\tparts.provider =\n\t\t\tproviderForBareModelId(parts.modelId, defaultProvider) ?? defaultProvider;\n\t}\n\n\tif (!parts.provider && !parts.modelId) {\n\t\tconst factoryDefault = getFactoryDefaultModelSelection();\n\t\tif (factoryDefault) {\n\t\t\treturn {\n\t\t\t\tprovider: factoryDefault.provider,\n\t\t\t\tmodelId: factoryDefault.modelId,\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tprovider: defaultProvider,\n\t\t\tmodelId: defaultModelId,\n\t\t};\n\t}\n\n\tconst finalProvider = parts.provider;\n\tconst finalModelId = parts.modelId;\n\tif (!finalProvider || !finalModelId) {\n\t\tthrow new ApiError(400, \"Model selection is incomplete\");\n\t}\n\n\treturn {\n\t\tprovider: finalProvider,\n\t\tmodelId: finalModelId,\n\t};\n}\n\nexport function getRegisteredModelOrThrow(\n\tselection: ModelSelection,\n): RegisteredModel {\n\tconst registeredModel = getRegisteredModels().find(\n\t\t(entry) =>\n\t\t\tentry.provider === selection.provider && entry.id === selection.modelId,\n\t);\n\tif (!registeredModel) {\n\t\tthrow new ApiError(\n\t\t\t404,\n\t\t\t`Model ${selection.provider}/${selection.modelId} not found in registry`,\n\t\t);\n\t}\n\treturn registeredModel;\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @fileoverview Rate Limiting for Composer Web Server
2
+ * @fileoverview Rate Limiting for Maestro Web Server
3
3
  *
4
4
  * This module provides a token bucket rate limiter with Redis support for
5
5
  * distributed deployments. It supports both per-IP global limits and
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @fileoverview Rate Limiting for Composer Web Server
2
+ * @fileoverview Rate Limiting for Maestro Web Server
3
3
  *
4
4
  * This module provides a token bucket rate limiter with Redis support for
5
5
  * distributed deployments. It supports both per-IP global limits and
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/server/rate-limiter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Rate Limiting for Composer Web Server\n *\n * This module provides a token bucket rate limiter with Redis support for\n * distributed deployments. It supports both per-IP global limits and\n * per-endpoint limits with tiered configuration.\n *\n * ## Features\n *\n * - **Token Bucket Algorithm**: Smooth rate limiting with burst capacity\n * - **Redis Support**: Distributed rate limiting across server instances\n * - **In-Memory Fallback**: Works without Redis for single-instance deployments\n * - **Tiered Limits**: Different limits per endpoint based on resource cost\n * - **Automatic Cleanup**: Old entries are purged to prevent memory leaks\n *\n * ## Configuration\n *\n * | Environment Variable | Description | Default |\n * |---------------------|-------------|---------|\n * | `MAESTRO_REDIS_URL` | Redis connection URL | (in-memory fallback) |\n *\n * ## Default Endpoint Limits\n *\n * | Endpoint | Limit | Rationale |\n * |----------|-------|-----------|\n * | `/api/chat` | 30/min | LLM inference is expensive |\n * | `/api/model` | 60/min | Model switching is moderate |\n * | `/api/files` | 200/min | File operations |\n * | `/api/commands` | 100/min | Command execution |\n * | `/api/status` | 500/min | Status checks are cheap |\n *\n * ## Usage\n *\n * ```typescript\n * import { RateLimiter, TieredRateLimiter } from \"./rate-limiter.js\";\n *\n * // Simple rate limiter\n * const limiter = new RateLimiter({ windowMs: 60000, max: 100 });\n * const result = await limiter.checkAsync(clientIp);\n * if (!result.allowed) {\n * res.setHeader(\"Retry-After\", Math.ceil((result.reset - Date.now()) / 1000));\n * res.writeHead(429);\n * return;\n * }\n *\n * // Tiered rate limiter with endpoint-specific limits\n * const tiered = new TieredRateLimiter();\n * const result = tiered.check(clientIp, \"/api/chat\");\n * ```\n *\n * @module web/rate-limiter\n */\nimport { Redis } from \"ioredis\";\nimport { createLogger } from \"../utils/logger.js\";\n\nconst logger = createLogger(\"rate-limiter\");\n\nexport interface RateLimitConfig {\n\twindowMs: number;\n\tmax: number;\n}\n\n/**\n * Per-endpoint rate limit overrides.\n * Endpoints not listed use the global rate limit.\n */\nexport interface EndpointRateLimits {\n\t[endpoint: string]: RateLimitConfig;\n}\n\n/**\n * Default endpoint-specific rate limits.\n * More restrictive for expensive operations.\n */\nexport const DEFAULT_ENDPOINT_LIMITS: EndpointRateLimits = {\n\t// Chat endpoint is expensive (LLM inference)\n\t\"/api/chat\": { windowMs: 60000, max: 30 },\n\t// Model switching is moderately expensive\n\t\"/api/model\": { windowMs: 60000, max: 60 },\n\t// File operations - moderate limit\n\t\"/api/files\": { windowMs: 60000, max: 200 },\n\t// Commands can trigger expensive operations\n\t\"/api/commands\": { windowMs: 60000, max: 100 },\n\t// Status endpoints are cheap\n\t\"/api/status\": { windowMs: 60000, max: 500 },\n\t\"/api/config\": { windowMs: 60000, max: 500 },\n};\n\ninterface ClientState {\n\ttokens: number;\n\tlastRefill: number;\n}\n\nexport interface RateLimitResult {\n\tallowed: boolean;\n\tremaining: number;\n\treset: number;\n\tlimit: number;\n}\n\n// ============================================================================\n// REDIS CONNECTION (shared singleton)\n// ============================================================================\n\nlet redis: Redis | null = null;\nlet redisAvailable = false;\nlet redisInitPromise: Promise<boolean> | null = null;\n\n/**\n * Initialize Redis connection if MAESTRO_REDIS_URL is configured.\n * Returns true if Redis is available, false otherwise.\n */\nexport async function initRedis(): Promise<boolean> {\n\tconst redisUrl = process.env.MAESTRO_REDIS_URL;\n\tif (!redisUrl) {\n\t\tlogger.debug(\n\t\t\t\"No MAESTRO_REDIS_URL configured, using in-memory rate limiting\",\n\t\t);\n\t\treturn false;\n\t}\n\n\tif (redisInitPromise) {\n\t\treturn redisInitPromise;\n\t}\n\n\tredisInitPromise = (async () => {\n\t\ttry {\n\t\t\tconst client = new Redis(redisUrl, {\n\t\t\t\tmaxRetriesPerRequest: 1,\n\t\t\t\tretryStrategy: (times: number) => {\n\t\t\t\t\tif (times > 3) return null;\n\t\t\t\t\treturn Math.min(times * 100, 1000);\n\t\t\t\t},\n\t\t\t\tlazyConnect: true,\n\t\t\t\tenableOfflineQueue: false,\n\t\t\t});\n\n\t\t\tclient.on(\"error\", (err: Error) => {\n\t\t\t\tlogger.warn(\"Redis error\", { error: err.message });\n\t\t\t\tredisAvailable = false;\n\t\t\t});\n\n\t\t\tclient.on(\"connect\", () => {\n\t\t\t\tredisAvailable = true;\n\t\t\t\tlogger.info(\"Redis connected for rate limiting\");\n\t\t\t});\n\n\t\t\tawait client.connect();\n\t\t\tredis = client;\n\t\t\tredisAvailable = true;\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tlogger.warn(\"Redis connection failed, using in-memory fallback\", {\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t});\n\t\t\tredis = null;\n\t\t\tredisAvailable = false;\n\t\t\treturn false;\n\t\t}\n\t})();\n\n\treturn redisInitPromise;\n}\n\n/**\n * Check if Redis is being used for rate limiting.\n */\nexport function isRedisAvailable(): boolean {\n\treturn redisAvailable;\n}\n\n/**\n * Get the Redis client (for testing or advanced usage).\n */\nexport function getRedisClient(): Redis | null {\n\treturn redis;\n}\n\n/**\n * Shutdown Redis connection gracefully.\n */\nexport async function shutdownRedis(): Promise<void> {\n\tif (redis) {\n\t\tawait redis.quit().catch((err) => {\n\t\t\tlogger.debug(\"Redis quit failed during shutdown\", {\n\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t});\n\t\t});\n\t\tredis = null;\n\t\tredisAvailable = false;\n\t\tredisInitPromise = null;\n\t}\n}\n\n// Initialize Redis on module load (non-blocking)\ninitRedis().catch((err) => {\n\tlogger.warn(\"Redis initialization failed\", {\n\t\terror: err instanceof Error ? err.message : String(err),\n\t});\n});\n\n// ============================================================================\n// RATE LIMITER\n// ============================================================================\n\nexport class RateLimiter {\n\tprivate clients = new Map<string, ClientState>();\n\tprivate windowMs: number;\n\tprivate max: number;\n\tprivate refillRate: number; // tokens per ms\n\tprivate keyPrefix: string;\n\tprivate cleanupInterval: ReturnType<typeof setInterval> | null = null;\n\n\tconstructor(\n\t\tconfig: RateLimitConfig = { windowMs: 60000, max: 100 },\n\t\tkeyPrefix = \"rl\",\n\t) {\n\t\tthis.windowMs = config.windowMs;\n\t\tthis.max = config.max;\n\t\tthis.refillRate = config.max / config.windowMs;\n\t\tthis.keyPrefix = keyPrefix;\n\n\t\t// Cleanup old entries every minute\n\t\tthis.cleanupInterval = setInterval(() => this.cleanup(), 60000);\n\t\tthis.cleanupInterval.unref();\n\t}\n\n\t/**\n\t * Check rate limit (async to support Redis).\n\t */\n\tasync checkAsync(ip: string): Promise<RateLimitResult> {\n\t\tif (redis && redisAvailable) {\n\t\t\ttry {\n\t\t\t\treturn await this.checkRedis(ip);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.debug(\"Redis check failed, using memory fallback\", {\n\t\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn this.checkMemory(ip);\n\t}\n\n\t/**\n\t * Synchronous check (memory only, for backwards compatibility).\n\t */\n\tcheck(ip: string): RateLimitResult {\n\t\treturn this.checkMemory(ip);\n\t}\n\n\tprivate async checkRedis(ip: string): Promise<RateLimitResult> {\n\t\tconst key = `${this.keyPrefix}:${ip}`;\n\t\tconst now = Date.now();\n\n\t\t// Lua script for atomic token bucket\n\t\tconst script = `\n\t\t\tlocal key = KEYS[1]\n\t\t\tlocal max = tonumber(ARGV[1])\n\t\t\tlocal refillRate = tonumber(ARGV[2])\n\t\t\tlocal now = tonumber(ARGV[3])\n\t\t\tlocal windowMs = tonumber(ARGV[4])\n\n\t\t\tlocal data = redis.call('HMGET', key, 'tokens', 'lastRefill')\n\t\t\tlocal tokens = tonumber(data[1]) or max\n\t\t\tlocal lastRefill = tonumber(data[2]) or now\n\n\t\t\t-- Refill tokens\n\t\t\tlocal timePassed = now - lastRefill\n\t\t\tlocal refillAmount = timePassed * refillRate\n\t\t\ttokens = math.min(max, tokens + refillAmount)\n\n\t\t\tlocal allowed = 0\n\t\t\tif tokens >= 1 then\n\t\t\t\ttokens = tokens - 1\n\t\t\t\tallowed = 1\n\t\t\tend\n\n\t\t\tredis.call('HMSET', key, 'tokens', tokens, 'lastRefill', now)\n\t\t\tredis.call('PEXPIRE', key, windowMs)\n\n\t\t\treturn {allowed, math.floor(tokens), now}\n\t\t`;\n\n\t\tif (!redis) {\n\t\t\tthrow new Error(\"Redis not available\");\n\t\t}\n\t\tconst result = (await redis.eval(\n\t\t\tscript,\n\t\t\t1,\n\t\t\tkey,\n\t\t\tthis.max,\n\t\t\tthis.refillRate,\n\t\t\tnow,\n\t\t\tthis.windowMs,\n\t\t)) as [number, number, number];\n\n\t\tconst allowed = result[0] === 1;\n\t\tconst remaining = result[1];\n\n\t\tif (!allowed) {\n\t\t\tconst tokensNeeded = 1 - remaining;\n\t\t\tconst msNeeded = tokensNeeded / this.refillRate;\n\t\t\treturn {\n\t\t\t\tallowed: false,\n\t\t\t\tremaining: 0,\n\t\t\t\treset: now + msNeeded,\n\t\t\t\tlimit: this.max,\n\t\t\t};\n\t\t}\n\n\t\tconst tokensNeeded = 1 - remaining;\n\t\tconst msNeeded = Math.max(0, tokensNeeded / this.refillRate);\n\t\treturn {\n\t\t\tallowed: true,\n\t\t\tremaining,\n\t\t\treset: now + msNeeded,\n\t\t\tlimit: this.max,\n\t\t};\n\t}\n\n\tprivate checkMemory(ip: string): RateLimitResult {\n\t\tconst now = Date.now();\n\t\tlet client = this.clients.get(ip);\n\n\t\tif (!client) {\n\t\t\tclient = {\n\t\t\t\ttokens: this.max,\n\t\t\t\tlastRefill: now,\n\t\t\t};\n\t\t\tthis.clients.set(ip, client);\n\t\t}\n\n\t\t// Refill tokens\n\t\tconst timePassed = now - client.lastRefill;\n\t\tconst refillAmount = timePassed * this.refillRate;\n\n\t\tclient.tokens = Math.min(this.max, client.tokens + refillAmount);\n\t\tclient.lastRefill = now;\n\n\t\tif (client.tokens >= 1) {\n\t\t\tclient.tokens -= 1;\n\t\t\tconst tokensNeeded = 1 - client.tokens;\n\t\t\tconst msNeeded = Math.max(0, tokensNeeded / this.refillRate);\n\t\t\treturn {\n\t\t\t\tallowed: true,\n\t\t\t\tremaining: Math.floor(client.tokens),\n\t\t\t\treset: now + msNeeded,\n\t\t\t\tlimit: this.max,\n\t\t\t};\n\t\t}\n\n\t\tconst tokensNeeded = 1 - client.tokens;\n\t\tconst msNeeded = tokensNeeded / this.refillRate;\n\t\treturn {\n\t\t\tallowed: false,\n\t\t\tremaining: 0,\n\t\t\treset: now + msNeeded,\n\t\t\tlimit: this.max,\n\t\t};\n\t}\n\n\tgetConfig(): RateLimitConfig {\n\t\treturn { windowMs: this.windowMs, max: this.max };\n\t}\n\n\t/**\n\t * Check if a request would be allowed without consuming a token.\n\t * Used by TieredRateLimiter to avoid token leaks.\n\t */\n\tpeek(ip: string): RateLimitResult {\n\t\tconst now = Date.now();\n\t\tconst client = this.clients.get(ip);\n\n\t\tif (!client) {\n\t\t\t// New client would have full tokens\n\t\t\treturn {\n\t\t\t\tallowed: true,\n\t\t\t\tremaining: this.max - 1, // Would have this many after consuming\n\t\t\t\treset: now,\n\t\t\t\tlimit: this.max,\n\t\t\t};\n\t\t}\n\n\t\t// Calculate current tokens (with refill) without mutating state\n\t\tconst timePassed = now - client.lastRefill;\n\t\tconst refillAmount = timePassed * this.refillRate;\n\t\tconst currentTokens = Math.min(this.max, client.tokens + refillAmount);\n\n\t\tif (currentTokens >= 1) {\n\t\t\treturn {\n\t\t\t\tallowed: true,\n\t\t\t\tremaining: Math.floor(currentTokens - 1),\n\t\t\t\treset: now,\n\t\t\t\tlimit: this.max,\n\t\t\t};\n\t\t}\n\n\t\tconst tokensNeeded = 1 - currentTokens;\n\t\tconst msNeeded = tokensNeeded / this.refillRate;\n\t\treturn {\n\t\t\tallowed: false,\n\t\t\tremaining: 0,\n\t\t\treset: now + msNeeded,\n\t\t\tlimit: this.max,\n\t\t};\n\t}\n\n\t/**\n\t * Reset rate limit for an IP (for testing).\n\t */\n\tasync reset(ip?: string): Promise<void> {\n\t\tif (ip) {\n\t\t\tthis.clients.delete(ip);\n\t\t\tif (redis && redisAvailable) {\n\t\t\t\tawait redis.del(`${this.keyPrefix}:${ip}`).catch((err) => {\n\t\t\t\t\tlogger.debug(\"Redis del failed during reset\", {\n\t\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tthis.clients.clear();\n\t\t\tif (redis && redisAvailable) {\n\t\t\t\t// Use SCAN instead of KEYS to avoid blocking Redis\n\t\t\t\tlet cursor = \"0\";\n\t\t\t\tdo {\n\t\t\t\t\tconst [nextCursor, keys] = await redis.scan(\n\t\t\t\t\t\tcursor,\n\t\t\t\t\t\t\"MATCH\",\n\t\t\t\t\t\t`${this.keyPrefix}:*`,\n\t\t\t\t\t\t\"COUNT\",\n\t\t\t\t\t\t100,\n\t\t\t\t\t);\n\t\t\t\t\tcursor = nextCursor;\n\t\t\t\t\tif (keys.length > 0) {\n\t\t\t\t\t\tawait redis.del(...keys).catch((err) => {\n\t\t\t\t\t\t\tlogger.debug(\"Redis bulk del failed during reset\", {\n\t\t\t\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} while (cursor !== \"0\");\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Stop cleanup interval (for graceful shutdown).\n\t */\n\tstop(): void {\n\t\tif (this.cleanupInterval) {\n\t\t\tclearInterval(this.cleanupInterval);\n\t\t\tthis.cleanupInterval = null;\n\t\t}\n\t}\n\n\tprivate cleanup() {\n\t\tconst now = Date.now();\n\t\tfor (const [ip, client] of this.clients.entries()) {\n\t\t\tif (now - client.lastRefill > this.windowMs) {\n\t\t\t\tthis.clients.delete(ip);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Multi-tier rate limiter with per-endpoint limits.\n *\n * Provides both global IP-based rate limiting and endpoint-specific limits.\n * The more restrictive limit applies.\n */\nexport class TieredRateLimiter {\n\tprivate globalLimiter: RateLimiter;\n\tprivate endpointLimiters = new Map<string, RateLimiter>();\n\tprivate endpointLimits: EndpointRateLimits;\n\n\tconstructor(\n\t\tglobalConfig: RateLimitConfig = { windowMs: 60000, max: 1000 },\n\t\tendpointLimits: EndpointRateLimits = DEFAULT_ENDPOINT_LIMITS,\n\t) {\n\t\tthis.globalLimiter = new RateLimiter(globalConfig);\n\t\tthis.endpointLimits = endpointLimits;\n\n\t\t// Pre-create endpoint limiters\n\t\tfor (const [endpoint, config] of Object.entries(endpointLimits)) {\n\t\t\tthis.endpointLimiters.set(endpoint, new RateLimiter(config));\n\t\t}\n\t}\n\n\t/**\n\t * Check rate limit for a specific IP and endpoint (async, uses Redis if available).\n\t * Returns the most restrictive result between global and endpoint limits.\n\t *\n\t * Uses peek-then-consume pattern to avoid token leaks:\n\t * - First peeks at both limits without consuming\n\t * - Only consumes tokens if both limits allow the request\n\t */\n\tasync checkAsync(ip: string, endpoint: string): Promise<RateLimitResult> {\n\t\t// Peek at global limit first (no consumption)\n\t\tconst globalPeek = this.globalLimiter.peek(ip);\n\t\tif (!globalPeek.allowed) {\n\t\t\treturn globalPeek;\n\t\t}\n\n\t\t// Find matching endpoint limiter and pattern\n\t\tconst match = this.findEndpointLimiter(endpoint);\n\t\tif (!match) {\n\t\t\t// No endpoint limit - consume global token and return\n\t\t\treturn this.globalLimiter.checkAsync(ip);\n\t\t}\n\n\t\t// Use the matched pattern (not full path) for the key so all sub-routes\n\t\t// share the same bucket. E.g., /api/chat/approval uses key \"ip:/api/chat\"\n\t\tconst endpointKey = `${ip}:${match.pattern}`;\n\t\tconst endpointPeek = match.limiter.peek(endpointKey);\n\t\tif (!endpointPeek.allowed) {\n\t\t\t// Endpoint limit would reject - return without consuming global token\n\t\t\treturn endpointPeek;\n\t\t}\n\n\t\t// Both limits allow - consume tokens from both\n\t\tconst [globalResult, endpointResult] = await Promise.all([\n\t\t\tthis.globalLimiter.checkAsync(ip),\n\t\t\tmatch.limiter.checkAsync(endpointKey),\n\t\t]);\n\n\t\t// Return the more restrictive result\n\t\treturn globalResult.remaining <= endpointResult.remaining\n\t\t\t? globalResult\n\t\t\t: endpointResult;\n\t}\n\n\t/**\n\t * Check rate limit for a specific IP and endpoint (sync, memory only).\n\t * Returns the most restrictive result between global and endpoint limits.\n\t *\n\t * Uses peek-then-consume pattern to avoid token leaks:\n\t * - First peeks at both limits without consuming\n\t * - Only consumes tokens if both limits allow the request\n\t */\n\tcheck(ip: string, endpoint: string): RateLimitResult {\n\t\t// Peek at global limit first (no consumption)\n\t\tconst globalPeek = this.globalLimiter.peek(ip);\n\t\tif (!globalPeek.allowed) {\n\t\t\treturn globalPeek;\n\t\t}\n\n\t\t// Find matching endpoint limiter and pattern\n\t\tconst match = this.findEndpointLimiter(endpoint);\n\t\tif (!match) {\n\t\t\t// No endpoint limit - consume global token and return\n\t\t\treturn this.globalLimiter.check(ip);\n\t\t}\n\n\t\t// Use the matched pattern (not full path) for the key so all sub-routes\n\t\t// share the same bucket. E.g., /api/chat/approval uses key \"ip:/api/chat\"\n\t\tconst endpointKey = `${ip}:${match.pattern}`;\n\t\tconst endpointPeek = match.limiter.peek(endpointKey);\n\t\tif (!endpointPeek.allowed) {\n\t\t\t// Endpoint limit would reject - return without consuming global token\n\t\t\treturn endpointPeek;\n\t\t}\n\n\t\t// Both limits allow - consume tokens from both\n\t\tconst globalResult = this.globalLimiter.check(ip);\n\t\tconst endpointResult = match.limiter.check(endpointKey);\n\n\t\t// Return the more restrictive result\n\t\treturn globalResult.remaining <= endpointResult.remaining\n\t\t\t? globalResult\n\t\t\t: endpointResult;\n\t}\n\n\t/**\n\t * Find the rate limiter for a given endpoint path.\n\t * Supports exact match and prefix matching.\n\t * Returns both the limiter and the matched pattern for consistent key generation.\n\t */\n\tprivate findEndpointLimiter(\n\t\tendpoint: string,\n\t): { limiter: RateLimiter; pattern: string } | undefined {\n\t\t// Exact match\n\t\tconst exactMatch = this.endpointLimiters.get(endpoint);\n\t\tif (exactMatch) {\n\t\t\treturn {\n\t\t\t\tlimiter: exactMatch,\n\t\t\t\tpattern: endpoint,\n\t\t\t};\n\t\t}\n\n\t\t// Prefix match (e.g., /api/files/read matches /api/files)\n\t\t// All sub-routes share the same bucket under the pattern\n\t\tfor (const [pattern, limiter] of this.endpointLimiters) {\n\t\t\tif (endpoint.startsWith(pattern)) {\n\t\t\t\treturn { limiter, pattern };\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Get all configured limits for debugging/metrics.\n\t */\n\tgetLimits(): { global: RateLimitConfig; endpoints: EndpointRateLimits } {\n\t\treturn {\n\t\t\tglobal: this.globalLimiter.getConfig(),\n\t\t\tendpoints: this.endpointLimits,\n\t\t};\n\t}\n\n\t/**\n\t * Add or update an endpoint-specific rate limit.\n\t */\n\tsetEndpointLimit(endpoint: string, config: RateLimitConfig): void {\n\t\tthis.endpointLimits[endpoint] = config;\n\t\tthis.endpointLimiters.set(endpoint, new RateLimiter(config));\n\t}\n\n\t/**\n\t * Stop all cleanup intervals (for graceful shutdown and test cleanup).\n\t */\n\tstop(): void {\n\t\tthis.globalLimiter.stop();\n\t\tfor (const limiter of this.endpointLimiters.values()) {\n\t\t\tlimiter.stop();\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/server/rate-limiter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Rate Limiting for Maestro Web Server\n *\n * This module provides a token bucket rate limiter with Redis support for\n * distributed deployments. It supports both per-IP global limits and\n * per-endpoint limits with tiered configuration.\n *\n * ## Features\n *\n * - **Token Bucket Algorithm**: Smooth rate limiting with burst capacity\n * - **Redis Support**: Distributed rate limiting across server instances\n * - **In-Memory Fallback**: Works without Redis for single-instance deployments\n * - **Tiered Limits**: Different limits per endpoint based on resource cost\n * - **Automatic Cleanup**: Old entries are purged to prevent memory leaks\n *\n * ## Configuration\n *\n * | Environment Variable | Description | Default |\n * |---------------------|-------------|---------|\n * | `MAESTRO_REDIS_URL` | Redis connection URL | (in-memory fallback) |\n *\n * ## Default Endpoint Limits\n *\n * | Endpoint | Limit | Rationale |\n * |----------|-------|-----------|\n * | `/api/chat` | 30/min | LLM inference is expensive |\n * | `/api/model` | 60/min | Model switching is moderate |\n * | `/api/files` | 200/min | File operations |\n * | `/api/commands` | 100/min | Command execution |\n * | `/api/status` | 500/min | Status checks are cheap |\n *\n * ## Usage\n *\n * ```typescript\n * import { RateLimiter, TieredRateLimiter } from \"./rate-limiter.js\";\n *\n * // Simple rate limiter\n * const limiter = new RateLimiter({ windowMs: 60000, max: 100 });\n * const result = await limiter.checkAsync(clientIp);\n * if (!result.allowed) {\n * res.setHeader(\"Retry-After\", Math.ceil((result.reset - Date.now()) / 1000));\n * res.writeHead(429);\n * return;\n * }\n *\n * // Tiered rate limiter with endpoint-specific limits\n * const tiered = new TieredRateLimiter();\n * const result = tiered.check(clientIp, \"/api/chat\");\n * ```\n *\n * @module web/rate-limiter\n */\nimport { Redis } from \"ioredis\";\nimport { createLogger } from \"../utils/logger.js\";\n\nconst logger = createLogger(\"rate-limiter\");\n\nexport interface RateLimitConfig {\n\twindowMs: number;\n\tmax: number;\n}\n\n/**\n * Per-endpoint rate limit overrides.\n * Endpoints not listed use the global rate limit.\n */\nexport interface EndpointRateLimits {\n\t[endpoint: string]: RateLimitConfig;\n}\n\n/**\n * Default endpoint-specific rate limits.\n * More restrictive for expensive operations.\n */\nexport const DEFAULT_ENDPOINT_LIMITS: EndpointRateLimits = {\n\t// Chat endpoint is expensive (LLM inference)\n\t\"/api/chat\": { windowMs: 60000, max: 30 },\n\t// Model switching is moderately expensive\n\t\"/api/model\": { windowMs: 60000, max: 60 },\n\t// File operations - moderate limit\n\t\"/api/files\": { windowMs: 60000, max: 200 },\n\t// Commands can trigger expensive operations\n\t\"/api/commands\": { windowMs: 60000, max: 100 },\n\t// Status endpoints are cheap\n\t\"/api/status\": { windowMs: 60000, max: 500 },\n\t\"/api/config\": { windowMs: 60000, max: 500 },\n};\n\ninterface ClientState {\n\ttokens: number;\n\tlastRefill: number;\n}\n\nexport interface RateLimitResult {\n\tallowed: boolean;\n\tremaining: number;\n\treset: number;\n\tlimit: number;\n}\n\n// ============================================================================\n// REDIS CONNECTION (shared singleton)\n// ============================================================================\n\nlet redis: Redis | null = null;\nlet redisAvailable = false;\nlet redisInitPromise: Promise<boolean> | null = null;\n\n/**\n * Initialize Redis connection if MAESTRO_REDIS_URL is configured.\n * Returns true if Redis is available, false otherwise.\n */\nexport async function initRedis(): Promise<boolean> {\n\tconst redisUrl = process.env.MAESTRO_REDIS_URL;\n\tif (!redisUrl) {\n\t\tlogger.debug(\n\t\t\t\"No MAESTRO_REDIS_URL configured, using in-memory rate limiting\",\n\t\t);\n\t\treturn false;\n\t}\n\n\tif (redisInitPromise) {\n\t\treturn redisInitPromise;\n\t}\n\n\tredisInitPromise = (async () => {\n\t\ttry {\n\t\t\tconst client = new Redis(redisUrl, {\n\t\t\t\tmaxRetriesPerRequest: 1,\n\t\t\t\tretryStrategy: (times: number) => {\n\t\t\t\t\tif (times > 3) return null;\n\t\t\t\t\treturn Math.min(times * 100, 1000);\n\t\t\t\t},\n\t\t\t\tlazyConnect: true,\n\t\t\t\tenableOfflineQueue: false,\n\t\t\t});\n\n\t\t\tclient.on(\"error\", (err: Error) => {\n\t\t\t\tlogger.warn(\"Redis error\", { error: err.message });\n\t\t\t\tredisAvailable = false;\n\t\t\t});\n\n\t\t\tclient.on(\"connect\", () => {\n\t\t\t\tredisAvailable = true;\n\t\t\t\tlogger.info(\"Redis connected for rate limiting\");\n\t\t\t});\n\n\t\t\tawait client.connect();\n\t\t\tredis = client;\n\t\t\tredisAvailable = true;\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tlogger.warn(\"Redis connection failed, using in-memory fallback\", {\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t});\n\t\t\tredis = null;\n\t\t\tredisAvailable = false;\n\t\t\treturn false;\n\t\t}\n\t})();\n\n\treturn redisInitPromise;\n}\n\n/**\n * Check if Redis is being used for rate limiting.\n */\nexport function isRedisAvailable(): boolean {\n\treturn redisAvailable;\n}\n\n/**\n * Get the Redis client (for testing or advanced usage).\n */\nexport function getRedisClient(): Redis | null {\n\treturn redis;\n}\n\n/**\n * Shutdown Redis connection gracefully.\n */\nexport async function shutdownRedis(): Promise<void> {\n\tif (redis) {\n\t\tawait redis.quit().catch((err) => {\n\t\t\tlogger.debug(\"Redis quit failed during shutdown\", {\n\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t});\n\t\t});\n\t\tredis = null;\n\t\tredisAvailable = false;\n\t\tredisInitPromise = null;\n\t}\n}\n\n// Initialize Redis on module load (non-blocking)\ninitRedis().catch((err) => {\n\tlogger.warn(\"Redis initialization failed\", {\n\t\terror: err instanceof Error ? err.message : String(err),\n\t});\n});\n\n// ============================================================================\n// RATE LIMITER\n// ============================================================================\n\nexport class RateLimiter {\n\tprivate clients = new Map<string, ClientState>();\n\tprivate windowMs: number;\n\tprivate max: number;\n\tprivate refillRate: number; // tokens per ms\n\tprivate keyPrefix: string;\n\tprivate cleanupInterval: ReturnType<typeof setInterval> | null = null;\n\n\tconstructor(\n\t\tconfig: RateLimitConfig = { windowMs: 60000, max: 100 },\n\t\tkeyPrefix = \"rl\",\n\t) {\n\t\tthis.windowMs = config.windowMs;\n\t\tthis.max = config.max;\n\t\tthis.refillRate = config.max / config.windowMs;\n\t\tthis.keyPrefix = keyPrefix;\n\n\t\t// Cleanup old entries every minute\n\t\tthis.cleanupInterval = setInterval(() => this.cleanup(), 60000);\n\t\tthis.cleanupInterval.unref();\n\t}\n\n\t/**\n\t * Check rate limit (async to support Redis).\n\t */\n\tasync checkAsync(ip: string): Promise<RateLimitResult> {\n\t\tif (redis && redisAvailable) {\n\t\t\ttry {\n\t\t\t\treturn await this.checkRedis(ip);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.debug(\"Redis check failed, using memory fallback\", {\n\t\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn this.checkMemory(ip);\n\t}\n\n\t/**\n\t * Synchronous check (memory only, for backwards compatibility).\n\t */\n\tcheck(ip: string): RateLimitResult {\n\t\treturn this.checkMemory(ip);\n\t}\n\n\tprivate async checkRedis(ip: string): Promise<RateLimitResult> {\n\t\tconst key = `${this.keyPrefix}:${ip}`;\n\t\tconst now = Date.now();\n\n\t\t// Lua script for atomic token bucket\n\t\tconst script = `\n\t\t\tlocal key = KEYS[1]\n\t\t\tlocal max = tonumber(ARGV[1])\n\t\t\tlocal refillRate = tonumber(ARGV[2])\n\t\t\tlocal now = tonumber(ARGV[3])\n\t\t\tlocal windowMs = tonumber(ARGV[4])\n\n\t\t\tlocal data = redis.call('HMGET', key, 'tokens', 'lastRefill')\n\t\t\tlocal tokens = tonumber(data[1]) or max\n\t\t\tlocal lastRefill = tonumber(data[2]) or now\n\n\t\t\t-- Refill tokens\n\t\t\tlocal timePassed = now - lastRefill\n\t\t\tlocal refillAmount = timePassed * refillRate\n\t\t\ttokens = math.min(max, tokens + refillAmount)\n\n\t\t\tlocal allowed = 0\n\t\t\tif tokens >= 1 then\n\t\t\t\ttokens = tokens - 1\n\t\t\t\tallowed = 1\n\t\t\tend\n\n\t\t\tredis.call('HMSET', key, 'tokens', tokens, 'lastRefill', now)\n\t\t\tredis.call('PEXPIRE', key, windowMs)\n\n\t\t\treturn {allowed, math.floor(tokens), now}\n\t\t`;\n\n\t\tif (!redis) {\n\t\t\tthrow new Error(\"Redis not available\");\n\t\t}\n\t\tconst result = (await redis.eval(\n\t\t\tscript,\n\t\t\t1,\n\t\t\tkey,\n\t\t\tthis.max,\n\t\t\tthis.refillRate,\n\t\t\tnow,\n\t\t\tthis.windowMs,\n\t\t)) as [number, number, number];\n\n\t\tconst allowed = result[0] === 1;\n\t\tconst remaining = result[1];\n\n\t\tif (!allowed) {\n\t\t\tconst tokensNeeded = 1 - remaining;\n\t\t\tconst msNeeded = tokensNeeded / this.refillRate;\n\t\t\treturn {\n\t\t\t\tallowed: false,\n\t\t\t\tremaining: 0,\n\t\t\t\treset: now + msNeeded,\n\t\t\t\tlimit: this.max,\n\t\t\t};\n\t\t}\n\n\t\tconst tokensNeeded = 1 - remaining;\n\t\tconst msNeeded = Math.max(0, tokensNeeded / this.refillRate);\n\t\treturn {\n\t\t\tallowed: true,\n\t\t\tremaining,\n\t\t\treset: now + msNeeded,\n\t\t\tlimit: this.max,\n\t\t};\n\t}\n\n\tprivate checkMemory(ip: string): RateLimitResult {\n\t\tconst now = Date.now();\n\t\tlet client = this.clients.get(ip);\n\n\t\tif (!client) {\n\t\t\tclient = {\n\t\t\t\ttokens: this.max,\n\t\t\t\tlastRefill: now,\n\t\t\t};\n\t\t\tthis.clients.set(ip, client);\n\t\t}\n\n\t\t// Refill tokens\n\t\tconst timePassed = now - client.lastRefill;\n\t\tconst refillAmount = timePassed * this.refillRate;\n\n\t\tclient.tokens = Math.min(this.max, client.tokens + refillAmount);\n\t\tclient.lastRefill = now;\n\n\t\tif (client.tokens >= 1) {\n\t\t\tclient.tokens -= 1;\n\t\t\tconst tokensNeeded = 1 - client.tokens;\n\t\t\tconst msNeeded = Math.max(0, tokensNeeded / this.refillRate);\n\t\t\treturn {\n\t\t\t\tallowed: true,\n\t\t\t\tremaining: Math.floor(client.tokens),\n\t\t\t\treset: now + msNeeded,\n\t\t\t\tlimit: this.max,\n\t\t\t};\n\t\t}\n\n\t\tconst tokensNeeded = 1 - client.tokens;\n\t\tconst msNeeded = tokensNeeded / this.refillRate;\n\t\treturn {\n\t\t\tallowed: false,\n\t\t\tremaining: 0,\n\t\t\treset: now + msNeeded,\n\t\t\tlimit: this.max,\n\t\t};\n\t}\n\n\tgetConfig(): RateLimitConfig {\n\t\treturn { windowMs: this.windowMs, max: this.max };\n\t}\n\n\t/**\n\t * Check if a request would be allowed without consuming a token.\n\t * Used by TieredRateLimiter to avoid token leaks.\n\t */\n\tpeek(ip: string): RateLimitResult {\n\t\tconst now = Date.now();\n\t\tconst client = this.clients.get(ip);\n\n\t\tif (!client) {\n\t\t\t// New client would have full tokens\n\t\t\treturn {\n\t\t\t\tallowed: true,\n\t\t\t\tremaining: this.max - 1, // Would have this many after consuming\n\t\t\t\treset: now,\n\t\t\t\tlimit: this.max,\n\t\t\t};\n\t\t}\n\n\t\t// Calculate current tokens (with refill) without mutating state\n\t\tconst timePassed = now - client.lastRefill;\n\t\tconst refillAmount = timePassed * this.refillRate;\n\t\tconst currentTokens = Math.min(this.max, client.tokens + refillAmount);\n\n\t\tif (currentTokens >= 1) {\n\t\t\treturn {\n\t\t\t\tallowed: true,\n\t\t\t\tremaining: Math.floor(currentTokens - 1),\n\t\t\t\treset: now,\n\t\t\t\tlimit: this.max,\n\t\t\t};\n\t\t}\n\n\t\tconst tokensNeeded = 1 - currentTokens;\n\t\tconst msNeeded = tokensNeeded / this.refillRate;\n\t\treturn {\n\t\t\tallowed: false,\n\t\t\tremaining: 0,\n\t\t\treset: now + msNeeded,\n\t\t\tlimit: this.max,\n\t\t};\n\t}\n\n\t/**\n\t * Reset rate limit for an IP (for testing).\n\t */\n\tasync reset(ip?: string): Promise<void> {\n\t\tif (ip) {\n\t\t\tthis.clients.delete(ip);\n\t\t\tif (redis && redisAvailable) {\n\t\t\t\tawait redis.del(`${this.keyPrefix}:${ip}`).catch((err) => {\n\t\t\t\t\tlogger.debug(\"Redis del failed during reset\", {\n\t\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tthis.clients.clear();\n\t\t\tif (redis && redisAvailable) {\n\t\t\t\t// Use SCAN instead of KEYS to avoid blocking Redis\n\t\t\t\tlet cursor = \"0\";\n\t\t\t\tdo {\n\t\t\t\t\tconst [nextCursor, keys] = await redis.scan(\n\t\t\t\t\t\tcursor,\n\t\t\t\t\t\t\"MATCH\",\n\t\t\t\t\t\t`${this.keyPrefix}:*`,\n\t\t\t\t\t\t\"COUNT\",\n\t\t\t\t\t\t100,\n\t\t\t\t\t);\n\t\t\t\t\tcursor = nextCursor;\n\t\t\t\t\tif (keys.length > 0) {\n\t\t\t\t\t\tawait redis.del(...keys).catch((err) => {\n\t\t\t\t\t\t\tlogger.debug(\"Redis bulk del failed during reset\", {\n\t\t\t\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} while (cursor !== \"0\");\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Stop cleanup interval (for graceful shutdown).\n\t */\n\tstop(): void {\n\t\tif (this.cleanupInterval) {\n\t\t\tclearInterval(this.cleanupInterval);\n\t\t\tthis.cleanupInterval = null;\n\t\t}\n\t}\n\n\tprivate cleanup() {\n\t\tconst now = Date.now();\n\t\tfor (const [ip, client] of this.clients.entries()) {\n\t\t\tif (now - client.lastRefill > this.windowMs) {\n\t\t\t\tthis.clients.delete(ip);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Multi-tier rate limiter with per-endpoint limits.\n *\n * Provides both global IP-based rate limiting and endpoint-specific limits.\n * The more restrictive limit applies.\n */\nexport class TieredRateLimiter {\n\tprivate globalLimiter: RateLimiter;\n\tprivate endpointLimiters = new Map<string, RateLimiter>();\n\tprivate endpointLimits: EndpointRateLimits;\n\n\tconstructor(\n\t\tglobalConfig: RateLimitConfig = { windowMs: 60000, max: 1000 },\n\t\tendpointLimits: EndpointRateLimits = DEFAULT_ENDPOINT_LIMITS,\n\t) {\n\t\tthis.globalLimiter = new RateLimiter(globalConfig);\n\t\tthis.endpointLimits = endpointLimits;\n\n\t\t// Pre-create endpoint limiters\n\t\tfor (const [endpoint, config] of Object.entries(endpointLimits)) {\n\t\t\tthis.endpointLimiters.set(endpoint, new RateLimiter(config));\n\t\t}\n\t}\n\n\t/**\n\t * Check rate limit for a specific IP and endpoint (async, uses Redis if available).\n\t * Returns the most restrictive result between global and endpoint limits.\n\t *\n\t * Uses peek-then-consume pattern to avoid token leaks:\n\t * - First peeks at both limits without consuming\n\t * - Only consumes tokens if both limits allow the request\n\t */\n\tasync checkAsync(ip: string, endpoint: string): Promise<RateLimitResult> {\n\t\t// Peek at global limit first (no consumption)\n\t\tconst globalPeek = this.globalLimiter.peek(ip);\n\t\tif (!globalPeek.allowed) {\n\t\t\treturn globalPeek;\n\t\t}\n\n\t\t// Find matching endpoint limiter and pattern\n\t\tconst match = this.findEndpointLimiter(endpoint);\n\t\tif (!match) {\n\t\t\t// No endpoint limit - consume global token and return\n\t\t\treturn this.globalLimiter.checkAsync(ip);\n\t\t}\n\n\t\t// Use the matched pattern (not full path) for the key so all sub-routes\n\t\t// share the same bucket. E.g., /api/chat/approval uses key \"ip:/api/chat\"\n\t\tconst endpointKey = `${ip}:${match.pattern}`;\n\t\tconst endpointPeek = match.limiter.peek(endpointKey);\n\t\tif (!endpointPeek.allowed) {\n\t\t\t// Endpoint limit would reject - return without consuming global token\n\t\t\treturn endpointPeek;\n\t\t}\n\n\t\t// Both limits allow - consume tokens from both\n\t\tconst [globalResult, endpointResult] = await Promise.all([\n\t\t\tthis.globalLimiter.checkAsync(ip),\n\t\t\tmatch.limiter.checkAsync(endpointKey),\n\t\t]);\n\n\t\t// Return the more restrictive result\n\t\treturn globalResult.remaining <= endpointResult.remaining\n\t\t\t? globalResult\n\t\t\t: endpointResult;\n\t}\n\n\t/**\n\t * Check rate limit for a specific IP and endpoint (sync, memory only).\n\t * Returns the most restrictive result between global and endpoint limits.\n\t *\n\t * Uses peek-then-consume pattern to avoid token leaks:\n\t * - First peeks at both limits without consuming\n\t * - Only consumes tokens if both limits allow the request\n\t */\n\tcheck(ip: string, endpoint: string): RateLimitResult {\n\t\t// Peek at global limit first (no consumption)\n\t\tconst globalPeek = this.globalLimiter.peek(ip);\n\t\tif (!globalPeek.allowed) {\n\t\t\treturn globalPeek;\n\t\t}\n\n\t\t// Find matching endpoint limiter and pattern\n\t\tconst match = this.findEndpointLimiter(endpoint);\n\t\tif (!match) {\n\t\t\t// No endpoint limit - consume global token and return\n\t\t\treturn this.globalLimiter.check(ip);\n\t\t}\n\n\t\t// Use the matched pattern (not full path) for the key so all sub-routes\n\t\t// share the same bucket. E.g., /api/chat/approval uses key \"ip:/api/chat\"\n\t\tconst endpointKey = `${ip}:${match.pattern}`;\n\t\tconst endpointPeek = match.limiter.peek(endpointKey);\n\t\tif (!endpointPeek.allowed) {\n\t\t\t// Endpoint limit would reject - return without consuming global token\n\t\t\treturn endpointPeek;\n\t\t}\n\n\t\t// Both limits allow - consume tokens from both\n\t\tconst globalResult = this.globalLimiter.check(ip);\n\t\tconst endpointResult = match.limiter.check(endpointKey);\n\n\t\t// Return the more restrictive result\n\t\treturn globalResult.remaining <= endpointResult.remaining\n\t\t\t? globalResult\n\t\t\t: endpointResult;\n\t}\n\n\t/**\n\t * Find the rate limiter for a given endpoint path.\n\t * Supports exact match and prefix matching.\n\t * Returns both the limiter and the matched pattern for consistent key generation.\n\t */\n\tprivate findEndpointLimiter(\n\t\tendpoint: string,\n\t): { limiter: RateLimiter; pattern: string } | undefined {\n\t\t// Exact match\n\t\tconst exactMatch = this.endpointLimiters.get(endpoint);\n\t\tif (exactMatch) {\n\t\t\treturn {\n\t\t\t\tlimiter: exactMatch,\n\t\t\t\tpattern: endpoint,\n\t\t\t};\n\t\t}\n\n\t\t// Prefix match (e.g., /api/files/read matches /api/files)\n\t\t// All sub-routes share the same bucket under the pattern\n\t\tfor (const [pattern, limiter] of this.endpointLimiters) {\n\t\t\tif (endpoint.startsWith(pattern)) {\n\t\t\t\treturn { limiter, pattern };\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Get all configured limits for debugging/metrics.\n\t */\n\tgetLimits(): { global: RateLimitConfig; endpoints: EndpointRateLimits } {\n\t\treturn {\n\t\t\tglobal: this.globalLimiter.getConfig(),\n\t\t\tendpoints: this.endpointLimits,\n\t\t};\n\t}\n\n\t/**\n\t * Add or update an endpoint-specific rate limit.\n\t */\n\tsetEndpointLimit(endpoint: string, config: RateLimitConfig): void {\n\t\tthis.endpointLimits[endpoint] = config;\n\t\tthis.endpointLimiters.set(endpoint, new RateLimiter(config));\n\t}\n\n\t/**\n\t * Stop all cleanup intervals (for graceful shutdown and test cleanup).\n\t */\n\tstop(): void {\n\t\tthis.globalLimiter.stop();\n\t\tfor (const limiter of this.endpointLimiters.values()) {\n\t\t\tlimiter.stop();\n\t\t}\n\t}\n}\n"]}
@@ -1,8 +1,8 @@
1
1
  /**
2
- * @fileoverview HTTP Router for Composer Web Server
2
+ * @fileoverview HTTP Router for Maestro Web Server
3
3
  *
4
4
  * This module provides a lightweight, Express-like router for handling HTTP requests
5
- * in the Composer web server. It supports:
5
+ * in the Maestro web server. It supports:
6
6
  *
7
7
  * - **Path Parameters**: Dynamic route segments using `:param` syntax (e.g., `/api/sessions/:id`)
8
8
  * - **Method Matching**: Routes are matched by HTTP method (GET, POST, PUT, DELETE, etc.)