@maudecode/talaria-web 1.17.2 → 1.19.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 (623) hide show
  1. package/_release.json +8 -8
  2. package/dist/api/auth-raw.d.ts +1 -1
  3. package/dist/api/auth-raw.js +20 -20
  4. package/dist/api/auth-raw.js.map +1 -1
  5. package/dist/api/automation-raw.d.ts +7 -1
  6. package/dist/api/automation-raw.js +74 -27
  7. package/dist/api/automation-raw.js.map +1 -1
  8. package/dist/api/automation-router.d.ts +128 -23
  9. package/dist/api/automation-router.js +29 -13
  10. package/dist/api/automation-router.js.map +1 -1
  11. package/dist/api/chat-router.d.ts +1845 -40
  12. package/dist/api/chat-router.js +196 -114
  13. package/dist/api/chat-router.js.map +1 -1
  14. package/dist/api/git-router.d.ts +37 -3
  15. package/dist/api/git-router.js +47 -48
  16. package/dist/api/git-router.js.map +1 -1
  17. package/dist/api/raw-routes.d.ts +9 -1
  18. package/dist/api/raw-routes.js +286 -73
  19. package/dist/api/raw-routes.js.map +1 -1
  20. package/dist/api/router.d.ts +16 -6
  21. package/dist/api/router.js +28 -26
  22. package/dist/api/router.js.map +1 -1
  23. package/dist/api/session-visibility.d.ts +4 -4
  24. package/dist/api/session-visibility.js +26 -16
  25. package/dist/api/session-visibility.js.map +1 -1
  26. package/dist/api/sessions-router.d.ts +3312 -131
  27. package/dist/api/sessions-router.js +287 -157
  28. package/dist/api/sessions-router.js.map +1 -1
  29. package/dist/api/settings-router.d.ts +457 -8
  30. package/dist/api/settings-router.js +54 -33
  31. package/dist/api/settings-router.js.map +1 -1
  32. package/dist/api/sse-routes.d.ts +7 -2
  33. package/dist/api/sse-routes.js +109 -62
  34. package/dist/api/sse-routes.js.map +1 -1
  35. package/dist/api/tools-raw.d.ts +5 -0
  36. package/dist/api/tools-raw.js +63 -55
  37. package/dist/api/tools-raw.js.map +1 -1
  38. package/dist/api/tools-router.d.ts +998 -85
  39. package/dist/api/tools-router.js +447 -61
  40. package/dist/api/tools-router.js.map +1 -1
  41. package/dist/api/transcribe-stream.d.ts +16 -0
  42. package/dist/api/transcribe-stream.js +172 -0
  43. package/dist/api/transcribe-stream.js.map +1 -0
  44. package/dist/app.d.ts +4 -1
  45. package/dist/app.js +98 -59
  46. package/dist/app.js.map +1 -1
  47. package/dist/auth/gate.js +15 -11
  48. package/dist/auth/gate.js.map +1 -1
  49. package/dist/auth/oidc.d.ts +5 -2
  50. package/dist/auth/oidc.js +8 -7
  51. package/dist/auth/oidc.js.map +1 -1
  52. package/dist/auth/passkeys.d.ts +15 -14
  53. package/dist/auth/passkeys.js +89 -91
  54. package/dist/auth/passkeys.js.map +1 -1
  55. package/dist/auth/store.d.ts +17 -7
  56. package/dist/auth/store.js +93 -52
  57. package/dist/auth/store.js.map +1 -1
  58. package/dist/bin/talaria-web.js +12 -81
  59. package/dist/bin/talaria-web.js.map +1 -1
  60. package/dist/cli/ctl.js +2 -1
  61. package/dist/cli/ctl.js.map +1 -1
  62. package/dist/cli/dotenv.d.ts +5 -0
  63. package/dist/cli/dotenv.js +15 -2
  64. package/dist/cli/dotenv.js.map +1 -1
  65. package/dist/cli/launcher.js +5 -5
  66. package/dist/cli/launcher.js.map +1 -1
  67. package/dist/cli/main.d.ts +1 -0
  68. package/dist/cli/main.js +85 -0
  69. package/dist/cli/main.js.map +1 -0
  70. package/dist/cli/supervise.d.ts +2 -0
  71. package/dist/cli/supervise.js +67 -4
  72. package/dist/cli/supervise.js.map +1 -1
  73. package/dist/config/agent-config.d.ts +34 -11
  74. package/dist/config/agent-config.js +116 -60
  75. package/dist/config/agent-config.js.map +1 -1
  76. package/dist/config.d.ts +4 -0
  77. package/dist/config.js +19 -6
  78. package/dist/config.js.map +1 -1
  79. package/dist/fs/atomic.d.ts +1 -0
  80. package/dist/fs/atomic.js +4 -1
  81. package/dist/fs/atomic.js.map +1 -1
  82. package/dist/fs/stat.d.ts +1 -0
  83. package/dist/fs/stat.js +11 -0
  84. package/dist/fs/stat.js.map +1 -0
  85. package/dist/http/context.d.ts +31 -12
  86. package/dist/http/context.js +60 -24
  87. package/dist/http/context.js.map +1 -1
  88. package/dist/http/csp.d.ts +2 -1
  89. package/dist/http/csp.js +3 -2
  90. package/dist/http/csp.js.map +1 -1
  91. package/dist/onboarding.d.ts +2 -2
  92. package/dist/onboarding.js +10 -8
  93. package/dist/onboarding.js.map +1 -1
  94. package/dist/profiles/profiles.d.ts +20 -4
  95. package/dist/profiles/profiles.js +115 -30
  96. package/dist/profiles/profiles.js.map +1 -1
  97. package/dist/projects.d.ts +15 -6
  98. package/dist/projects.js +55 -47
  99. package/dist/projects.js.map +1 -1
  100. package/dist/providers/catalog.d.ts +84 -14
  101. package/dist/providers/catalog.js +474 -151
  102. package/dist/providers/catalog.js.map +1 -1
  103. package/dist/providers/env-file.d.ts +10 -3
  104. package/dist/providers/env-file.js +24 -75
  105. package/dist/providers/env-file.js.map +1 -1
  106. package/dist/providers/runtime-env.d.ts +4 -2
  107. package/dist/providers/runtime-env.js +9 -6
  108. package/dist/providers/runtime-env.js.map +1 -1
  109. package/dist/providers/tables.d.ts +3 -1
  110. package/dist/providers/tables.js +4 -2
  111. package/dist/providers/tables.js.map +1 -1
  112. package/dist/raster-image.d.ts +7 -0
  113. package/dist/raster-image.js +267 -0
  114. package/dist/raster-image.js.map +1 -0
  115. package/dist/redact.js +342 -46
  116. package/dist/redact.js.map +1 -1
  117. package/dist/release.d.ts +7 -0
  118. package/dist/release.js +14 -0
  119. package/dist/release.js.map +1 -1
  120. package/dist/runtime.d.ts +5 -1
  121. package/dist/runtime.js +305 -96
  122. package/dist/runtime.js.map +1 -1
  123. package/dist/server.js +15 -0
  124. package/dist/server.js.map +1 -1
  125. package/dist/sessions/anchor.d.ts +9 -3
  126. package/dist/sessions/anchor.js +28 -36
  127. package/dist/sessions/anchor.js.map +1 -1
  128. package/dist/sessions/background-events.d.ts +2 -0
  129. package/dist/sessions/background-events.js +10 -0
  130. package/dist/sessions/background-events.js.map +1 -0
  131. package/dist/sessions/background-tasks.d.ts +26 -27
  132. package/dist/sessions/background-tasks.js +89 -97
  133. package/dist/sessions/background-tasks.js.map +1 -1
  134. package/dist/sessions/background-updates.d.ts +15 -8
  135. package/dist/sessions/background-updates.js +101 -25
  136. package/dist/sessions/background-updates.js.map +1 -1
  137. package/dist/sessions/cli-sessions.d.ts +27 -6
  138. package/dist/sessions/cli-sessions.js +152 -42
  139. package/dist/sessions/cli-sessions.js.map +1 -1
  140. package/dist/sessions/completions.d.ts +77 -9
  141. package/dist/sessions/completions.js +482 -45
  142. package/dist/sessions/completions.js.map +1 -1
  143. package/dist/sessions/compress.d.ts +8 -0
  144. package/dist/sessions/compress.js +2 -2
  145. package/dist/sessions/compress.js.map +1 -1
  146. package/dist/sessions/drafts.d.ts +14 -10
  147. package/dist/sessions/drafts.js +38 -43
  148. package/dist/sessions/drafts.js.map +1 -1
  149. package/dist/sessions/export.d.ts +5 -0
  150. package/dist/sessions/export.js +30 -0
  151. package/dist/sessions/export.js.map +1 -1
  152. package/dist/sessions/gateway-sessions.d.ts +46 -0
  153. package/dist/sessions/gateway-sessions.js +378 -0
  154. package/dist/sessions/gateway-sessions.js.map +1 -0
  155. package/dist/sessions/gateway-watcher.d.ts +7 -3
  156. package/dist/sessions/gateway-watcher.js +31 -19
  157. package/dist/sessions/gateway-watcher.js.map +1 -1
  158. package/dist/sessions/goals.d.ts +31 -0
  159. package/dist/sessions/goals.js +75 -0
  160. package/dist/sessions/goals.js.map +1 -0
  161. package/dist/sessions/handoff.d.ts +32 -0
  162. package/dist/sessions/handoff.js +114 -0
  163. package/dist/sessions/handoff.js.map +1 -0
  164. package/dist/sessions/journal.d.ts +5 -79
  165. package/dist/sessions/journal.js +15 -606
  166. package/dist/sessions/journal.js.map +1 -1
  167. package/dist/sessions/list.d.ts +31 -16
  168. package/dist/sessions/list.js +139 -129
  169. package/dist/sessions/list.js.map +1 -1
  170. package/dist/sessions/merge.d.ts +69 -13
  171. package/dist/sessions/merge.js +265 -64
  172. package/dist/sessions/merge.js.map +1 -1
  173. package/dist/sessions/notices.d.ts +22 -0
  174. package/dist/sessions/notices.js +72 -0
  175. package/dist/sessions/notices.js.map +1 -0
  176. package/dist/sessions/pending.d.ts +10 -4
  177. package/dist/sessions/pending.js +83 -7
  178. package/dist/sessions/pending.js.map +1 -1
  179. package/dist/sessions/prefix-index.d.ts +82 -0
  180. package/dist/sessions/prefix-index.js +232 -0
  181. package/dist/sessions/prefix-index.js.map +1 -0
  182. package/dist/sessions/recovery.d.ts +19 -0
  183. package/dist/sessions/recovery.js +322 -0
  184. package/dist/sessions/recovery.js.map +1 -0
  185. package/dist/sessions/relay.d.ts +38 -19
  186. package/dist/sessions/relay.js +302 -79
  187. package/dist/sessions/relay.js.map +1 -1
  188. package/dist/sessions/service.d.ts +260 -55
  189. package/dist/sessions/service.js +1448 -462
  190. package/dist/sessions/service.js.map +1 -1
  191. package/dist/sessions/session.d.ts +24 -2
  192. package/dist/sessions/session.js +69 -7
  193. package/dist/sessions/session.js.map +1 -1
  194. package/dist/sessions/shares.d.ts +7 -6
  195. package/dist/sessions/shares.js +22 -45
  196. package/dist/sessions/shares.js.map +1 -1
  197. package/dist/sessions/source-kind.js +1 -0
  198. package/dist/sessions/source-kind.js.map +1 -1
  199. package/dist/sessions/state-db-identity.d.ts +18 -0
  200. package/dist/sessions/state-db-identity.js +67 -0
  201. package/dist/sessions/state-db-identity.js.map +1 -0
  202. package/dist/sessions/state-db-worker.d.ts +1 -0
  203. package/dist/sessions/state-db-worker.js +35 -0
  204. package/dist/sessions/state-db-worker.js.map +1 -0
  205. package/dist/sessions/state-db.d.ts +113 -7
  206. package/dist/sessions/state-db.js +861 -44
  207. package/dist/sessions/state-db.js.map +1 -1
  208. package/dist/sessions/storage/backend.d.ts +162 -0
  209. package/dist/sessions/storage/backend.js +19 -0
  210. package/dist/sessions/storage/backend.js.map +1 -0
  211. package/dist/sessions/storage/conformance.d.ts +20 -0
  212. package/dist/sessions/storage/conformance.js +237 -0
  213. package/dist/sessions/storage/conformance.js.map +1 -0
  214. package/dist/sessions/storage/document.d.ts +16 -0
  215. package/dist/sessions/storage/document.js +44 -0
  216. package/dist/sessions/storage/document.js.map +1 -0
  217. package/dist/sessions/storage/json-documents.d.ts +23 -0
  218. package/dist/sessions/storage/json-documents.js +233 -0
  219. package/dist/sessions/storage/json-documents.js.map +1 -0
  220. package/dist/sessions/storage/json-files.d.ts +12 -0
  221. package/dist/sessions/storage/json-files.js +124 -0
  222. package/dist/sessions/storage/json-files.js.map +1 -0
  223. package/dist/sessions/storage/json-installation.d.ts +3 -0
  224. package/dist/sessions/storage/json-installation.js +31 -0
  225. package/dist/sessions/storage/json-installation.js.map +1 -0
  226. package/dist/sessions/storage/json-journal.d.ts +114 -0
  227. package/dist/sessions/storage/json-journal.js +686 -0
  228. package/dist/sessions/storage/json-journal.js.map +1 -0
  229. package/dist/sessions/storage/json-recovery.d.ts +4 -0
  230. package/dist/sessions/storage/json-recovery.js +195 -0
  231. package/dist/sessions/storage/json-recovery.js.map +1 -0
  232. package/dist/sessions/storage/json.d.ts +68 -0
  233. package/dist/sessions/storage/json.js +258 -0
  234. package/dist/sessions/storage/json.js.map +1 -0
  235. package/dist/sessions/storage/row.d.ts +6 -0
  236. package/dist/sessions/storage/row.js +49 -0
  237. package/dist/sessions/storage/row.js.map +1 -0
  238. package/dist/sessions/storage/search-text.d.ts +4 -0
  239. package/dist/sessions/storage/search-text.js +16 -0
  240. package/dist/sessions/storage/search-text.js.map +1 -0
  241. package/dist/sessions/store.d.ts +65 -68
  242. package/dist/sessions/store.js +305 -602
  243. package/dist/sessions/store.js.map +1 -1
  244. package/dist/sessions/streams.d.ts +4 -0
  245. package/dist/sessions/streams.js +9 -1
  246. package/dist/sessions/streams.js.map +1 -1
  247. package/dist/sessions/titles.d.ts +2 -0
  248. package/dist/sessions/titles.js +5 -1
  249. package/dist/sessions/titles.js.map +1 -1
  250. package/dist/sessions/todo.d.ts +5 -0
  251. package/dist/sessions/todo.js +28 -21
  252. package/dist/sessions/todo.js.map +1 -1
  253. package/dist/sessions/tool-display.d.ts +5 -4
  254. package/dist/sessions/tool-display.js +30 -50
  255. package/dist/sessions/tool-display.js.map +1 -1
  256. package/dist/sessions/turn-context.d.ts +11 -2
  257. package/dist/sessions/turn-context.js +18 -11
  258. package/dist/sessions/turn-context.js.map +1 -1
  259. package/dist/sessions/turn.d.ts +122 -17
  260. package/dist/sessions/turn.js +939 -358
  261. package/dist/sessions/turn.js.map +1 -1
  262. package/dist/sessions/wakeup-pause.d.ts +54 -0
  263. package/dist/sessions/wakeup-pause.js +163 -0
  264. package/dist/sessions/wakeup-pause.js.map +1 -0
  265. package/dist/sessions/window.js +13 -12
  266. package/dist/sessions/window.js.map +1 -1
  267. package/dist/settings.d.ts +19 -7
  268. package/dist/settings.js +178 -184
  269. package/dist/settings.js.map +1 -1
  270. package/dist/sidecar/client.d.ts +17 -3
  271. package/dist/sidecar/client.js +78 -8
  272. package/dist/sidecar/client.js.map +1 -1
  273. package/dist/sidecar/discover.d.ts +2 -1
  274. package/dist/sidecar/discover.js +93 -10
  275. package/dist/sidecar/discover.js.map +1 -1
  276. package/dist/sidecar/env.d.ts +4 -0
  277. package/dist/sidecar/env.js +3 -0
  278. package/dist/sidecar/env.js.map +1 -0
  279. package/dist/sidecar/fake.d.ts +2 -2
  280. package/dist/sidecar/fake.js +19 -2
  281. package/dist/sidecar/fake.js.map +1 -1
  282. package/dist/startup.d.ts +13 -5
  283. package/dist/startup.js +48 -0
  284. package/dist/startup.js.map +1 -1
  285. package/dist/test/env-file.d.ts +5 -0
  286. package/dist/test/env-file.js +88 -0
  287. package/dist/test/env-file.js.map +1 -0
  288. package/dist/test/harness.d.ts +1 -0
  289. package/dist/test/harness.js +1 -1
  290. package/dist/test/harness.js.map +1 -1
  291. package/dist/test/passkeys.d.ts +22 -0
  292. package/dist/test/passkeys.js +62 -0
  293. package/dist/test/passkeys.js.map +1 -0
  294. package/dist/test/storage.d.ts +15 -0
  295. package/dist/test/storage.js +26 -0
  296. package/dist/test/storage.js.map +1 -0
  297. package/dist/test/ts-worker-hooks.d.ts +1 -0
  298. package/dist/test/ts-worker-hooks.js +24 -0
  299. package/dist/test/ts-worker-hooks.js.map +1 -0
  300. package/dist/text/diff.d.ts +9 -14
  301. package/dist/text/diff.js +74 -108
  302. package/dist/text/diff.js.map +1 -1
  303. package/dist/tools/commands.d.ts +6 -1
  304. package/dist/tools/commands.js +8 -2
  305. package/dist/tools/commands.js.map +1 -1
  306. package/dist/tools/connectors.d.ts +33 -0
  307. package/dist/tools/connectors.js +121 -0
  308. package/dist/tools/connectors.js.map +1 -0
  309. package/dist/tools/crons.d.ts +38 -1
  310. package/dist/tools/crons.js +122 -18
  311. package/dist/tools/crons.js.map +1 -1
  312. package/dist/tools/dashboard-plugins.d.ts +53 -0
  313. package/dist/tools/dashboard-plugins.js +188 -0
  314. package/dist/tools/dashboard-plugins.js.map +1 -0
  315. package/dist/tools/extensions.d.ts +18 -5
  316. package/dist/tools/extensions.js +344 -266
  317. package/dist/tools/extensions.js.map +1 -1
  318. package/dist/tools/gateway-restart.d.ts +62 -0
  319. package/dist/tools/gateway-restart.js +142 -0
  320. package/dist/tools/gateway-restart.js.map +1 -0
  321. package/dist/tools/health.d.ts +44 -0
  322. package/dist/tools/health.js +201 -46
  323. package/dist/tools/health.js.map +1 -1
  324. package/dist/tools/hygiene.d.ts +4 -3
  325. package/dist/tools/hygiene.js +23 -9
  326. package/dist/tools/hygiene.js.map +1 -1
  327. package/dist/tools/kanban.d.ts +4 -2
  328. package/dist/tools/kanban.js +28 -19
  329. package/dist/tools/kanban.js.map +1 -1
  330. package/dist/tools/mcp.d.ts +13 -0
  331. package/dist/tools/mcp.js +88 -0
  332. package/dist/tools/mcp.js.map +1 -1
  333. package/dist/tools/memory-masks.d.ts +5 -0
  334. package/dist/tools/memory-masks.js +256 -0
  335. package/dist/tools/memory-masks.js.map +1 -0
  336. package/dist/tools/memory.d.ts +29 -3
  337. package/dist/tools/memory.js +69 -27
  338. package/dist/tools/memory.js.map +1 -1
  339. package/dist/tools/plugin-settings.d.ts +15 -0
  340. package/dist/tools/plugin-settings.js +90 -0
  341. package/dist/tools/plugin-settings.js.map +1 -0
  342. package/dist/tools/project-os.d.ts +11 -0
  343. package/dist/tools/project-os.js +267 -0
  344. package/dist/tools/project-os.js.map +1 -0
  345. package/dist/tools/skills.d.ts +14 -5
  346. package/dist/tools/skills.js +49 -16
  347. package/dist/tools/skills.js.map +1 -1
  348. package/dist/tools/update-notifications.d.ts +34 -15
  349. package/dist/tools/update-notifications.js +141 -57
  350. package/dist/tools/update-notifications.js.map +1 -1
  351. package/dist/tools/update-rollback.d.ts +11 -0
  352. package/dist/tools/update-rollback.js +28 -0
  353. package/dist/tools/update-rollback.js.map +1 -0
  354. package/dist/tools/updates.d.ts +110 -32
  355. package/dist/tools/updates.js +1112 -294
  356. package/dist/tools/updates.js.map +1 -1
  357. package/dist/tools/wiki.d.ts +68 -0
  358. package/dist/tools/wiki.js +413 -0
  359. package/dist/tools/wiki.js.map +1 -0
  360. package/dist/util.d.ts +2 -0
  361. package/dist/util.js +5 -0
  362. package/dist/util.js.map +1 -1
  363. package/dist/workspace/escape.d.ts +61 -0
  364. package/dist/workspace/escape.js +149 -0
  365. package/dist/workspace/escape.js.map +1 -0
  366. package/dist/workspace/extract.d.ts +22 -0
  367. package/dist/workspace/extract.js +308 -0
  368. package/dist/workspace/extract.js.map +1 -0
  369. package/dist/workspace/fs.d.ts +12 -0
  370. package/dist/workspace/fs.js +92 -23
  371. package/dist/workspace/fs.js.map +1 -1
  372. package/dist/workspace/git.d.ts +34 -1
  373. package/dist/workspace/git.js +328 -35
  374. package/dist/workspace/git.js.map +1 -1
  375. package/dist/workspace/media.d.ts +16 -13
  376. package/dist/workspace/media.js +43 -61
  377. package/dist/workspace/media.js.map +1 -1
  378. package/dist/workspace/rollback.d.ts +36 -22
  379. package/dist/workspace/rollback.js +178 -272
  380. package/dist/workspace/rollback.js.map +1 -1
  381. package/dist/workspace/unzip.js +4 -1
  382. package/dist/workspace/unzip.js.map +1 -1
  383. package/dist/workspace/upload.d.ts +7 -4
  384. package/dist/workspace/upload.js +5 -2
  385. package/dist/workspace/upload.js.map +1 -1
  386. package/dist/workspace/workspaces.d.ts +15 -19
  387. package/dist/workspace/workspaces.js +55 -127
  388. package/dist/workspace/workspaces.js.map +1 -1
  389. package/dist/workspace/worktrees.d.ts +2 -1
  390. package/dist/workspace/worktrees.js +179 -42
  391. package/dist/workspace/worktrees.js.map +1 -1
  392. package/package.json +7 -3
  393. package/sidecar/agent_dependency.json +4 -4
  394. package/sidecar/agent_support.json +26 -0
  395. package/sidecar/scripts/record-fixtures.py +12 -3
  396. package/sidecar/scripts/replay_sidecar.py +32 -0
  397. package/sidecar/scripts/suite_runner.py +302 -0
  398. package/sidecar/scripts/test.sh +12 -4
  399. package/sidecar/talaria_sidecar/__init__.py +6 -1
  400. package/sidecar/talaria_sidecar/__main__.py +4 -2
  401. package/sidecar/talaria_sidecar/agent_mutation.py +975 -0
  402. package/sidecar/talaria_sidecar/agent_services.py +1053 -0
  403. package/sidecar/talaria_sidecar/dependency_sync.py +85 -0
  404. package/sidecar/talaria_sidecar/home.py +56 -3
  405. package/sidecar/talaria_sidecar/methods/__init__.py +2 -2
  406. package/sidecar/talaria_sidecar/methods/aux.py +166 -24
  407. package/sidecar/talaria_sidecar/methods/chat.py +852 -135
  408. package/sidecar/talaria_sidecar/methods/checkpoints.py +89 -0
  409. package/sidecar/talaria_sidecar/methods/commands.py +294 -4
  410. package/sidecar/talaria_sidecar/methods/config.py +123 -4
  411. package/sidecar/talaria_sidecar/methods/connectors.py +343 -0
  412. package/sidecar/talaria_sidecar/methods/cron.py +395 -36
  413. package/sidecar/talaria_sidecar/methods/cron_execution.py +284 -0
  414. package/sidecar/talaria_sidecar/methods/gateway.py +212 -55
  415. package/sidecar/talaria_sidecar/methods/gateway_sessions.py +234 -0
  416. package/sidecar/talaria_sidecar/methods/goals.py +81 -41
  417. package/sidecar/talaria_sidecar/methods/kanban.py +108 -34
  418. package/sidecar/talaria_sidecar/methods/mcp.py +1 -1
  419. package/sidecar/talaria_sidecar/methods/memory.py +84 -0
  420. package/sidecar/talaria_sidecar/methods/oauth.py +5 -2
  421. package/sidecar/talaria_sidecar/methods/process.py +218 -15
  422. package/sidecar/talaria_sidecar/methods/profiles.py +121 -13
  423. package/sidecar/talaria_sidecar/methods/providers.py +217 -28
  424. package/sidecar/talaria_sidecar/methods/runtime.py +69 -1
  425. package/sidecar/talaria_sidecar/methods/skills.py +67 -4
  426. package/sidecar/talaria_sidecar/methods/state_db.py +316 -75
  427. package/sidecar/talaria_sidecar/methods/stt.py +159 -78
  428. package/sidecar/talaria_sidecar/methods/text.py +14 -1
  429. package/sidecar/talaria_sidecar/methods/toolsets.py +49 -0
  430. package/sidecar/talaria_sidecar/methods/usage.py +113 -14
  431. package/sidecar/talaria_sidecar/methods/worktree.py +26 -19
  432. package/sidecar/talaria_sidecar/methods/write_approval.py +181 -0
  433. package/sidecar/talaria_sidecar/rpc.py +45 -4
  434. package/sidecar/talaria_sidecar/runtime.py +98 -13
  435. package/sidecar/talaria_sidecar/speed.py +35 -0
  436. package/static/dist/FILES.txt +126 -126
  437. package/static/dist/assets/AppShell-cey33v9s.js +8 -0
  438. package/static/dist/assets/ChatPage-i8wnugr7.js +18 -0
  439. package/static/dist/assets/ConnectTargets-hg19553x.js +1 -0
  440. package/static/dist/assets/ExtensionRoute-cly4apm5.js +1 -0
  441. package/static/dist/assets/Field-j8uqoigz.js +9 -0
  442. package/static/dist/assets/HubRoute-e4bgz41j.js +2 -0
  443. package/static/dist/assets/Markdown-lahuichm.js +598 -0
  444. package/static/dist/assets/RightPanel-lbo4i0fn.js +1 -0
  445. package/static/dist/assets/Select-gqatm2e0.js +1 -0
  446. package/static/dist/assets/SessionListPanel-mfqayfjh.js +1 -0
  447. package/static/dist/assets/SettingsLayout-b8980u7k.js +1 -0
  448. package/static/dist/assets/States-e7dkgtxf.js +1 -0
  449. package/static/dist/assets/Toaster-bfqqy786.js +1 -0
  450. package/static/dist/assets/_app-n1n6pfx1.js +1 -0
  451. package/static/dist/assets/{_app.ext._extensionId-opyh9y0v.js → _app.ext._extensionId-buxjxav3.js} +1 -1
  452. package/static/dist/assets/_app.index-jt8zwiu2.js +1 -0
  453. package/static/dist/assets/_app.insights-cv76ml71.js +1 -0
  454. package/static/dist/assets/_app.kanban-h6ts53j7.js +1 -0
  455. package/static/dist/assets/_app.logs-dm873z90.js +1 -0
  456. package/static/dist/assets/_app.memory-glk5y6m8.js +1 -0
  457. package/static/dist/assets/_app.profiles-ka6zpstq.js +1 -0
  458. package/static/dist/assets/{_app.session._sessionId-bfd4h3id.js → _app.session._sessionId-g2vzghvc.js} +1 -1
  459. package/static/dist/assets/_app.settings-hgjdhzcd.js +1 -0
  460. package/static/dist/assets/_app.settings._section-jf2kmhae.js +3 -0
  461. package/static/dist/assets/_app.skills-cii852yq.js +1 -0
  462. package/static/dist/assets/_app.tasks-fp9q7atm.js +1 -0
  463. package/static/dist/assets/_app.todos-dw94qzue.js +1 -0
  464. package/static/dist/assets/_app.workspaces-inyygzze.js +1 -0
  465. package/static/dist/assets/{abnfDiagram-VCTEODGH-b2x1lqot.js → abnfDiagram-VCTEODGH-gjayq3ra.js} +1 -1
  466. package/static/dist/assets/architecture-7GRP2DOG-lp56972r.js +1 -0
  467. package/static/dist/assets/{architectureDiagram-5GKGNRK7-h38o5l7b.js → architectureDiagram-5GKGNRK7-nwb3xovn.js} +1 -1
  468. package/static/dist/assets/archive-b1j004vn.js +1 -0
  469. package/static/dist/assets/back-g74gkozu.js +1 -0
  470. package/static/dist/assets/{blockDiagram-I7D4REHJ-bqquxv2u.js → blockDiagram-I7D4REHJ-joedghi3.js} +1 -1
  471. package/static/dist/assets/{c4Diagram-7LVT6UL2-f3fb8w6z.js → c4Diagram-7LVT6UL2-hyrjrohe.js} +1 -1
  472. package/static/dist/assets/channel-es95o4y8.js +1 -0
  473. package/static/dist/assets/{chunk-4HAMMTFA-bzfyyzp3.js → chunk-4HAMMTFA-koouqbut.js} +1 -1
  474. package/static/dist/assets/{chunk-75Z2AOVW-ly99rfx5.js → chunk-75Z2AOVW-bl4bhdnt.js} +1 -1
  475. package/static/dist/assets/{chunk-DU6HZSFF-bg6ecfqf.js → chunk-DU6HZSFF-gpedttsp.js} +3 -3
  476. package/static/dist/assets/{chunk-F27PBJKO-e8k7mmqw.js → chunk-F27PBJKO-d8xxi0zi.js} +1 -1
  477. package/static/dist/assets/{chunk-GMAD6QVW-cmalnoaj.js → chunk-GMAD6QVW-jro0hl73.js} +1 -1
  478. package/static/dist/assets/{chunk-GVQU2GXP-gmif5o01.js → chunk-GVQU2GXP-djn6gbyu.js} +1 -1
  479. package/static/dist/assets/{chunk-IMKFNOWR-f1nwwh6u.js → chunk-IMKFNOWR-vw4p5p7o.js} +1 -1
  480. package/static/dist/assets/{chunk-L3NEJ4N5-oktfh5v7.js → chunk-L3NEJ4N5-n1hj77q8.js} +1 -1
  481. package/static/dist/assets/{chunk-OSK3NFVY-b1sdx96z.js → chunk-OSK3NFVY-oy0gwn2n.js} +1 -1
  482. package/static/dist/assets/{chunk-P2QGCYS3-fhu4nzxt.js → chunk-P2QGCYS3-onf1hz6c.js} +1 -1
  483. package/static/dist/assets/{chunk-POPQ4Y6H-em31rnef.js → chunk-POPQ4Y6H-m8sqn7cs.js} +1 -1
  484. package/static/dist/assets/{chunk-PWAF6VOD-bxhhyftw.js → chunk-PWAF6VOD-ek4smc8x.js} +1 -1
  485. package/static/dist/assets/{chunk-SHT3W25Y-fmrvwcav.js → chunk-SHT3W25Y-g9gfvefo.js} +3 -3
  486. package/static/dist/assets/{chunk-SVP7TREG-lymukl2j.js → chunk-SVP7TREG-f9nfv2cu.js} +1 -1
  487. package/static/dist/assets/{chunk-TICWLB2K-lmza6k23.js → chunk-TICWLB2K-bnk3m1mq.js} +1 -1
  488. package/static/dist/assets/classDiagram-ZZMXUADV-kmihoqxh.js +1 -0
  489. package/static/dist/assets/classDiagram-v2-VYDZK3BY-kmihoqxh.js +1 -0
  490. package/static/dist/assets/copied-bli9tbcx.js +1 -0
  491. package/static/dist/assets/{copy-fw5b1pc6.js → copy-jamtd1pf.js} +1 -1
  492. package/static/dist/assets/{cynefin-OW5HDTMX-czlhbyhs.js → cynefin-OW5HDTMX-f8xfdd3f.js} +1 -1
  493. package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-gq7mvswb.js → cynefinDiagram-5FMLGOSQ-n9lb99h9.js} +1 -1
  494. package/static/dist/assets/{dagre-GXQ25YYZ-cqdbf7dr.js → dagre-GXQ25YYZ-dgailddi.js} +4 -4
  495. package/static/dist/assets/{diagram-S7CK7UJ4-o6arxa58.js → diagram-S7CK7UJ4-m6aeoe7c.js} +1 -1
  496. package/static/dist/assets/{diagram-UQ7AKVKN-nhnd68tz.js → diagram-UQ7AKVKN-jall3j0x.js} +1 -1
  497. package/static/dist/assets/{diagram-VSXAHHWV-dk2sclzn.js → diagram-VSXAHHWV-hbawi7hn.js} +1 -1
  498. package/static/dist/assets/{diagram-VX7I27RA-n3k5nyx3.js → diagram-VX7I27RA-hendl2tt.js} +1 -1
  499. package/static/dist/assets/{diagram-Z3DM3KII-m6q9cwdh.js → diagram-Z3DM3KII-igwc35p3.js} +1 -1
  500. package/static/dist/assets/{ebnfDiagram-PWID7BFC-lsa5641p.js → ebnfDiagram-PWID7BFC-c64knz08.js} +1 -1
  501. package/static/dist/assets/{erDiagram-RLTQ6QDP-fo2ckbe6.js → erDiagram-RLTQ6QDP-brdu9lcm.js} +1 -1
  502. package/static/dist/assets/eventmodeling-NTZA5JFV-njk1j8wl.js +1 -0
  503. package/static/dist/assets/flowDiagram-HODETNUW-nma6f0ga.js +1 -0
  504. package/static/dist/assets/folder-plus-lvt9kudb.js +1 -0
  505. package/static/dist/assets/{ganttDiagram-EL5Y4UJY-nzqz6x9g.js → ganttDiagram-EL5Y4UJY-ma6jxj5i.js} +1 -1
  506. package/static/dist/assets/{gitGraph-4MIJSDKK-gukvcxe6.js → gitGraph-4MIJSDKK-naa9w6xa.js} +1 -1
  507. package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-lqhdp8f0.js → gitGraphDiagram-WWUBYQGX-hzltvsod.js} +1 -1
  508. package/static/dist/assets/{highlighted-body-KPVGNVTW-igw6cp39.js → highlighted-body-KPVGNVTW-ghoavj8d.js} +1 -1
  509. package/static/dist/assets/host-hzm8n85n.js +1 -0
  510. package/static/dist/assets/index-drdcaqeq.css +2 -0
  511. package/static/dist/assets/index-jzm844he.js +11 -0
  512. package/static/dist/assets/{info-A6RAGUB7-gvu7a93l.js → info-A6RAGUB7-mn2ut5ko.js} +1 -1
  513. package/static/dist/assets/{infoDiagram-27XIBGKW-m8t8g6w1.js → infoDiagram-27XIBGKW-h6kuqvsb.js} +1 -1
  514. package/static/dist/assets/{ishikawaDiagram-5VMMS53U-l07vkbgj.js → ishikawaDiagram-5VMMS53U-e7bnwq7h.js} +1 -1
  515. package/static/dist/assets/{journeyDiagram-3NMN7TZE-hybkgj8l.js → journeyDiagram-3NMN7TZE-etd1bi6p.js} +1 -1
  516. package/static/dist/assets/{kanban-definition-UXKFOSKX-by13uvtn.js → kanban-definition-UXKFOSKX-emb1g9dz.js} +4 -4
  517. package/static/dist/assets/lazyRouteComponent-o816ytzl.js +1 -0
  518. package/static/dist/assets/{line-osxq6fq7.js → line-h0ojzsvs.js} +1 -1
  519. package/static/dist/assets/link-k01ryaf9.js +1 -0
  520. package/static/dist/assets/login-bsae49ew.js +1 -0
  521. package/static/dist/assets/mermaid-HWGCJPDP-ihl34s74.js +1 -0
  522. package/static/dist/assets/{mermaid-parser.core-i91oxmou.js → mermaid-parser.core-bnre27u8.js} +3 -3
  523. package/static/dist/assets/{mindmap-definition-YA3MSWOX-m82mx8ww.js → mindmap-definition-YA3MSWOX-o1vathns.js} +1 -1
  524. package/static/dist/assets/onboarding-c65tysya.js +1 -0
  525. package/static/dist/assets/onboarding_model_label-gpn28uix.js +1 -0
  526. package/static/dist/assets/{packet-AYTQ26CC-nbtgge2o.js → packet-AYTQ26CC-hatq7m2e.js} +1 -1
  527. package/static/dist/assets/pcmTap.worklet-74EKjWAZ.js +1 -0
  528. package/static/dist/assets/{pegDiagram-XKGWAZYB-f1zxzga1.js → pegDiagram-XKGWAZYB-gwisz8jv.js} +1 -1
  529. package/static/dist/assets/{pie-WAS4IAKB-of8vuhxs.js → pie-WAS4IAKB-fpftf0mk.js} +1 -1
  530. package/static/dist/assets/{pieDiagram-E7YTZNPT-o7y8ftio.js → pieDiagram-E7YTZNPT-khm1o9a6.js} +1 -1
  531. package/static/dist/assets/{quadrantDiagram-AXDQQJYC-iqiwia1t.js → quadrantDiagram-AXDQQJYC-owqc4uqn.js} +1 -1
  532. package/static/dist/assets/{radar-RG4KPBEZ-delnsy2v.js → radar-RG4KPBEZ-cntfwjpq.js} +1 -1
  533. package/static/dist/assets/{railroad-74A4TZTK-nspnyq9u.js → railroad-74A4TZTK-a7t5eibp.js} +1 -1
  534. package/static/dist/assets/railroad-abnf-HS5TGJTU-ol8cdktf.js +1 -0
  535. package/static/dist/assets/railroad-ebnf-LZEXJU2U-i8vzd429.js +1 -0
  536. package/static/dist/assets/railroad-peg-WCYAUIDC-nw3ulewz.js +1 -0
  537. package/static/dist/assets/{railroadDiagram-O6MQD6OU-z41tqx5z.js → railroadDiagram-O6MQD6OU-etuh0qa0.js} +1 -1
  538. package/static/dist/assets/{refresh-cw-nt1dtsx4.js → refresh-cw-mqbkv2a3.js} +1 -1
  539. package/static/dist/assets/refresh-l29ljp76.js +1 -0
  540. package/static/dist/assets/{requirementDiagram-BXWQKSXE-bdvif194.js → requirementDiagram-BXWQKSXE-oq2ulk22.js} +1 -1
  541. package/static/dist/assets/{sankeyDiagram-P5KCCOFB-h73e0rol.js → sankeyDiagram-P5KCCOFB-iqc02emv.js} +1 -1
  542. package/static/dist/assets/saved-ndd4t2xb.js +1 -0
  543. package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-iv95mb1z.js → sequenceDiagram-WJ2MYXX4-i0v116q0.js} +2 -2
  544. package/static/dist/assets/settings_section_extensions_title-jhfo6o8z.js +1 -0
  545. package/static/dist/assets/share._token-c1ri0hy1.js +2 -0
  546. package/static/dist/assets/sliders-horizontal-j3jjt9tv.js +1 -0
  547. package/static/dist/assets/{stateDiagram-D77RDMKH-k417ixmf.js → stateDiagram-D77RDMKH-dnpt1ato.js} +1 -1
  548. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-bxjacpk6.js +1 -0
  549. package/static/dist/assets/{swimlanes-42K2YHIH-esola70w.js → swimlanes-42K2YHIH-loqbdazb.js} +1 -1
  550. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-id62p9hz.js +8 -0
  551. package/static/dist/assets/{timeline-definition-24CTP7MA-getrz2y8.js → timeline-definition-24CTP7MA-ol2hnvma.js} +1 -1
  552. package/static/dist/assets/toast-i3h34v6o.js +64 -0
  553. package/static/dist/assets/{treeView-Q6P3EWNA-hc7ap1q7.js → treeView-Q6P3EWNA-idrj6iox.js} +1 -1
  554. package/static/dist/assets/{treemap-WGGIJYW6-b7k1syy5.js → treemap-WGGIJYW6-lzr49vv5.js} +1 -1
  555. package/static/dist/assets/untitled-oaoya4qj.js +1 -0
  556. package/static/dist/assets/useForm-nfaxgmsk.js +1 -0
  557. package/static/dist/assets/{useParams-lhg566ew.js → useParams-gjc70qru.js} +1 -1
  558. package/static/dist/assets/{useSearch-lbrh6ejn.js → useSearch-e6ae539u.js} +1 -1
  559. package/static/dist/assets/{vennDiagram-4TSXK5OY-n6pcy5qb.js → vennDiagram-4TSXK5OY-bvwr9o2z.js} +1 -1
  560. package/static/dist/assets/{wardley-WFR3VGLG-lpa18vz1.js → wardley-WFR3VGLG-31ui8tma.js} +1 -1
  561. package/static/dist/assets/{wardleyDiagram-VM6X3IG4-kpclwwg7.js → wardleyDiagram-VM6X3IG4-k5wqtx4b.js} +1 -1
  562. package/static/dist/assets/{xychartDiagram-S5SC5T6Z-paa2n8y0.js → xychartDiagram-S5SC5T6Z-aqbgvujg.js} +1 -1
  563. package/static/dist/index.html +1 -1
  564. package/static/dist/sw.js +1 -1
  565. package/static/dist/assets/AppShell-fb2td9zi.js +0 -1
  566. package/static/dist/assets/ChatPage-cj96kiy9.js +0 -25
  567. package/static/dist/assets/Dialog-kxcg7ard.js +0 -1
  568. package/static/dist/assets/ExtensionRoute-jf7h0754.js +0 -1
  569. package/static/dist/assets/HubRoute-gmanpd5y.js +0 -2
  570. package/static/dist/assets/Markdown-mdwlvj3w.js +0 -598
  571. package/static/dist/assets/RightPanel-ftvrjlcp.js +0 -1
  572. package/static/dist/assets/Select-bilaypej.js +0 -1
  573. package/static/dist/assets/SessionListPanel-og8n36qs.js +0 -1
  574. package/static/dist/assets/SettingsLayout-jonjefmj.js +0 -1
  575. package/static/dist/assets/States-nmejrwrm.js +0 -1
  576. package/static/dist/assets/Toaster-nnl8zkt9.js +0 -1
  577. package/static/dist/assets/_app-gdidzd94.js +0 -1
  578. package/static/dist/assets/_app.index-hbarzbjx.js +0 -1
  579. package/static/dist/assets/_app.insights-luywlarz.js +0 -1
  580. package/static/dist/assets/_app.kanban-kincnbr8.js +0 -1
  581. package/static/dist/assets/_app.logs-oi2gr3gs.js +0 -1
  582. package/static/dist/assets/_app.memory-b6jfivt6.js +0 -1
  583. package/static/dist/assets/_app.profiles-lpvixmqp.js +0 -1
  584. package/static/dist/assets/_app.settings-vowx3iq0.js +0 -1
  585. package/static/dist/assets/_app.settings._section-cnntg1tu.js +0 -3
  586. package/static/dist/assets/_app.skills-fb57lpau.js +0 -1
  587. package/static/dist/assets/_app.tasks-eszpx1q7.js +0 -2
  588. package/static/dist/assets/_app.todos-nr05ac6w.js +0 -1
  589. package/static/dist/assets/_app.workspaces-d2luomu6.js +0 -1
  590. package/static/dist/assets/architecture-7GRP2DOG-hd0o7bde.js +0 -1
  591. package/static/dist/assets/back-bemaer09.js +0 -1
  592. package/static/dist/assets/cancel-drd0g6d9.js +0 -1
  593. package/static/dist/assets/channel-cpdgf867.js +0 -1
  594. package/static/dist/assets/classDiagram-ZZMXUADV-ko09sguk.js +0 -1
  595. package/static/dist/assets/classDiagram-v2-VYDZK3BY-ko09sguk.js +0 -1
  596. package/static/dist/assets/copied-ima3pysb.js +0 -1
  597. package/static/dist/assets/endpoints-d33siokx.js +0 -64
  598. package/static/dist/assets/eventmodeling-NTZA5JFV-emctlo64.js +0 -1
  599. package/static/dist/assets/flowDiagram-HODETNUW-bfi3moqa.js +0 -1
  600. package/static/dist/assets/index-cxq58xb1.js +0 -11
  601. package/static/dist/assets/index-hgtx08n5.css +0 -2
  602. package/static/dist/assets/lazyRouteComponent-af0lvgjx.js +0 -1
  603. package/static/dist/assets/link-jyxicdhg.js +0 -1
  604. package/static/dist/assets/login-ec21t39x.js +0 -1
  605. package/static/dist/assets/mermaid-HWGCJPDP-gfl8z3ep.js +0 -1
  606. package/static/dist/assets/onboarding-btnltvyz.js +0 -1
  607. package/static/dist/assets/onboarding_model_label-dp7xffoh.js +0 -1
  608. package/static/dist/assets/railroad-abnf-HS5TGJTU-nst1qxyn.js +0 -1
  609. package/static/dist/assets/railroad-ebnf-LZEXJU2U-ci37x8qy.js +0 -1
  610. package/static/dist/assets/railroad-peg-WCYAUIDC-aimkk07z.js +0 -1
  611. package/static/dist/assets/refresh-b4uams1i.js +0 -1
  612. package/static/dist/assets/saved-kg52csy7.js +0 -1
  613. package/static/dist/assets/settings_section_extensions_title-ej0iapxe.js +0 -1
  614. package/static/dist/assets/share._token-f97e94r0.js +0 -2
  615. package/static/dist/assets/sliders-horizontal-fj18it47.js +0 -1
  616. package/static/dist/assets/sse-fwpqtzbg.js +0 -1
  617. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-hwn4apct.js +0 -1
  618. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-d1h97oyg.js +0 -8
  619. package/static/dist/assets/todoStore-eginf9h4.js +0 -1
  620. package/static/dist/assets/tts-lxdxnmjd.js +0 -1
  621. package/static/dist/assets/untitled-ovpfthg4.js +0 -1
  622. package/static/dist/assets/useForm-bcblv1rx.js +0 -1
  623. package/static/dist/assets/useLocale-fi5jb8ma.js +0 -1
package/dist/runtime.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { AsyncLocalStorage } from 'node:async_hooks';
2
2
  import { pinnedFetch, systemDnsLookup } from './http/pinned.js';
3
- import { mkdirSync, readFileSync } from 'node:fs';
3
+ import { mkdirSync, readdirSync, readFileSync } from 'node:fs';
4
4
  import { resolve } from 'node:path';
5
5
  import { AuthStore } from './auth/store.js';
6
6
  import { OidcService } from './auth/oidc.js';
@@ -9,6 +9,8 @@ import { PresenceLeases, RelayService } from './sessions/relay.js';
9
9
  import { CliSessionSource } from './sessions/cli-sessions.js';
10
10
  import { ClaudeCodeSessionSource, claudeCodeProjectsDir } from './sessions/claude-code.js';
11
11
  import { GatewayWatcherRegistry } from './sessions/gateway-watcher.js';
12
+ import { GatewaySessions, gatewayStreamVisible } from './sessions/gateway-sessions.js';
13
+ import { readImportableAgentSessionRowsAsync } from './sessions/state-db.js';
12
14
  import { CompletionDrain } from './sessions/completions.js';
13
15
  import { BackgroundActivity, BackgroundTaskStore } from './sessions/background-tasks.js';
14
16
  import { HygieneTicker } from './tools/hygiene.js';
@@ -22,10 +24,12 @@ import { displayBotName, pyBool, SettingsStore } from './settings.js';
22
24
  import { AssetCache, SpaShell } from './spa.js';
23
25
  import { StartupGate } from './startup.js';
24
26
  import { SessionStore } from './sessions/store.js';
27
+ import { JsonStorage } from './sessions/storage/json.js';
25
28
  import { DraftStore } from './sessions/drafts.js';
26
29
  import { SessionEventBus } from './sessions/events.js';
27
30
  import { ShareStore } from './sessions/shares.js';
28
- import { SessionService } from './sessions/service.js';
31
+ import { ensureAgentRuntimeCurrent, HttpFailure, SessionService } from './sessions/service.js';
32
+ import { recoveryStampingSince } from './sessions/recovery.js';
29
33
  import { ProjectStore } from './projects.js';
30
34
  import { WorkspaceRegistry } from './workspace/workspaces.js';
31
35
  import { resolvePathLikePython } from './workspace/paths.js';
@@ -34,22 +38,24 @@ import { basename, delimiter, dirname, join } from 'node:path';
34
38
  import { GitRunner, GitWorkspaceError, pathsOverlap } from './workspace/git.js';
35
39
  import { RollbackStore } from './workspace/rollback.js';
36
40
  import { UploadInbox } from './workspace/upload.js';
41
+ import { EscapeGrants } from './workspace/escape.js';
37
42
  import { TurnRunner } from './sessions/turn.js';
38
43
  import { SessionChannels, StreamRegistry } from './sessions/streams.js';
39
44
  import { PendingPrompts } from './sessions/pending.js';
40
- import { RunJournal } from './sessions/journal.js';
41
45
  import { StreamSlots } from './api/sse-routes.js';
42
46
  import { AgentConfig, coerceProviderCostBudgetValue, dict as asDict, parseProviderQualifiedModel } from './config/agent-config.js';
43
47
  import { ProviderCatalog } from './providers/catalog.js';
44
- import { ProfileService } from './profiles/profiles.js';
48
+ import { containedProfileHome, escapedProfileMessage, ProfileError, ProfileService } from './profiles/profiles.js';
45
49
  import { Onboarding } from './onboarding.js';
46
50
  import { SkillsService } from './tools/skills.js';
47
51
  import { McpService } from './tools/mcp.js';
48
52
  import { WindowLimiter } from './api/tools-router.js';
49
53
  import { CronService } from './tools/crons.js';
50
54
  import { KanbanService } from './tools/kanban.js';
55
+ import { DashboardPlugins } from './tools/dashboard-plugins.js';
51
56
  import { ExtensionService } from './tools/extensions.js';
52
- import { dashboardStatus } from './tools/health.js';
57
+ import { dashboardStatus, gatewayRestartBlockers } from './tools/health.js';
58
+ import { GatewayRestartQueue, restartGateway } from './tools/gateway-restart.js';
53
59
  import { TerminalRegistry } from './tools/terminal.js';
54
60
  export function packageVersion() {
55
61
  try {
@@ -59,40 +65,44 @@ export function packageVersion() {
59
65
  return undefined;
60
66
  }
61
67
  }
62
- export function createDeps(opts) {
68
+ export async function createDeps(opts) {
63
69
  const log = opts.log ?? ((line) => { console.log(line); });
64
70
  const config = loadConfig(opts);
65
71
  const env = config.env;
66
72
  mkdirSync(config.stateDir, { recursive: true });
67
73
  mkdirSync(config.sessionDir, { recursive: true });
68
- const settings = new SettingsStore({ file: config.settingsFile, env, stateDir: config.stateDir, defaultWorkspace: config.defaultWorkspace, botName: config.botName, log });
69
74
  const now = opts.now ?? (() => Date.now() / 1000);
70
- const passkeys = new PasskeyStore(config.stateDir, now);
75
+ const storage = opts.storage?.(config) ?? createStorage(config, now, (name) => profileHome(name));
76
+ const settings = new SettingsStore({ documents: storage.documents, env, stateDir: config.stateDir, defaultWorkspace: config.defaultWorkspace, botName: config.botName, log });
77
+ await settings.load();
78
+ const passkeys = new PasskeyStore(storage.documents, now);
71
79
  // Resolved below once the sidecar-backed config store exists; the auth store reads it lazily.
72
80
  let oidc = null;
73
81
  let operatorConfigPeek = () => null;
74
82
  const auth = new AuthStore({
75
- stateDir: config.stateDir, env, settings, log, now,
76
- passkeysEnabled: () => passkeys.available(),
83
+ documents: storage.documents, env, settings, log, now,
84
+ passkeysEnabled: async () => (await passkeys.available()),
77
85
  oidcEnabled: () => oidc?.enabledSync() ?? false,
78
86
  oidcAvailable: () => oidc?.availableSync() ?? false,
79
87
  oidcProbe: () => oidc?.resolve() ?? Promise.resolve(),
80
88
  passkeyConfigFlag: () => { const cfg = operatorConfigPeek(); return cfg === null ? null : cfg.webui_passkey_enabled; },
81
89
  });
90
+ await auth.initialize();
82
91
  settings.hooks = {
83
- hashPassword: (pw) => auth.hashPassword(pw),
92
+ hashPassword: async (pw) => (await auth.hashPassword(pw)),
84
93
  onPasswordChanged: () => { auth.invalidatePasswordHashCache(); },
85
94
  };
86
- settings.applyStartupWorkspace();
95
+ await settings.applyStartupWorkspace();
87
96
  config.defaultWorkspace = settings.defaultWorkspace;
88
97
  const release = loadReleaseInfo({ webRoot: config.webRoot });
89
98
  const stampedRelease = loadReleaseInfo({ webRoot: config.webRoot }, { verifyCheckout: false });
90
99
  const runningSourceRevision = checkoutRevision(config.webRoot);
91
100
  // Container images bake `TALARIA_WEB_VERSION` (Python `api/_version.py`) because .git is not shipped.
92
101
  const version = opts.version ?? detectWebuiVersion(release, config.webRoot, (env.TALARIA_WEB_VERSION ?? '').trim() || packageVersion());
93
- const updateNotifications = new UpdateNotificationStore(config.stateDir, () => new Date(now() * 1000));
102
+ const updateNotifications = new UpdateNotificationStore(storage.documents, () => new Date(now() * 1000));
103
+ await updateNotifications.initialize();
94
104
  const verifiedRunningVersion = /^web-(?:exp-)?v\d+\.\d+\.\d+$/.test(version) ? version : null;
95
- updateNotifications.reconcileInterruptedUpdates(runningSourceRevision ?? release.sourceRevision, verifiedRunningVersion);
105
+ await updateNotifications.reconcileInterruptedUpdates(runningSourceRevision ?? release.sourceRevision, verifiedRunningVersion);
96
106
  const home = opts.home ?? config.homeDir;
97
107
  const PROFILE_RE = /^[a-z0-9][a-z0-9_-]{0,63}$/;
98
108
  // Python `init_profile_state` + `switch_profile(process_wide=False)`: the sticky `~/.hermes/active_profile` is
@@ -124,15 +134,39 @@ export function createDeps(opts) {
124
134
  if (profile && !isRootProfile(profile))
125
135
  return profile.charAt(0).toUpperCase() + profile.slice(1);
126
136
  try {
127
- return displayBotName(settings.load().bot_name);
137
+ return displayBotName(settings.peek().bot_name);
128
138
  }
129
139
  catch {
130
140
  return displayBotName(null);
131
141
  }
132
142
  };
133
- // Python `_resolve_profile_home_for_name`: root aliases and invalid names clamp to the base home.
134
- // Isolated mode never resolves outside the pinned home, whatever name is asked for (Python `_resolve_profile_home_for_name`).
135
- const profileHome = (name) => (isolatedProfile === null && name && !isRootProfile(name) && PROFILE_RE.test(name) ? join(baseHome, 'profiles', name) : isolatedProfile === null ? baseHome : config.hermesHome);
143
+ // Python `_resolve_profile_home_for_name`: root aliases and invalid names clamp to the base home; a named home resolving
144
+ // outside the profiles root throws (Python `relative_to`), so no consumer runs it against the root or outside home.
145
+ // Isolated mode never resolves outside the pinned home, whatever name is asked for.
146
+ const profileHome = (name) => {
147
+ if (isolatedProfile !== null)
148
+ return config.hermesHome;
149
+ if (!name || isRootProfile(name) || !PROFILE_RE.test(name))
150
+ return baseHome;
151
+ const contained = containedProfileHome(baseHome, name);
152
+ if (contained === null)
153
+ throw new ProfileError(escapedProfileMessage(name), 400);
154
+ return contained;
155
+ };
156
+ const agentHomes = () => {
157
+ if (isolatedProfileMode())
158
+ return [baseHome];
159
+ let names;
160
+ try {
161
+ names = readdirSync(join(baseHome, 'profiles'));
162
+ }
163
+ catch (error) {
164
+ if (error.code !== 'ENOENT')
165
+ throw error;
166
+ names = [];
167
+ }
168
+ return [...new Set([baseHome, ...names.filter((name) => PROFILE_RE.test(name)).map(profileHome)])];
169
+ };
136
170
  const attachmentRoot = () => {
137
171
  const override = (env.HERMES_WEBUI_ATTACHMENT_DIR ?? '').trim();
138
172
  return resolvePathLikePython(override ? override.replace(/^~(?=$|\/)/, home) : join(config.stateDir, 'attachments'));
@@ -141,19 +175,25 @@ export function createDeps(opts) {
141
175
  const agentConfig = new AgentConfig({ sidecar: () => sidecar, env });
142
176
  /** A profile's config.yaml `model` as [model, provider] as written; '' / null when unset or not yet read. */
143
177
  const profileDefaultModel = (profile) => {
144
- const cfg = agentConfig.peek(profileHome(profile ?? activeProfile()));
178
+ let cfg;
179
+ try {
180
+ cfg = agentConfig.peek(profileHome(profile ?? activeProfile()));
181
+ }
182
+ catch {
183
+ return ['', null];
184
+ }
145
185
  if (typeof cfg?.model === 'string')
146
186
  return [cfg.model.trim(), null];
147
187
  const { default: d, provider: p } = asDict(cfg?.model);
148
188
  return [typeof d === 'string' ? d.trim() : '', typeof p === 'string' && p ? p : null];
149
189
  };
150
190
  const events = new SessionEventBus(isRootProfile);
151
- const drafts = new DraftStore(config.sessionDir);
152
- const registry = new StreamRegistry();
191
+ const drafts = new DraftStore(storage.documents);
192
+ const registry = new StreamRegistry((id) => gatewayStreamVisible(id, profileHome(activeProfile())));
153
193
  const activeStreamIds = registry.liveIds;
154
194
  const runningCronJobs = new Map();
155
195
  const workspaces = new WorkspaceRegistry({
156
- stateDir: config.stateDir,
196
+ documents: storage.documents,
157
197
  defaultWorkspace: () => config.defaultWorkspace,
158
198
  profileHome,
159
199
  activeProfile,
@@ -172,34 +212,34 @@ export function createDeps(opts) {
172
212
  return Number.isFinite(raw) && raw >= 1 ? raw : 100;
173
213
  };
174
214
  const store = new SessionStore({
175
- sessionDir: config.sessionDir,
215
+ storage,
176
216
  drafts,
177
217
  events,
178
218
  // Python `_profile_default_model_state`: the profile's own config.yaml model, else the global default. The provider
179
219
  // always comes with its model, so a provider-only profile never pairs with another profile's model.
180
- defaults: (profile) => {
220
+ defaults: async (profile) => {
181
221
  let [model, provider] = profileDefaultModel(profile);
182
222
  if (!model) {
183
- const s = settings.load();
223
+ const s = settings.peek();
184
224
  model = typeof s.default_model === 'string' ? s.default_model : '';
185
225
  provider = model && typeof s.default_model_provider === 'string' && s.default_model_provider ? s.default_model_provider : null;
186
226
  }
187
227
  const [bare, modelProvider] = parseProviderQualifiedModel(model) ?? [model || null, provider];
188
- return { workspace: workspaces.lastWorkspace(profile), model: bare, modelProvider };
228
+ return { workspace: (await workspaces.lastWorkspace(profile)), model: bare, modelProvider };
189
229
  },
190
230
  activeStreamIds: () => activeStreamIds,
191
231
  now,
192
232
  log,
193
233
  cacheMax,
194
- onDeleted: (sid) => { backgroundStore.evict(sid); },
234
+ onDeleted: async (sid) => { (await backgroundStore.delete(sid)); },
195
235
  });
196
- const projects = new ProjectStore(resolve(config.stateDir, 'projects.json'), () => store.readIndexEntries(), isRootProfile);
197
- const shares = new ShareStore(resolve(config.stateDir, 'shares'), now);
236
+ const projects = new ProjectStore(storage.documents, async () => (await store.readIndexEntries()), isRootProfile);
237
+ const shares = new ShareStore(storage.documents, now);
198
238
  const yoloSessions = new Set();
199
239
  const attachmentDir = (sid) => join(attachmentRoot(), (sid || 'session').replace(/[^\w.-]/g, '_').slice(0, 120));
200
- const cliSessions = new CliSessionSource({ store, profileHome, lastWorkspace: (p) => workspaces.lastWorkspace(p), backgroundProjectId: (kind, p) => projects.ensureSystemProject(kind, p, { create: kind === 'webhook' || projects.hasUserProjects(p) }), now, log });
240
+ const cliSessions = new CliSessionSource({ store, profileHome, profilesMatch, lastWorkspace: async (p) => (await workspaces.lastWorkspace(p)), backgroundProjectId: async (kind, p) => (await projects.ensureSystemProject(kind, p, { create: kind === 'webhook' || (await projects.hasUserProjects(p)) })), now, log });
201
241
  const gatewayWatchers = new GatewayWatcherRegistry({ profileHome, now, log, ...(opts.gatewayPollMs !== undefined ? { pollIntervalMs: opts.gatewayPollMs } : {}) });
202
- const journal = new RunJournal(config.sessionDir, env);
242
+ const journal = storage.journals;
203
243
  const contextLengths = new Map();
204
244
  const contextInflight = new Map();
205
245
  const contextKey = (model, provider, profile) => (model?.trim() ? `${profileHome(profile ?? activeProfile())}\0${provider?.trim() ?? ''}\0${model.trim()}` : null);
@@ -239,52 +279,75 @@ export function createDeps(opts) {
239
279
  profileOps.delete(key);
240
280
  };
241
281
  };
242
- const mediaActiveWorkspace = () => {
282
+ const mediaActiveWorkspace = async () => {
243
283
  if (!workspaces.profileSupportsLocalIo(null))
244
284
  return null;
245
285
  try {
246
- const ws = resolvePathLikePython(workspaces.lastWorkspace(activeProfile()));
286
+ const ws = resolvePathLikePython((await workspaces.lastWorkspace(activeProfile())));
247
287
  return statSync(ws).isDirectory() ? ws : null;
248
288
  }
249
289
  catch {
250
290
  return null;
251
291
  }
252
292
  };
253
- const snapshotDir = () => {
254
- const override = (env.HERMES_WEBUI_MEDIA_SNAPSHOT_DIR ?? '').trim();
255
- return override ? override.replace(/^~(?=$|\/)/, home) : join(config.stateDir, 'media_snapshots');
256
- };
257
- const mediaPolicy = { home, hermesHome: config.hermesHome, stateDir: config.stateDir, snapshotDir, activeWorkspace: mediaActiveWorkspace };
293
+ const legacySnapshotDir = (env.HERMES_WEBUI_MEDIA_SNAPSHOT_DIR ?? '').trim().replace(/^~(?=$|\/)/, home) || undefined;
294
+ const mediaPolicy = { home, hermesHome: config.hermesHome, stateDir: config.stateDir, legacySnapshotDir, activeWorkspace: mediaActiveWorkspace };
258
295
  const mediaAccess = { home: config.homeDir, hermesHome: config.hermesHome, extraRoots: env.MEDIA_ALLOWED_ROOTS ?? '', activeWorkspace: mediaActiveWorkspace, policy: mediaPolicy };
296
+ // TAL-259: record when this server started stamping deliberate shrinks; older backups go to manual review.
297
+ try {
298
+ await recoveryStampingSince(storage.documents);
299
+ }
300
+ catch (error) {
301
+ log(`[webui] WARNING: could not record recovery_stamping_since: ${error.message}`);
302
+ }
259
303
  const sessions = new SessionService({
304
+ recoveryStampingSince: async () => await recoveryStampingSince(storage.documents),
260
305
  sidecar: () => sidecar,
261
306
  media: { access: mediaAccess, localIo: (profile) => workspaces.profileSupportsLocalIo(profile) },
262
307
  profileActivity,
263
308
  profileDeleting: (profile) => profiles.isDeleting(profile),
264
- backgroundReceipts: (sid) => background.receipts(sid),
309
+ backgroundReceipts: async (sid) => (await background.receipts(sid)),
310
+ backgroundPending: async (sid) => (await completions.pendingDelegations(sid)),
265
311
  journal,
266
- clearRelayCompletions: (sid, profile) => { relay.clearDeleted(sid, profile); },
312
+ clearRelayCompletions: async (sid, profile) => { (await relay.clearDeleted(sid, profile)); },
267
313
  store,
268
- cliSessions: (profile, o) => cliSessions.read(profile, o),
314
+ cliSessions: async (profile, o) => (await cliSessions.read(profile, o)),
315
+ cliSessionsSync: async (profile, o) => (await cliSessions.readSync(profile, o)),
269
316
  claudeCode: new ClaudeCodeSessionSource(() => claudeCodeProjectsDir(env, home)),
270
317
  profileHome,
271
318
  // The commit runs detached from the request, so it is registered as profile activity until it settles: profile
272
319
  // deletion must not remove the memory files the cached Agent is still writing.
273
- commitSessionMemory: (sid) => {
320
+ commitSessionMemory: async (sid) => {
274
321
  if (!sidecar)
275
322
  return;
323
+ const callerProfile = activeProfile();
324
+ // Reserve deletion protection before the asynchronous lookup knows which profile owns the session.
325
+ let release = profileActivity('*');
276
326
  let profile = null;
277
327
  try {
278
- profile = store.get(sid, { metadataOnly: true }).profile ?? null;
328
+ profile = (await store.get(sid, { metadataOnly: true })).profile ?? null;
279
329
  }
280
330
  catch {
281
331
  profile = null;
282
332
  }
283
- const release = profileActivity(profile);
284
- void sidecar.call('chat.commit_memory', { profile_home: profileHome(profile ?? activeProfile()), session_id: sid })
333
+ const targetProfile = profile ?? callerProfile;
334
+ const releaseOwner = profileActivity(targetProfile);
335
+ release();
336
+ release = releaseOwner;
337
+ void Promise.resolve().then(async () => {
338
+ await sessions.assertWritable(sid, targetProfile);
339
+ return sidecar.call('chat.commit_memory', { profile_home: profileHome(targetProfile), session_id: sid });
340
+ })
285
341
  .catch((error) => { log(`[webui] memory commit for ${sid} failed: ${error.message}`); })
286
342
  .finally(release);
287
343
  },
344
+ // Detached like a memory commit: profile deletion waits for the title job, which reads the profile's config.
345
+ titleClaimed: (session) => {
346
+ if (profiles.isDeleting(session.profile ?? null))
347
+ return;
348
+ const release = profileActivity(session.profile ?? null);
349
+ void turns.titleClaimed(session).finally(release);
350
+ },
288
351
  drafts,
289
352
  events,
290
353
  workspaces,
@@ -297,12 +360,12 @@ export function createDeps(opts) {
297
360
  profilesMatch,
298
361
  assistantName,
299
362
  redactEnabled: () => { try {
300
- return settings.load().api_redact_enabled !== false;
363
+ return settings.peek().api_redact_enabled !== false;
301
364
  }
302
365
  catch {
303
366
  return true;
304
367
  } },
305
- pinnedSessionsLimit: () => { const v = settings.load().pinned_sessions_limit; return typeof v === 'number' && v >= 1 ? v : 3; },
368
+ pinnedSessionsLimit: () => { const v = settings.peek().pinned_sessions_limit; return typeof v === 'number' && v >= 1 ? v : 3; },
306
369
  // Chat runtime (checkpoint 6) replaces these with live stream and cron state.
307
370
  runtime: {
308
371
  activeStreamIds,
@@ -321,25 +384,34 @@ export function createDeps(opts) {
321
384
  activeRunStream: (sid) => registry.activeRunStreamForSession(sid),
322
385
  journalDegraded: (streamId) => registry.degradedJournals.has(streamId),
323
386
  pendingSteers: (streamId) => turns.pendingSteers(streamId),
324
- evictAgent: (sid, endSession) => { if (sidecar)
387
+ runStatus: (streamId) => turns.runStatus(streamId),
388
+ compressionStartedAt: (streamId) => turns.compressionStartedAt(streamId),
389
+ automaticTurnsHeld: async (sid) => (await turns.automaticTurnsHeld(sid)),
390
+ sessionNotices: (sid) => turns.sessionNotices(sid),
391
+ sessionGoal: (sid) => turns.sessionGoal(sid),
392
+ evictAgent: async (sid, endSession) => { if (sidecar && (!endSession || !(await sessions.readOnlyReason(sid))))
325
393
  sidecar.call('chat.evict_agent', endSession ? { session_id: sid, clear_session: true } : { session_id: sid }).catch(() => undefined); },
326
394
  closeTerminal: (sid) => { deps.terminals.close(sid); },
327
395
  deleteCliSession: async (profile, sid) => {
328
396
  if (!sidecar)
329
- return false;
330
- return (await sidecar.call('state_db.delete_cli_session', { profile_home: profileHome(profile ?? activeProfile()), session_id: sid })).ok;
397
+ return { ok: false };
398
+ const targetProfile = profile ?? activeProfile();
399
+ await sessions.assertWritable(sid, targetProfile);
400
+ return await sidecar.call('state_db.delete_cli_session', { profile_home: profileHome(targetProfile), session_id: sid, include_compression_lineage: true });
331
401
  },
332
402
  },
333
403
  attachmentDir,
334
404
  hermesHome: config.hermesHome,
335
405
  home,
336
406
  // Python `_sync_session_title_to_state_db`: with `sync_to_insights` on, the state.db row follows a rename.
337
- syncTitle: async (session) => {
338
- if (!sidecar || !pyBool(settings.load().sync_to_insights))
407
+ syncTitle: async (session, manual) => {
408
+ if (!sidecar || !pyBool(settings.peek().sync_to_insights))
339
409
  return;
340
410
  // Awaited by callers: the rename/regenerate response and the title stream's teardown follow the state.db write.
341
411
  try {
342
- await sidecar.call('state_db.sync_title', { profile_home: profileHome(session.profile ?? activeProfile()), session_id: session.session_id, title: session.title });
412
+ const targetProfile = session.profile ?? activeProfile();
413
+ sessions.assertWritable(session, targetProfile);
414
+ await sidecar.call('state_db.sync_title', { profile_home: profileHome(targetProfile), session_id: session.session_id, title: session.title, manual: manual === true });
343
415
  }
344
416
  catch (error) {
345
417
  log(`[webui] state.db title sync failed for ${session.session_id}: ${error.message}`);
@@ -383,15 +455,22 @@ export function createDeps(opts) {
383
455
  });
384
456
  // A working-tree mutation refuses while a run is active anywhere it would change files.
385
457
  const git = new GitRunner({ env, activeRunIn: (path) => [...registry.activeRuns.values()].some((run) => Boolean(run.workspace) && pathsOverlap(run.workspace, path)) });
386
- const rollback = new RollbackStore({ hermesHome: () => profileHome(activeProfile()), knownWorkspaces: () => workspaces.load(activeProfile()).map((w) => w.path) });
458
+ const rollback = new RollbackStore({
459
+ sidecar: () => sidecar, profileHome: () => profileHome(activeProfile()), knownWorkspaces: async () => (await workspaces.load(activeProfile())).map((w) => w.path),
460
+ // A run whose session cannot be read counts as one in the profile: refusing is the safe answer.
461
+ activeRunInProfile: (home) => [...registry.activeRuns.values()].some((run) => {
462
+ const session = store.sessions.get(run.session_id);
463
+ return !session || profileHome(session.profile ?? activeProfile()) === home;
464
+ }),
465
+ });
387
466
  const uploads = new UploadInbox(attachmentRoot);
388
467
  const channels = new SessionChannels();
389
468
  const pending = new PendingPrompts(events, now);
390
469
  // TAL-372: one durable record per piece of background work; a change refreshes every client showing the session.
391
- const backgroundStore = new BackgroundTaskStore(config.sessionDir, now, (sid) => {
470
+ const backgroundStore = new BackgroundTaskStore(storage.documents, now, async (sid) => {
392
471
  let profile = null;
393
472
  try {
394
- profile = store.get(sid, { metadataOnly: true, promote: false, cacheOnMiss: false }).profile;
473
+ profile = (await store.get(sid, { metadataOnly: true, promote: false, cacheOnMiss: false })).profile;
395
474
  }
396
475
  catch {
397
476
  profile = null;
@@ -405,7 +484,8 @@ export function createDeps(opts) {
405
484
  let completions;
406
485
  const relay = new RelayService({
407
486
  registry, pending, store, presence: new PresenceLeases(now), profileHome, profilesMatch, fetch: () => lazyFetch, now, log,
408
- stateDir: config.stateDir, env, canonicalProfile: (p) => (isRootProfile(p) ? 'default' : p), addListener: (listener) => events.addListener(listener),
487
+ agentSessions: (profile) => readImportableAgentSessionRowsAsync(join(profileHome(profile), 'state.db')),
488
+ documents: storage.documents, env, canonicalProfile: (p) => (isRootProfile(p) ? 'default' : p), addListener: (listener) => events.addListener(listener),
409
489
  });
410
490
  const turns = new TurnRunner({
411
491
  store,
@@ -416,14 +496,17 @@ export function createDeps(opts) {
416
496
  profileDeleting: (profile) => profiles.isDeleting(profile),
417
497
  updateInProgress: () => deps.updates.blocksNewWork(),
418
498
  workspaceBusy: (workspace) => deps.git.workspaceBusy(workspace),
499
+ checkpointStoreBusy: (profile) => rollback.storeBusy(profileHome(profile ?? activeProfile())),
419
500
  syncTitle: (session) => sessions.deps.syncTitle(session),
420
501
  // Python `sync_session_usage` after a settled turn: with `sync_to_insights` on, the state.db row carries the usage.
421
502
  syncUsage: async (session, model) => {
422
- if (!sidecar || !pyBool(settings.load().sync_to_insights))
503
+ if (!sidecar || !pyBool(settings.peek().sync_to_insights))
423
504
  return;
424
505
  try {
506
+ const targetProfile = session.profile ?? activeProfile();
507
+ sessions.assertWritable(session, targetProfile);
425
508
  await sidecar.call('state_db.sync_usage', {
426
- profile_home: profileHome(session.profile ?? activeProfile()), session_id: session.session_id,
509
+ profile_home: profileHome(targetProfile), session_id: session.session_id,
427
510
  input_tokens: session.input_tokens || 0, output_tokens: session.output_tokens || 0, estimated_cost: typeof session.estimated_cost === 'number' ? session.estimated_cost : null,
428
511
  cache_read_tokens: session.cache_read_tokens || 0, cache_write_tokens: session.cache_write_tokens || 0,
429
512
  model, title: session.title, message_count: session.messages.length,
@@ -433,12 +516,22 @@ export function createDeps(opts) {
433
516
  log(`[webui] state.db usage sync failed for ${session.session_id}: ${error.message}`);
434
517
  }
435
518
  },
519
+ configPath: (home) => agentConfig.path(home),
436
520
  profileConfig: async (profile) => { try {
437
521
  return await agentConfig.read(profileHome(profile ?? activeProfile()));
438
522
  }
439
523
  catch {
440
524
  return null;
441
525
  } },
526
+ personalities: (profile) => agentConfig.agentPersonalities(profileHome(profile ?? activeProfile())),
527
+ providerLabel: (profile, provider) => catalog.providerLabel(profileHome(profile ?? activeProfile()), provider),
528
+ titleRefreshEvery: () => { try {
529
+ const every = Number(settings.peek().auto_title_refresh_every);
530
+ return Number.isInteger(every) && every > 0 ? every : 0;
531
+ }
532
+ catch {
533
+ return 0;
534
+ } },
442
535
  env,
443
536
  hermesHome: config.hermesHome,
444
537
  // Python `display_hermes_home`: the home shown to the model, `~`-relative when it sits under $HOME.
@@ -453,7 +546,7 @@ export function createDeps(opts) {
453
546
  now,
454
547
  log,
455
548
  redactEnabled: () => { try {
456
- return settings.load().api_redact_enabled !== false;
549
+ return settings.peek().api_redact_enabled !== false;
457
550
  }
458
551
  catch {
459
552
  return true;
@@ -464,7 +557,7 @@ export function createDeps(opts) {
464
557
  });
465
558
  // Services read `deps.fetch` lazily so tests can swap the outbound HTTP client after boot.
466
559
  const lazyFetch = (input, init) => deps.fetch(input, init);
467
- const catalog = new ProviderCatalog({ sidecar: () => sidecar, config: agentConfig, env, now, log, costBudget: () => coerceProviderCostBudgetValue(settings.load().provider_cost_budget), quotaThresholds: (profile) => settings.quotaThresholds(profile), isRootProfileHome: (h) => resolvePathLikePython(h) === resolvePathLikePython(config.hermesHome), stateDir: config.stateDir });
560
+ const catalog = new ProviderCatalog({ sidecar: () => sidecar, config: agentConfig, env, now, log, costBudget: () => coerceProviderCostBudgetValue(settings.peek().provider_cost_budget), quotaThresholds: async (profile) => (await settings.quotaThresholds(profile)), isRootProfileHome: (h) => resolvePathLikePython(h) === resolvePathLikePython(config.hermesHome), documents: storage.documents });
468
561
  const agentStatus = () => {
469
562
  const describe = sidecar?.describe ?? null;
470
563
  const found = Boolean(describe?.agent_dir);
@@ -478,7 +571,7 @@ export function createDeps(opts) {
478
571
  isolatedProfileMode,
479
572
  isolatedProfileName,
480
573
  config: agentConfig,
481
- defaultWorkspace: (profile) => workspaces.profileDefaultWorkspace(profile),
574
+ defaultWorkspace: async (profile) => (await workspaces.profileDefaultWorkspace(profile)),
482
575
  models: (h) => catalog.models(h),
483
576
  streamsActive: () => activeStreamIds.size > 0,
484
577
  profileRunsActive: (name) => {
@@ -494,23 +587,22 @@ export function createDeps(opts) {
494
587
  }
495
588
  for (const sessionId of sessionIds) {
496
589
  let profile = null;
497
- try {
498
- profile = store.get(sessionId, { metadataOnly: true }).profile ?? null;
499
- }
500
- catch {
501
- continue;
502
- }
590
+ const session = store.sessions.get(sessionId);
591
+ if (!session)
592
+ return true;
593
+ profile = session.profile ?? null;
503
594
  if (profiles.isRootProfile(profile ?? 'default') ? profiles.isRootProfile(name) : profile === name)
504
595
  return true;
505
596
  }
506
597
  for (const [profile, count] of profileOps)
507
- if (count > 0 && (profiles.isRootProfile(profile) ? profiles.isRootProfile(name) : profile === name))
598
+ if (count > 0 && (profile === '*' || (profiles.isRootProfile(profile) ? profiles.isRootProfile(name) : profile === name)))
508
599
  return true;
509
600
  return false;
510
601
  },
511
- tombstoneFile: join(config.stateDir, 'deleted-profiles.json'),
602
+ documents: storage.documents,
512
603
  log,
513
604
  }, now);
605
+ await profiles.initialize();
514
606
  rootAlias = (name) => profiles.isRootProfile(name);
515
607
  const onboarding = new Onboarding({
516
608
  settings,
@@ -521,13 +613,13 @@ export function createDeps(opts) {
521
613
  sidecar: () => sidecar,
522
614
  agentStatus,
523
615
  isAuthEnabled: () => auth.isAuthEnabled(),
524
- workspaces: () => ({ items: workspaces.load(activeProfile()), last: workspaces.lastWorkspace(activeProfile()) }),
616
+ workspaces: async () => ({ items: (await workspaces.load(activeProfile())), last: (await workspaces.lastWorkspace(activeProfile())) }),
525
617
  models: (h) => catalog.models(h),
526
618
  defaultWorkspace: () => config.defaultWorkspace,
527
619
  defaultModel: () => (env.HERMES_WEBUI_DEFAULT_MODEL ?? '').trim(),
528
620
  log,
529
621
  });
530
- oidc = new OidcService({ env, operatorConfig: () => agentConfig.read(config.hermesHome), profileHome, fetch: () => lazyFetch, pinned: () => ({ lookup: deps.dnsLookup, fetch: deps.pinnedFetch }), now, log });
622
+ oidc = new OidcService({ env, operatorConfig: () => agentConfig.read(baseHome), profileHome, fetch: () => lazyFetch, pinned: () => ({ lookup: deps.dnsLookup, fetch: deps.pinnedFetch }), now, log });
531
623
  operatorConfigPeek = () => agentConfig.peek(config.hermesHome);
532
624
  settings.hooks.defaultModel = () => profileDefaultModel(null)[0];
533
625
  settings.hooks.defaultModelProvider = () => profileDefaultModel(null)[1] ?? undefined;
@@ -571,10 +663,18 @@ export function createDeps(opts) {
571
663
  },
572
664
  };
573
665
  };
574
- completions = new CompletionDrain({ sidecar: () => sidecar, baseHome, profileHome: (p) => profileHome(p ?? activeProfile()), activeProfile, store, channels, registry, startTurn: (session, prompt) => {
575
- // TAL-542: a wakeup repairs a stale pair from the cached catalog only (Python `prefer_cached_catalog`), never waiting on a build.
576
- const [model, modelProvider] = (session.model ? catalog.sessionModelRepair(profileHome(session.profile ?? activeProfile()), session.model, session.model_provider) : null) ?? [session.model, session.model_provider];
577
- return turns.start(session, { msg: prompt, attachments: [], workspace: session.workspace, model, modelProvider, source: 'process_wakeup' });
666
+ completions = new CompletionDrain({ documents: storage.documents, sidecar: () => sidecar, configPath: (home) => agentConfig.path(home), readConfig: (home) => agentConfig.read(home), env, baseHome, profileHome: (p) => profileHome(p ?? activeProfile()), activeProfile, store, channels, registry, isReadOnly: async (session) => (await sessions.isReadOnly(session)), startTurn: async (session, prompt, completionKeys, backgroundUpdate) => {
667
+ // TAL-577: a wakeup passes the user-turn admission; a stale runtime answers a retryable 409, which defers it on a retry timer.
668
+ // TAL-542: its model repair reads the cached catalog only (Python `prefer_cached_catalog`), never waiting on a build.
669
+ try {
670
+ await ensureAgentRuntimeCurrent(sidecar);
671
+ return (await turns.startServerTurn(session, { msg: prompt, source: 'process_wakeup', completionKeys, backgroundUpdate }));
672
+ }
673
+ catch (error) {
674
+ if (error instanceof HttpFailure)
675
+ return { _status: error.status, error: error.message, retryable: error.extra.retryable === true };
676
+ throw error;
677
+ }
578
678
  }, background, now, log, ...(opts.completionPollMs !== undefined ? { pollMs: opts.completionPollMs } : {}) });
579
679
  const mcpHealth = new McpHealthProber({ fetch: () => lazyFetch, now, log });
580
680
  // Dashboard reachability is probed in the background (Python `dashboard_probe.get_dashboard_status`), never per request.
@@ -585,7 +685,7 @@ export function createDeps(opts) {
585
685
  if (at - dashboardCheckedAt < 30)
586
686
  return;
587
687
  dashboardCheckedAt = at;
588
- agentConfig.read(profileHome(activeProfile())).then((cfg) => dashboardStatus(cfg, env, lazyFetch)).then((status) => { dashboardRunning = status.running === true; }).catch(() => { dashboardRunning = false; });
688
+ Promise.resolve().then(() => agentConfig.read(profileHome(activeProfile()))).then((cfg) => dashboardStatus(cfg, env, lazyFetch)).then((status) => { dashboardRunning = status.running === true; }).catch(() => { dashboardRunning = false; });
589
689
  };
590
690
  const extensionsEnabled = () => { try {
591
691
  return deps.extensions.enabledSync();
@@ -593,6 +693,8 @@ export function createDeps(opts) {
593
693
  catch {
594
694
  return false;
595
695
  } };
696
+ sessions.owner = new GatewaySessions({ service: sessions, sidecar: () => sidecar, registry, journal, events,
697
+ profileHome, activeProfile, redactEnabled: sessions.deps.redactEnabled, now, log });
596
698
  const deps = {
597
699
  config,
598
700
  settings,
@@ -611,7 +713,7 @@ export function createDeps(opts) {
611
713
  requestScope,
612
714
  isRootProfile,
613
715
  assistantName,
614
- onboardingCompleted: () => truthy(env.HERMES_WEBUI_SKIP_ONBOARDING) || Boolean(settings.load().onboarding_completed),
716
+ onboardingCompleted: () => truthy(env.HERMES_WEBUI_SKIP_ONBOARDING) || Boolean(settings.peek().onboarding_completed),
615
717
  health: () => ({ sessions: store.sessions.size, activeStreams: activeStreamIds.size, activeRuns: registry.activeRuns.size, runs: [...registry.activeRuns.values()].map((r) => ({ phase: r.phase, started_at: r.started_at })), lastRunFinishedAt: registry.lastRunFinishedAt }),
616
718
  sessions,
617
719
  sessionStore: store,
@@ -634,7 +736,7 @@ export function createDeps(opts) {
634
736
  git,
635
737
  rollback,
636
738
  uploads,
637
- mediaPolicy,
739
+ escapeGrants: new EscapeGrants(now),
638
740
  mediaAccess,
639
741
  worktreeLocks: { lockedByStream: (s) => Boolean(s.active_stream_id && activeStreamIds.has(s.active_stream_id)), lockedByTerminal: (sid, worktreePath) => { const term = deps.terminals.get(sid); return Boolean(term?.isAlive) && resolvePathLikePython(term?.workspace ?? '') === resolvePathLikePython(worktreePath); } },
640
742
  sidecar: () => sidecar,
@@ -657,11 +759,11 @@ export function createDeps(opts) {
657
759
  oidc,
658
760
  passkeys,
659
761
  nativeOidcLimiter: new WindowLimiter(60, 10, now),
660
- clearPasskeys: () => { passkeys.clear(); },
762
+ clearPasskeys: async () => { (await passkeys.clear()); },
661
763
  skills: new SkillsService({ sidecar: () => sidecar, config: agentConfig, log }),
662
764
  mcp: new McpService({ sidecar: () => sidecar, config: agentConfig, health: mcpHealth }),
663
765
  completions,
664
- hygiene: new HygieneTicker({ env, stateDir: config.stateDir, port: () => config.port, journal, activeJournalPaths: () => turns.activeJournalPaths(), now, log, sweeps: [() => { completions.sweep(); }] }),
766
+ hygiene: new HygieneTicker({ env, stateDir: config.stateDir, port: () => config.port, journal, now, log, sweeps: [() => { completions.sweep(); }, async () => { (await turns.sweep()); }] }),
665
767
  mcpHealth,
666
768
  nowSeconds: now,
667
769
  // Python `_webui_runtime_payload`: the four owner sections with their `available` flags.
@@ -680,12 +782,14 @@ export function createDeps(opts) {
680
782
  requestShutdown: () => { setTimeout(() => { process.kill(process.pid, 'SIGINT'); }, 300).unref(); },
681
783
  // Embedded shells are separate process groups that would outlive the worker: terminate and reap them on both exits.
682
784
  // A running retention sweep stops before the exit, like on shutdown.
683
- requestRestart: () => { void waitUntilRestartSafe(restartBlockers, { log }).then(() => deps.hygiene.stop()).then(() => auth.flushPersistence()).then(() => { deps.terminals.closeAll({ immediate: true }); purgeAgentPycache(); process.exit(RESTART_EXIT_CODE); }); },
785
+ requestRestart: () => { void waitUntilRestartSafe(restartBlockers, { log }).then(() => deps.gatewayRestarts.quiesce()).then(() => deps.hygiene.stop()).then(() => auth.flushPersistence()).then(() => store.close()).then(() => { deps.terminals.closeAll({ immediate: true }); purgeAgentPycache(); process.exit(RESTART_EXIT_CODE); }); },
684
786
  updates: null,
685
787
  updateNotifications,
788
+ gatewayRestarts: null,
686
789
  cspLimiter: new WindowLimiter(60, 100, now),
687
790
  clientEventLimiter: new WindowLimiter(60, 30, now),
688
791
  ttsLimiter: new WindowLimiter(2, 1, now),
792
+ profileActivity,
689
793
  fetch: opts.fetch ?? fetch,
690
794
  dnsLookup: systemDnsLookup,
691
795
  pinnedFetch,
@@ -698,10 +802,12 @@ export function createDeps(opts) {
698
802
  log,
699
803
  publishSessionsChanged: (reason, profile) => { events.publish(reason, { profile }); },
700
804
  runningJobs: runningCronJobs,
805
+ updateInProgress: () => deps.updates.blocksNewWork(),
701
806
  modelOptionFor: async (home, model, provider) => { await catalog.warmModelOptions(home); return catalog.modelOptionFor(home, model, provider); },
702
807
  }),
703
808
  kanban: new KanbanService({ sidecar: () => sidecar, config: agentConfig }),
704
- extensions: new ExtensionService({ env, stateDir: config.stateDir, isAuthEnabled: () => auth.isAuthEnabled(), fetch: lazyFetch, log }),
809
+ extensions: new ExtensionService({ documents: storage.documents, env, stateDir: config.stateDir, isAuthEnabled: () => auth.isAuthEnabled(), fetch: lazyFetch, log }),
810
+ dashboardPlugins: new DashboardPlugins({ env, hermesHome: config.hermesHome, settings }),
705
811
  terminals,
706
812
  commitMessage: async (session, systemPrompt, userPrompt) => {
707
813
  if (!sidecar)
@@ -725,9 +831,12 @@ export function createDeps(opts) {
725
831
  };
726
832
  const purgeAgentPycache = () => { const dir = sidecar?.describe?.agent_dir; if (dir)
727
833
  purgePycache(dir); };
834
+ let recoveredAgentRevision = null;
835
+ let pendingRuntimeRecovery = null;
728
836
  deps.updates = new UpdateService({
729
837
  webRoot: config.webRoot,
730
838
  getJson: githubJson(lazyFetch, env),
839
+ getPublicJson: githubJson(lazyFetch, env, 'https://api.github.com'),
731
840
  experimental: ghcrExperimental(lazyFetch),
732
841
  stateDir: config.stateDir,
733
842
  identity: { release: () => release, stamped: () => stampedRelease, runningSourceRevision: () => runningSourceRevision },
@@ -739,30 +848,124 @@ export function createDeps(opts) {
739
848
  return deps.version;
740
849
  },
741
850
  agentDir: () => sidecar?.describe?.agent_dir ?? null,
742
- channel: () => normalizeChannel(settings.load().update_channel),
743
- agentChannel: () => normalizeChannel(settings.load().agent_update_channel),
744
- includeAgent: () => !pyBool(settings.load().ignore_agent_updates),
745
- autoApply: () => settings.load().check_for_updates !== false && settings.load().auto_apply_updates === true,
746
- checkEnabled: () => !truthy(env.HERMES_WEBUI_TEST_NETWORK_BLOCK) && settings.load().check_for_updates !== false,
747
- autoNotification: {
748
- begin: () => updateNotifications.begin({ owner: '*', profile: 'default', serverOwner: true }, 'webui').id,
749
- transition: (id, phase, expectedIdentity, verifiedIdentity, detail) => { updateNotifications.transition(id, phase, expectedIdentity, verifiedIdentity, detail); },
851
+ agentHomes,
852
+ ...(sidecar?.onHandshake ? { onAgentReconnect: (listener) => sidecar.onHandshake(listener) } : {}),
853
+ recoverAgent: async (probe = false, signal) => {
854
+ if (!sidecar)
855
+ throw new Error('Hermes Agent sidecar is unavailable for recovery.');
856
+ if (sidecar.status === 'starting' || sidecar.status === 'restarting' || sidecar.status === 'stopped')
857
+ throw new Error('Agent recovery is waiting for its sidecar connection.');
858
+ let result = await sidecar.call('runtime.agent_recovery', { probe }, { ...(signal ? { signal } : {}), timeoutMs: 660_000 });
859
+ if (signal?.aborted)
860
+ throw new Error('Agent recovery was cancelled.');
861
+ if (!probe && result.local_restore && result.revision)
862
+ recoveredAgentRevision = result.revision;
863
+ if (probe) {
864
+ if (pendingRuntimeRecovery?.fingerprint === result.fingerprint && restartBlockers().restart_blocked
865
+ && (sidecar.describe?.agent_revision !== recoveredAgentRevision || !sidecar.describe?.compatible)) {
866
+ return { ...result, waiting_for_idle: true, detail: 'Agent recovery is waiting for active Web work to finish before refreshing its runtime.' };
867
+ }
868
+ return result;
869
+ }
870
+ if (!result.ok || (result.owed && !result.runtime_pending))
871
+ return result;
872
+ if (result.revision)
873
+ recoveredAgentRevision = result.revision;
874
+ if (result.runtime_pending)
875
+ pendingRuntimeRecovery = result;
876
+ const runtime = await sidecar.call('runtime.status', {}, { ...(signal ? { signal } : {}), timeoutMs: 5000 });
877
+ if (signal?.aborted)
878
+ throw new Error('Agent recovery was cancelled.');
879
+ if (recoveredAgentRevision && (runtime.agent_revision !== recoveredAgentRevision || !runtime.compatible)) {
880
+ if (restartBlockers().restart_blocked)
881
+ return { ...result, waiting_for_idle: true, detail: 'Agent recovery is waiting for active Web work to finish before refreshing its runtime.' };
882
+ if (['ready', 'incompatible'].includes(sidecar.status))
883
+ sidecar.recycle('Verified retained Agent recovery requires the current interpreter and source');
884
+ throw new Error('Agent services recovered; waiting for the current sidecar runtime to become ready.');
885
+ }
886
+ if (result.runtime_pending && recoveredAgentRevision)
887
+ result = await sidecar.call('runtime.agent_recovery', { complete_revision: recoveredAgentRevision }, { ...(signal ? { signal } : {}), timeoutMs: 660_000 });
888
+ if (signal?.aborted || !result.ok || result.owed)
889
+ throw new Error(result.detail || 'Agent recovery remains recorded until loaded readiness is verified.');
890
+ await sidecar.call('runtime.ensure_current', {}, { ...(signal ? { signal } : {}), timeoutMs: 5000 });
891
+ if (signal?.aborted)
892
+ throw new Error('Agent recovery was cancelled.');
893
+ if (!runtime.compatible || runtime.stale)
894
+ throw new Error('Agent recovery has no matching loaded runtime evidence; admission remains closed.');
895
+ catalog.invalidate(undefined, undefined, { preserveConfirmed: true });
896
+ recoveredAgentRevision = null;
897
+ pendingRuntimeRecovery = null;
898
+ return result;
750
899
  },
751
- blockers: restartBlockers,
752
- scheduleRestart: () => { setTimeout(() => { void waitUntilRestartSafe(restartBlockers, { maxWaitMs: Infinity, log }).then(() => { deps.requestRestart(); }); }, 2000).unref(); },
753
- gatewayRestart: async () => {
900
+ recoveryChanged: (state) => updateNotifications.agentRecovery(state),
901
+ hasPendingRecovery: () => updateNotifications.hasPendingAgentRecovery(),
902
+ agentMutation: async (path, revision, mutate, consent) => {
754
903
  if (!sidecar)
755
904
  throw new Error('Hermes Agent sidecar is unavailable');
756
- return sidecar.call('gateway.restart', { profile_home: profileHome(activeProfile()) }, { timeoutMs: 300_000 });
905
+ const begin = await sidecar.call('runtime.agent_mutation', { action: 'begin', agent_dir: path, revision, homes: agentHomes(), ...(consent?.mutationIntent ? { intent: consent.mutationIntent } : {}), ...(consent?.refreshToken ? { refresh_token: consent.refreshToken } : {}) }, { timeoutMs: 330_000 });
906
+ if (begin.refresh_confirmation)
907
+ return { ok: false, refresh_confirmation: begin.refresh_confirmation, message: begin.detail };
908
+ if (!begin.ok || !begin.token)
909
+ throw new Error(begin.detail || 'Agent writer quiescence was not verified.');
910
+ const token = begin.token;
911
+ const leasedGit = async (args, cwd, timeoutMs = 10_000) => {
912
+ if (resolve(cwd) !== resolve(path))
913
+ throw new Error('Agent writer lease cannot mutate another checkout.');
914
+ const result = await sidecar.call('runtime.agent_mutation', { action: 'git', agent_dir: path, token, args, timeout_ms: timeoutMs }, { timeoutMs: 330_000 });
915
+ return { ok: result.ok, out: result.detail };
916
+ };
917
+ let result;
918
+ try {
919
+ result = await mutate(leasedGit, () => sidecar.call('runtime.agent_mutation', { action: 'sync', agent_dir: path, token }, { timeoutMs: 330_000 }));
920
+ }
921
+ catch (error) {
922
+ try {
923
+ await sidecar.call('runtime.agent_mutation', { action: 'finish', agent_dir: path, token }, { timeoutMs: 330_000 });
924
+ }
925
+ catch { /* The native pause journal retains any unverified recovery obligation. */ }
926
+ throw error;
927
+ }
928
+ const resumed = await sidecar.call('runtime.agent_mutation', { action: 'finish', agent_dir: path, token }, { timeoutMs: 330_000 });
929
+ return resumed.ok ? { ...result, ...(result.gateway_restart === 'waiting_for_idle' ? { gateway_restart: 'resumed' } : {}) }
930
+ : { ...result, ok: false, restart_scheduled: false, message: resumed.detail || 'Agent writer resume remains unverified; its recovery obligation is retained.' };
757
931
  },
932
+ agentSync: async (agentDir) => {
933
+ if (!sidecar)
934
+ throw new Error('Hermes Agent sidecar is unavailable');
935
+ return sidecar.call('runtime.sync_dependencies', { agent_dir: agentDir }, { timeoutMs: 330_000 });
936
+ },
937
+ channel: () => normalizeChannel(settings.peek().update_channel),
938
+ agentChannel: () => normalizeChannel(settings.peek().agent_update_channel),
939
+ includeAgent: () => !pyBool(settings.peek().ignore_agent_updates),
940
+ summarizeAutomatically: () => settings.peek().check_for_updates !== false && settings.peek().summarize_updates_automatically !== false,
941
+ autoApply: () => settings.peek().check_for_updates !== false && settings.peek().auto_apply_updates === true,
942
+ checkEnabled: () => !truthy(env.HERMES_WEBUI_TEST_NETWORK_BLOCK) && settings.peek().check_for_updates !== false,
943
+ autoNotification: {
944
+ begin: async () => (await updateNotifications.begin({ owner: '*', profile: 'default', serverOwner: true }, 'webui')).id,
945
+ transition: async (id, phase, expectedIdentity, verifiedIdentity, detail) => { (await updateNotifications.transition(id, phase, expectedIdentity, verifiedIdentity, detail)); },
946
+ },
947
+ blockers: restartBlockers,
948
+ scheduleRestart: () => { setTimeout(() => { void waitUntilRestartSafe(restartBlockers, { maxWaitMs: Infinity, log }).then(() => { deps.requestRestart(); }); }, 2000).unref(); },
949
+ gatewayRestarting: () => deps.gatewayRestarts.restarting(),
758
950
  llm: async (system, user) => {
759
- if (!sidecar || !pyBool(settings.load().whats_new_summary_enabled))
951
+ if (!sidecar)
760
952
  return '';
761
953
  const result = await sidecar.call('aux.complete', { profile_home: profileHome(activeProfile()), task: 'update_summary', messages: [{ role: 'system', content: system }, { role: 'user', content: user }] });
762
954
  return result.text;
763
955
  },
764
956
  log,
765
957
  });
958
+ deps.gatewayRestarts = new GatewayRestartQueue({
959
+ notifications: updateNotifications,
960
+ blockers: (profile) => gatewayRestartBlockers(config.hermesHome, profileHome(profile), now()),
961
+ updating: () => deps.updates.blocksNewWork(),
962
+ restart: async (profile) => {
963
+ if (!sidecar)
964
+ throw new Error('Hermes Agent sidecar is unavailable');
965
+ return restartGateway(sidecar, profileHome(profile));
966
+ },
967
+ log,
968
+ });
766
969
  return deps;
767
970
  }
768
971
  /** Python `_read_active_profile_file`: the sticky profile name, or `default` when absent, unreadable, or malformed. */
@@ -775,4 +978,10 @@ function readActiveProfileFile(hermesHome, pattern) {
775
978
  return 'default';
776
979
  }
777
980
  }
981
+ export function createStorage(config, now = () => Date.now() / 1000, profileHome = (name) => name === 'default' ? config.hermesHome : join(config.hermesHome, 'profiles', name)) {
982
+ if (config.storage !== 'json')
983
+ throw new Error(`Unknown TALARIA_STORAGE=${JSON.stringify(config.storage)}; supported backends: json`);
984
+ const storage = new JsonStorage({ directory: config.sessionDir, stateDir: config.stateDir, profileHome, env: config.env, now, stampingSince: async () => (await recoveryStampingSince(storage.documents)) });
985
+ return storage;
986
+ }
778
987
  //# sourceMappingURL=runtime.js.map