@maudecode/talaria-web 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (876) hide show
  1. package/contract_versions.json +18 -0
  2. package/dist/api/auth-raw.d.ts +9 -0
  3. package/dist/api/auth-raw.js +134 -0
  4. package/dist/api/auth-raw.js.map +1 -0
  5. package/dist/api/automation-raw.d.ts +16 -0
  6. package/dist/api/automation-raw.js +340 -0
  7. package/dist/api/automation-raw.js.map +1 -0
  8. package/dist/api/automation-router.d.ts +788 -0
  9. package/dist/api/automation-router.js +248 -0
  10. package/dist/api/automation-router.js.map +1 -0
  11. package/dist/api/chat-router.d.ts +375 -0
  12. package/dist/api/chat-router.js +446 -0
  13. package/dist/api/chat-router.js.map +1 -0
  14. package/dist/api/git-router.d.ts +681 -0
  15. package/dist/api/git-router.js +275 -0
  16. package/dist/api/git-router.js.map +1 -0
  17. package/dist/api/raw-routes.d.ts +10 -0
  18. package/dist/api/raw-routes.js +466 -0
  19. package/dist/api/raw-routes.js.map +1 -0
  20. package/dist/api/router.d.ts +226 -0
  21. package/dist/api/router.js +331 -0
  22. package/dist/api/router.js.map +1 -0
  23. package/dist/api/session-visibility.d.ts +12 -0
  24. package/dist/api/session-visibility.js +51 -0
  25. package/dist/api/session-visibility.js.map +1 -0
  26. package/dist/api/sessions-router.d.ts +1728 -0
  27. package/dist/api/sessions-router.js +815 -0
  28. package/dist/api/sessions-router.js.map +1 -0
  29. package/dist/api/settings-router.d.ts +592 -0
  30. package/dist/api/settings-router.js +474 -0
  31. package/dist/api/settings-router.js.map +1 -0
  32. package/dist/api/sse-routes.d.ts +51 -0
  33. package/dist/api/sse-routes.js +602 -0
  34. package/dist/api/sse-routes.js.map +1 -0
  35. package/dist/api/tools-raw.d.ts +5 -0
  36. package/dist/api/tools-raw.js +291 -0
  37. package/dist/api/tools-raw.js.map +1 -0
  38. package/dist/api/tools-router.d.ts +494 -0
  39. package/dist/api/tools-router.js +349 -0
  40. package/dist/api/tools-router.js.map +1 -0
  41. package/dist/app.d.ts +4787 -0
  42. package/dist/app.js +453 -0
  43. package/dist/app.js.map +1 -0
  44. package/dist/auth/cookies.d.ts +17 -0
  45. package/dist/auth/cookies.js +42 -0
  46. package/dist/auth/cookies.js.map +1 -0
  47. package/dist/auth/crypto.d.ts +9 -0
  48. package/dist/auth/crypto.js +38 -0
  49. package/dist/auth/crypto.js.map +1 -0
  50. package/dist/auth/gate.d.ts +39 -0
  51. package/dist/auth/gate.js +406 -0
  52. package/dist/auth/gate.js.map +1 -0
  53. package/dist/auth/oidc.d.ts +138 -0
  54. package/dist/auth/oidc.js +836 -0
  55. package/dist/auth/oidc.js.map +1 -0
  56. package/dist/auth/passkeys.d.ts +49 -0
  57. package/dist/auth/passkeys.js +310 -0
  58. package/dist/auth/passkeys.js.map +1 -0
  59. package/dist/auth/store.d.ts +116 -0
  60. package/dist/auth/store.js +485 -0
  61. package/dist/auth/store.js.map +1 -0
  62. package/dist/bin/talaria-web-mcp.d.ts +2 -0
  63. package/dist/bin/talaria-web-mcp.js +12 -0
  64. package/dist/bin/talaria-web-mcp.js.map +1 -0
  65. package/dist/bin/talaria-web.d.ts +2 -0
  66. package/dist/bin/talaria-web.js +87 -0
  67. package/dist/bin/talaria-web.js.map +1 -0
  68. package/dist/cli/ctl.d.ts +58 -0
  69. package/dist/cli/ctl.js +643 -0
  70. package/dist/cli/ctl.js.map +1 -0
  71. package/dist/cli/dotenv.d.ts +30 -0
  72. package/dist/cli/dotenv.js +115 -0
  73. package/dist/cli/dotenv.js.map +1 -0
  74. package/dist/cli/launcher.d.ts +49 -0
  75. package/dist/cli/launcher.js +213 -0
  76. package/dist/cli/launcher.js.map +1 -0
  77. package/dist/cli/supervise.d.ts +10 -0
  78. package/dist/cli/supervise.js +33 -0
  79. package/dist/cli/supervise.js.map +1 -0
  80. package/dist/cli/web-root.d.ts +2 -0
  81. package/dist/cli/web-root.js +23 -0
  82. package/dist/cli/web-root.js.map +1 -0
  83. package/dist/config/agent-config.d.ts +109 -0
  84. package/dist/config/agent-config.js +632 -0
  85. package/dist/config/agent-config.js.map +1 -0
  86. package/dist/config.d.ts +36 -0
  87. package/dist/config.js +105 -0
  88. package/dist/config.js.map +1 -0
  89. package/dist/fs/atomic.d.ts +7 -0
  90. package/dist/fs/atomic.js +68 -0
  91. package/dist/fs/atomic.js.map +1 -0
  92. package/dist/http/addresses.d.ts +5 -0
  93. package/dist/http/addresses.js +68 -0
  94. package/dist/http/addresses.js.map +1 -0
  95. package/dist/http/capped.d.ts +2 -0
  96. package/dist/http/capped.js +22 -0
  97. package/dist/http/capped.js.map +1 -0
  98. package/dist/http/context.d.ts +281 -0
  99. package/dist/http/context.js +327 -0
  100. package/dist/http/context.js.map +1 -0
  101. package/dist/http/csp.d.ts +11 -0
  102. package/dist/http/csp.js +51 -0
  103. package/dist/http/csp.js.map +1 -0
  104. package/dist/http/origin.d.ts +39 -0
  105. package/dist/http/origin.js +183 -0
  106. package/dist/http/origin.js.map +1 -0
  107. package/dist/http/pinned.d.ts +18 -0
  108. package/dist/http/pinned.js +62 -0
  109. package/dist/http/pinned.js.map +1 -0
  110. package/dist/index.d.ts +10 -0
  111. package/dist/index.js +12 -0
  112. package/dist/index.js.map +1 -0
  113. package/dist/mcp/server.d.ts +29 -0
  114. package/dist/mcp/server.js +221 -0
  115. package/dist/mcp/server.js.map +1 -0
  116. package/dist/onboarding.d.ts +57 -0
  117. package/dist/onboarding.js +381 -0
  118. package/dist/onboarding.js.map +1 -0
  119. package/dist/profiles/profiles.d.ts +96 -0
  120. package/dist/profiles/profiles.js +476 -0
  121. package/dist/profiles/profiles.js.map +1 -0
  122. package/dist/projects.d.ts +36 -0
  123. package/dist/projects.js +102 -0
  124. package/dist/projects.js.map +1 -0
  125. package/dist/providers/catalog.d.ts +118 -0
  126. package/dist/providers/catalog.js +868 -0
  127. package/dist/providers/catalog.js.map +1 -0
  128. package/dist/providers/env-file.d.ts +6 -0
  129. package/dist/providers/env-file.js +106 -0
  130. package/dist/providers/env-file.js.map +1 -0
  131. package/dist/providers/runtime-env.d.ts +20 -0
  132. package/dist/providers/runtime-env.js +85 -0
  133. package/dist/providers/runtime-env.js.map +1 -0
  134. package/dist/providers/tables.d.ts +54 -0
  135. package/dist/providers/tables.js +54 -0
  136. package/dist/providers/tables.js.map +1 -0
  137. package/dist/redact.d.ts +23 -0
  138. package/dist/redact.js +337 -0
  139. package/dist/redact.js.map +1 -0
  140. package/dist/release.d.ts +16 -0
  141. package/dist/release.js +114 -0
  142. package/dist/release.js.map +1 -0
  143. package/dist/runtime.d.ts +21 -0
  144. package/dist/runtime.js +680 -0
  145. package/dist/runtime.js.map +1 -0
  146. package/dist/server.d.ts +20 -0
  147. package/dist/server.js +90 -0
  148. package/dist/server.js.map +1 -0
  149. package/dist/sessions/anchor.d.ts +43 -0
  150. package/dist/sessions/anchor.js +311 -0
  151. package/dist/sessions/anchor.js.map +1 -0
  152. package/dist/sessions/cli-sessions.d.ts +27 -0
  153. package/dist/sessions/cli-sessions.js +158 -0
  154. package/dist/sessions/cli-sessions.js.map +1 -0
  155. package/dist/sessions/completions.d.ts +62 -0
  156. package/dist/sessions/completions.js +332 -0
  157. package/dist/sessions/completions.js.map +1 -0
  158. package/dist/sessions/drafts.d.ts +26 -0
  159. package/dist/sessions/drafts.js +117 -0
  160. package/dist/sessions/drafts.js.map +1 -0
  161. package/dist/sessions/events.d.ts +32 -0
  162. package/dist/sessions/events.js +80 -0
  163. package/dist/sessions/events.js.map +1 -0
  164. package/dist/sessions/export.d.ts +4 -0
  165. package/dist/sessions/export.js +186 -0
  166. package/dist/sessions/export.js.map +1 -0
  167. package/dist/sessions/gateway-watcher.d.ts +58 -0
  168. package/dist/sessions/gateway-watcher.js +199 -0
  169. package/dist/sessions/gateway-watcher.js.map +1 -0
  170. package/dist/sessions/journal.d.ts +103 -0
  171. package/dist/sessions/journal.js +543 -0
  172. package/dist/sessions/journal.js.map +1 -0
  173. package/dist/sessions/list.d.ts +130 -0
  174. package/dist/sessions/list.js +846 -0
  175. package/dist/sessions/list.js.map +1 -0
  176. package/dist/sessions/merge.d.ts +57 -0
  177. package/dist/sessions/merge.js +517 -0
  178. package/dist/sessions/merge.js.map +1 -0
  179. package/dist/sessions/pending.d.ts +69 -0
  180. package/dist/sessions/pending.js +271 -0
  181. package/dist/sessions/pending.js.map +1 -0
  182. package/dist/sessions/reasoning-titles.d.ts +31 -0
  183. package/dist/sessions/reasoning-titles.js +143 -0
  184. package/dist/sessions/reasoning-titles.js.map +1 -0
  185. package/dist/sessions/relay.d.ts +131 -0
  186. package/dist/sessions/relay.js +577 -0
  187. package/dist/sessions/relay.js.map +1 -0
  188. package/dist/sessions/service.d.ts +189 -0
  189. package/dist/sessions/service.js +1344 -0
  190. package/dist/sessions/service.js.map +1 -0
  191. package/dist/sessions/session.d.ts +131 -0
  192. package/dist/sessions/session.js +505 -0
  193. package/dist/sessions/session.js.map +1 -0
  194. package/dist/sessions/shares.d.ts +31 -0
  195. package/dist/sessions/shares.js +267 -0
  196. package/dist/sessions/shares.js.map +1 -0
  197. package/dist/sessions/state-db.d.ts +52 -0
  198. package/dist/sessions/state-db.js +641 -0
  199. package/dist/sessions/state-db.js.map +1 -0
  200. package/dist/sessions/state-saved.d.ts +13 -0
  201. package/dist/sessions/state-saved.js +47 -0
  202. package/dist/sessions/state-saved.js.map +1 -0
  203. package/dist/sessions/store.d.ts +124 -0
  204. package/dist/sessions/store.js +790 -0
  205. package/dist/sessions/store.js.map +1 -0
  206. package/dist/sessions/streams.d.ts +90 -0
  207. package/dist/sessions/streams.js +200 -0
  208. package/dist/sessions/streams.js.map +1 -0
  209. package/dist/sessions/titles.d.ts +17 -0
  210. package/dist/sessions/titles.js +231 -0
  211. package/dist/sessions/titles.js.map +1 -0
  212. package/dist/sessions/todo.d.ts +8 -0
  213. package/dist/sessions/todo.js +72 -0
  214. package/dist/sessions/todo.js.map +1 -0
  215. package/dist/sessions/turn-context.d.ts +27 -0
  216. package/dist/sessions/turn-context.js +136 -0
  217. package/dist/sessions/turn-context.js.map +1 -0
  218. package/dist/sessions/turn.d.ts +178 -0
  219. package/dist/sessions/turn.js +1357 -0
  220. package/dist/sessions/turn.js.map +1 -0
  221. package/dist/sessions/window.d.ts +10 -0
  222. package/dist/sessions/window.js +151 -0
  223. package/dist/sessions/window.js.map +1 -0
  224. package/dist/settings.d.ts +57 -0
  225. package/dist/settings.js +481 -0
  226. package/dist/settings.js.map +1 -0
  227. package/dist/sidecar/client.d.ts +75 -0
  228. package/dist/sidecar/client.js +252 -0
  229. package/dist/sidecar/client.js.map +1 -0
  230. package/dist/sidecar/discover.d.ts +22 -0
  231. package/dist/sidecar/discover.js +146 -0
  232. package/dist/sidecar/discover.js.map +1 -0
  233. package/dist/sidecar/fake.d.ts +37 -0
  234. package/dist/sidecar/fake.js +79 -0
  235. package/dist/sidecar/fake.js.map +1 -0
  236. package/dist/spa.d.ts +42 -0
  237. package/dist/spa.js +145 -0
  238. package/dist/spa.js.map +1 -0
  239. package/dist/startup.d.ts +19 -0
  240. package/dist/startup.js +44 -0
  241. package/dist/startup.js.map +1 -0
  242. package/dist/test/harness.d.ts +41 -0
  243. package/dist/test/harness.js +123 -0
  244. package/dist/test/harness.js.map +1 -0
  245. package/dist/text/diff.d.ts +16 -0
  246. package/dist/text/diff.js +122 -0
  247. package/dist/text/diff.js.map +1 -0
  248. package/dist/text/markdown.d.ts +8 -0
  249. package/dist/text/markdown.js +185 -0
  250. package/dist/text/markdown.js.map +1 -0
  251. package/dist/tools/crons.d.ts +51 -0
  252. package/dist/tools/crons.js +317 -0
  253. package/dist/tools/crons.js.map +1 -0
  254. package/dist/tools/extensions.d.ts +92 -0
  255. package/dist/tools/extensions.js +1096 -0
  256. package/dist/tools/extensions.js.map +1 -0
  257. package/dist/tools/health.d.ts +21 -0
  258. package/dist/tools/health.js +334 -0
  259. package/dist/tools/health.js.map +1 -0
  260. package/dist/tools/hygiene.d.ts +29 -0
  261. package/dist/tools/hygiene.js +112 -0
  262. package/dist/tools/hygiene.js.map +1 -0
  263. package/dist/tools/insights.d.ts +3 -0
  264. package/dist/tools/insights.js +92 -0
  265. package/dist/tools/insights.js.map +1 -0
  266. package/dist/tools/kanban.d.ts +25 -0
  267. package/dist/tools/kanban.js +79 -0
  268. package/dist/tools/kanban.js.map +1 -0
  269. package/dist/tools/mcp-health.d.ts +28 -0
  270. package/dist/tools/mcp-health.js +207 -0
  271. package/dist/tools/mcp-health.js.map +1 -0
  272. package/dist/tools/mcp.d.ts +34 -0
  273. package/dist/tools/mcp.js +269 -0
  274. package/dist/tools/mcp.js.map +1 -0
  275. package/dist/tools/memory.d.ts +20 -0
  276. package/dist/tools/memory.js +216 -0
  277. package/dist/tools/memory.js.map +1 -0
  278. package/dist/tools/skills.d.ts +43 -0
  279. package/dist/tools/skills.js +193 -0
  280. package/dist/tools/skills.js.map +1 -0
  281. package/dist/tools/terminal.d.ts +96 -0
  282. package/dist/tools/terminal.js +324 -0
  283. package/dist/tools/terminal.js.map +1 -0
  284. package/dist/tools/updates.d.ts +151 -0
  285. package/dist/tools/updates.js +1151 -0
  286. package/dist/tools/updates.js.map +1 -0
  287. package/dist/util.d.ts +6 -0
  288. package/dist/util.js +40 -0
  289. package/dist/util.js.map +1 -0
  290. package/dist/workspace/fs.d.ts +61 -0
  291. package/dist/workspace/fs.js +555 -0
  292. package/dist/workspace/fs.js.map +1 -0
  293. package/dist/workspace/git.d.ts +204 -0
  294. package/dist/workspace/git.js +1236 -0
  295. package/dist/workspace/git.js.map +1 -0
  296. package/dist/workspace/media.d.ts +47 -0
  297. package/dist/workspace/media.js +448 -0
  298. package/dist/workspace/media.js.map +1 -0
  299. package/dist/workspace/paths.d.ts +6 -0
  300. package/dist/workspace/paths.js +41 -0
  301. package/dist/workspace/paths.js.map +1 -0
  302. package/dist/workspace/rollback.d.ts +29 -0
  303. package/dist/workspace/rollback.js +337 -0
  304. package/dist/workspace/rollback.js.map +1 -0
  305. package/dist/workspace/unzip.d.ts +9 -0
  306. package/dist/workspace/unzip.js +61 -0
  307. package/dist/workspace/unzip.js.map +1 -0
  308. package/dist/workspace/upload.d.ts +40 -0
  309. package/dist/workspace/upload.js +215 -0
  310. package/dist/workspace/upload.js.map +1 -0
  311. package/dist/workspace/workspaces.d.ts +84 -0
  312. package/dist/workspace/workspaces.js +663 -0
  313. package/dist/workspace/workspaces.js.map +1 -0
  314. package/dist/workspace/worktrees.d.ts +14 -0
  315. package/dist/workspace/worktrees.js +171 -0
  316. package/dist/workspace/worktrees.js.map +1 -0
  317. package/dist/workspace/zip.d.ts +16 -0
  318. package/dist/workspace/zip.js +205 -0
  319. package/dist/workspace/zip.js.map +1 -0
  320. package/package.json +54 -0
  321. package/sidecar/agent_dependency.json +11 -0
  322. package/sidecar/scripts/record-fixtures.py +72 -0
  323. package/sidecar/scripts/replay_sidecar.py +113 -0
  324. package/sidecar/scripts/test.sh +22 -0
  325. package/sidecar/talaria_sidecar/__init__.py +10 -0
  326. package/sidecar/talaria_sidecar/__main__.py +46 -0
  327. package/sidecar/talaria_sidecar/errors.py +41 -0
  328. package/sidecar/talaria_sidecar/home.py +103 -0
  329. package/sidecar/talaria_sidecar/methods/__init__.py +37 -0
  330. package/sidecar/talaria_sidecar/methods/aux.py +160 -0
  331. package/sidecar/talaria_sidecar/methods/chat.py +791 -0
  332. package/sidecar/talaria_sidecar/methods/commands.py +340 -0
  333. package/sidecar/talaria_sidecar/methods/config.py +131 -0
  334. package/sidecar/talaria_sidecar/methods/cron.py +558 -0
  335. package/sidecar/talaria_sidecar/methods/gateway.py +106 -0
  336. package/sidecar/talaria_sidecar/methods/goals.py +225 -0
  337. package/sidecar/talaria_sidecar/methods/kanban.py +723 -0
  338. package/sidecar/talaria_sidecar/methods/mcp.py +65 -0
  339. package/sidecar/talaria_sidecar/methods/process.py +155 -0
  340. package/sidecar/talaria_sidecar/methods/profiles.py +254 -0
  341. package/sidecar/talaria_sidecar/methods/providers.py +241 -0
  342. package/sidecar/talaria_sidecar/methods/runtime.py +68 -0
  343. package/sidecar/talaria_sidecar/methods/skills.py +262 -0
  344. package/sidecar/talaria_sidecar/methods/state_db.py +418 -0
  345. package/sidecar/talaria_sidecar/methods/stt.py +131 -0
  346. package/sidecar/talaria_sidecar/methods/text.py +85 -0
  347. package/sidecar/talaria_sidecar/methods/usage.py +59 -0
  348. package/sidecar/talaria_sidecar/methods/worktree.py +71 -0
  349. package/sidecar/talaria_sidecar/rpc.py +218 -0
  350. package/sidecar/talaria_sidecar/runtime.py +330 -0
  351. package/static/brand/apple-touch-icon.png +0 -0
  352. package/static/brand/brandmark.svg +12 -0
  353. package/static/brand/favicon-192.png +0 -0
  354. package/static/brand/favicon-32.png +0 -0
  355. package/static/brand/favicon-512.png +0 -0
  356. package/static/brand/favicon-512.svg +14 -0
  357. package/static/brand/favicon-dark.svg +14 -0
  358. package/static/brand/favicon-light.svg +14 -0
  359. package/static/brand/favicon.ico +0 -0
  360. package/static/brand/favicon.svg +14 -0
  361. package/static/dist/FILES.txt +515 -0
  362. package/static/dist/assets/AppShell-gs0grlbs.js +1 -0
  363. package/static/dist/assets/ChatPage-gi1xlz52.js +18 -0
  364. package/static/dist/assets/ChatPage-gmu5c7lf.css +1 -0
  365. package/static/dist/assets/HubRoute-qs9vzuh0.js +2 -0
  366. package/static/dist/assets/InterVariable-nonokl6i.woff2 +0 -0
  367. package/static/dist/assets/KaTeX_AMS-Regular-e1why8ff.woff2 +0 -0
  368. package/static/dist/assets/KaTeX_AMS-Regular-mec5w1mt.woff +0 -0
  369. package/static/dist/assets/KaTeX_AMS-Regular-mos1wgtv.ttf +0 -0
  370. package/static/dist/assets/KaTeX_Caligraphic-Bold-axibvb5b.ttf +0 -0
  371. package/static/dist/assets/KaTeX_Caligraphic-Bold-eccvbn5c.woff +0 -0
  372. package/static/dist/assets/KaTeX_Caligraphic-Bold-n63xiolk.woff2 +0 -0
  373. package/static/dist/assets/KaTeX_Caligraphic-Regular-c5dvswgu.ttf +0 -0
  374. package/static/dist/assets/KaTeX_Caligraphic-Regular-iz5gexw5.woff +0 -0
  375. package/static/dist/assets/KaTeX_Caligraphic-Regular-npwmqylf.woff2 +0 -0
  376. package/static/dist/assets/KaTeX_Fraktur-Bold-ftsn4fxp.ttf +0 -0
  377. package/static/dist/assets/KaTeX_Fraktur-Bold-gokmhdpe.woff +0 -0
  378. package/static/dist/assets/KaTeX_Fraktur-Bold-ikhebgtj.woff2 +0 -0
  379. package/static/dist/assets/KaTeX_Fraktur-Regular-hzce8q9o.ttf +0 -0
  380. package/static/dist/assets/KaTeX_Fraktur-Regular-i0egury6.woff2 +0 -0
  381. package/static/dist/assets/KaTeX_Fraktur-Regular-okwm110b.woff +0 -0
  382. package/static/dist/assets/KaTeX_Main-Bold-c5g2m5kh.ttf +0 -0
  383. package/static/dist/assets/KaTeX_Main-Bold-ktk38ybk.woff2 +0 -0
  384. package/static/dist/assets/KaTeX_Main-Bold-ureqgmzo.woff +0 -0
  385. package/static/dist/assets/KaTeX_Main-BoldItalic-bd0upj71.woff +0 -0
  386. package/static/dist/assets/KaTeX_Main-BoldItalic-oj033t4i.woff2 +0 -0
  387. package/static/dist/assets/KaTeX_Main-BoldItalic-opttanob.ttf +0 -0
  388. package/static/dist/assets/KaTeX_Main-Italic-2p4bq1jf.woff2 +0 -0
  389. package/static/dist/assets/KaTeX_Main-Italic-dj86j9xo.ttf +0 -0
  390. package/static/dist/assets/KaTeX_Main-Italic-esmxqs8d.woff +0 -0
  391. package/static/dist/assets/KaTeX_Main-Regular-c978jrkj.ttf +0 -0
  392. package/static/dist/assets/KaTeX_Main-Regular-hbkzldb8.woff2 +0 -0
  393. package/static/dist/assets/KaTeX_Main-Regular-n865mmt0.woff +0 -0
  394. package/static/dist/assets/KaTeX_Math-BoldItalic-cbkxiib1.woff +0 -0
  395. package/static/dist/assets/KaTeX_Math-BoldItalic-hcom2j4y.ttf +0 -0
  396. package/static/dist/assets/KaTeX_Math-BoldItalic-jdo1yxu8.woff2 +0 -0
  397. package/static/dist/assets/KaTeX_Math-Italic-b5lfnctb.ttf +0 -0
  398. package/static/dist/assets/KaTeX_Math-Italic-cz4b2ure.woff2 +0 -0
  399. package/static/dist/assets/KaTeX_Math-Italic-lo894bvj.woff +0 -0
  400. package/static/dist/assets/KaTeX_SansSerif-Bold-h55uj19s.ttf +0 -0
  401. package/static/dist/assets/KaTeX_SansSerif-Bold-m9bkcp3c.woff +0 -0
  402. package/static/dist/assets/KaTeX_SansSerif-Bold-otxc8itm.woff2 +0 -0
  403. package/static/dist/assets/KaTeX_SansSerif-Italic-bp85cocg.ttf +0 -0
  404. package/static/dist/assets/KaTeX_SansSerif-Italic-g42k16nn.woff +0 -0
  405. package/static/dist/assets/KaTeX_SansSerif-Italic-k4kksncm.woff2 +0 -0
  406. package/static/dist/assets/KaTeX_SansSerif-Regular-evq9548m.ttf +0 -0
  407. package/static/dist/assets/KaTeX_SansSerif-Regular-izeggh93.woff +0 -0
  408. package/static/dist/assets/KaTeX_SansSerif-Regular-ltw53ck4.woff2 +0 -0
  409. package/static/dist/assets/KaTeX_Script-Regular-k8v4ghws.ttf +0 -0
  410. package/static/dist/assets/KaTeX_Script-Regular-o2nd302f.woff +0 -0
  411. package/static/dist/assets/KaTeX_Script-Regular-oybd33cp.woff2 +0 -0
  412. package/static/dist/assets/KaTeX_Size1-Regular-cjccv44r.woff2 +0 -0
  413. package/static/dist/assets/KaTeX_Size1-Regular-k13yopgz.woff +0 -0
  414. package/static/dist/assets/KaTeX_Size1-Regular-naiuhmx7.ttf +0 -0
  415. package/static/dist/assets/KaTeX_Size2-Regular-cnnxwlt7.woff +0 -0
  416. package/static/dist/assets/KaTeX_Size2-Regular-hlh6jazj.ttf +0 -0
  417. package/static/dist/assets/KaTeX_Size2-Regular-onxq3bzc.woff2 +0 -0
  418. package/static/dist/assets/KaTeX_Size3-Regular-i00haf83.woff +0 -0
  419. package/static/dist/assets/KaTeX_Size3-Regular-nk2kx36d.ttf +0 -0
  420. package/static/dist/assets/KaTeX_Size4-Regular-effsfy3y.woff +0 -0
  421. package/static/dist/assets/KaTeX_Size4-Regular-myjqyche.ttf +0 -0
  422. package/static/dist/assets/KaTeX_Size4-Regular-nv9nppzf.woff2 +0 -0
  423. package/static/dist/assets/KaTeX_Typewriter-Regular-iqvr3vwu.woff2 +0 -0
  424. package/static/dist/assets/KaTeX_Typewriter-Regular-kzj4h457.woff +0 -0
  425. package/static/dist/assets/KaTeX_Typewriter-Regular-owzsy8p5.ttf +0 -0
  426. package/static/dist/assets/Markdown-bt9bqd6a.js +598 -0
  427. package/static/dist/assets/Markdown-lwviulmg.css +1 -0
  428. package/static/dist/assets/RightPanel-dn19xu42.js +1 -0
  429. package/static/dist/assets/Select-y7wtf85g.js +1 -0
  430. package/static/dist/assets/SessionListPanel-igwdj9xr.js +1 -0
  431. package/static/dist/assets/SettingsLayout-n6mu0ghg.js +1 -0
  432. package/static/dist/assets/States-oil2issf.js +1 -0
  433. package/static/dist/assets/Toaster-jtn59pjm.js +1 -0
  434. package/static/dist/assets/_app-k4jrkgfa.js +1 -0
  435. package/static/dist/assets/_app.ext._extensionId-mmf1mepm.js +1 -0
  436. package/static/dist/assets/_app.index-mb41nf00.js +1 -0
  437. package/static/dist/assets/_app.insights-mz5cep8m.js +1 -0
  438. package/static/dist/assets/_app.kanban-ocgw506i.js +1 -0
  439. package/static/dist/assets/_app.logs-lstmoju6.js +1 -0
  440. package/static/dist/assets/_app.memory-dishj9ra.js +1 -0
  441. package/static/dist/assets/_app.profiles-dynpvsio.js +1 -0
  442. package/static/dist/assets/_app.session._sessionId-kevi4qd2.js +1 -0
  443. package/static/dist/assets/_app.settings-c2czm9v4.js +1 -0
  444. package/static/dist/assets/_app.settings._section-exwflld7.js +1 -0
  445. package/static/dist/assets/_app.skills-j5jh2nug.js +1 -0
  446. package/static/dist/assets/_app.tasks-b99d98fo.js +2 -0
  447. package/static/dist/assets/_app.todos-ma8urvn3.js +1 -0
  448. package/static/dist/assets/_app.workspaces-l86cxeod.js +1 -0
  449. package/static/dist/assets/abap-ij37pki6.js +1 -0
  450. package/static/dist/assets/abnfDiagram-VCTEODGH-hvrr25lb.js +1 -0
  451. package/static/dist/assets/actionscript-3-dz7y3j1x.js +1 -0
  452. package/static/dist/assets/ada-k9zgv987.js +1 -0
  453. package/static/dist/assets/andromeeda-c2n0n86o.js +1 -0
  454. package/static/dist/assets/angular-html-nu6l31w3.js +1 -0
  455. package/static/dist/assets/angular-ts-fbx4f8mm.js +1 -0
  456. package/static/dist/assets/apache-binppq6z.js +1 -0
  457. package/static/dist/assets/apex-h8illjly.js +1 -0
  458. package/static/dist/assets/apl-bx2xr7dh.js +1 -0
  459. package/static/dist/assets/applescript-h0ok5sww.js +1 -0
  460. package/static/dist/assets/ara-dlpjioua.js +1 -0
  461. package/static/dist/assets/arc-7popfhbk.js +1 -0
  462. package/static/dist/assets/architecture-7GRP2DOG-mqft9w2p.js +1 -0
  463. package/static/dist/assets/architectureDiagram-5GKGNRK7-b3r0z8sq.js +36 -0
  464. package/static/dist/assets/array-f36850hm.js +1 -0
  465. package/static/dist/assets/asciidoc-lx0cuujr.js +1 -0
  466. package/static/dist/assets/asm-j5diz3sz.js +1 -0
  467. package/static/dist/assets/astro-g77i97cb.js +1 -0
  468. package/static/dist/assets/aurora-x-h2hngdsl.js +1 -0
  469. package/static/dist/assets/awk-fecghegf.js +1 -0
  470. package/static/dist/assets/ayu-dark-nvvuggz9.js +1 -0
  471. package/static/dist/assets/ayu-light-k5fxgplt.js +1 -0
  472. package/static/dist/assets/ayu-mirage-gltrvhcx.js +1 -0
  473. package/static/dist/assets/ballerina-hk9oga18.js +1 -0
  474. package/static/dist/assets/bat-ghs7lag5.js +1 -0
  475. package/static/dist/assets/beancount-pc6q2dmq.js +1 -0
  476. package/static/dist/assets/berry-l96jp8n4.js +1 -0
  477. package/static/dist/assets/bibtex-jxn7maz2.js +1 -0
  478. package/static/dist/assets/bicep-i1yv3ngd.js +1 -0
  479. package/static/dist/assets/bird2-k3aagqn0.js +1 -0
  480. package/static/dist/assets/blade-boo0u92y.js +1 -0
  481. package/static/dist/assets/blockDiagram-I7D4REHJ-hd3gw0cj.js +129 -0
  482. package/static/dist/assets/bsl-f8m1ja7w.js +1 -0
  483. package/static/dist/assets/c-cat0w3sc.js +1 -0
  484. package/static/dist/assets/c3-j6ile59o.js +1 -0
  485. package/static/dist/assets/c4Diagram-7LVT6UL2-jlmbjiji.js +38 -0
  486. package/static/dist/assets/cadence-e3x2pgsu.js +1 -0
  487. package/static/dist/assets/cairo-mblac9dt.js +1 -0
  488. package/static/dist/assets/catppuccin-frappe-dj7qsd4s.js +1 -0
  489. package/static/dist/assets/catppuccin-latte-oh2bx7qn.js +1 -0
  490. package/static/dist/assets/catppuccin-macchiato-m3xyazph.js +1 -0
  491. package/static/dist/assets/catppuccin-mocha-m3rjj89j.js +1 -0
  492. package/static/dist/assets/channel-ix8cxdld.js +1 -0
  493. package/static/dist/assets/chunk-2Q5K7J3B-k08c29qw.js +1 -0
  494. package/static/dist/assets/chunk-4HAMMTFA-oydbpsin.js +62 -0
  495. package/static/dist/assets/chunk-5VM5RSS4-br0zxsux.js +15 -0
  496. package/static/dist/assets/chunk-75Z2AOVW-j633otj1.js +2 -0
  497. package/static/dist/assets/chunk-DU6HZSFF-ods2l027.js +128 -0
  498. package/static/dist/assets/chunk-F27PBJKO-ln4n2cwt.js +1 -0
  499. package/static/dist/assets/chunk-FOHPRMQF-opuflp73.js +161 -0
  500. package/static/dist/assets/chunk-GMAD6QVW-fpz133eh.js +72 -0
  501. package/static/dist/assets/chunk-GVQU2GXP-abs9ixiy.js +1 -0
  502. package/static/dist/assets/chunk-IMKFNOWR-j9vukdy1.js +231 -0
  503. package/static/dist/assets/chunk-JWPE2WC7-mw03m5s9.js +1 -0
  504. package/static/dist/assets/chunk-L3NEJ4N5-cfyw87r3.js +1 -0
  505. package/static/dist/assets/chunk-OSK3NFVY-baja78wr.js +10 -0
  506. package/static/dist/assets/chunk-P2QGCYS3-g66xby8h.js +1 -0
  507. package/static/dist/assets/chunk-POPQ4Y6H-osqu864t.js +1 -0
  508. package/static/dist/assets/chunk-PWAF6VOD-egejasv1.js +1 -0
  509. package/static/dist/assets/chunk-SHT3W25Y-l014h8zz.js +168 -0
  510. package/static/dist/assets/chunk-SVP7TREG-n3z10bp3.js +88 -0
  511. package/static/dist/assets/chunk-TICWLB2K-bzozkjc0.js +206 -0
  512. package/static/dist/assets/chunk-XXDRQBXY-n40pf9vy.js +1 -0
  513. package/static/dist/assets/chunk-Y2CYZVJY-n9gs7k4d.js +1 -0
  514. package/static/dist/assets/clarity-bdn1d8fx.js +1 -0
  515. package/static/dist/assets/classDiagram-ZZMXUADV-c210y3il.js +1 -0
  516. package/static/dist/assets/classDiagram-v2-VYDZK3BY-c210y3il.js +1 -0
  517. package/static/dist/assets/clojure-n5b9o4lq.js +1 -0
  518. package/static/dist/assets/cmake-f68p68h5.js +1 -0
  519. package/static/dist/assets/cobol-go622aep.js +1 -0
  520. package/static/dist/assets/codeowners-lgfjmw2s.js +1 -0
  521. package/static/dist/assets/codeql-cojlysyb.js +1 -0
  522. package/static/dist/assets/coffee-jwo1xjhq.js +1 -0
  523. package/static/dist/assets/common-lisp-ko58h8pe.js +1 -0
  524. package/static/dist/assets/copied-cjsttec1.js +1 -0
  525. package/static/dist/assets/coq-gns70ukp.js +1 -0
  526. package/static/dist/assets/cose-bilkent-JH36ORCC-eclcy6ja.js +1 -0
  527. package/static/dist/assets/cpp-nre7j0kq.js +1 -0
  528. package/static/dist/assets/crystal-lviso2je.js +1 -0
  529. package/static/dist/assets/csharp-kkz9hcxp.js +1 -0
  530. package/static/dist/assets/css-ywz9j4hb.js +1 -0
  531. package/static/dist/assets/csv-ol0sxk26.js +1 -0
  532. package/static/dist/assets/cue-h5naoluy.js +1 -0
  533. package/static/dist/assets/cynefin-OW5HDTMX-elpt7h1j.js +1 -0
  534. package/static/dist/assets/cynefinDiagram-5FMLGOSQ-5mzl5pi2.js +62 -0
  535. package/static/dist/assets/cypher-j2an42no.js +1 -0
  536. package/static/dist/assets/cytoscape.esm-bqu53u12.js +321 -0
  537. package/static/dist/assets/d-crxkca3p.js +1 -0
  538. package/static/dist/assets/dagre-GXQ25YYZ-ihwlhmfl.js +4 -0
  539. package/static/dist/assets/dagre-lkoknbjn.js +1 -0
  540. package/static/dist/assets/dark-plus-kin19s9x.js +1 -0
  541. package/static/dist/assets/dart-nsg0xvqh.js +1 -0
  542. package/static/dist/assets/dax-f82777dv.js +1 -0
  543. package/static/dist/assets/defaultLocale-eeoev87l.js +1 -0
  544. package/static/dist/assets/desktop-nvg88bea.js +1 -0
  545. package/static/dist/assets/diagram-S7CK7UJ4-4z90agaz.js +30 -0
  546. package/static/dist/assets/diagram-UQ7AKVKN-eifw0lg7.js +41 -0
  547. package/static/dist/assets/diagram-VSXAHHWV-ksh3sjqv.js +3 -0
  548. package/static/dist/assets/diagram-VX7I27RA-ett72f71.js +24 -0
  549. package/static/dist/assets/diagram-Z3DM3KII-l8scp8nu.js +24 -0
  550. package/static/dist/assets/diff-c5xjoml2.js +1 -0
  551. package/static/dist/assets/dist-c4c2m3kv.js +1 -0
  552. package/static/dist/assets/docker-s0pf2u92.js +1 -0
  553. package/static/dist/assets/dotenv-d2gvqxc1.js +1 -0
  554. package/static/dist/assets/dracula-eicfho73.js +1 -0
  555. package/static/dist/assets/dracula-soft-doslejd2.js +1 -0
  556. package/static/dist/assets/dream-maker-mz8d3pqb.js +1 -0
  557. package/static/dist/assets/ebnfDiagram-PWID7BFC-f0pxcmit.js +1 -0
  558. package/static/dist/assets/edge-dvv35byi.js +1 -0
  559. package/static/dist/assets/elixir-i2f1ki1g.js +1 -0
  560. package/static/dist/assets/elm-cpepyjm4.js +1 -0
  561. package/static/dist/assets/emacs-lisp-lhl63kmy.js +1 -0
  562. package/static/dist/assets/endpoints-ipnv1hd4.js +64 -0
  563. package/static/dist/assets/erDiagram-RLTQ6QDP-f47m5xh0.js +99 -0
  564. package/static/dist/assets/erb-idlyfheg.js +1 -0
  565. package/static/dist/assets/erlang-kbk8e1kh.js +1 -0
  566. package/static/dist/assets/eventmodeling-NTZA5JFV-d9b5a0ia.js +1 -0
  567. package/static/dist/assets/everforest-dark-cv4maom7.js +1 -0
  568. package/static/dist/assets/everforest-light-njdw7fx6.js +1 -0
  569. package/static/dist/assets/fennel-mm8r79co.js +1 -0
  570. package/static/dist/assets/fish-em0xdaat.js +1 -0
  571. package/static/dist/assets/flowDiagram-HODETNUW-kfxxsyrk.js +1 -0
  572. package/static/dist/assets/fluent-kzq1mil2.js +1 -0
  573. package/static/dist/assets/fortran-fixed-form-lwddxd99.js +1 -0
  574. package/static/dist/assets/fortran-free-form-jao3bzvo.js +1 -0
  575. package/static/dist/assets/fsharp-ouam7w4k.js +1 -0
  576. package/static/dist/assets/ganttDiagram-EL5Y4UJY-bmktjdi0.js +292 -0
  577. package/static/dist/assets/gdresource-gawivel9.js +1 -0
  578. package/static/dist/assets/gdscript-kcamxf4c.js +1 -0
  579. package/static/dist/assets/gdshader-hx54new5.js +1 -0
  580. package/static/dist/assets/genie-i5n3m91v.js +1 -0
  581. package/static/dist/assets/gherkin-lxn181dy.js +1 -0
  582. package/static/dist/assets/git-commit-e6qgtuh5.js +1 -0
  583. package/static/dist/assets/git-rebase-d9lpfpbn.js +1 -0
  584. package/static/dist/assets/gitGraph-4MIJSDKK-j2ueg258.js +1 -0
  585. package/static/dist/assets/gitGraphDiagram-WWUBYQGX-ms6586v9.js +106 -0
  586. package/static/dist/assets/github-dark-default-m0qs6qki.js +1 -0
  587. package/static/dist/assets/github-dark-dimmed-g0vz4qee.js +1 -0
  588. package/static/dist/assets/github-dark-high-contrast-hugubo52.js +1 -0
  589. package/static/dist/assets/github-dark-ljlyim8s.js +1 -0
  590. package/static/dist/assets/github-light-default-fgfak5mv.js +1 -0
  591. package/static/dist/assets/github-light-high-contrast-hka6wb3r.js +1 -0
  592. package/static/dist/assets/github-light-jhyi45t4.js +1 -0
  593. package/static/dist/assets/gleam-ix1dym3g.js +1 -0
  594. package/static/dist/assets/glimmer-js-39i0urfb.js +1 -0
  595. package/static/dist/assets/glimmer-ts-gdtd6n73.js +1 -0
  596. package/static/dist/assets/glsl-o1djm5pp.js +1 -0
  597. package/static/dist/assets/gn-cbzhsgl9.js +1 -0
  598. package/static/dist/assets/gnuplot-dr8f9gvm.js +1 -0
  599. package/static/dist/assets/go-enhtrrw8.js +1 -0
  600. package/static/dist/assets/graphlib-mrng1xrk.js +1 -0
  601. package/static/dist/assets/graphql-kj6rz55t.js +1 -0
  602. package/static/dist/assets/groovy-jff59t9e.js +1 -0
  603. package/static/dist/assets/gruvbox-dark-hard-lgsj7y5r.js +1 -0
  604. package/static/dist/assets/gruvbox-dark-medium-ezt86wrc.js +1 -0
  605. package/static/dist/assets/gruvbox-dark-soft-1a3jfdlm.js +1 -0
  606. package/static/dist/assets/gruvbox-light-hard-d82lddjc.js +1 -0
  607. package/static/dist/assets/gruvbox-light-medium-d3ffitv3.js +1 -0
  608. package/static/dist/assets/gruvbox-light-soft-e5gf7i2q.js +1 -0
  609. package/static/dist/assets/hack-pe1qqr2i.js +1 -0
  610. package/static/dist/assets/haml-cknnbcqs.js +1 -0
  611. package/static/dist/assets/handlebars-hwq64orh.js +1 -0
  612. package/static/dist/assets/haskell-o7nor2z2.js +1 -0
  613. package/static/dist/assets/haxe-4rwdh42h.js +1 -0
  614. package/static/dist/assets/hcl-nnng763h.js +1 -0
  615. package/static/dist/assets/highlighted-body-KPVGNVTW-ev52d2si.js +1 -0
  616. package/static/dist/assets/hjson-kscwmuzk.js +1 -0
  617. package/static/dist/assets/hlsl-kopkvwox.js +1 -0
  618. package/static/dist/assets/horizon-bright-gn4aqinx.js +1 -0
  619. package/static/dist/assets/horizon-h5nzrwlb.js +1 -0
  620. package/static/dist/assets/houston-kifsbmbx.js +1 -0
  621. package/static/dist/assets/html-derivative-h2i2pyjc.js +1 -0
  622. package/static/dist/assets/html-ha05xtvt.js +1 -0
  623. package/static/dist/assets/http-cf94zu27.js +1 -0
  624. package/static/dist/assets/hurl-lslax568.js +1 -0
  625. package/static/dist/assets/hxml-g52gxet6.js +1 -0
  626. package/static/dist/assets/hy-jc9www1l.js +1 -0
  627. package/static/dist/assets/imba-n9x1ej2f.js +1 -0
  628. package/static/dist/assets/index-bz7g7rhx.css +2 -0
  629. package/static/dist/assets/index-hywfjw88.js +11 -0
  630. package/static/dist/assets/info-A6RAGUB7-j717vyt7.js +1 -0
  631. package/static/dist/assets/infoDiagram-27XIBGKW-dsbpib36.js +2 -0
  632. package/static/dist/assets/ini-hg6eosim.js +1 -0
  633. package/static/dist/assets/init-ljpdkjra.js +1 -0
  634. package/static/dist/assets/ishikawaDiagram-5VMMS53U-n0sz3i2d.js +70 -0
  635. package/static/dist/assets/java-ndjf2o89.js +1 -0
  636. package/static/dist/assets/javascript-coftlwy3.js +1 -0
  637. package/static/dist/assets/jinja-etei9wy7.js +1 -0
  638. package/static/dist/assets/jison-hyekgft1.js +1 -0
  639. package/static/dist/assets/journeyDiagram-3NMN7TZE-mcxz1mme.js +139 -0
  640. package/static/dist/assets/json-lok0yaho.js +1 -0
  641. package/static/dist/assets/json5-e4tr07tg.js +1 -0
  642. package/static/dist/assets/jsonc-jbmkhoep.js +1 -0
  643. package/static/dist/assets/jsonl-j35ke6at.js +1 -0
  644. package/static/dist/assets/jsonnet-iewuy86o.js +1 -0
  645. package/static/dist/assets/jssm-m1449zlc.js +1 -0
  646. package/static/dist/assets/jsx-b64w0nbx.js +1 -0
  647. package/static/dist/assets/jsx-runtime-eu92a5pu.js +1 -0
  648. package/static/dist/assets/julia-jxxzz2yn.js +1 -0
  649. package/static/dist/assets/just-mc29iw9t.js +1 -0
  650. package/static/dist/assets/kanagawa-dragon-i9mmmgud.js +1 -0
  651. package/static/dist/assets/kanagawa-lotus-ev5oro17.js +1 -0
  652. package/static/dist/assets/kanagawa-wave-i06560uw.js +1 -0
  653. package/static/dist/assets/kanban-definition-UXKFOSKX-n6hq2lyc.js +89 -0
  654. package/static/dist/assets/kdl-kgzv1x9e.js +1 -0
  655. package/static/dist/assets/kotlin-nmx05b3f.js +1 -0
  656. package/static/dist/assets/kusto-fawmdms4.js +1 -0
  657. package/static/dist/assets/laserwave-goebpayr.js +1 -0
  658. package/static/dist/assets/latex-pafa03ft.js +1 -0
  659. package/static/dist/assets/lazyRouteComponent-faquioun.js +1 -0
  660. package/static/dist/assets/lean-jom31nm3.js +1 -0
  661. package/static/dist/assets/less-mwvscr3d.js +1 -0
  662. package/static/dist/assets/light-plus-mws1g85f.js +1 -0
  663. package/static/dist/assets/line-h5xq20s4.js +1 -0
  664. package/static/dist/assets/linear-becwlnhk.js +1 -0
  665. package/static/dist/assets/link-ib4prsn5.js +1 -0
  666. package/static/dist/assets/liquid-hz5c2pov.js +1 -0
  667. package/static/dist/assets/llvm-j5wmr3g9.js +1 -0
  668. package/static/dist/assets/log-eur4gurm.js +1 -0
  669. package/static/dist/assets/login-mvjys1ol.js +1 -0
  670. package/static/dist/assets/logo-j3h8r0pu.js +1 -0
  671. package/static/dist/assets/lua-leyf8mlb.js +1 -0
  672. package/static/dist/assets/luau-im5d6q8k.js +1 -0
  673. package/static/dist/assets/make-npl27xqy.js +1 -0
  674. package/static/dist/assets/markdown-fibv6lrm.js +1 -0
  675. package/static/dist/assets/marko-cn1fzpdv.js +1 -0
  676. package/static/dist/assets/matchContext-f8oy3lo7.js +1 -0
  677. package/static/dist/assets/material-theme-darker-dhm8zmok.js +1 -0
  678. package/static/dist/assets/material-theme-gdimc61s.js +1 -0
  679. package/static/dist/assets/material-theme-lighter-c1fszbb2.js +1 -0
  680. package/static/dist/assets/material-theme-ocean-iakojpmy.js +1 -0
  681. package/static/dist/assets/material-theme-palenight-hgxmykmi.js +1 -0
  682. package/static/dist/assets/matlab-o6nvvbf2.js +1 -0
  683. package/static/dist/assets/mdc-huhy88df.js +1 -0
  684. package/static/dist/assets/mdx-mmgeh26h.js +1 -0
  685. package/static/dist/assets/mermaid-HWGCJPDP-gmnkgf1n.js +1 -0
  686. package/static/dist/assets/mermaid-f9ad87lb.js +1 -0
  687. package/static/dist/assets/mermaid-parser.core-n9cuu5ue.js +7 -0
  688. package/static/dist/assets/min-dark-e5sicuw2.js +1 -0
  689. package/static/dist/assets/min-light-gst87fvf.js +1 -0
  690. package/static/dist/assets/mindmap-definition-YA3MSWOX-gta3u7z4.js +96 -0
  691. package/static/dist/assets/mipsasm-etoqqos6.js +1 -0
  692. package/static/dist/assets/mojo-fyyk0b1z.js +1 -0
  693. package/static/dist/assets/monokai-jl389a9o.js +1 -0
  694. package/static/dist/assets/moonbit-je86hbgx.js +1 -0
  695. package/static/dist/assets/move-g7w7k042.js +1 -0
  696. package/static/dist/assets/narrat-d1cszt6i.js +1 -0
  697. package/static/dist/assets/nextflow-fpd3eqgm.js +1 -0
  698. package/static/dist/assets/nextflow-groovy-nc95p6pm.js +1 -0
  699. package/static/dist/assets/nginx-e7lvhsmn.js +1 -0
  700. package/static/dist/assets/night-owl-light-b2j1bc8t.js +1 -0
  701. package/static/dist/assets/night-owl-nm3cgqfv.js +1 -0
  702. package/static/dist/assets/nim-dun5d8mk.js +1 -0
  703. package/static/dist/assets/nix-sxazvl0w.js +1 -0
  704. package/static/dist/assets/nord-jiiendyo.js +1 -0
  705. package/static/dist/assets/not-found-ccnnac39.js +1 -0
  706. package/static/dist/assets/nushell-nbi9xmdg.js +1 -0
  707. package/static/dist/assets/objective-c-oshe4ycx.js +1 -0
  708. package/static/dist/assets/objective-cpp-go29ofq1.js +1 -0
  709. package/static/dist/assets/ocaml-56kivtnr.js +1 -0
  710. package/static/dist/assets/odin-g772bhi5.js +1 -0
  711. package/static/dist/assets/onboarding-l6quy6gz.js +1 -0
  712. package/static/dist/assets/one-dark-pro-ext74l87.js +1 -0
  713. package/static/dist/assets/one-light-o5mlsn8i.js +1 -0
  714. package/static/dist/assets/openscad-e9e9mfyg.js +1 -0
  715. package/static/dist/assets/ordinal-d88pfdla.js +1 -0
  716. package/static/dist/assets/packet-AYTQ26CC-bpzuq5n6.js +1 -0
  717. package/static/dist/assets/pascal-dmg2rs6d.js +1 -0
  718. package/static/dist/assets/passkeys-ktie3sr0.js +1 -0
  719. package/static/dist/assets/path-b509aej0.js +1 -0
  720. package/static/dist/assets/pegDiagram-XKGWAZYB-juye13e5.js +1 -0
  721. package/static/dist/assets/perl-bj3oqtet.js +1 -0
  722. package/static/dist/assets/php-buzp12r0.js +1 -0
  723. package/static/dist/assets/pie-WAS4IAKB-odhb8buq.js +1 -0
  724. package/static/dist/assets/pieDiagram-E7YTZNPT-mgb14ksh.js +39 -0
  725. package/static/dist/assets/pkl-co2grztk.js +1 -0
  726. package/static/dist/assets/plastic-mm7c7uq7.js +1 -0
  727. package/static/dist/assets/plsql-l0i9f33n.js +1 -0
  728. package/static/dist/assets/po-f3ga9osn.js +1 -0
  729. package/static/dist/assets/poimandres-mnwq5v4d.js +1 -0
  730. package/static/dist/assets/polar-ldicpe6g.js +1 -0
  731. package/static/dist/assets/postcss-fgpvnt75.js +1 -0
  732. package/static/dist/assets/powerquery-mflxo46x.js +1 -0
  733. package/static/dist/assets/powershell-oado4mxi.js +1 -0
  734. package/static/dist/assets/prepaint-f14kbd49.js +21 -0
  735. package/static/dist/assets/prisma-go1e7wq8.js +1 -0
  736. package/static/dist/assets/prolog-cbjal8aj.js +1 -0
  737. package/static/dist/assets/proto-lrhov7xc.js +1 -0
  738. package/static/dist/assets/pug-mjad7he9.js +1 -0
  739. package/static/dist/assets/puppet-h22szrmn.js +1 -0
  740. package/static/dist/assets/purescript-dwpj7hdb.js +1 -0
  741. package/static/dist/assets/python-b767fgue.js +1 -0
  742. package/static/dist/assets/qml-d1gdp10s.js +1 -0
  743. package/static/dist/assets/qmldir-lsawched.js +1 -0
  744. package/static/dist/assets/qss-lyvmg4f4.js +1 -0
  745. package/static/dist/assets/quadrantDiagram-AXDQQJYC-cg36naog.js +7 -0
  746. package/static/dist/assets/r-o3r9c7ao.js +1 -0
  747. package/static/dist/assets/racket-nbfqjw5h.js +1 -0
  748. package/static/dist/assets/radar-RG4KPBEZ-lgzfpnef.js +1 -0
  749. package/static/dist/assets/railroad-74A4TZTK-gmglc3ua.js +1 -0
  750. package/static/dist/assets/railroad-abnf-HS5TGJTU-5mjl5wpv.js +1 -0
  751. package/static/dist/assets/railroad-ebnf-LZEXJU2U-bfram8v8.js +1 -0
  752. package/static/dist/assets/railroad-peg-WCYAUIDC-nwfczn88.js +1 -0
  753. package/static/dist/assets/railroadDiagram-O6MQD6OU-cmxwjt73.js +1 -0
  754. package/static/dist/assets/raku-hcy6uwm6.js +1 -0
  755. package/static/dist/assets/razor-ilc585yr.js +1 -0
  756. package/static/dist/assets/red-if4jt303.js +1 -0
  757. package/static/dist/assets/refresh-cw-mf192q3f.js +1 -0
  758. package/static/dist/assets/reg-ivi9d1my.js +1 -0
  759. package/static/dist/assets/regexp-mpjtcvwm.js +1 -0
  760. package/static/dist/assets/rel-gqpkg3ta.js +1 -0
  761. package/static/dist/assets/requirementDiagram-BXWQKSXE-ir0s2mek.js +84 -0
  762. package/static/dist/assets/riscv-j1f2yjp2.js +1 -0
  763. package/static/dist/assets/rolldown-runtime-b9miacsj.js +1 -0
  764. package/static/dist/assets/ron-bjqasg78.js +1 -0
  765. package/static/dist/assets/root-mbklpuv4.js +1 -0
  766. package/static/dist/assets/rose-pine-dawn-nlpzqzob.js +1 -0
  767. package/static/dist/assets/rose-pine-grpwpg67.js +1 -0
  768. package/static/dist/assets/rose-pine-moon-b9yyevxr.js +1 -0
  769. package/static/dist/assets/rosmsg-hv3wcot6.js +1 -0
  770. package/static/dist/assets/rough.esm-on4k4je3.js +1 -0
  771. package/static/dist/assets/rst-jrkwjdyi.js +1 -0
  772. package/static/dist/assets/ruby-n4tjcbpz.js +1 -0
  773. package/static/dist/assets/rust-jqduclx1.js +1 -0
  774. package/static/dist/assets/sankeyDiagram-P5KCCOFB-jo7jcdq0.js +40 -0
  775. package/static/dist/assets/sas-hjo6y93k.js +1 -0
  776. package/static/dist/assets/sass-m1yncbwu.js +1 -0
  777. package/static/dist/assets/saved-g777hp1t.js +1 -0
  778. package/static/dist/assets/scala-l9ahg4e9.js +1 -0
  779. package/static/dist/assets/scheme-mlodf39l.js +1 -0
  780. package/static/dist/assets/scss-ncidjv48.js +1 -0
  781. package/static/dist/assets/sdbl-bwg2t5pt.js +1 -0
  782. package/static/dist/assets/search-i2kfogyx.js +1 -0
  783. package/static/dist/assets/sequenceDiagram-WJ2MYXX4-n0pf6xk5.js +162 -0
  784. package/static/dist/assets/settings_section_extensions_title-hgvh507l.js +1 -0
  785. package/static/dist/assets/shaderlab-be89ch6g.js +1 -0
  786. package/static/dist/assets/share._token-il3y6js2.js +2 -0
  787. package/static/dist/assets/shellscript-m8whjpqd.js +1 -0
  788. package/static/dist/assets/shellsession-i5bj6syz.js +1 -0
  789. package/static/dist/assets/sizeCapture-INFHLROL-g612l48j.js +1 -0
  790. package/static/dist/assets/slack-dark-ny9l0r7b.js +1 -0
  791. package/static/dist/assets/slack-ochin-g98102hs.js +1 -0
  792. package/static/dist/assets/sliders-horizontal-kd99ffvl.js +1 -0
  793. package/static/dist/assets/smalltalk-g9lpwisn.js +1 -0
  794. package/static/dist/assets/snazzy-light-dlu9q2m5.js +1 -0
  795. package/static/dist/assets/solarized-dark-mx1nd4sm.js +1 -0
  796. package/static/dist/assets/solarized-light-mqzd33fz.js +1 -0
  797. package/static/dist/assets/solidity-ih313ji4.js +1 -0
  798. package/static/dist/assets/soy-hhh36ysq.js +1 -0
  799. package/static/dist/assets/sparql-pewjbauq.js +1 -0
  800. package/static/dist/assets/splunk-d8q89juf.js +1 -0
  801. package/static/dist/assets/sql-j21bzcl6.js +1 -0
  802. package/static/dist/assets/src-hjyib4mu.js +1 -0
  803. package/static/dist/assets/ssh-config-fzxlymn8.js +1 -0
  804. package/static/dist/assets/stata-bbu2onh1.js +1 -0
  805. package/static/dist/assets/stateDiagram-D77RDMKH-olbrwyv9.js +1 -0
  806. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-dnzlmdpu.js +1 -0
  807. package/static/dist/assets/stylus-hifjg0ye.js +1 -0
  808. package/static/dist/assets/surrealql-l5vczuco.js +1 -0
  809. package/static/dist/assets/svelte-idn422g6.js +1 -0
  810. package/static/dist/assets/swift-n11rc3v3.js +1 -0
  811. package/static/dist/assets/swimlanes-42K2YHIH-od14zrw6.js +1 -0
  812. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-ck0eqqdp.js +8 -0
  813. package/static/dist/assets/synthwave-84-clkt7319.js +1 -0
  814. package/static/dist/assets/system-verilog-l8k1po2l.js +1 -0
  815. package/static/dist/assets/systemd-d1zoxedb.js +1 -0
  816. package/static/dist/assets/talonscript-j9gt5qb1.js +1 -0
  817. package/static/dist/assets/tasl-meer3lyk.js +1 -0
  818. package/static/dist/assets/tcl-jdc54rsg.js +1 -0
  819. package/static/dist/assets/templ-e22qou3c.js +1 -0
  820. package/static/dist/assets/terraform-oav3wzsy.js +1 -0
  821. package/static/dist/assets/tex-deqpc5ee.js +1 -0
  822. package/static/dist/assets/timeline-definition-24CTP7MA-l0qokmnb.js +120 -0
  823. package/static/dist/assets/todoStore-la6uyqzj.js +1 -0
  824. package/static/dist/assets/tokyo-night-cnyqlmc2.js +1 -0
  825. package/static/dist/assets/toml-jj1ee1k1.js +1 -0
  826. package/static/dist/assets/trash-bxz1k9cw.js +1 -0
  827. package/static/dist/assets/treeView-Q6P3EWNA-hma3ip8m.js +1 -0
  828. package/static/dist/assets/treemap-WGGIJYW6-bghjng5m.js +1 -0
  829. package/static/dist/assets/ts-tags-ctnibc27.js +1 -0
  830. package/static/dist/assets/tsv-cxbgj4wh.js +1 -0
  831. package/static/dist/assets/tsx-i163n32g.js +1 -0
  832. package/static/dist/assets/turtle-g1kfgpwv.js +1 -0
  833. package/static/dist/assets/twig-x0fi7wm8.js +1 -0
  834. package/static/dist/assets/typescript-g18c34xz.js +1 -0
  835. package/static/dist/assets/typespec-hokgy7ic.js +1 -0
  836. package/static/dist/assets/typst-l6lt2vta.js +1 -0
  837. package/static/dist/assets/untitled-nfaw0q7m.js +1 -0
  838. package/static/dist/assets/useForm-k7fj2zsr.js +1 -0
  839. package/static/dist/assets/useLocale-evhacmv2.js +1 -0
  840. package/static/dist/assets/useParams-gpbjxj8s.js +1 -0
  841. package/static/dist/assets/useSearch-bhdptos7.js +1 -0
  842. package/static/dist/assets/useSelector-f2aak1ol.js +1 -0
  843. package/static/dist/assets/v-lwnsi8rl.js +1 -0
  844. package/static/dist/assets/vala-db1h2kp7.js +1 -0
  845. package/static/dist/assets/vb-nrezymby.js +1 -0
  846. package/static/dist/assets/vennDiagram-4TSXK5OY-bo97zf3z.js +34 -0
  847. package/static/dist/assets/verilog-jworpiw4.js +1 -0
  848. package/static/dist/assets/vesper-o1vwtlg2.js +1 -0
  849. package/static/dist/assets/vhdl-gnn4vfnm.js +1 -0
  850. package/static/dist/assets/viml-ogfqutxv.js +1 -0
  851. package/static/dist/assets/vitesse-black-b5y62t71.js +1 -0
  852. package/static/dist/assets/vitesse-dark-fj1ju380.js +1 -0
  853. package/static/dist/assets/vitesse-light-bjycd3ha.js +1 -0
  854. package/static/dist/assets/vue-html-nskj3du0.js +1 -0
  855. package/static/dist/assets/vue-mwu5l1bb.js +1 -0
  856. package/static/dist/assets/vue-vine-cqe77smq.js +1 -0
  857. package/static/dist/assets/vyper-jsmo764l.js +1 -0
  858. package/static/dist/assets/wardley-WFR3VGLG-pbjl6jav.js +1 -0
  859. package/static/dist/assets/wardleyDiagram-VM6X3IG4-bmy9i09l.js +78 -0
  860. package/static/dist/assets/wasm-g1zrybde.js +1 -0
  861. package/static/dist/assets/wasm-gezzbmz0.js +1 -0
  862. package/static/dist/assets/wenyan-lgcd7t1n.js +1 -0
  863. package/static/dist/assets/wgsl-gotoh48n.js +1 -0
  864. package/static/dist/assets/wikitext-j1379ez7.js +1 -0
  865. package/static/dist/assets/wit-neu67rwu.js +1 -0
  866. package/static/dist/assets/wolfram-mbb1p6oi.js +1 -0
  867. package/static/dist/assets/xml-gau7gvrv.js +1 -0
  868. package/static/dist/assets/xsl-ew09zq8b.js +1 -0
  869. package/static/dist/assets/xychartDiagram-S5SC5T6Z-eercu0mc.js +7 -0
  870. package/static/dist/assets/yaml-ofnrxtvf.js +1 -0
  871. package/static/dist/assets/zenscript-ge1h0r83.js +1 -0
  872. package/static/dist/assets/zig-ik06evde.js +1 -0
  873. package/static/dist/extension-sdk.js +1 -0
  874. package/static/dist/index.html +1 -0
  875. package/static/dist/manifest.webmanifest +29 -0
  876. package/static/dist/sw.js +944 -0
@@ -0,0 +1,1344 @@
1
+ import { str } from '../util.js';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { rmSync } from 'node:fs';
4
+ import { copyJson, redactSessionData, stripPublicInternalFields } from '../redact.js';
5
+ import { DraftVersionConflict, normalizeDraftVersion } from './drafts.js';
6
+ import { allSessions, buildSessionListPayload, isMessagingSessionRecord, lineageRootId, mergeCliSidebarMetadata, sessionListResponse, sessionSearchMessageText, sessionSearchPreview } from './list.js';
7
+ import { anchorSceneIntOrNull, hydrateAnchorActivityScenes, normalizeAnchorSceneMessageRef, readAnchorSceneRows, storeAnchorScene } from './anchor.js';
8
+ import { isSafeSessionId, lastMessageTimestamp, Session, titleFrom } from './session.js';
9
+ import { SessionBusy, SessionNotFound, statSignature } from './store.js';
10
+ import { attachTodoState } from './todo.js';
11
+ import { stateDbSessionMessages, stateDbSessionRow } from './state-db.js';
12
+ import { mergeSessionMessagesAppendOnly } from './merge.js';
13
+ import { messagesForLimitedPayload, messageWindowForDisplay, MAX_MSG_LIMIT, parseMsgLimit, toolCallsForMessageWindow } from './window.js';
14
+ import { redactText } from '../redact.js';
15
+ import { buildShareSnapshot } from './shares.js';
16
+ import { loadGatewaySessionIdentityMap } from './list.js';
17
+ import { join } from 'node:path';
18
+ export class HttpFailure extends Error {
19
+ status;
20
+ extra;
21
+ constructor(status, message, extra = {}) {
22
+ super(message);
23
+ this.status = status;
24
+ this.extra = extra;
25
+ this.name = 'HttpFailure';
26
+ }
27
+ }
28
+ const isDict = (v) => Boolean(v) && typeof v === 'object' && !Array.isArray(v);
29
+ export class SessionService {
30
+ deps;
31
+ constructor(deps) {
32
+ this.deps = deps;
33
+ }
34
+ get store() { return this.deps.store; }
35
+ publish(reason, profile, sessionId) {
36
+ this.deps.events.publish(reason, { profile: profile ?? null, sessionId: sessionId ?? null });
37
+ }
38
+ visibleToActiveProfile(profile) {
39
+ return this.deps.profilesMatch(typeof profile === 'string' ? profile : null, this.deps.activeProfile());
40
+ }
41
+ /**
42
+ * Python `_session_id_visible_to_request_profile`, applied to the id as handlers see it (trimmed): a padded id must
43
+ * not slip past the profile check into a handler that trims and trusts it. A non-empty id that is still unsafe after
44
+ * trimming can name no session and is refused here instead of falling through.
45
+ */
46
+ sessionIdVisible(raw) {
47
+ if (typeof raw !== 'string' || !raw.trim())
48
+ return true;
49
+ const sid = raw.trim();
50
+ if (!isSafeSessionId(sid))
51
+ return false;
52
+ let session;
53
+ try {
54
+ session = this.store.get(sid, { metadataOnly: true });
55
+ }
56
+ catch {
57
+ return true;
58
+ }
59
+ return this.visibleToActiveProfile(session.profile);
60
+ }
61
+ /** Python `_lookup_cli_session_metadata(...).get('read_only')` plus the persisted sidecar flag and a not-claimable foreign owner. */
62
+ isReadOnlyImport(sid) {
63
+ try {
64
+ const s = this.store.get(sid, { metadataOnly: true });
65
+ if (s.read_only)
66
+ return true;
67
+ }
68
+ catch {
69
+ // No sidecar: a foreign state.db transcript whose owner refuses claiming is read-only too.
70
+ const { session, reason } = this.claimOrSynthesizeCliSession(sid);
71
+ if (session && reason === 'not_claimable')
72
+ return true;
73
+ }
74
+ const meta = this.lookupCliMeta(sid);
75
+ return meta !== null && Boolean(meta.read_only);
76
+ }
77
+ /** Python `_session_is_subagent_view_only`: a delegated child by any signal — the persisted sidecar or the state.db row. */
78
+ isSubagentViewOnly(sid) {
79
+ try {
80
+ const s = this.store.get(sid);
81
+ if (str(s.source_tag || s.raw_source || s.session_source).trim().toLowerCase() === 'subagent')
82
+ return true;
83
+ }
84
+ catch { /* no sidecar */ }
85
+ const meta = this.lookupCliMeta(sid);
86
+ return meta !== null && str(meta.source_tag || meta.raw_source || meta.source).trim().toLowerCase() === 'subagent';
87
+ }
88
+ /** Full session for mutation, refusing read-only imports (Python `_get_or_materialize_session`). */
89
+ getForMutation(sid) {
90
+ let s = this.get404(sid);
91
+ s = this.store.ensureFull(sid, s);
92
+ if (s.read_only)
93
+ throw new HttpFailure(403, 'Read-only imported sessions cannot be modified from WebUI');
94
+ if (str(s.source_tag || s.raw_source).trim().toLowerCase() === 'subagent')
95
+ throw new HttpFailure(403, 'Read-only subagent child session');
96
+ return s;
97
+ }
98
+ get404(sid, opts = {}) {
99
+ try {
100
+ return this.store.get(sid, opts);
101
+ }
102
+ catch (error) {
103
+ if (error instanceof SessionNotFound) {
104
+ // Python `_get_or_materialize_session`: a claimable foreign (CLI/TUI/Desktop) session gains a WebUI sidecar
105
+ // on its first mutation; a read-only foreign source answers 403 from `getForMutation`, a missing one 404.
106
+ const synth = this.claimOrSynthesizeCliSession(sid);
107
+ if (synth.session && synth.reason === 'materialized') {
108
+ this.store.save(synth.session);
109
+ return synth.session;
110
+ }
111
+ if (synth.session)
112
+ return synth.session;
113
+ throw new HttpFailure(404, 'Session not found');
114
+ }
115
+ throw error;
116
+ }
117
+ }
118
+ /** The Agent's state.db rows for this session (empty for subagent views, which never merge). */
119
+ stateDbRows(s) {
120
+ if (str(s.source_tag || s.raw_source || s.session_source).trim().toLowerCase() === 'subagent')
121
+ return [];
122
+ return stateDbSessionMessages(join(this.deps.profileHome(s.profile ?? this.deps.activeProfile()), 'state.db'), s.session_id, { stitch: false });
123
+ }
124
+ /**
125
+ * Python `_merged_session_messages_for_display`: the sidecar transcript merged append-only with the Agent's state.db
126
+ * rows (a WebUI conversation continued from the CLI shows the CLI turns). This is the coordinate space `GET
127
+ * /api/session` exposes, so branching and the next model history slice/extend the same list.
128
+ */
129
+ mergedTranscript(s, local = s.messages) {
130
+ const stateRows = this.stateDbRows(s);
131
+ if (!stateRows.length)
132
+ return local;
133
+ return mergeSessionMessagesAppendOnly(local, stateRows, { truncationWatermark: s.truncation_watermark });
134
+ }
135
+ /** Python `_lookup_cli_session_metadata`: the sidebar row for a state.db session in the active profile. */
136
+ lookupCliMeta(sid) {
137
+ try {
138
+ return this.deps.cliSessions(this.deps.activeProfile(), { sourceFilter: null }).find((r) => str(r.session_id) === sid) ?? null;
139
+ }
140
+ catch {
141
+ return null;
142
+ }
143
+ }
144
+ /** Python `_is_claimable_cli_source`: a denylist of foreign families that own their sessions. */
145
+ claimableCliSource(meta, stateDbSource) {
146
+ if (meta.read_only)
147
+ return false;
148
+ const sessionSource = str(meta.session_source).trim().toLowerCase();
149
+ if (['messaging', 'external_agent'].includes(sessionSource))
150
+ return false;
151
+ const tag = str(meta.source_tag || meta.raw_source).trim().toLowerCase();
152
+ const refused = new Set(['claude_code', 'cron', 'external_agent', 'gateway', 'messaging', 'subagent', 'unknown']);
153
+ if (tag && refused.has(tag))
154
+ return false;
155
+ if (isMessagingSessionRecord(meta))
156
+ return false;
157
+ if (!tag && stateDbSource && refused.has(stateDbSource.trim().toLowerCase()))
158
+ return false;
159
+ return true;
160
+ }
161
+ /** Python `_session_index_marks_was_webui`: an index row that once owned a WebUI sidecar (self-heal 404). */
162
+ indexMarksWasWebui(sid) {
163
+ let entries;
164
+ try {
165
+ entries = this.store.readIndexEntries();
166
+ }
167
+ catch {
168
+ return false;
169
+ }
170
+ for (const entry of entries) {
171
+ if (str(entry.session_id) !== sid)
172
+ continue;
173
+ const explicit = [entry.source_tag, entry.raw_source, entry.session_source].map((v) => str(v).trim().toLowerCase()).filter(Boolean);
174
+ if (explicit.some((v) => v === 'webui' || v === 'fork'))
175
+ return true;
176
+ if (explicit.length)
177
+ return false;
178
+ return !(entry.is_cli_session === true || Boolean(entry.read_only || entry.is_read_only));
179
+ }
180
+ return false;
181
+ }
182
+ /**
183
+ * Python `_claim_or_synthesize_cli_session`: build a `Session` from the active profile's state.db for an id without
184
+ * a WebUI sidecar. `materialized` sessions are writeable (the caller persists the sidecar), `not_claimable` ones are
185
+ * read-only stubs, `was_webui`/`no_foreign_state`/`invalid_sid` answer 404.
186
+ */
187
+ claimOrSynthesizeCliSession(sid, metaIn) {
188
+ if (!isSafeSessionId(sid))
189
+ return { session: null, reason: 'invalid_sid' };
190
+ const profile = this.deps.activeProfile();
191
+ const dbPath = join(this.deps.profileHome(profile), 'state.db');
192
+ const row = stateDbSessionRow(dbPath, sid);
193
+ const stateDbSource = str(row?.source).trim().toLowerCase();
194
+ const subagentChild = stateDbSource === 'subagent';
195
+ if ((this.indexMarksWasWebui(sid) || (this.store.wasDeleted(sid) && ['', 'webui', 'fork'].includes(stateDbSource))) && !subagentChild)
196
+ return { session: null, reason: 'was_webui' };
197
+ const msgs = stateDbSessionMessages(dbPath, sid, { stitch: true });
198
+ if (!msgs.length)
199
+ return { session: null, reason: 'no_foreign_state' };
200
+ const meta = { ...(metaIn ?? this.lookupCliMeta(sid) ?? {}) };
201
+ if (row) {
202
+ if (!meta.source_tag && stateDbSource)
203
+ meta.source_tag = stateDbSource;
204
+ if (!meta.raw_source && stateDbSource)
205
+ meta.raw_source = stateDbSource;
206
+ if (!meta.title && row.title)
207
+ meta.title = row.title;
208
+ if (!meta.model && row.model)
209
+ meta.model = row.model;
210
+ if (!meta.workspace && row.cwd)
211
+ meta.workspace = row.cwd;
212
+ if (!meta.created_at && row.started_at)
213
+ meta.created_at = row.started_at;
214
+ if (!meta.updated_at && (row.ended_at || row.started_at))
215
+ meta.updated_at = row.ended_at || row.started_at;
216
+ }
217
+ const claimable = this.claimableCliSource(meta, stateDbSource);
218
+ const workspace = str(meta.workspace || meta.cwd).trim() || this.deps.workspaces.lastWorkspace(profile);
219
+ const defaults = this.store.deps.defaults(profile);
220
+ const session = new Session({
221
+ session_id: sid, title: str(meta.title) || 'CLI Session', workspace, model: str(meta.model) || 'unknown', model_provider: str(meta.model_provider) || null,
222
+ messages: msgs, created_at: Number(meta.created_at) || 0, updated_at: Number(meta.updated_at) || 0, profile: str(meta.profile) || null,
223
+ is_cli_session: claimable ? true : !subagentChild, source_tag: str(meta.source_tag) || null, raw_source: str(meta.raw_source) || null,
224
+ session_source: str(meta.session_source) || null, source_label: str(meta.source_label) || null, read_only: !claimable,
225
+ }, defaults);
226
+ return { session, reason: claimable ? 'materialized' : 'not_claimable' };
227
+ }
228
+ mutationTarget(sid, verb) {
229
+ try {
230
+ return this.getForMutation(sid);
231
+ }
232
+ catch (error) {
233
+ if (error instanceof SessionNotFound)
234
+ throw new HttpFailure(404, 'Session not found');
235
+ if (error instanceof HttpFailure && error.status === 403)
236
+ throw new HttpFailure(403, `Read-only imported sessions cannot be ${verb} from WebUI`);
237
+ throw error;
238
+ }
239
+ }
240
+ rejectSubagent(sid, verb) {
241
+ if (this.isSubagentViewOnly(sid))
242
+ throw new HttpFailure(400, `Subagent sessions are view-only and cannot be ${verb} from WebUI`);
243
+ }
244
+ /** `compact()` plus messages, redacted for the wire (Python `_public_session_projection`). */
245
+ publicSession(s, withMessages = true) {
246
+ const payload = s.compact();
247
+ if (withMessages)
248
+ payload.messages = s.messages;
249
+ return redactSessionData(payload, this.deps.redactEnabled());
250
+ }
251
+ /** Python `public_session_projection(s.__dict__)`: every persisted field, redacted (session export). */
252
+ publicSessionDocument(s) {
253
+ return redactSessionData(s.toDocument(), this.deps.redactEnabled());
254
+ }
255
+ // ── detail ──────────────────────────────────────────────────────────────
256
+ loadRevision(s) {
257
+ return statSignature(this.store.pathFor(s.session_id));
258
+ }
259
+ /** Python `_handle_session_get` on the WebUI sidecar (state.db merge pending). */
260
+ detail(sid, query) {
261
+ if (!sid)
262
+ throw new HttpFailure(400, 'session_id is required');
263
+ const loadMessages = (query.messages ?? '1') !== '0';
264
+ const msgLimit = parseMsgLimit(query.msg_limit ?? null);
265
+ const msgBeforeRaw = query.msg_before;
266
+ const msgBefore = msgBeforeRaw ? (Number.isInteger(Number(msgBeforeRaw)) ? Number(msgBeforeRaw) : null) : null;
267
+ let s;
268
+ try {
269
+ s = this.store.get(sid, { metadataOnly: !loadMessages });
270
+ }
271
+ catch {
272
+ return this.foreignSessionDetail(sid);
273
+ }
274
+ const revisionBefore = this.loadRevision(s);
275
+ if (!this.visibleToActiveProfile(s.profile)) {
276
+ if (s.profile)
277
+ throw new HttpFailure(409, 'Session belongs to a different profile', { code: 'session_profile_mismatch', session_id: sid, profile: s.profile });
278
+ throw new HttpFailure(404, 'Session not found');
279
+ }
280
+ this.clearStaleStreamState(s);
281
+ const all = loadMessages ? this.mergedTranscript(s) : [];
282
+ let truncated = [];
283
+ let offset = 0;
284
+ let summaryCount = null;
285
+ let summaryLast = null;
286
+ if (loadMessages) {
287
+ ;
288
+ [truncated, offset] = messageWindowForDisplay(all, msgLimit, msgBefore);
289
+ if (msgLimit !== null)
290
+ truncated = messagesForLimitedPayload(truncated);
291
+ truncated = hydrateAnchorActivityScenes(truncated, s.anchor_activity_scenes, offset);
292
+ }
293
+ else {
294
+ summaryCount = s.metadataMessageCount ?? s.messages.length;
295
+ summaryLast = lastMessageTimestamp(s.messages) ?? 0;
296
+ }
297
+ const windowed = loadMessages && msgLimit !== null && (msgBefore !== null || truncated.length < all.length);
298
+ let toolCalls = loadMessages ? s.tool_calls : [];
299
+ if (windowed)
300
+ toolCalls = toolCallsForMessageWindow(toolCalls, offset, truncated.length);
301
+ const mergedCount = summaryCount ?? all.length;
302
+ let mergedLast = summaryLast ?? 0;
303
+ if (summaryLast === null && all.length) {
304
+ mergedLast = Math.max(...all.map((m) => (isDict(m) ? Number(m.timestamp ?? 0) || 0 : 0)));
305
+ }
306
+ const activeStreamIds = this.deps.runtime.activeStreamIds;
307
+ const raw = {
308
+ ...s.compact({ includeRuntime: true, activeStreamIds }),
309
+ messages: truncated,
310
+ message_count: mergedCount,
311
+ tool_calls: toolCalls,
312
+ active_stream_id: s.active_stream_id,
313
+ pending_user_message: s.pending_user_message,
314
+ pending_attachments: loadMessages ? s.pending_attachments : [],
315
+ pending_started_at: s.pending_started_at,
316
+ pending_user_source: s.pending_user_source,
317
+ context_length: Number(s.context_length ?? 0) || this.deps.contextLengthFor(s.model, s.model_provider) || 0,
318
+ threshold_tokens: Number(s.threshold_tokens ?? 0) || 0,
319
+ last_prompt_tokens: Number(s.last_prompt_tokens ?? 0) || 0,
320
+ };
321
+ if (loadMessages && all.length)
322
+ attachTodoState(raw, all);
323
+ if (mergedLast) {
324
+ raw.last_message_at = Math.max(Number(raw.last_message_at ?? 0) || 0, mergedLast);
325
+ raw.updated_at = Math.max(Number(raw.updated_at ?? 0) || 0, mergedLast);
326
+ }
327
+ const isTruncated = loadMessages && msgLimit !== null && offset > 0;
328
+ raw._messages_truncated = isTruncated;
329
+ raw._messages_offset = offset;
330
+ raw._msg_limit_max = MAX_MSG_LIMIT;
331
+ const revisionAfter = this.loadRevision(s);
332
+ raw._load_revision = revisionBefore !== null && revisionBefore === revisionAfter ? hashRevision(revisionBefore) : `unstable-${randomUUID().replace(/-/g, '')}`;
333
+ if (str(raw.source_tag || raw.raw_source || raw.session_source).trim().toLowerCase() === 'subagent') {
334
+ raw.is_cli_session = false;
335
+ raw.read_only = true;
336
+ }
337
+ return redactSessionData(raw, this.deps.redactEnabled());
338
+ }
339
+ /** Python `_handle_session_get` without a sidecar: the state.db transcript as a (read-only or claimable) foreign stub. */
340
+ foreignSessionDetail(sid) {
341
+ const meta = this.lookupCliMeta(sid);
342
+ const profile = str(meta?.profile) || null;
343
+ const profileAgnostic = str(meta?.source_tag || meta?.raw_source).trim().toLowerCase() === 'claude_code';
344
+ if (!profileAgnostic && !this.visibleToActiveProfile(profile)) {
345
+ if (profile)
346
+ throw new HttpFailure(409, 'Session belongs to a different profile', { code: 'session_profile_mismatch', session_id: sid, profile });
347
+ throw new HttpFailure(404, 'Session not found');
348
+ }
349
+ const { session: synth, reason } = this.claimOrSynthesizeCliSession(sid, meta);
350
+ if (!synth || reason === 'was_webui')
351
+ throw new HttpFailure(404, 'Session not found');
352
+ const msgs = synth.messages;
353
+ const lastTs = Number(msgs[msgs.length - 1]?.timestamp ?? 0) || 0;
354
+ const sess = {
355
+ session_id: synth.session_id, title: synth.title, workspace: synth.workspace, model: synth.model, message_count: msgs.length,
356
+ created_at: synth.created_at, updated_at: synth.updated_at, last_message_at: meta?.last_message_at || meta?.updated_at || lastTs,
357
+ pinned: synth.pinned, archived: synth.archived, project_id: synth.project_id ?? null, profile: synth.profile,
358
+ is_cli_session: synth.is_cli_session, source_tag: synth.source_tag, raw_source: synth.raw_source, session_source: synth.session_source,
359
+ source_label: synth.source_label, read_only: synth.read_only, messages: msgs, tool_calls: [],
360
+ };
361
+ attachTodoState(sess, msgs);
362
+ const merged = meta ? mergeCliSidebarMetadata(sess, meta) : sess;
363
+ return redactSessionData(merged, this.deps.redactEnabled());
364
+ }
365
+ /** Clear persisted streaming flags when no live stream backs them (Python `_clear_stale_stream_state`, no journal recovery). */
366
+ clearStaleStreamState(session) {
367
+ const streamId = session.active_stream_id;
368
+ if (!streamId)
369
+ return false;
370
+ if (this.deps.runtime.activeStreamIds.has(streamId))
371
+ return false;
372
+ if (this.deps.runtime.activeRunStream(session.session_id))
373
+ return false;
374
+ const pendingAge = session.pending_started_at ? this.deps.now() - session.pending_started_at : null;
375
+ if (session.pending_user_message && pendingAge !== null && pendingAge < 30)
376
+ return false;
377
+ let target = session;
378
+ if (session.loadedMetadataOnly) {
379
+ const full = this.store.load(session.session_id);
380
+ if (!full)
381
+ return false;
382
+ target = full;
383
+ if (!target.active_stream_id) {
384
+ session.active_stream_id = null;
385
+ session.pending_user_message = null;
386
+ session.pending_attachments = [];
387
+ session.pending_started_at = null;
388
+ session.pending_user_source = null;
389
+ return false;
390
+ }
391
+ }
392
+ // Python `_materialize_pending_user_turn_before_error` (#1361): the prompt that was in flight becomes a durable user
393
+ // turn and an interruption marker follows it, so a dead stream never silently drops what the user sent.
394
+ const pendingText = str(target.pending_user_message);
395
+ if (pendingText) {
396
+ const startedAt = typeof target.pending_started_at === 'number' && target.pending_started_at > 0 ? target.pending_started_at : this.deps.now();
397
+ const attachments = [...target.pending_attachments];
398
+ target.messages.push({ role: 'user', content: pendingText, timestamp: Math.trunc(startedAt), ...(attachments.length ? { attachments } : {}), _recovered: true, _source: target.pending_user_source ?? 'webui' });
399
+ target.messages.push({ role: 'assistant', content: '**Interrupted:** The reply was interrupted before it could be saved.', timestamp: Math.trunc(this.deps.now()), _error: true });
400
+ }
401
+ target.active_stream_id = null;
402
+ target.pending_user_message = null;
403
+ target.pending_attachments = [];
404
+ target.pending_started_at = null;
405
+ target.pending_user_source = null;
406
+ try {
407
+ this.store.save(target, { touchUpdatedAt: false });
408
+ }
409
+ catch {
410
+ return false;
411
+ }
412
+ if (target !== session) {
413
+ session.active_stream_id = null;
414
+ session.pending_user_message = null;
415
+ session.pending_attachments = [];
416
+ session.pending_started_at = null;
417
+ session.pending_user_source = null;
418
+ this.store.touch(target);
419
+ }
420
+ return true;
421
+ }
422
+ // ── list / search ────────────────────────────────────────────────────────
423
+ list(params) {
424
+ const activeProfile = this.deps.activeProfile();
425
+ const wantState = params.showCliSessions || params.showCronSessions || params.showWebhookSessions || params.showKanbanSessions;
426
+ // Python reads every profile's state.db under all_profiles; this port projects the active profile only.
427
+ const cliRows = wantState ? this.deps.cliSessions(activeProfile, { sourceFilter: params.sourceFilter ?? null }) : undefined;
428
+ const gatewayIdentity = loadGatewaySessionIdentityMap(join(this.deps.profileHome(activeProfile), 'sessions', 'sessions.json'));
429
+ const payload = buildSessionListPayload(this.store, { ...params, ...(cliRows ? { cliRows } : {}), gatewayIdentity, activeProfile, isolatedProfileMode: this.deps.isolatedProfileMode(), profilesMatch: this.deps.profilesMatch });
430
+ return sessionListResponse(payload, this.deps.runtime, this.deps.redactEnabled(), this.deps.now());
431
+ }
432
+ search(q, opts) {
433
+ const activeProfile = this.deps.activeProfile();
434
+ let sessions = allSessions(this.store);
435
+ if (!opts.allProfiles)
436
+ sessions = sessions.filter((r) => this.deps.profilesMatch(str(r.profile) || null, activeProfile));
437
+ const redact = this.deps.redactEnabled();
438
+ const redactRow = (item) => {
439
+ if (typeof item.title === 'string')
440
+ item.title = redactText(item.title, redact);
441
+ for (const f of ['display_title', '_state_db_title', 'parent_title'])
442
+ if (typeof item[f] === 'string')
443
+ item[f] = redactText(item[f], redact);
444
+ return item;
445
+ };
446
+ const query = q.toLowerCase().trim();
447
+ if (!query)
448
+ return { sessions: sessions.map((s) => redactRow({ ...s })), all_profiles: opts.allProfiles, active_profile: activeProfile };
449
+ const results = [];
450
+ for (const s of sessions) {
451
+ if (str(s.title).toLowerCase().includes(query)) {
452
+ results.push(redactRow({ ...s, match_type: 'title' }));
453
+ continue;
454
+ }
455
+ if (!opts.content)
456
+ continue;
457
+ let sess;
458
+ try {
459
+ sess = this.store.get(str(s.session_id), { promote: false, cacheOnMiss: false });
460
+ }
461
+ catch {
462
+ continue;
463
+ }
464
+ const msgs = opts.depth ? sess.messages.slice(0, opts.depth) : sess.messages;
465
+ for (const m of msgs) {
466
+ const c = sessionSearchMessageText(m);
467
+ if (c.toLowerCase().includes(query)) {
468
+ const item = { ...s, match_type: 'content' };
469
+ const preview = sessionSearchPreview(c, query);
470
+ if (preview)
471
+ item.match_preview = redactText(preview, redact);
472
+ results.push(redactRow(item));
473
+ break;
474
+ }
475
+ }
476
+ }
477
+ return { sessions: results, query, count: results.length, all_profiles: opts.allProfiles, active_profile: activeProfile };
478
+ }
479
+ // ── status / usage ───────────────────────────────────────────────────────
480
+ status(sid) {
481
+ const s = this.get404(sid, { metadataOnly: true });
482
+ this.clearStaleStreamState(s);
483
+ const full = this.get404(sid);
484
+ const inp = Math.trunc(full.input_tokens) || 0;
485
+ const out = Math.trunc(full.output_tokens) || 0;
486
+ const profile = full.profile || 'default';
487
+ let hermesHome = '';
488
+ try {
489
+ hermesHome = this.deps.workspaces.deps.profileHome(profile);
490
+ }
491
+ catch {
492
+ hermesHome = '';
493
+ }
494
+ const live = full.active_stream_id && this.deps.runtime.activeStreamIds.has(full.active_stream_id) ? full.active_stream_id : null;
495
+ return {
496
+ session_id: full.session_id, title: full.title, model: full.model, profile, hermes_home: hermesHome, workspace: full.workspace, personality: full.personality,
497
+ message_count: full.messages.length, created_at: full.created_at, updated_at: full.updated_at, agent_running: Boolean(full.active_stream_id), active_stream_id: live,
498
+ input_tokens: inp, output_tokens: out, total_tokens: inp + out, estimated_cost: full.estimated_cost,
499
+ };
500
+ }
501
+ usage(sid) {
502
+ const s = this.get404(sid);
503
+ const inp = Math.trunc(s.input_tokens) || 0;
504
+ const out = Math.trunc(s.output_tokens) || 0;
505
+ return { input_tokens: inp, output_tokens: out, total_tokens: inp + out, estimated_cost: s.estimated_cost, model: s.model };
506
+ }
507
+ // ── creation ─────────────────────────────────────────────────────────────
508
+ resolveNewSessionWorkspace(body, visiblePrevSessionId, profile) {
509
+ const candidate = body.workspace;
510
+ if (!candidate)
511
+ return null;
512
+ const value = str(candidate);
513
+ if (body.workspace_inherited_from_prev_session !== true || !visiblePrevSessionId)
514
+ return this.deps.workspaces.resolveTrusted(value, profile);
515
+ let previous;
516
+ try {
517
+ previous = this.store.get(visiblePrevSessionId, { metadataOnly: true });
518
+ }
519
+ catch {
520
+ return this.deps.workspaces.resolveTrusted(value, profile);
521
+ }
522
+ if (previous.workspace !== value)
523
+ return this.deps.workspaces.resolveTrusted(value, profile);
524
+ const [workspace] = this.deps.workspaces.resolveImplicitWithRecovery(value, (p) => this.deps.workspaces.profileDefaultWorkspaceForBoot(p), profile);
525
+ return workspace;
526
+ }
527
+ validateToolsetsShape(toolsets) {
528
+ if (toolsets === null || toolsets === undefined)
529
+ return null;
530
+ if (!Array.isArray(toolsets) || !toolsets.length)
531
+ throw new HttpFailure(400, 'toolsets must be a non-empty list or null');
532
+ if (!toolsets.every((t) => typeof t === 'string' && t))
533
+ throw new HttpFailure(400, 'each toolset must be a non-empty string');
534
+ return toolsets;
535
+ }
536
+ create(body, opts = {}) {
537
+ const profile = (typeof body.profile === 'string' && body.profile) || null;
538
+ let prevSessionId = typeof body.prev_session_id === 'string' && body.prev_session_id ? body.prev_session_id : null;
539
+ if (prevSessionId && !this.sessionIdVisible(prevSessionId))
540
+ prevSessionId = null;
541
+ // Python: leaving a session for a new one flushes the previous session's memory in the background (W6).
542
+ if (prevSessionId)
543
+ this.deps.commitSessionMemory?.(prevSessionId);
544
+ let workspace;
545
+ try {
546
+ workspace = this.resolveNewSessionWorkspace(body, prevSessionId, profile);
547
+ }
548
+ catch (error) {
549
+ throw new HttpFailure(400, error.message);
550
+ }
551
+ const [model, provider] = this.deps.modelStateFromRequest(body.model, body.model_provider, null);
552
+ const toolsets = this.validateToolsetsShape(body.enabled_toolsets);
553
+ const s = this.store.newSession({ workspace, model, modelProvider: provider, profile, projectId: typeof body.project_id === 'string' && body.project_id ? body.project_id : null, worktree: opts.worktree ?? null, enabledToolsets: toolsets });
554
+ if (opts.worktree)
555
+ this.publish('session_new', s.profile, s.session_id);
556
+ return s;
557
+ }
558
+ // ── simple metadata mutations ────────────────────────────────────────────
559
+ /** Python `_persist_generated_session_title`: title + generated/manual flags under the session lock, then insights sync. */
560
+ async persistGeneratedTitle(sid, nextTitle, eventReason) {
561
+ const title = nextTitle.trim().slice(0, 80) || 'Untitled';
562
+ let current;
563
+ try {
564
+ current = this.store.get(sid);
565
+ }
566
+ catch {
567
+ throw new HttpFailure(404, 'Session not found');
568
+ }
569
+ if (current.read_only)
570
+ throw new HttpFailure(403, `Session ${sid} is read-only`);
571
+ await this.store.withLock(sid, () => {
572
+ current.title = title;
573
+ markSessionTitleGenerated(current);
574
+ this.store.save(current, { touchUpdatedAt: false });
575
+ });
576
+ await this.deps.syncTitle(current);
577
+ this.publish(eventReason, current.profile, current.session_id);
578
+ return current;
579
+ }
580
+ async rename(sid, rawTitle) {
581
+ const s = this.mutationTarget(sid, 'renamed');
582
+ await this.store.withLock(sid, () => {
583
+ applySessionTitleRename(s, rawTitle);
584
+ this.store.save(s);
585
+ });
586
+ await this.deps.syncTitle(s);
587
+ this.publish('session_rename', s.profile, s.session_id);
588
+ return { session: s.compact() };
589
+ }
590
+ // The pin quota is counted across sessions, so the count-and-save transaction runs on one process-wide chain;
591
+ // per-session locks alone would let two pins of different sessions both see the last free slot.
592
+ pinChain = Promise.resolve();
593
+ pin(sid, pinRequested) {
594
+ const run = this.pinChain.then(() => this.pinUnserialized(sid, pinRequested));
595
+ this.pinChain = run.catch(() => undefined);
596
+ return run;
597
+ }
598
+ async pinUnserialized(sid, pinRequested) {
599
+ this.rejectSubagent(sid, 'modified');
600
+ let s = this.get404(sid);
601
+ s = this.store.ensureFull(sid, s);
602
+ if (pinRequested && !s.pinned) {
603
+ const rows = allSessions(this.store);
604
+ const byId = new Map(rows.filter((r) => r.session_id).map((r) => [str(r.session_id), r]));
605
+ byId.set(s.session_id, s.compact());
606
+ const targetLineage = lineageRootId(s.compact(), byId);
607
+ const pinnedLineages = new Set(rows.filter((r) => r.pinned && !r.pre_compression_snapshot).map((r) => lineageRootId(r, byId)));
608
+ pinnedLineages.delete(targetLineage);
609
+ const limit = this.deps.pinnedSessionsLimit();
610
+ if (pinnedLineages.size >= limit)
611
+ throw new HttpFailure(400, `Up to ${limit} sessions can be pinned. Unpin one before pinning another.`);
612
+ }
613
+ await this.store.withLock(sid, () => {
614
+ s.pinned = pinRequested;
615
+ this.store.save(s);
616
+ });
617
+ this.publish('session_pin', s.profile, s.session_id);
618
+ return { ok: true, session: s.compact() };
619
+ }
620
+ async archive(sid, archived) {
621
+ this.rejectSubagent(sid, 'archived');
622
+ let s = this.get404(sid);
623
+ s = this.store.ensureFull(sid, s);
624
+ await this.store.withLock(sid, () => {
625
+ s.archived = archived;
626
+ if (archived)
627
+ s.pinned = false;
628
+ this.store.save(s, { touchUpdatedAt: false });
629
+ });
630
+ this.publish('session_archive', s.profile, s.session_id);
631
+ return { ok: true, session: s.compact(), ...worktreeRetainedPayload(s) };
632
+ }
633
+ async move(sid, targetProjectId) {
634
+ const s = this.mutationTarget(sid, 'moved');
635
+ if (targetProjectId) {
636
+ const sessionProfile = s.profile || this.deps.activeProfile();
637
+ const target = this.deps.projects.load().find((p) => p.project_id === targetProjectId);
638
+ if (!target || !this.deps.profilesMatch(target.profile ?? null, sessionProfile))
639
+ throw new HttpFailure(404, 'Project not found');
640
+ }
641
+ try {
642
+ await this.store.withLock(sid, () => {
643
+ s.project_id = targetProjectId;
644
+ this.store.save(s);
645
+ }, { timeoutMs: 5000 });
646
+ }
647
+ catch (error) {
648
+ if (error instanceof SessionBusy)
649
+ throw new HttpFailure(503, 'Session is busy (streaming). Please try again in a moment.');
650
+ throw error;
651
+ }
652
+ this.publish('session_move', s.profile, s.session_id);
653
+ return { ok: true, session: s.compact() };
654
+ }
655
+ async update(sid, body) {
656
+ const s = this.mutationTarget(sid, 'updated');
657
+ const oldWs = s.workspace;
658
+ const oldModel = s.model;
659
+ const oldProvider = s.model_provider;
660
+ let newWs;
661
+ try {
662
+ newWs = this.deps.workspaces.resolveTrusted(typeof body.workspace === 'string' ? body.workspace : s.workspace, s.profile);
663
+ }
664
+ catch (error) {
665
+ throw new HttpFailure(400, error.message);
666
+ }
667
+ await this.store.withLock(sid, async () => {
668
+ s.workspace = newWs;
669
+ if ('model' in body || 'model_provider' in body) {
670
+ const [model, provider] = this.deps.modelStateFromRequest('model' in body ? body.model : s.model, 'model_provider' in body ? body.model_provider : undefined, s.model_provider);
671
+ if (model !== null)
672
+ s.model = model;
673
+ s.model_provider = provider;
674
+ if (str(oldModel) !== str(s.model) || str(oldProvider) !== str(s.model_provider)) {
675
+ s.context_length = this.deps.resolveContextLength ? await this.deps.resolveContextLength(s.model, s.model_provider, s.profile) : this.deps.contextLengthFor(s.model, s.model_provider);
676
+ s.threshold_tokens = 0;
677
+ s.last_prompt_tokens = 0;
678
+ this.deps.runtime.evictAgent(sid);
679
+ }
680
+ }
681
+ this.store.save(s);
682
+ });
683
+ if (str(oldWs) !== str(newWs))
684
+ this.deps.runtime.closeTerminal(sid);
685
+ this.deps.workspaces.setLastWorkspace(newWs, s.profile);
686
+ return { session: this.publicSession(s) };
687
+ }
688
+ async setToolsets(sid, toolsets) {
689
+ this.rejectSubagent(sid, 'modified');
690
+ const cleaned = this.validateToolsetsShape(toolsets);
691
+ const s = this.get404(sid);
692
+ await this.store.withLock(sid, () => {
693
+ s.enabled_toolsets = cleaned;
694
+ this.store.save(s);
695
+ });
696
+ return { ok: true, enabled_toolsets: s.enabled_toolsets };
697
+ }
698
+ /** Python `/api/personality/set` persistence: the name only; the prompt is resolved by the caller. */
699
+ async setPersonality(sid, name) {
700
+ this.rejectSubagent(sid, 'modified');
701
+ const s = this.mutationTarget(sid, 'modified');
702
+ await this.store.withLock(sid, () => {
703
+ s.personality = name;
704
+ this.store.save(s);
705
+ });
706
+ return typeof s.personality === 'string' ? s.personality : null;
707
+ }
708
+ // ── transcript mutations ─────────────────────────────────────────────────
709
+ async truncate(sid, keepRaw) {
710
+ this.rejectSubagent(sid, 'modified');
711
+ if (keepRaw === null || keepRaw === undefined)
712
+ throw new HttpFailure(400, 'Missing required field(s): keep_count');
713
+ const s = this.get404(sid);
714
+ // Python `int(body["keep_count"])`: a float truncates, a non-integer string is rejected.
715
+ let keep;
716
+ if (typeof keepRaw === 'number')
717
+ keep = Number.isFinite(keepRaw) ? Math.trunc(keepRaw) : Number.NaN;
718
+ else if (typeof keepRaw === 'boolean')
719
+ keep = keepRaw ? 1 : 0;
720
+ else
721
+ keep = /^[+-]?\d+$/.test(str(keepRaw).trim()) ? Number.parseInt(str(keepRaw).trim(), 10) : Number.NaN;
722
+ if (!Number.isInteger(keep))
723
+ throw new HttpFailure(400, 'keep_count must be an integer');
724
+ if (keep < 0)
725
+ throw new HttpFailure(400, 'keep_count must be non-negative');
726
+ await this.store.withLock(sid, () => {
727
+ truncateSessionAtKeep(s, keep);
728
+ this.store.save(s);
729
+ });
730
+ this.deps.runtime.evictAgent(sid);
731
+ return { ok: true, session: this.publicSession(s) };
732
+ }
733
+ async clear(sid) {
734
+ this.rejectSubagent(sid, 'modified');
735
+ const s = this.get404(sid);
736
+ await this.store.withLock(sid, () => {
737
+ const hadMessages = s.messages.length > 0;
738
+ truncateSessionAtKeep(s, 0);
739
+ s.tool_calls = [];
740
+ if (s.parent_session_id) {
741
+ let parentIsSnapshot = false;
742
+ try {
743
+ parentIsSnapshot = this.store.get(s.parent_session_id, { metadataOnly: true }).pre_compression_snapshot;
744
+ }
745
+ catch {
746
+ parentIsSnapshot = false;
747
+ }
748
+ if (parentIsSnapshot) {
749
+ s.parent_session_id = null;
750
+ s.compression_anchor_visible_idx = null;
751
+ s.compression_anchor_message_key = null;
752
+ }
753
+ }
754
+ s.active_stream_id = null;
755
+ s.pending_user_message = null;
756
+ s.pending_attachments = [];
757
+ s.pending_started_at = null;
758
+ s.pending_user_source = null;
759
+ s.clear_generation = hadMessages ? randomUUID().replace(/-/g, '') : null;
760
+ applySessionTitleRename(s, 'Untitled');
761
+ this.store.save(s);
762
+ if (hadMessages) {
763
+ try {
764
+ rmSync(`${this.store.pathFor(sid)}.bak`, { force: true });
765
+ }
766
+ catch { /* ignore */ }
767
+ }
768
+ });
769
+ this.deps.runtime.evictAgent(sid);
770
+ return { ok: true, session: s.compact() };
771
+ }
772
+ async retry(sid) {
773
+ this.rejectSubagent(sid, 'modified');
774
+ return this.store.withLock(sid, () => {
775
+ const s = this.get404(sid);
776
+ const history = s.messages;
777
+ const lastUser = findLastUserIndex(history);
778
+ if (lastUser === null)
779
+ return { error: 'No previous message to retry.' };
780
+ const lastUserText = extractText(history[lastUser]?.content);
781
+ const removed = history.length - lastUser;
782
+ shrinkTo(s, lastUser);
783
+ this.store.save(s);
784
+ return { ok: true, last_user_text: lastUserText, removed_count: removed };
785
+ });
786
+ }
787
+ async undo(sid) {
788
+ this.rejectSubagent(sid, 'modified');
789
+ return this.store.withLock(sid, () => {
790
+ const s = this.get404(sid);
791
+ const history = s.messages;
792
+ const lastUser = findLastUserIndex(history);
793
+ if (lastUser === null)
794
+ return { error: 'Nothing to undo.' };
795
+ const removedText = extractText(history[lastUser]?.content);
796
+ const removed = history.length - lastUser;
797
+ shrinkTo(s, lastUser);
798
+ this.store.save(s);
799
+ const preview = removedText.length > 40 ? `${removedText.slice(0, 40)}...` : removedText;
800
+ return { ok: true, removed_count: removed, removed_preview: preview };
801
+ });
802
+ }
803
+ duplicate(sid) {
804
+ this.rejectSubagent(sid, 'duplicated');
805
+ const session = this.store.load(sid);
806
+ if (!session)
807
+ throw new HttpFailure(404, 'Session not found');
808
+ const now = this.deps.now();
809
+ const copied = new Session({
810
+ title: `${session.title || 'Untitled'} (copy)`, workspace: session.workspace, model: session.model, model_provider: session.model_provider,
811
+ messages: copyJson(session.messages), tool_calls: copyJson(session.tool_calls), pinned: false, archived: false, project_id: session.project_id, profile: session.profile,
812
+ input_tokens: session.input_tokens, output_tokens: session.output_tokens, estimated_cost: session.estimated_cost, cache_read_tokens: session.cache_read_tokens, cache_write_tokens: session.cache_write_tokens,
813
+ personality: session.personality, enabled_toolsets: session.enabled_toolsets, context_length: session.context_length, threshold_tokens: session.threshold_tokens,
814
+ truncation_watermark: session.truncation_watermark, truncation_boundary: session.truncation_boundary, context_messages: copyJson(session.context_messages),
815
+ gateway_routing: copyJson(session.gateway_routing), gateway_routing_history: copyJson(session.gateway_routing_history), llm_title_generated: session.llm_title_generated,
816
+ manual_title: session.manual_title, composer_draft: copyJson(session.composer_draft), context_engine: session.context_engine, context_engine_state: copyJson(session.context_engine_state),
817
+ created_at: now, updated_at: now,
818
+ }, { workspace: session.workspace, model: session.model });
819
+ this.store.touch(copied);
820
+ this.store.save(copied);
821
+ this.publish('session_duplicate', copied.profile, copied.session_id);
822
+ return { session: this.publicSession(copied) };
823
+ }
824
+ branch(sid, body) {
825
+ if (this.isSubagentViewOnly(sid))
826
+ throw new HttpFailure(400, 'Subagent sessions are view-only and cannot be branched from WebUI');
827
+ const source = this.get404(sid);
828
+ if (source.read_only) {
829
+ if (str(source.source_tag || source.raw_source).trim().toLowerCase() !== 'cron')
830
+ throw new HttpFailure(403, 'Read-only sessions cannot be branched from WebUI');
831
+ source.branchSourceReadonly = true;
832
+ }
833
+ let keepCount = null;
834
+ if (body.keep_count !== null && body.keep_count !== undefined) {
835
+ keepCount = Number(body.keep_count);
836
+ if (!Number.isInteger(keepCount))
837
+ throw new HttpFailure(400, 'keep_count must be an integer');
838
+ if (keepCount < 0)
839
+ throw new HttpFailure(400, 'keep_count must be non-negative');
840
+ }
841
+ const customTitle = body.title ? str(body.title).trim().slice(0, 80) || null : null;
842
+ if (!source.branchSourceReadonly) {
843
+ try {
844
+ this.store.save(source);
845
+ }
846
+ catch { /* ignore */ }
847
+ }
848
+ // Python: `keep_count` indexes the merged display transcript, never the raw sidecar array.
849
+ const sourceMessages = this.mergedTranscript(source);
850
+ const forked = keepCount !== null ? sourceMessages.slice(0, keepCount) : [...sourceMessages];
851
+ const title = customTitle ?? `${source.title || 'Untitled'} (fork)`;
852
+ const forkKeep = keepCount ?? sourceMessages.length;
853
+ // The branch's model context must carry the retained state.db rows too: the new id has no state.db rows of its
854
+ // own, and the runner prefers a non-empty context over the displayed messages.
855
+ const stateRows = this.stateDbRows(source);
856
+ const sourceContext = stateRows.length ? this.mergedTranscript(source, source.context_messages.length ? source.context_messages : source.messages) : source.context_messages;
857
+ const forkedContext = copyJson(truncateContextForDisplayKeep(sourceContext, sourceMessages, forkKeep));
858
+ const branch = new Session({
859
+ workspace: source.workspace, model: source.model, model_provider: source.model_provider, profile: source.profile, title, messages: forked, project_id: source.project_id,
860
+ personality: source.personality, enabled_toolsets: source.enabled_toolsets, context_length: source.context_length, threshold_tokens: source.threshold_tokens,
861
+ context_messages: forkedContext, gateway_routing: copyJson(source.gateway_routing), context_engine: source.context_engine, context_engine_state: copyJson(source.context_engine_state),
862
+ parent_session_id: source.session_id, session_source: 'fork',
863
+ }, { workspace: source.workspace, model: source.model });
864
+ this.store.touch(branch);
865
+ if (forked.length) {
866
+ this.store.save(branch);
867
+ this.publish('session_branch', branch.profile, branch.session_id);
868
+ }
869
+ return { session_id: branch.session_id, title, parent_session_id: source.session_id };
870
+ }
871
+ async delete(sid) {
872
+ if (!sid)
873
+ throw new HttpFailure(400, 'session_id is required');
874
+ if (!isSafeSessionId(sid))
875
+ throw new HttpFailure(400, 'Invalid session_id');
876
+ // Python: a read-only import (persisted sidecar flag, sidebar metadata, or a foreign state.db owner such as a
877
+ // Claude Code session) is never deleted — that would erase the owner's authoritative transcript.
878
+ if (this.isReadOnlyImport(sid))
879
+ throw new HttpFailure(400, 'Read-only imported sessions cannot be deleted from WebUI');
880
+ if (this.isSubagentViewOnly(sid))
881
+ throw new HttpFailure(400, 'Subagent sessions are view-only and cannot be deleted from WebUI');
882
+ const retained = (() => { try {
883
+ return worktreeRetainedPayload(this.store.get(sid, { metadataOnly: true }));
884
+ }
885
+ catch {
886
+ return {};
887
+ } })();
888
+ let eventProfile = null;
889
+ try {
890
+ eventProfile = this.store.get(sid, { metadataOnly: true }).profile;
891
+ }
892
+ catch {
893
+ eventProfile = null;
894
+ }
895
+ // Python `_is_messaging_session_id`: decided before the JSON is gone, from WebUI metadata or the Agent's row.
896
+ const isMessaging = (() => { try {
897
+ if (isMessagingSessionRecord(this.store.get(sid, { metadataOnly: true }).compact()))
898
+ return true;
899
+ }
900
+ catch { /* absent */ } const meta = this.lookupCliMeta(sid); return meta !== null && isMessagingSessionRecord(meta); })();
901
+ const blocking = () => {
902
+ const live = this.deps.runtime.activeRunStream(sid);
903
+ if (live)
904
+ return live;
905
+ try {
906
+ const snapshot = this.store.get(sid, { metadataOnly: true });
907
+ const candidate = str(snapshot.active_stream_id).trim();
908
+ if (candidate && this.deps.runtime.activeStreamIds.has(candidate))
909
+ return candidate;
910
+ }
911
+ catch { /* absent */ }
912
+ return null;
913
+ };
914
+ if (blocking())
915
+ throw new HttpFailure(409, 'Session has an active run; stop it before deleting');
916
+ try {
917
+ await this.store.withLock(sid, () => {
918
+ if (blocking())
919
+ throw new HttpFailure(409, 'Session has an active run; stop it before deleting');
920
+ if (!this.store.deleteFiles(sid))
921
+ throw new HttpFailure(500, 'Failed to delete session data');
922
+ }, { timeoutMs: 5000 });
923
+ }
924
+ catch (error) {
925
+ if (error instanceof SessionBusy)
926
+ throw new HttpFailure(503, 'Session busy, try again');
927
+ throw error;
928
+ }
929
+ this.deps.runtime.evictAgent(sid);
930
+ try {
931
+ rmSync(this.deps.attachmentDir(sid), { recursive: true, force: true });
932
+ }
933
+ catch { /* ignore */ }
934
+ // Python `delete_run_journal` (#3802): a deleted session leaves no replayable run journal behind.
935
+ try {
936
+ this.deps.journal?.deleteSession(sid);
937
+ }
938
+ catch { /* ignore */ }
939
+ this.deps.runtime.closeTerminal(sid);
940
+ // Python: the Agent/CLI transcript in state.db goes too (else a claimable CLI row resurfaces in the sidebar), but a
941
+ // messaging channel's memory is never erased from the WebUI; the actual outcome is reported.
942
+ let stateDbCleanupFailed = false;
943
+ if (!isMessaging) {
944
+ try {
945
+ stateDbCleanupFailed = !(await this.deps.runtime.deleteCliSession(eventProfile, sid));
946
+ }
947
+ catch {
948
+ stateDbCleanupFailed = true;
949
+ }
950
+ }
951
+ this.publish('session_delete', eventProfile);
952
+ return { ok: true, state_db_cleanup_failed: stateDbCleanupFailed, ...retained };
953
+ }
954
+ cleanup(zeroOnly) {
955
+ let cleaned = 0;
956
+ const removed = new Set();
957
+ for (const s of this.store.scanAll()) {
958
+ const shouldDelete = zeroOnly ? s.messages.length === 0 : s.title === 'Untitled' && s.messages.length === 0;
959
+ if (!shouldDelete)
960
+ continue;
961
+ this.store.sessions.delete(s.session_id);
962
+ rmSync(this.store.pathFor(s.session_id), { force: true });
963
+ cleaned += 1;
964
+ removed.add(s.session_id);
965
+ }
966
+ this.store.invalidatePersistedIds();
967
+ let rewroteIndex = false;
968
+ try {
969
+ const rows = this.store.readIndexEntries();
970
+ const live = this.store.persistedIds();
971
+ const survivors = rows.filter((entry) => {
972
+ const id = str(entry.session_id);
973
+ if (!id || live.has(id) || this.store.sessions.has(id))
974
+ return true;
975
+ if (removed.has(id))
976
+ return false;
977
+ cleaned += 1;
978
+ return false;
979
+ });
980
+ if (survivors.length < rows.length) {
981
+ this.store.writeIndex();
982
+ rewroteIndex = true;
983
+ }
984
+ }
985
+ catch { /* corrupt index is rebuilt below */ }
986
+ if (removed.size && !rewroteIndex) {
987
+ try {
988
+ this.store.writeIndex();
989
+ }
990
+ catch { /* ignore */ }
991
+ }
992
+ return { ok: true, cleaned };
993
+ }
994
+ import(body) {
995
+ const messages = stripPublicInternalFields(body.messages, { messageRecords: true });
996
+ if (!Array.isArray(messages))
997
+ throw new HttpFailure(400, 'JSON must contain a "messages" array');
998
+ const rawToolCalls = body.tool_calls ?? [];
999
+ if (!Array.isArray(rawToolCalls))
1000
+ throw new HttpFailure(400, 'JSON "tool_calls" must be an array');
1001
+ let workspace;
1002
+ try {
1003
+ workspace = this.deps.workspaces.resolveTrusted(typeof body.workspace === 'string' ? body.workspace : null);
1004
+ }
1005
+ catch (error) {
1006
+ throw new HttpFailure(400, error.message);
1007
+ }
1008
+ const defaults = this.store.deps.defaults(this.deps.activeProfile());
1009
+ const s = new Session({ title: typeof body.title === 'string' ? body.title : 'Imported session', workspace, model: typeof body.model === 'string' ? body.model : defaults.model, messages: messages, tool_calls: stripPublicInternalFields(rawToolCalls), profile: this.deps.activeProfile() }, defaults);
1010
+ s.pinned = Boolean(body.pinned);
1011
+ this.store.touch(s);
1012
+ this.store.save(s);
1013
+ this.publish('session_import');
1014
+ return { ok: true, session: this.publicSession(s) };
1015
+ }
1016
+ // ── drafts ───────────────────────────────────────────────────────────────
1017
+ readDraft(sid) {
1018
+ if (!sid)
1019
+ throw new HttpFailure(400, 'session_id is required');
1020
+ let hasSidecar;
1021
+ try {
1022
+ hasSidecar = this.deps.drafts.exists(sid);
1023
+ }
1024
+ catch {
1025
+ throw new HttpFailure(400, 'Invalid session_id');
1026
+ }
1027
+ if (hasSidecar) {
1028
+ const cached = this.store.sessions.get(sid);
1029
+ if (!cached && !existsSessionFile(this.store, sid))
1030
+ throw new HttpFailure(404, 'Session not found');
1031
+ const [draft, version] = this.deps.drafts.readState(sid);
1032
+ if (cached)
1033
+ cached.composer_draft = draft;
1034
+ return { draft, draft_version: version };
1035
+ }
1036
+ const s = this.get404(sid, { metadataOnly: true });
1037
+ const [draft, version] = this.deps.drafts.readState(sid, s.composer_draft);
1038
+ return { draft, draft_version: version };
1039
+ }
1040
+ async writeDraft(body) {
1041
+ const sid = str(body.session_id);
1042
+ if (!sid)
1043
+ throw new HttpFailure(400, 'Missing required field(s): session_id');
1044
+ if (this.isSubagentViewOnly(sid))
1045
+ throw new HttpFailure(400, 'Subagent sessions are view-only and cannot store a draft from WebUI');
1046
+ let text = body.text;
1047
+ let files = body.files;
1048
+ if (text !== null && text !== undefined && typeof text !== 'string')
1049
+ text = '';
1050
+ if (typeof text === 'string' && text.length > 50_000)
1051
+ text = text.slice(0, 50_000);
1052
+ if (files !== null && files !== undefined && !Array.isArray(files))
1053
+ files = [];
1054
+ if (Array.isArray(files) && files.length > 50)
1055
+ files = files.slice(0, 50);
1056
+ try {
1057
+ this.deps.drafts.path(sid);
1058
+ }
1059
+ catch {
1060
+ throw new HttpFailure(400, 'Invalid session_id');
1061
+ }
1062
+ let draftVersion;
1063
+ try {
1064
+ draftVersion = normalizeDraftVersion(body.draft_version);
1065
+ }
1066
+ catch {
1067
+ throw new HttpFailure(400, 'Invalid draft_version');
1068
+ }
1069
+ if (draftVersion !== null) {
1070
+ const maxVersion = BigInt(Math.trunc((this.deps.now() + 300) * 1_000_000)) + 999n;
1071
+ if (BigInt(draftVersion) > maxVersion)
1072
+ throw new HttpFailure(400, 'draft_version is too far in the future');
1073
+ }
1074
+ return this.store.withLock(sid, () => {
1075
+ let s = this.store.sessions.get(sid) ?? null;
1076
+ if (s && s.session_id !== sid)
1077
+ s = null;
1078
+ const sessionExists = existsSessionFile(this.store, sid);
1079
+ if (!s) {
1080
+ if (!sessionExists)
1081
+ throw new HttpFailure(404, 'Session not found');
1082
+ if (!this.deps.drafts.exists(sid))
1083
+ s = this.get404(sid, { metadataOnly: true });
1084
+ }
1085
+ const [currentDraft, currentVersion] = this.deps.drafts.readState(sid, s?.composer_draft);
1086
+ const next = { ...currentDraft };
1087
+ if (text !== null && text !== undefined)
1088
+ next.text = text;
1089
+ if (files !== null && files !== undefined)
1090
+ next.files = files;
1091
+ let versionCmp = null;
1092
+ if (currentVersion !== null) {
1093
+ versionCmp = draftVersion === null ? -1 : Number(BigInt(draftVersion) - BigInt(currentVersion) > 0n) - Number(BigInt(draftVersion) - BigInt(currentVersion) < 0n);
1094
+ if (versionCmp < 0 || (versionCmp === 0 && JSON.stringify(next) !== JSON.stringify(currentDraft))) {
1095
+ throw new HttpFailure(409, 'Composer draft changed in another request', { draft: currentDraft, draft_version: currentVersion });
1096
+ }
1097
+ }
1098
+ let unchanged = false;
1099
+ let saved = currentDraft;
1100
+ if (JSON.stringify(next) === JSON.stringify(currentDraft) && (draftVersion === null || versionCmp === 0))
1101
+ unchanged = true;
1102
+ else {
1103
+ const cachedOwnerIsCurrent = s !== null && this.store.sessions.get(sid) === s;
1104
+ if (!sessionExists && !cachedOwnerIsCurrent)
1105
+ throw new HttpFailure(404, 'Session not found');
1106
+ if (!sessionExists && s) {
1107
+ s.composer_draft = next;
1108
+ this.store.save(s, { touchUpdatedAt: false });
1109
+ }
1110
+ try {
1111
+ saved = this.deps.drafts.write(sid, next, draftVersion);
1112
+ }
1113
+ catch (error) {
1114
+ if (error instanceof DraftVersionConflict)
1115
+ throw new HttpFailure(409, error.message, { draft: error.currentDraft, draft_version: error.currentVersion });
1116
+ throw error;
1117
+ }
1118
+ if (s)
1119
+ s.composer_draft = saved;
1120
+ }
1121
+ const payload = { ok: true, draft: saved, draft_version: draftVersion ?? currentVersion };
1122
+ if (unchanged)
1123
+ payload.unchanged = true;
1124
+ return payload;
1125
+ });
1126
+ }
1127
+ // ── anchor scenes ────────────────────────────────────────────────────────
1128
+ async saveAnchorScene(body) {
1129
+ const sid = str(body.session_id).trim();
1130
+ if (!sid)
1131
+ throw new HttpFailure(400, 'session_id is required');
1132
+ if (body.scene === undefined)
1133
+ throw new HttpFailure(400, 'Missing required field(s): scene');
1134
+ let s;
1135
+ try {
1136
+ s = this.getForMutation(sid);
1137
+ }
1138
+ catch (error) {
1139
+ if (error instanceof SessionNotFound)
1140
+ throw new HttpFailure(404, 'Session not found');
1141
+ if (error instanceof HttpFailure && error.status === 403)
1142
+ throw new HttpFailure(403, 'Read-only imported sessions cannot persist anchor scenes');
1143
+ throw error;
1144
+ }
1145
+ if (!this.visibleToActiveProfile(s.profile))
1146
+ throw new HttpFailure(404, 'Session not found');
1147
+ return this.store.withLock(sid, () => {
1148
+ let placement;
1149
+ try {
1150
+ placement = storeAnchorScene(s, body, this.deps.now());
1151
+ }
1152
+ catch (error) {
1153
+ throw new HttpFailure(400, error.message);
1154
+ }
1155
+ if (!placement)
1156
+ throw new HttpFailure(404, 'Assistant message not found');
1157
+ this.store.save(s, { touchUpdatedAt: false, skipIndex: true });
1158
+ return { ok: true, ...placement };
1159
+ });
1160
+ }
1161
+ readAnchorScene(query) {
1162
+ const sid = str(query.session_id).trim();
1163
+ const messageRef = normalizeAnchorSceneMessageRef(query.message_ref);
1164
+ const messageIndex = anchorSceneIntOrNull(query.message_index);
1165
+ if (!sid || (!messageRef && messageIndex === null))
1166
+ throw new HttpFailure(400, 'session_id and message_ref or message_index are required');
1167
+ let session;
1168
+ try {
1169
+ session = this.store.get(sid);
1170
+ if (session.loadedMetadataOnly)
1171
+ session = this.store.load(sid) ?? session;
1172
+ }
1173
+ catch {
1174
+ throw new HttpFailure(404, 'Session not found');
1175
+ }
1176
+ if (!this.visibleToActiveProfile(session.profile))
1177
+ throw new HttpFailure(404, 'Session not found');
1178
+ const result = readAnchorSceneRows(session, { messageRef, messageIndex, before: anchorSceneIntOrNull(query.before), limit: anchorSceneIntOrNull(query.limit) });
1179
+ if (!result)
1180
+ throw new HttpFailure(404, 'Anchor activity scene not found');
1181
+ return result;
1182
+ }
1183
+ // ── shares ───────────────────────────────────────────────────────────────
1184
+ createShare(sid) {
1185
+ let s = this.get404(sid);
1186
+ if (!this.visibleToActiveProfile(s.profile))
1187
+ throw new HttpFailure(404, 'Session not found');
1188
+ s = this.store.ensureFull(sid, s);
1189
+ let snapshot;
1190
+ try {
1191
+ snapshot = buildShareSnapshot(s, s.messages, { hermesHome: this.deps.hermesHome, attachmentRoot: this.deps.attachmentDir('').replace(/\/[^/]*$/, ''), home: this.deps.home });
1192
+ }
1193
+ catch (error) {
1194
+ throw new HttpFailure(400, error.message);
1195
+ }
1196
+ const meta = this.deps.shares.createOrRefresh(s, snapshot);
1197
+ s.share_token = meta.share_token;
1198
+ s.share_created_at = meta.share_created_at;
1199
+ this.store.save(s, { touchUpdatedAt: false });
1200
+ this.publish('session_share_create', s.profile, sid);
1201
+ return {
1202
+ ok: true,
1203
+ share: { token: meta.share_token, url: `/share/${meta.share_token}`, title: meta.share_title, message_count: meta.share_message_count, created_at: meta.share_created_at, updated_at: meta.share_updated_at },
1204
+ session: this.publicSession(s),
1205
+ };
1206
+ }
1207
+ revokeShare(sid) {
1208
+ let s = this.get404(sid);
1209
+ if (!this.visibleToActiveProfile(s.profile))
1210
+ throw new HttpFailure(404, 'Session not found');
1211
+ s = this.store.ensureFull(sid, s);
1212
+ this.deps.shares.revoke(s);
1213
+ s.share_token = null;
1214
+ s.share_created_at = null;
1215
+ this.store.save(s, { touchUpdatedAt: false });
1216
+ this.publish('session_share_revoke', s.profile, sid);
1217
+ return { ok: true, session: this.publicSession(s) };
1218
+ }
1219
+ loadShare(token) {
1220
+ const share = this.deps.shares.load(token);
1221
+ if (!share)
1222
+ throw new HttpFailure(404, 'Shared conversation not found');
1223
+ return { share };
1224
+ }
1225
+ // ── yolo ─────────────────────────────────────────────────────────────────
1226
+ yolo(sid) {
1227
+ if (!sid)
1228
+ throw new HttpFailure(400, 'Missing session_id');
1229
+ return { yolo_enabled: this.deps.yolo.isEnabled(sid) };
1230
+ }
1231
+ setYolo(sid, enabled) {
1232
+ if (!sid)
1233
+ throw new HttpFailure(400, 'Missing required field(s): session_id');
1234
+ this.deps.yolo.set(sid, enabled);
1235
+ return { ok: true, yolo_enabled: this.deps.yolo.isEnabled(sid) };
1236
+ }
1237
+ }
1238
+ function existsSessionFile(store, sid) {
1239
+ return store.persistedIds().has(sid);
1240
+ }
1241
+ import { createHash } from 'node:crypto';
1242
+ function hashRevision(signature) {
1243
+ return createHash('sha256').update(signature, 'utf8').digest('hex').slice(0, 32);
1244
+ }
1245
+ export const AUTO_TITLE_LABELS = new Set(['untitled', 'new chat']);
1246
+ /** Python `apply_session_title_rename`. */
1247
+ export function applySessionTitleRename(session, rawTitle) {
1248
+ let title = str(rawTitle).trim().slice(0, 80);
1249
+ if (!title)
1250
+ title = 'Untitled';
1251
+ session.title = title;
1252
+ session.manual_title = !AUTO_TITLE_LABELS.has(title.trim().toLowerCase());
1253
+ session.llm_title_generated = false;
1254
+ return title;
1255
+ }
1256
+ export function markSessionTitleGenerated(session) {
1257
+ session.llm_title_generated = true;
1258
+ session.manual_title = false;
1259
+ }
1260
+ function findLastUserIndex(history) {
1261
+ for (let i = history.length - 1; i >= 0; i -= 1)
1262
+ if (isDict(history[i]) && history[i].role === 'user')
1263
+ return i;
1264
+ return null;
1265
+ }
1266
+ function truncationWatermarkFor(messages) {
1267
+ if (!messages.length)
1268
+ return 0.0;
1269
+ const last = messages[messages.length - 1];
1270
+ const ts = isDict(last) ? Number(last.timestamp ?? 0) : 0;
1271
+ return Number.isFinite(ts) ? ts : 0.0;
1272
+ }
1273
+ function stampIntentionalShrink(session, oldCount, newCount) {
1274
+ if (newCount >= oldCount)
1275
+ return false;
1276
+ session.intentional_shrink_generation = randomUUID().replace(/-/g, '');
1277
+ return true;
1278
+ }
1279
+ /** Align model context with the display prefix (Python `truncate_context_for_display_keep`, simplified to the row-count contract). */
1280
+ export function truncateContextForDisplayKeep(context, full, keep) {
1281
+ if (keep <= 0)
1282
+ return [];
1283
+ const rows = context ?? [];
1284
+ if (!rows.length)
1285
+ return [];
1286
+ if (keep >= full.length)
1287
+ return [...rows];
1288
+ // ponytail: context rows map 1:1 onto display rows for WebUI-authored transcripts; fuzzy alignment stays in Python until compression lands.
1289
+ return rows.slice(0, Math.min(rows.length, keep));
1290
+ }
1291
+ export function truncateSessionAtKeep(session, keep) {
1292
+ const full = [...session.messages];
1293
+ const oldMsgCount = full.length;
1294
+ const oldCtxCount = session.context_messages.length;
1295
+ session.messages = full.slice(0, keep);
1296
+ stampIntentionalShrink(session, oldMsgCount, session.messages.length);
1297
+ session.context_messages = truncateContextForDisplayKeep(session.context_messages, full, keep);
1298
+ session.truncation_watermark = truncationWatermarkFor(session.messages);
1299
+ session.truncation_boundary = session.truncation_watermark;
1300
+ return [oldMsgCount, oldCtxCount];
1301
+ }
1302
+ function shrinkTo(session, lastUserIdx) {
1303
+ const history = session.messages;
1304
+ session.messages = history.slice(0, lastUserIdx);
1305
+ stampIntentionalShrink(session, history.length, session.messages.length);
1306
+ session.truncation_watermark = truncationWatermarkFor(session.messages);
1307
+ session.truncation_boundary = session.truncation_watermark;
1308
+ if (session.context_messages.length) {
1309
+ const ctxLast = findLastUserIndex(session.context_messages);
1310
+ if (ctxLast !== null)
1311
+ session.context_messages = session.context_messages.slice(0, ctxLast);
1312
+ }
1313
+ }
1314
+ /** Python `_extract_text`: flatten content to the user-typed text. */
1315
+ export function extractText(content) {
1316
+ if (typeof content === 'string')
1317
+ return content;
1318
+ if (Array.isArray(content)) {
1319
+ const parts = [];
1320
+ for (const p of content) {
1321
+ if (!isDict(p))
1322
+ continue;
1323
+ const type = str(p.type).toLowerCase();
1324
+ if (!['', 'text', 'input_text', 'output_text'].includes(type))
1325
+ continue;
1326
+ parts.push(str(p.text || p.content || p.input_text || p.output_text));
1327
+ }
1328
+ return parts.join(' ');
1329
+ }
1330
+ return str(content);
1331
+ }
1332
+ export function worktreeRetainedPayload(session) {
1333
+ const path = session?.worktree_path;
1334
+ if (!path)
1335
+ return {};
1336
+ const payload = { worktree_retained: true, worktree_path: path };
1337
+ if (session?.worktree_branch)
1338
+ payload.worktree_branch = session.worktree_branch;
1339
+ if (session?.worktree_repo_root)
1340
+ payload.worktree_repo_root = session.worktree_repo_root;
1341
+ return payload;
1342
+ }
1343
+ export { titleFrom };
1344
+ //# sourceMappingURL=service.js.map