@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,1151 @@
1
+ /**
2
+ * Self-update (Python `api/updates.py` + `api/talaria_releases.py`, ticket §13).
3
+ *
4
+ * Web: a recognized clean Talaria checkout fast-forwards to the newest completed
5
+ * release set (stable) or `origin/main` (experimental) and stamps `web/_release.json`
6
+ * from immutable git blobs. npm builds and unrecognized checkouts report
7
+ * `manual_update`. Agent: the external checkout follows its own `v*` tags with a
8
+ * stash/pull or force reset, then the gateway restarts through the sidecar.
9
+ * Nothing here deletes git locks; `clearLock` only inventories them.
10
+ */
11
+ import { readCapped } from '../http/capped.js';
12
+ import { execFile } from 'node:child_process';
13
+ import { createHash } from 'node:crypto';
14
+ import { existsSync, lstatSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, unlinkSync, writeFileSync } from 'node:fs';
15
+ import { dirname, join, resolve } from 'node:path';
16
+ import { dict } from '../config/agent-config.js';
17
+ import { str } from '../util.js';
18
+ export const REPOSITORY = 'MaudeCode/talaria';
19
+ export const REPOSITORY_URL = `https://github.com/${REPOSITORY}`;
20
+ export const API_ROOT = `https://api.github.com/repos/${REPOSITORY}`;
21
+ /** Anchored paths work from both the git root and Web's nested working directory. */
22
+ export const WEB_UPDATE_PATHS = [':(top)web/', ':(top)contracts/'];
23
+ /** Relative to the git root: the release stamp and the blobs it is verified against. */
24
+ export const RELEASE_STAMP = 'web/_release.json';
25
+ const RELEASE_BLOBS = ['sidecar/agent_dependency.json', 'contract_versions.json'];
26
+ export const CACHE_TTL_S = 1800;
27
+ export const RESTART_MAX_WAIT_S = 300;
28
+ export const DEFAULT_CHANNEL = 'stable';
29
+ const SHA = /^[a-f0-9]{40}$/;
30
+ const VERSION = '(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)';
31
+ const AGENT_TAG_GLOB = 'v*';
32
+ const GIT_LOCK_SIGNATURES = ["index.lock': file exists", ".lock': file exists", 'another git process seems to be running', 'unable to create .git/index.lock'];
33
+ const NETWORK_FAILURES = ['could not resolve host', 'failed to connect', 'network is unreachable', 'no route to host', 'connection timed out', 'timed out after', 'connection reset by peer', 'remote end hung up unexpectedly', 'tls connection was non-properly terminated', 'ssl certificate problem'];
34
+ export const normalizeChannel = (channel) => (channel === 'experimental' ? 'experimental' : 'stable');
35
+ /** Python `_run_git`: stdout on success, else stderr/stdout/a status line, never a throw. */
36
+ export const runGit = (args, cwd, timeoutMs = 10_000) => new Promise((done) => {
37
+ execFile('git', args, { cwd, encoding: 'utf8', timeout: timeoutMs, maxBuffer: 16 * 1024 * 1024, env: { ...process.env, GIT_TERMINAL_PROMPT: '0' } }, (error, stdout, stderr) => {
38
+ const out = stdout.trim();
39
+ const err = stderr.trim();
40
+ if (!error) {
41
+ done({ out, ok: true });
42
+ return;
43
+ }
44
+ const e = error;
45
+ if (e.code === 'ENOENT') {
46
+ done({ out: 'git executable not found', ok: false });
47
+ return;
48
+ }
49
+ if (e.killed) {
50
+ done({ out: err || `git ${args.join(' ')} timed out after ${String(timeoutMs / 1000)}s`, ok: false });
51
+ return;
52
+ }
53
+ done({ out: err || out || `git exited with status ${String(e.code)}`, ok: false });
54
+ });
55
+ });
56
+ /** The steps a source checkout needs after its files change (README "From a source checkout"), run from `<root>/web`. */
57
+ export const WEB_BUILD_STEPS = [
58
+ ['ci', '--workspace', 'packages/contracts', '--workspace', 'packages/server', '--include=dev'],
59
+ ['run', 'build', '--workspace', 'packages/contracts'],
60
+ ['run', 'build', '--workspace', 'packages/server'],
61
+ ];
62
+ export const WEB_BUILD_TIMEOUT_MS = 10 * 60_000;
63
+ /** The artifact the supervisor re-executes; a build that does not leave it behind did not succeed. */
64
+ export const WEB_SERVER_ENTRY = 'packages/server/dist/bin/talaria-web.js';
65
+ export const runNpm = (args, cwd, timeoutMs) => new Promise((done) => {
66
+ // Prefer the npm beside the running node so a supervisor started with an absolute node path still finds it.
67
+ const beside = join(dirname(process.execPath), 'npm');
68
+ execFile(existsSync(beside) ? beside : 'npm', args, { cwd, encoding: 'utf8', timeout: timeoutMs, maxBuffer: 16 * 1024 * 1024, env: { ...process.env, NODE_ENV: 'development' } }, (error, stdout, stderr) => {
69
+ if (!error) {
70
+ done({ out: stdout.trim(), ok: true });
71
+ return;
72
+ }
73
+ const e = error;
74
+ if (e.code === 'ENOENT') {
75
+ done({ out: 'npm executable not found', ok: false });
76
+ return;
77
+ }
78
+ if (e.killed) {
79
+ done({ out: `npm ${args.join(' ')} timed out after ${String(timeoutMs / 1000)}s`, ok: false });
80
+ return;
81
+ }
82
+ done({ out: (stderr.trim() || stdout.trim() || `npm exited with status ${String(e.code)}`).slice(-4000), ok: false });
83
+ });
84
+ });
85
+ /** Install and build the checkout's Web packages; null on success, else the message for the caller. */
86
+ async function buildWeb(root, build) {
87
+ const cwd = join(root, 'web');
88
+ for (const step of WEB_BUILD_STEPS) {
89
+ const result = await build(step, cwd, WEB_BUILD_TIMEOUT_MS);
90
+ if (!result.ok)
91
+ return `\`npm ${step.join(' ')}\` failed: ${result.out || 'unknown error'}`;
92
+ }
93
+ if (!existsSync(join(cwd, WEB_SERVER_ENTRY)))
94
+ return `build finished without producing ${WEB_SERVER_ENTRY}`;
95
+ return null;
96
+ }
97
+ export const isGitLockError = (output) => { const l = output.toLowerCase(); return GIT_LOCK_SIGNATURES.some((s) => l.includes(s)); };
98
+ /** Python `_sanitize_git_diagnostic`: strip URL userinfo, GitHub token shapes, and secret query values. */
99
+ export function sanitizeGitDiagnostic(output, limit = 300) {
100
+ let s = output.replace(/([a-zA-Z][a-zA-Z0-9+.-]*:\/\/)([^/@\s'"]+)@/g, '$1<redacted>@');
101
+ s = s.replace(/\b(?:gh[pousr]_[A-Za-z0-9_]{20,}|github_pat_[A-Za-z0-9_]{20,})\b/g, '<redacted>');
102
+ s = s.replace(/([?&](?:access_token|oauth_token|private_token|client_secret|app_secret|api[_-]?key|token|password|secret|auth|key)=)[^&\s'"]+/gi, '$1<redacted>').trim();
103
+ return s.length > limit ? `${s.slice(0, limit).trimEnd()}…` : s;
104
+ }
105
+ function fetchFailureMessage(out, network) {
106
+ const detail = sanitizeGitDiagnostic(out);
107
+ if (!detail)
108
+ return network;
109
+ const lower = detail.toLowerCase();
110
+ return NETWORK_FAILURES.some((s) => lower.includes(s)) ? network : `fetch failed: ${detail}`;
111
+ }
112
+ function gitFailure(out, message) {
113
+ if (isGitLockError(out))
114
+ return { ok: false, lock_conflict: true, message: 'Web update is blocked by a repository lock. Wait for the other Git operation or inspect the checkout manually.' };
115
+ return { ok: false, message };
116
+ }
117
+ function normalizeRemoteUrl(remote) {
118
+ let url = remote.trim();
119
+ if (!url)
120
+ return url;
121
+ if (url.startsWith('git@'))
122
+ url = url.replace(':', '/').replace('git@', 'https://');
123
+ url = url.replace(/\/+$/, '');
124
+ if (url.endsWith('.git'))
125
+ url = url.slice(0, -4);
126
+ return url.replace(/\/+$/, '');
127
+ }
128
+ function compareUrl(repoUrl, current, latest) {
129
+ if (!repoUrl || !current || !latest)
130
+ return null;
131
+ try {
132
+ const u = new URL(repoUrl);
133
+ if (u.protocol !== 'http:' && u.protocol !== 'https:')
134
+ return null;
135
+ }
136
+ catch {
137
+ return null;
138
+ }
139
+ return `${repoUrl}/compare/${current}...${latest}`;
140
+ }
141
+ const canon = (value) => JSON.stringify(sortKeys(value));
142
+ function sortKeys(value) {
143
+ if (Array.isArray(value))
144
+ return value.map(sortKeys);
145
+ if (value && typeof value === 'object')
146
+ return Object.fromEntries(Object.keys(value).sort().map((k) => [k, sortKeys(value[k])]));
147
+ return value;
148
+ }
149
+ const same = (a, b) => canon(a) === canon(b);
150
+ // ── published release sets ───────────────────────────────────────────────────
151
+ export class ReleaseUnavailable extends Error {
152
+ }
153
+ /** GitHub API client: opt-in `TALARIA_RELEASE_TOKEN`, 2 MB cap, and asset redirects only to GitHub's release host with the token stripped. */
154
+ export function githubJson(fetchImpl, env) {
155
+ return async (path, { asset }) => {
156
+ const headers = { Accept: asset ? 'application/octet-stream' : 'application/vnd.github+json', 'User-Agent': 'Talaria-Web', 'X-GitHub-Api-Version': '2026-03-10' };
157
+ const token = (env.TALARIA_RELEASE_TOKEN ?? '').trim();
158
+ if (token)
159
+ headers.Authorization = `Bearer ${token}`;
160
+ let res = await fetchImpl(API_ROOT + path, { headers, redirect: 'manual', signal: AbortSignal.timeout(5000) });
161
+ if (res.status >= 300 && res.status < 400) {
162
+ const target = new URL(res.headers.get('location') ?? '', API_ROOT + path);
163
+ if (target.protocol !== 'https:' || target.hostname !== 'release-assets.githubusercontent.com')
164
+ throw new ReleaseUnavailable('Unexpected release download redirect');
165
+ const anonymous = { ...headers };
166
+ delete anonymous.Authorization;
167
+ res = await fetchImpl(target.toString(), { headers: anonymous, signal: AbortSignal.timeout(5000) });
168
+ }
169
+ if (!res.ok)
170
+ throw new ReleaseUnavailable(`GitHub answered ${String(res.status)}`);
171
+ const body = await readCapped(res, 2_000_000);
172
+ if (!body)
173
+ throw new ReleaseUnavailable('Release metadata exceeds the download limit');
174
+ return JSON.parse(body.toString('utf8'));
175
+ };
176
+ }
177
+ /** Python `published_web_release`: the newest completed `release-set-<sha>` whose Web component matches the channel's tag family. */
178
+ export async function publishedWebRelease(channel, getJson, now = () => performance.now()) {
179
+ const tagPattern = new RegExp(`^${channel === 'experimental' ? 'web-exp-v' : 'web-v'}${VERSION}$`);
180
+ const deadline = now() + 15_000;
181
+ const fetchJson = (path, asset = false) => {
182
+ if (now() >= deadline)
183
+ throw new ReleaseUnavailable('Release lookup exceeded its deadline; retry or update manually');
184
+ return getJson(path, { asset });
185
+ };
186
+ const published = [];
187
+ let exhausted = true;
188
+ for (let page = 1; page <= 5; page += 1) {
189
+ const releases = await fetchJson(`/releases?per_page=100&page=${String(page)}`);
190
+ if (!Array.isArray(releases))
191
+ throw new ReleaseUnavailable('Invalid published release list');
192
+ for (const item of releases)
193
+ if (item && typeof item === 'object' && !item.draft && typeof item.published_at === 'string')
194
+ published.push(item);
195
+ if (releases.length < 100) {
196
+ exhausted = false;
197
+ break;
198
+ }
199
+ }
200
+ if (exhausted)
201
+ throw new ReleaseUnavailable('Release history exceeds automatic lookup; update manually');
202
+ published.sort((a, b) => (str(a.published_at) < str(b.published_at) ? 1 : str(a.published_at) > str(b.published_at) ? -1 : 0));
203
+ for (const release of published) {
204
+ const tag = release.tag_name;
205
+ if (typeof tag !== 'string' || !/^release-set-[a-f0-9]{40}$/.test(tag))
206
+ continue;
207
+ if (!Array.isArray(release.assets))
208
+ throw new ReleaseUnavailable('Published release set has invalid assets');
209
+ const assets = release.assets.filter((a) => Boolean(a) && typeof a === 'object' && a.name === 'release-set.json');
210
+ const id = assets[0]?.id;
211
+ if (assets.length !== 1 || typeof id !== 'number' || !Number.isInteger(id) || id < 1)
212
+ throw new ReleaseUnavailable('Published release set lacks its immutable manifest');
213
+ const manifest = await fetchJson(`/releases/assets/${String(id)}`, true);
214
+ const m = manifest && typeof manifest === 'object' && !Array.isArray(manifest) ? manifest : null;
215
+ if (m?.schemaVersion !== 1 || m.status !== 'complete' || m.releaseSet !== tag.slice('release-set-'.length))
216
+ throw new ReleaseUnavailable('Release set is incomplete or has inconsistent provenance');
217
+ if (!m.components || typeof m.components !== 'object' || Array.isArray(m.components))
218
+ throw new ReleaseUnavailable('Release set lacks component metadata');
219
+ const componentRaw = m.components.web ?? {};
220
+ if (!componentRaw || typeof componentRaw !== 'object' || Array.isArray(componentRaw))
221
+ throw new ReleaseUnavailable('Release set lacks Web metadata');
222
+ const component = componentRaw;
223
+ const componentTag = component.tag;
224
+ if (typeof componentTag !== 'string' || !tagPattern.test(componentTag))
225
+ continue;
226
+ const source = component.sourceRevision;
227
+ if (typeof source !== 'string' || !SHA.test(source) || component.releaseSet !== source || component.version !== componentTag.split('-v').pop() || typeof component.image !== 'string' || !/^ghcr\.io\/maudecode\/talaria-web@sha256:[a-f0-9]{64}$/.test(component.image)) {
228
+ throw new ReleaseUnavailable('Web release references are mutable or inconsistent');
229
+ }
230
+ const contracts = dict(m.contracts);
231
+ const supported = {};
232
+ for (const name of ['appWeb', 'webRelay']) {
233
+ const items = dict(contracts[name]).web;
234
+ if (!Array.isArray(items) || !items.length || !items.every((v) => Number.isInteger(v) && v > 0))
235
+ throw new ReleaseUnavailable('Release set lacks Web compatibility provenance');
236
+ supported[name] = items;
237
+ }
238
+ const agent = m.agent;
239
+ if (!agent || typeof agent !== 'object' || Array.isArray(agent))
240
+ throw new ReleaseUnavailable('Release set lacks Web compatibility provenance');
241
+ return {
242
+ ...component,
243
+ tag: componentTag,
244
+ version: str(component.version),
245
+ sourceRevision: source,
246
+ releaseSet: source,
247
+ image: component.image,
248
+ manifestReleaseSet: str(m.releaseSet),
249
+ runtime: { tag: componentTag, version: component.version, sourceRevision: source, releaseSet: source, contracts: supported, compatibleAgent: agent },
250
+ release_url: `${REPOSITORY_URL}/releases/tag/${tag}`,
251
+ };
252
+ }
253
+ throw new ReleaseUnavailable('No completed Talaria Web release is available on this channel');
254
+ }
255
+ // ── Web checkout ─────────────────────────────────────────────────────────────
256
+ /** The git root when `webRoot` is `<root>/web` of a Talaria checkout with a GitHub `maudecode/talaria` origin; else null. */
257
+ export async function checkoutRoot(webRoot, git) {
258
+ if (!webRoot || !existsSync(webRoot))
259
+ return null;
260
+ const web = realpathSync(webRoot);
261
+ const top = await git(['rev-parse', '--show-toplevel'], web);
262
+ if (!top.ok || !top.out || resolve(realpathSync(top.out), 'web') !== web)
263
+ return null;
264
+ const root = realpathSync(top.out);
265
+ if (!existsSync(join(root, 'contracts', 'versions.json')) || !existsSync(join(web, 'package.json')))
266
+ return null;
267
+ const remote = await git(['remote', 'get-url', 'origin'], root);
268
+ if (!remote.ok)
269
+ return null;
270
+ const normalized = remote.out.trim().replace(/\/+$/, '').replace(/\.git$/, '').toLowerCase();
271
+ if (normalized === 'git@github.com:maudecode/talaria')
272
+ return root;
273
+ try {
274
+ const u = new URL(normalized);
275
+ const port = u.port === '' ? null : u.port;
276
+ if ((u.protocol !== 'https:' && u.protocol !== 'ssh:') || u.hostname !== 'github.com' || u.pathname !== '/maudecode/talaria' || u.search || u.hash)
277
+ return null;
278
+ if (port !== null && port !== (u.protocol === 'https:' ? '443' : '22'))
279
+ return null;
280
+ return root;
281
+ }
282
+ catch {
283
+ return null;
284
+ }
285
+ }
286
+ /** Python `verify_release_source`: the stamp Web expects for `release`, computed from immutable blobs at its source revision. */
287
+ export async function verifyReleaseSource(root, release, git) {
288
+ const files = {};
289
+ for (const name of RELEASE_BLOBS) {
290
+ const shown = await git(['show', `${release.sourceRevision}:web/${name}`], root);
291
+ if (!shown.ok)
292
+ throw new Error('missing release metadata');
293
+ files[name] = JSON.parse(shown.out);
294
+ }
295
+ const pin = dict(files['sidecar/agent_dependency.json']);
296
+ const versions = dict(files['contract_versions.json']);
297
+ const expected = {
298
+ tag: release.tag,
299
+ version: release.version,
300
+ sourceRevision: release.sourceRevision,
301
+ releaseSet: release.sourceRevision,
302
+ contracts: { appWeb: [dict(versions.appWeb).fixtureVersion], webRelay: [dict(versions.webRelay).protocolVersion] },
303
+ compatibleAgent: { ...dict(pin['x-talaria']), image: dict(dict(pin.services)['hermes-agent']).image },
304
+ };
305
+ if (!same(expected, release.runtime))
306
+ throw new Error('release metadata differs from source');
307
+ return expected;
308
+ }
309
+ const stampPath = (root) => join(root, RELEASE_STAMP);
310
+ const readStamp = (path) => {
311
+ if (!existsSync(path) && !isSymlink(path))
312
+ return null;
313
+ if (isSymlink(path))
314
+ throw new Error('local release stamp is a symbolic link');
315
+ return readFileSync(path, 'utf8');
316
+ };
317
+ const isSymlink = (path) => { try {
318
+ return lstatSync(path).isSymbolicLink();
319
+ }
320
+ catch {
321
+ return false;
322
+ } };
323
+ /** Python `_verified_release_stamp`: `[expected, installed]`; throws on a modified stamp. */
324
+ async function verifiedReleaseStamp(root, release, git, id) {
325
+ const expected = await verifyReleaseSource(root, release, git);
326
+ const raw = readStamp(stampPath(root));
327
+ const installed = raw === null ? null : JSON.parse(raw);
328
+ if (installed !== null && ![id.release(), id.stamped(), expected].some((c) => same(c, installed)))
329
+ throw new Error('local release stamp was modified');
330
+ return [expected, installed];
331
+ }
332
+ /** Python `_main_stamp`: the unchanged generated stamp bytes (to discard when leaving a release), else null. */
333
+ function mainStamp(root, id) {
334
+ const data = readStamp(stampPath(root));
335
+ if (data !== null && (!id.stamped().tag || !same(JSON.parse(data), id.stamped())))
336
+ throw new Error('local release stamp was modified');
337
+ return data;
338
+ }
339
+ async function mainRevision(root, git) {
340
+ const fetched = await git(['fetch', '--no-tags', 'origin', 'refs/heads/main:refs/remotes/origin/main'], root, 30_000);
341
+ if (!fetched.ok)
342
+ return [null, fetched.out];
343
+ const source = await git(['rev-parse', 'refs/remotes/origin/main^{commit}'], root);
344
+ return source.ok && SHA.test(source.out) ? [source.out, ''] : [null, ''];
345
+ }
346
+ async function mainPathsDiffer(root, before, after, git) {
347
+ const files = await git(['diff', '--no-renames', '--name-only', before, after, '--', ...WEB_UPDATE_PATHS], root);
348
+ return files.ok ? Boolean(files.out) : null;
349
+ }
350
+ async function mainChangeCount(root, before, after, git) {
351
+ const changed = await mainPathsDiffer(root, before, after, git);
352
+ if (changed === null)
353
+ return null;
354
+ if (!changed)
355
+ return 0;
356
+ const count = await git(['rev-list', '--count', '--full-history', `${before}..${after}`, '--', ...WEB_UPDATE_PATHS], root);
357
+ const n = Number.parseInt(count.out, 10);
358
+ return count.ok && /^\d+$/.test(count.out) && n > 0 ? n : null;
359
+ }
360
+ async function mainRestartPending(root, head, git, id) {
361
+ const running = id.runningSourceRevision();
362
+ if (running === head)
363
+ return false;
364
+ if (!running)
365
+ return true;
366
+ return (await mainPathsDiffer(root, running, head, git)) !== false;
367
+ }
368
+ async function checkMainUpdate(root, result, git, id) {
369
+ Object.assign(result, { branch: 'origin/main', release_based: false });
370
+ if (root === null)
371
+ return { ...result, manual_update: true, message: 'Main updates require an authenticated Talaria source checkout with Web under web/.' };
372
+ const [source, error] = await mainRevision(root, git);
373
+ if (source === null)
374
+ return { ...result, error: gitFailure(error, 'Could not fetch origin/main; check Git read access.').message };
375
+ Object.assign(result, { latest_sha: source, latest_version: `main@${source.slice(0, 12)}` });
376
+ const head = await git(['rev-parse', 'HEAD'], root);
377
+ const status = await git(['status', '--porcelain', '--untracked-files=all'], root);
378
+ if (!head.ok || !SHA.test(head.out) || !status.ok)
379
+ return { ...result, manual_update: true, error: 'Could not verify the source checkout' };
380
+ Object.assign(result, { installed_sha: head.out, dirty: Boolean(status.out) });
381
+ const base = await git(['merge-base', head.out, source], root);
382
+ result.current_sha = base.ok && SHA.test(base.out) ? base.out : null;
383
+ if (result.current_sha)
384
+ result.compare_url = `${REPOSITORY_URL}/compare/${base.out}...${source}`;
385
+ if (!base.ok || base.out !== head.out)
386
+ return { ...result, manual_update: true, message: 'This checkout is ahead of or diverged from origin/main; reconcile it manually.' };
387
+ const count = await mainChangeCount(root, head.out, source, git);
388
+ if (count === null)
389
+ return { ...result, error: 'Could not compare the source checkout with origin/main' };
390
+ try {
391
+ mainStamp(root, id);
392
+ }
393
+ catch {
394
+ return { ...result, manual_update: true, error: 'Inspect the modified release stamp before updating.' };
395
+ }
396
+ Object.assign(result, { behind: count, metadata_repair: count === 0 && (await mainRestartPending(root, head.out, git, id)) });
397
+ if (status.out)
398
+ Object.assign(result, { manual_update: true, message: 'Commit or remove local changes before updating; Web updates never discard them.' });
399
+ else if (result.metadata_repair)
400
+ result.message = 'Source is current; finish the update to restart with that revision.';
401
+ return result;
402
+ }
403
+ /** Python `check_web_update`. */
404
+ export async function checkWebUpdate(webRoot, currentVersion, channel, git, getJson, id) {
405
+ const root = await checkoutRoot(webRoot, git);
406
+ const result = { name: 'webui', channel, repo_url: REPOSITORY_URL, current_version: currentVersion, behind: null, no_git: root === null };
407
+ if (channel === 'experimental' && root !== null)
408
+ return checkMainUpdate(root, result, git, id);
409
+ let release;
410
+ try {
411
+ release = await publishedWebRelease(channel, getJson);
412
+ }
413
+ catch (error) {
414
+ if (error instanceof ReleaseUnavailable)
415
+ return { ...result, manual_update: true, error: error.message };
416
+ return { ...result, manual_update: true, error: 'Talaria release metadata is unavailable. Private repositories require TALARIA_RELEASE_TOKEN with Contents read access.' };
417
+ }
418
+ Object.assign(result, { latest_version: release.tag, latest_sha: release.sourceRevision, branch: release.tag, release_based: true, release_url: release.release_url, image: release.image });
419
+ if (root === null) {
420
+ const current = id.release().sourceRevision ?? null;
421
+ const version = new RegExp(`^${channel === 'experimental' ? 'web-exp-v' : 'web-v'}${VERSION}$`).exec(currentVersion);
422
+ let behind = version && current === release.sourceRevision ? 0 : null;
423
+ if (behind === null && version) {
424
+ const installed = version.slice(1).map(Number);
425
+ const latest = release.version.split('.').map(Number);
426
+ const cmp = installed.map((v, i) => Math.sign(v - (latest[i] ?? 0))).find((s) => s !== 0) ?? 0;
427
+ if (cmp !== 0)
428
+ behind = cmp < 0 ? 1 : 0;
429
+ }
430
+ return { ...result, current_sha: current, behind, no_git: true, manual_update: true, message: 'Use the published Talaria Web image or authenticated monorepo installation; legacy checkouts require migration.' };
431
+ }
432
+ const head = await git(['rev-parse', 'HEAD'], root);
433
+ const status = await git(['status', '--porcelain', '--untracked-files=all'], root);
434
+ if (!head.ok || !SHA.test(head.out) || !status.ok)
435
+ return { ...result, manual_update: true, error: 'Could not verify the source checkout' };
436
+ const current = head.out;
437
+ Object.assign(result, { installed_sha: current, dirty: Boolean(status.out) });
438
+ let base;
439
+ let knownBase;
440
+ if (current === release.sourceRevision) {
441
+ try {
442
+ const [expected, installed] = await verifiedReleaseStamp(root, release, git, id);
443
+ result.behind = 0;
444
+ result.metadata_repair = !same(installed, expected) || !same(id.release(), expected);
445
+ if (result.metadata_repair)
446
+ result.message = 'Apply the selected release again to repair its metadata or restart with its recorded identity.';
447
+ }
448
+ catch {
449
+ Object.assign(result, { behind: null, manual_update: true, error: 'Could not verify local release provenance; inspect the release stamp before updating.' });
450
+ }
451
+ base = current;
452
+ knownBase = true;
453
+ }
454
+ else {
455
+ const contains = await git(['merge-base', '--is-ancestor', release.sourceRevision, current], root);
456
+ if (contains.ok)
457
+ return { ...result, behind: null, manual_update: true, current_sha: null, message: 'This checkout is ahead of the selected release. Manage it manually or check out the published release and restart Web.' };
458
+ result.behind = 1;
459
+ const mb = await git(['merge-base', current, release.sourceRevision], root);
460
+ base = mb.out;
461
+ knownBase = mb.ok;
462
+ if (knownBase && base !== current)
463
+ Object.assign(result, { manual_update: true, message: 'Reconcile divergent source history before updating Web.' });
464
+ }
465
+ // Local-only commits cannot appear in a GitHub comparison; omit unresolvable links.
466
+ result.current_sha = knownBase && SHA.test(base) ? base : null;
467
+ if (result.current_sha)
468
+ result.compare_url = `${REPOSITORY_URL}/compare/${base}...${release.sourceRevision}`;
469
+ if (status.out)
470
+ Object.assign(result, { manual_update: true, message: 'Commit or remove local changes before updating; Web updates never discard them.' });
471
+ return result;
472
+ }
473
+ /** Python `apply_web_update`: fast-forward a recognized clean checkout to main or a published Stable tag. */
474
+ export async function applyWebUpdate(webRoot, channel, git, getJson, id, build = runNpm) {
475
+ const root = await checkoutRoot(webRoot, git);
476
+ if (root === null)
477
+ return { ok: false, manual_update: true, message: 'Automatic updates require a Talaria monorepo checkout with Web under web/. Migrate this installation manually.' };
478
+ const status = await git(['status', '--porcelain', '--untracked-files=all'], root);
479
+ if (!status.ok || status.out)
480
+ return { ok: false, dirty: true, message: 'Web update refused: the checkout must be clean, including untracked files.' };
481
+ for (const marker of ['MERGE_HEAD', 'CHERRY_PICK_HEAD', 'REVERT_HEAD', 'rebase-merge', 'rebase-apply', 'BISECT_LOG']) {
482
+ const path = await git(['rev-parse', '--git-path', marker], root);
483
+ if (!path.ok || existsSync(resolve(root, path.out)))
484
+ return { ok: false, message: 'Finish or abort the repository operation before updating Web.' };
485
+ }
486
+ const headRes = await git(['rev-parse', 'HEAD'], root);
487
+ if (!headRes.ok || !SHA.test(headRes.out))
488
+ return { ok: false, message: 'Could not verify the current source revision' };
489
+ const head = headRes.out;
490
+ const main = channel === 'experimental';
491
+ let source;
492
+ let tag;
493
+ let release = null;
494
+ if (main) {
495
+ const [revision, error] = await mainRevision(root, git);
496
+ if (revision === null)
497
+ return gitFailure(error, 'Could not fetch origin/main; check Git read access.');
498
+ source = revision;
499
+ tag = 'main';
500
+ }
501
+ else {
502
+ try {
503
+ release = await publishedWebRelease(channel, getJson);
504
+ }
505
+ catch {
506
+ return { ok: false, message: 'Cannot resolve a completed Talaria release. Check private-repository read access.' };
507
+ }
508
+ source = release.sourceRevision;
509
+ tag = release.tag;
510
+ }
511
+ if (head !== source && !main) {
512
+ // Fetch only this immutable tag; never force-replace a local tag or pull an unrecorded tip.
513
+ const fetched = await git(['fetch', '--no-tags', 'origin', `refs/tags/${tag}:refs/tags/${tag}`], root, 30_000);
514
+ if (!fetched.ok)
515
+ return gitFailure(fetched.out, 'Could not fetch the published Web tag. Check Git credentials or a conflicting local tag.');
516
+ const resolved = await git(['rev-parse', `refs/tags/${tag}^{commit}`], root);
517
+ if (!resolved.ok || resolved.out !== source)
518
+ return { ok: false, message: 'Published Web tag does not match the immutable release manifest' };
519
+ }
520
+ if (head !== source) {
521
+ const forward = await git(['merge-base', '--is-ancestor', head, source], root);
522
+ if (!forward.ok) {
523
+ const contains = await git(['merge-base', '--is-ancestor', source, head], root);
524
+ if (contains.ok)
525
+ return { ok: false, manual_update: true, target: 'webui', channel, message: 'This checkout is ahead of the selected source. Manage it manually; updates never rewind local work.' };
526
+ return { ok: false, message: 'Web update refused: source histories diverge; reconcile the checkout manually.' };
527
+ }
528
+ }
529
+ if (main) {
530
+ const count = await mainChangeCount(root, head, source, git);
531
+ if (count === null)
532
+ return { ok: false, message: 'Could not compare Web and contract changes against origin/main.' };
533
+ if (count === 0)
534
+ source = head; // No checkout mutation for App/Relay-only changes.
535
+ }
536
+ // Compare provenance with the immutable incoming files before modifying the checkout.
537
+ let expected = null;
538
+ let installed;
539
+ try {
540
+ if (main)
541
+ installed = mainStamp(root, id);
542
+ else
543
+ [expected, installed] = await verifiedReleaseStamp(root, release, git, id);
544
+ }
545
+ catch {
546
+ return { ok: false, message: 'Web update refused: source or local provenance does not match the release manifest.' };
547
+ }
548
+ const runtimeCurrent = main ? !(await mainRestartPending(root, head, git, id)) : same(installed, expected) && same(id.release(), expected);
549
+ if (head === source && runtimeCurrent)
550
+ return { ok: true, up_to_date: true, target: 'webui', channel, message: main ? 'Web and shared contracts are current on main.' : 'Talaria Web already contains the selected release.' };
551
+ const again = await git(['rev-parse', 'HEAD'], root);
552
+ const clean = await git(['status', '--porcelain', '--untracked-files=all'], root);
553
+ if (!again.ok || again.out !== head || !clean.ok || clean.out)
554
+ return { ok: false, message: 'The checkout changed during the update; retry after it is clean.' };
555
+ if (head !== source) {
556
+ const merged = await git(['merge', '--ff-only', '--no-stat', '--no-overwrite-ignore', source], root, 30_000);
557
+ const actual = await git(['rev-parse', 'HEAD'], root);
558
+ if (!merged.ok || !actual.ok || actual.out !== source)
559
+ return gitFailure(merged.out, 'Web fast-forward failed; no local changes were discarded.');
560
+ }
561
+ // The supervisor re-executes the built artifact, so the checkout is installed and rebuilt before the stamp claims
562
+ // the new release; a failed build leaves the old stamp (and the running server) truthful.
563
+ const buildError = await buildWeb(root, build);
564
+ if (buildError !== null)
565
+ return { ok: false, build_failed: true, target: 'webui', channel, sourceRevision: source, message: `Source advanced to ${tag}, but the Web build failed: ${buildError}. Run \`npm ci\` and \`npm run build\` in web/ (see README), then restart Web.` };
566
+ const stamp = stampPath(root);
567
+ if (main && installed !== null) {
568
+ try {
569
+ if (isSymlink(stamp) || readFileSync(stamp, 'utf8') !== installed)
570
+ throw new Error('release stamp changed during update');
571
+ unlinkSync(stamp);
572
+ }
573
+ catch {
574
+ return { ok: false, message: 'Source advanced but its release stamp could not be cleared; inspect it before restarting Web.' };
575
+ }
576
+ }
577
+ else if (!main && !same(installed, expected)) {
578
+ const temporary = join(dirname(stamp), `.release-${String(process.pid)}-${String(Date.now())}`);
579
+ try {
580
+ writeFileSync(temporary, `${JSON.stringify(expected, null, 2)}\n`);
581
+ renameSync(temporary, stamp);
582
+ }
583
+ catch {
584
+ rmSync(temporary, { force: true });
585
+ return { ok: false, message: 'Source advanced, but release metadata could not be written. Repair file permissions before restarting Web.' };
586
+ }
587
+ }
588
+ return { ok: true, target: 'webui', channel, sourceRevision: source, message: `Updated Talaria Web to ${tag}.` };
589
+ }
590
+ // ── Agent checkout (external project, `v*` tags, stable only) ────────────────
591
+ async function releaseTags(path, git) {
592
+ const out = await git(['tag', '--list', AGENT_TAG_GLOB, '--sort=-v:refname'], path);
593
+ return out.ok ? out.out.split('\n').map((l) => l.trim()).filter(Boolean) : [];
594
+ }
595
+ async function currentReleaseTag(path, git) {
596
+ const out = await git(['describe', '--tags', '--abbrev=0', '--match', AGENT_TAG_GLOB], path);
597
+ return out.ok && out.out ? out.out : null;
598
+ }
599
+ const releaseGap = (tags, current, latest) => (current === latest ? 0 : current !== null && tags.includes(current) ? tags.indexOf(current) : 1);
600
+ async function headIsPastLatestTag(path, current, git) {
601
+ if (!current)
602
+ return false;
603
+ const full = await git(['describe', '--tags', '--always', '--match', AGENT_TAG_GLOB], path);
604
+ return full.ok && Boolean(full.out) && full.out !== current;
605
+ }
606
+ const headContainsRef = async (path, ref, git) => (await git(['merge-base', '--is-ancestor', ref, 'HEAD'], path)).ok;
607
+ const canFastForwardTo = async (path, ref, git) => (await git(['merge-base', '--is-ancestor', 'HEAD', ref], path)).ok;
608
+ async function detectDefaultBranch(path, git) {
609
+ const out = await git(['symbolic-ref', 'refs/remotes/origin/HEAD'], path);
610
+ if (out.ok && out.out)
611
+ return out.out.split('/').pop() ?? 'master';
612
+ for (const branch of ['master', 'main'])
613
+ if ((await git(['rev-parse', '--verify', `origin/${branch}`], path)).ok)
614
+ return branch;
615
+ return 'master';
616
+ }
617
+ async function upstreamRef(path, git) {
618
+ const upstream = await git(['rev-parse', '--abbrev-ref', '@{upstream}'], path);
619
+ return upstream.ok && upstream.out ? upstream.out : `origin/${await detectDefaultBranch(path, git)}`;
620
+ }
621
+ /** Python `_select_apply_compare_ref` for the Agent: the latest reachable `v*` tag, else the tracking branch. */
622
+ async function selectAgentCompareRef(path, git) {
623
+ const tags = await releaseTags(path, git);
624
+ const latest = tags[0];
625
+ if (latest) {
626
+ const current = await currentReleaseTag(path, git);
627
+ const behind = releaseGap(tags, current, latest);
628
+ const fallthrough = (behind === 0 && (await headIsPastLatestTag(path, current, git))) || (behind > 0 && (await headContainsRef(path, latest, git))) || (behind > 0 && !(await canFastForwardTo(path, latest, git)));
629
+ if (!fallthrough)
630
+ return latest;
631
+ }
632
+ return upstreamRef(path, git);
633
+ }
634
+ async function checkAgentRelease(path, git) {
635
+ const tags = await releaseTags(path, git);
636
+ const latest = tags[0];
637
+ if (!latest)
638
+ return null;
639
+ const current = await currentReleaseTag(path, git);
640
+ let behind = releaseGap(tags, current, latest);
641
+ if (current === null) {
642
+ const ahead = await git(['tag', '--list', AGENT_TAG_GLOB, '--contains', 'HEAD'], path);
643
+ const count = ahead.ok ? ahead.out.split('\n').filter((l) => l.trim()).length : 0;
644
+ if (count > 0)
645
+ behind = count;
646
+ }
647
+ if (behind === 0 && (await headIsPastLatestTag(path, current, git)))
648
+ return null;
649
+ if (behind > 0 && (await headContainsRef(path, latest, git)))
650
+ return null;
651
+ if (behind > 0 && !(await canFastForwardTo(path, latest, git)))
652
+ return null;
653
+ const remote = normalizeRemoteUrl((await git(['remote', 'get-url', 'origin'], path)).out);
654
+ return { name: 'agent', behind, current_sha: current, latest_sha: latest, branch: latest, repo_url: remote, release_based: true, current_version: current, latest_version: latest, channel: DEFAULT_CHANNEL };
655
+ }
656
+ async function checkAgentBranch(path, git) {
657
+ const ref = await upstreamRef(path, git);
658
+ const count = await git(['rev-list', '--count', `HEAD..${ref}`], path);
659
+ const behind = count.ok && /^\d+$/.test(count.out) ? Number.parseInt(count.out, 10) : 0;
660
+ const mb = await git(['merge-base', 'HEAD', ref], path);
661
+ let current = null;
662
+ if (mb.ok && mb.out) {
663
+ const short = await git(['rev-parse', '--short', mb.out], path);
664
+ current = short.ok && short.out ? short.out : null;
665
+ }
666
+ const latest = (await git(['rev-parse', '--short', ref], path)).out;
667
+ const remote = normalizeRemoteUrl((await git(['remote', 'get-url', 'origin'], path)).out);
668
+ return { name: 'agent', behind, current_sha: current, latest_sha: latest, branch: ref, repo_url: remote, compare_url: compareUrl(remote, current, latest) };
669
+ }
670
+ async function isDirty(path, git) {
671
+ const out = await git(['diff-index', '--quiet', 'HEAD', '--'], path, 1000);
672
+ return !out.ok && (out.out === 'git exited with status 1' || !out.out || out.out.startsWith('git exited with status '));
673
+ }
674
+ /** Python `_check_repo` for the Agent checkout: fetch tags, prefer the release view, else the branch view. */
675
+ export async function checkAgentUpdate(path, git) {
676
+ if (!path || !existsSync(join(path, '.git')))
677
+ return { name: 'agent', behind: null, no_git: true };
678
+ const fetched = await git(['fetch', 'origin', '--tags', '--force'], path, 15_000);
679
+ if (!fetched.ok) {
680
+ const message = fetched.out ? `fetch failed: ${sanitizeGitDiagnostic(fetched.out)}` : 'fetch failed';
681
+ const info = (await checkAgentRelease(path, git)) ?? { name: 'agent', behind: null };
682
+ return { ...info, error: message, stale_check: true, dirty: await isDirty(path, git) };
683
+ }
684
+ const info = (await checkAgentRelease(path, git)) ?? { ...(await checkAgentBranch(path, git)), channel: DEFAULT_CHANNEL };
685
+ return { ...info, dirty: await isDirty(path, git) };
686
+ }
687
+ /** Python `_apply_update_inner` (agent branch): fetch, stash, `pull --ff-only`, pop. */
688
+ export async function applyAgentUpdate(path, git) {
689
+ if (!path || !existsSync(join(path, '.git')))
690
+ return { ok: false, message: 'Not a git repository' };
691
+ const fetched = await git(['fetch', 'origin', '--quiet', '--tags', '--force'], path, 15_000);
692
+ if (!fetched.ok) {
693
+ if (isGitLockError(fetched.out))
694
+ return { ok: false, message: `Fetch failed due to a repository lock: ${fetched.out.trim()}`, lock_conflict: true };
695
+ return { ok: false, message: fetchFailureMessage(fetched.out, 'Could not reach the remote repository. Check your internet connection and try again.') };
696
+ }
697
+ const ref = await selectAgentCompareRef(path, git);
698
+ const status = await git(['status', '--porcelain', '--untracked-files=no'], path);
699
+ if (!status.ok) {
700
+ if (isGitLockError(status.out))
701
+ return { ok: false, message: `Failed to inspect repo status due to a repository lock: ${status.out.trim()}`, lock_conflict: true };
702
+ return { ok: false, message: `Failed to inspect repo status: ${status.out.slice(0, 200)}` };
703
+ }
704
+ if (status.out.split('\n').some((line) => ['DD', 'AU', 'UD', 'UA', 'DU', 'AA', 'UU'].includes(line.slice(0, 2)))) {
705
+ return { ok: false, message: `The local agent repo has unresolved merge conflicts. To reset to the latest remote version run: git -C ${path} checkout . && git -C ${path} pull --ff-only`, conflict: true };
706
+ }
707
+ let stashed = false;
708
+ if (status.out) {
709
+ if (!(await git(['stash', 'push', '-m', 'hermes-update-autostash'], path)).ok)
710
+ return { ok: false, message: 'Failed to stash local changes' };
711
+ stashed = true;
712
+ }
713
+ const slash = ref.indexOf('/');
714
+ const pullArgs = slash > 0 ? ['pull', '--ff-only', ref.slice(0, slash), ref.slice(slash + 1)] : ['pull', '--ff-only', 'origin', ref];
715
+ const pulled = await git(pullArgs, path, 30_000);
716
+ if (!pulled.ok) {
717
+ let note = '';
718
+ if (stashed)
719
+ note = ` ${await restoreStash(path, git, pulled.out)}`;
720
+ if (isGitLockError(pulled.out))
721
+ return { ok: false, message: `Pull failed due to a repository lock: ${pulled.out.trim()}.${note}`, lock_conflict: true };
722
+ return { ok: false, message: `Pull failed: ${sanitizeGitDiagnostic(pulled.out)}.${note}` };
723
+ }
724
+ let message = `agent updated to ${ref}`;
725
+ if (stashed) {
726
+ const popped = await git(['stash', 'pop'], path);
727
+ if (!popped.ok)
728
+ message += '. Local changes remain in `git stash list`; resolve them manually.';
729
+ }
730
+ return { ok: true, message, target: 'agent', ref };
731
+ }
732
+ async function restoreStash(path, git, pullOut) {
733
+ if ((await git(['stash', 'pop'], path)).ok)
734
+ return 'Local modifications were restored from the temporary stash.';
735
+ if ((await git(['stash', 'apply'], path)).ok) {
736
+ await git(['stash', 'drop'], path);
737
+ return 'Local modifications were restored from the temporary stash.';
738
+ }
739
+ return `Your local modifications could not be restored automatically (stash pop failed after pull error: ${pullOut.trim().slice(0, 200) || 'no detail'}). They remain safely in \`git stash list\`; run \`git -C ${path} stash pop\` once the lock is cleared.`;
740
+ }
741
+ /** Python `apply_force_update` (agent branch): fetch, refuse a pure-ancestor rewind, `checkout . && clean -fd && reset --hard`. */
742
+ export async function forceAgentUpdate(path, git, log) {
743
+ if (!path || !existsSync(join(path, '.git')))
744
+ return { ok: false, message: 'Not a git repository' };
745
+ const fetched = await git(['fetch', 'origin', '--quiet', '--tags', '--force'], path, 15_000);
746
+ if (!fetched.ok)
747
+ return { ok: false, message: fetchFailureMessage(fetched.out, 'Could not reach the remote repository. Check your connection.') };
748
+ const ref = await selectAgentCompareRef(path, git);
749
+ if ((await headContainsRef(path, ref, git)) && !(await canFastForwardTo(path, ref, git))) {
750
+ return { ok: false, message: `agent is already ahead of the stable channel (${ref}); refusing to rewind the checkout. Switching to a slower channel keeps your current version until that channel catches up.`, target: 'agent', channel: DEFAULT_CHANNEL, refused_rewind: true };
751
+ }
752
+ await git(['checkout', '.'], path);
753
+ const cleaned = await git(['clean', '-fd'], path);
754
+ if (!cleaned.ok)
755
+ log(`[updates] force update: git clean -fd failed (continuing to reset --hard): ${cleaned.out}`);
756
+ if (!(await git(['reset', '--hard', ref], path)).ok)
757
+ return { ok: false, message: `Force reset to ${ref} failed` };
758
+ return { ok: true, message: `agent force-updated to ${ref}`, target: 'agent', ref };
759
+ }
760
+ /** Python `_inventory_locks`: report `.git/**\/*.lock` without touching any of them. */
761
+ export function inventoryLocks(path) {
762
+ const gitDir = join(path, '.git');
763
+ const out = { well_known_lock_present: false, well_known_lock_path: null, other_locks: [] };
764
+ if (!existsSync(gitDir))
765
+ return out;
766
+ const wellKnown = join(gitDir, 'index.lock');
767
+ try {
768
+ out.well_known_lock_present = existsSync(wellKnown);
769
+ }
770
+ catch {
771
+ out.well_known_lock_present = true;
772
+ }
773
+ out.well_known_lock_path = wellKnown;
774
+ try {
775
+ for (const entry of readdirSync(gitDir, { recursive: true, encoding: 'utf8' }).sort()) {
776
+ const rel = entry.split('\\').join('/');
777
+ if (rel.endsWith('.lock') && rel !== 'index.lock')
778
+ out.other_locks.push(rel);
779
+ }
780
+ }
781
+ catch { /* unreadable subtrees are skipped */ }
782
+ return out;
783
+ }
784
+ /** Python `_purge_agent_pycache`: stale bytecode after a pull must not outlive the restart. */
785
+ export function purgePycache(root) {
786
+ if (!existsSync(root))
787
+ return;
788
+ const skip = new Set(['.git', 'venv', '.venv', 'node_modules']);
789
+ const walk = (dir) => {
790
+ let entries;
791
+ try {
792
+ entries = readdirSync(dir, { withFileTypes: true });
793
+ }
794
+ catch {
795
+ return;
796
+ }
797
+ for (const entry of entries) {
798
+ if (!entry.isDirectory() || skip.has(entry.name))
799
+ continue;
800
+ const full = join(dir, entry.name);
801
+ if (entry.name === '__pycache__')
802
+ rmSync(full, { recursive: true, force: true });
803
+ else
804
+ walk(full);
805
+ }
806
+ };
807
+ walk(root);
808
+ }
809
+ // ── summary ──────────────────────────────────────────────────────────────────
810
+ const BULLET = /^\s*(?:[-*•]+|\d+[.)])\s*/;
811
+ function cleanBullet(line) {
812
+ let s = line.replace(BULLET, '').trim().replace(/\s+/g, ' ');
813
+ if (!s)
814
+ return '';
815
+ if (!'.!?'.includes(s[s.length - 1]))
816
+ s += '.';
817
+ return s.slice(0, 240);
818
+ }
819
+ function uniqueBullets(items) {
820
+ const seen = new Set();
821
+ const out = [];
822
+ for (const item of items) {
823
+ const c = cleanBullet(item);
824
+ if (c && !seen.has(c.toLowerCase())) {
825
+ seen.add(c.toLowerCase());
826
+ out.push(c);
827
+ }
828
+ }
829
+ return out;
830
+ }
831
+ function splitCategory(line) {
832
+ const raw = line.trim();
833
+ const m = /^\s*(?:[-*•]+|\d+[.)])?\s*(notice|what you(?:ll|'ll| will) notice|user(?:s)? will notice|worth knowing|worth|note)\s*:\s*(.+)$/i.exec(raw);
834
+ if (!m)
835
+ return [null, raw];
836
+ const label = (m[1] ?? '').toLowerCase();
837
+ return [['worth knowing', 'worth', 'note'].includes(label) ? 'worth' : 'notice', m[2] ?? ''];
838
+ }
839
+ function fallbackBullets(details) {
840
+ const out = details.map((item) => {
841
+ const label = str(item.label || item.name) || 'Hermes';
842
+ const commits = item.commits;
843
+ if (commits.length)
844
+ return `${label} has ${String(item.behind)} update(s), including ${item.commits_truncated ? 'recent updates' : 'updates'}: ${commits.slice(0, 3).join('; ')}.`;
845
+ return `${label} has ${String(item.behind)} update(s) available.`;
846
+ });
847
+ return out.length ? out : ['Updates are available.'];
848
+ }
849
+ function worthKnowingBullets(details) {
850
+ const truncated = details.filter((d) => d.commits_truncated && d.commits_limit);
851
+ if (truncated.length)
852
+ return truncated.slice(0, 2).map((d) => `${str(d.label || d.name) || 'Hermes'} has ${String(d.behind)} updates; this summary uses the latest ${String(d.commits_limit)} commit subjects, with the full comparison still available in the diff link.`);
853
+ const targets = details.filter((d) => d.behind).map((d) => `${str(d.label || d.name) || 'Hermes'} (${String(d.behind)} update${d.behind === 1 ? '' : 's'})`);
854
+ return targets.length > 1 ? [`This summary combines updates from ${targets.join(' and ')}.`] : [];
855
+ }
856
+ function formatSections(text, details) {
857
+ const noticeRaw = [];
858
+ const worthRaw = [];
859
+ for (const line of text.split('\n')) {
860
+ const [category, body] = splitCategory(line);
861
+ if (category === 'notice')
862
+ noticeRaw.push(body);
863
+ else if (category === 'worth')
864
+ worthRaw.push(body);
865
+ else if (/^\s*(?:[-*•]+|\d+[.)])?\s*[A-Za-z][A-Za-z ]{1,32}\s*:/.test(line))
866
+ noticeRaw.push(body);
867
+ }
868
+ let notice = uniqueBullets(noticeRaw);
869
+ if (!notice.length) {
870
+ const raw = text.trim();
871
+ let candidates = raw.split('\n').map((l) => cleanBullet(splitCategory(l)[1])).filter(Boolean);
872
+ if (candidates.length <= 1 && raw)
873
+ candidates = raw.split(/(?<=[.!?])\s+/).map(cleanBullet).filter(Boolean);
874
+ if (!candidates.length)
875
+ candidates = fallbackBullets(details).map(cleanBullet);
876
+ notice = uniqueBullets(candidates);
877
+ if (!notice.length)
878
+ notice = ['Updates are available.'];
879
+ }
880
+ const keys = new Set(notice.map((n) => n.toLowerCase()));
881
+ const worth = uniqueBullets(worthRaw).filter((w) => !keys.has(w.toLowerCase()));
882
+ for (const item of worthKnowingBullets(details))
883
+ if (!keys.has(item.toLowerCase()) && !worth.some((w) => w.toLowerCase() === item.toLowerCase()))
884
+ worth.push(item);
885
+ const sections = [{ title: "What you'll notice", items: notice }];
886
+ if (worth.length)
887
+ sections.push({ title: 'Worth knowing', items: worth });
888
+ const summary = sections.map((s) => [str(s.title), ...s.items.map((i) => `- ${i}`), ''].join('\n')).join('\n').trim();
889
+ return [sections, summary];
890
+ }
891
+ function summaryPrompt(details) {
892
+ const system = 'You write human-readable release summaries for Hermes users. Focus on what the user will notice in the product. Keep it simple, specific, and short. avoid technical jargon, implementation details, SHA names, branch names, and file paths unless necessary. Return only bullets. Do not include headings, markdown tables, intro paragraphs, or closing notes.';
893
+ const lines = ['Summarize these available updates as concise bullets.', 'Prefix each bullet with `Notice:` for user-visible behavior changes or `Worth knowing:` for useful context.', 'Put user-visible Notice bullets first and include every meaningful user-facing change from the available commit subjects.', 'Use Worth knowing only for helpful context that is not a duplicate of a Notice bullet.', 'Use everyday language and explain visible behavior changes, not code mechanics.', 'Return only prefixed bullets; the WebUI will add the fixed section headings separately.', ''];
894
+ for (const item of details) {
895
+ lines.push(`${str(item.label)}: ${String(item.behind)} commit(s) behind`);
896
+ const commits = item.commits;
897
+ if (commits.length) {
898
+ if (item.commits_truncated)
899
+ lines.push(`- Showing latest ${String(commits.length)} of ${String(item.behind)} commit subjects; summarize trends, not every commit.`);
900
+ lines.push(...commits.map((c) => `- ${c}`));
901
+ }
902
+ else
903
+ lines.push('- No local commit subjects available; summarize only the update count.');
904
+ lines.push('');
905
+ }
906
+ return [system, lines.join('\n')];
907
+ }
908
+ export class UpdateService {
909
+ deps;
910
+ cache = { webui: null, agent: null, checked_at: 0, include_agent: true, channel: DEFAULT_CHANNEL };
911
+ checking = null;
912
+ applying = false;
913
+ summaries = new Map();
914
+ git;
915
+ now;
916
+ sleep;
917
+ constructor(deps) {
918
+ this.deps = deps;
919
+ this.git = deps.git ?? runGit;
920
+ this.now = deps.now ?? (() => Date.now() / 1000);
921
+ this.sleep = deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
922
+ }
923
+ /** Python `cached_update_status`: no network, no git mutations. */
924
+ cachedStatus(includeAgent = this.deps.includeAgent(), channel = this.deps.channel()) {
925
+ const cached = { ...this.cache };
926
+ if (cached.channel !== channel) {
927
+ cached.channel = channel;
928
+ cached.stale_channel = true;
929
+ }
930
+ if (cached.include_agent !== includeAgent) {
931
+ cached.include_agent = includeAgent;
932
+ if (!includeAgent)
933
+ cached.agent = ignoredAgent();
934
+ }
935
+ cached.cached = true;
936
+ return cached;
937
+ }
938
+ /** Python `check_for_updates`: 30 min cache keyed on channel + include_agent; one in-flight check per key. */
939
+ async check(force = false, includeAgent = this.deps.includeAgent(), channel = this.deps.channel()) {
940
+ const matches = this.cache.include_agent === includeAgent && this.cache.channel === channel;
941
+ if (!force && matches && this.now() - Number(this.cache.checked_at) < CACHE_TTL_S)
942
+ return { ...this.cache };
943
+ if (this.checking && matches)
944
+ return this.checking;
945
+ this.checking = (async () => {
946
+ try {
947
+ const webui = await checkWebUpdate(this.deps.webRoot, this.deps.webuiVersion, channel, this.git, this.deps.getJson, this.deps.identity);
948
+ // The channel is a Web concept; the Agent always follows its own stable tags.
949
+ const agent = includeAgent ? await checkAgentUpdate(this.deps.agentDir(), this.git) : ignoredAgent();
950
+ Object.assign(this.cache, { webui, agent, checked_at: this.now(), include_agent: includeAgent, channel });
951
+ return { ...this.cache };
952
+ }
953
+ finally {
954
+ this.checking = null;
955
+ }
956
+ })();
957
+ return this.checking;
958
+ }
959
+ blockedResponse(target) {
960
+ const b = this.deps.blockers();
961
+ if (!b.restart_blocked)
962
+ return null;
963
+ const parts = [];
964
+ if (b.active_streams)
965
+ parts.push(`${String(b.active_streams)} active chat stream${b.active_streams === 1 ? '' : 's'}`);
966
+ if (b.active_runs)
967
+ parts.push(`${String(b.active_runs)} active agent run${b.active_runs === 1 ? '' : 's'}`);
968
+ return { ok: false, message: `Cannot update ${target} while ${parts.join(' and ') || 'active chat work'} is running. Wait for the response to finish, then retry the update.`, target, restart_blocked: true, active_streams: b.active_streams, active_runs: b.active_runs, blocking_stream_ids: b.blocking_stream_ids, blocking_run_ids: b.blocking_run_ids };
969
+ }
970
+ async locked(fn) {
971
+ if (this.applying)
972
+ return { ok: false, message: 'Update already in progress' };
973
+ this.applying = true;
974
+ try {
975
+ return await fn();
976
+ }
977
+ finally {
978
+ this.applying = false;
979
+ }
980
+ }
981
+ /** Python `apply_update`. */
982
+ apply(target, channel) {
983
+ const blocked = this.blockedResponse(target);
984
+ if (blocked)
985
+ return Promise.resolve(blocked);
986
+ return this.locked(() => this.applyInner(target, channel ?? this.deps.channel()));
987
+ }
988
+ async applyInner(target, channel) {
989
+ if (target === 'webui') {
990
+ const result = await applyWebUpdate(this.deps.webRoot, channel, this.git, this.deps.getJson, this.deps.identity, this.deps.build ?? runNpm);
991
+ if (result.ok && !result.up_to_date) {
992
+ this.cache.checked_at = 0;
993
+ this.deps.scheduleRestart();
994
+ result.restart_scheduled = true;
995
+ }
996
+ return result;
997
+ }
998
+ if (target !== 'agent')
999
+ return { ok: false, message: `Unknown target: ${target}` };
1000
+ const result = await applyAgentUpdate(this.deps.agentDir(), this.git);
1001
+ if (!result.ok)
1002
+ return result;
1003
+ return this.finishAgent(result);
1004
+ }
1005
+ async finishAgent(result) {
1006
+ this.cache.checked_at = 0;
1007
+ const [ok, gateway] = await this.restartGateway();
1008
+ if (!ok)
1009
+ return { ok: false, message: gateway.message ? `agent updated, but gateway restart did not complete: ${str(gateway.message)}. Run \`hermes gateway restart\` manually.` : 'agent updated, but gateway restart did not complete. Run `hermes gateway restart` manually.', target: 'agent', gateway_restart: gateway.status };
1010
+ this.deps.scheduleRestart();
1011
+ return { ...result, restart_scheduled: true, gateway_restart: gateway.status };
1012
+ }
1013
+ /** Python `_ensure_gateway_restart_for_agent_update`: retry once after a transient supervisor handoff failure. */
1014
+ async restartGateway() {
1015
+ const attempt = async () => { try {
1016
+ return await this.deps.gatewayRestart();
1017
+ }
1018
+ catch (error) {
1019
+ return { status: 'failed', message: error.message };
1020
+ } };
1021
+ const first = await attempt();
1022
+ const status = str(first.status);
1023
+ if (status === 'completed' || status === 'in_progress')
1024
+ return [true, first];
1025
+ if (status !== 'failed')
1026
+ return [false, first];
1027
+ await this.sleep(1000);
1028
+ const retry = await attempt();
1029
+ const retryStatus = str(retry.status);
1030
+ const annotated = { ...retry, retry_attempted: true, initial_failure: first.message };
1031
+ if (retryStatus === 'completed' || retryStatus === 'in_progress')
1032
+ return [true, annotated];
1033
+ if (retryStatus !== 'failed')
1034
+ return [false, annotated];
1035
+ return [false, { ...annotated, message: `${str(first.message) || 'Restart failed'}; recovery retry did not complete: ${str(retry.message) || 'retry did not complete'}` }];
1036
+ }
1037
+ /** Python `apply_force_update`: Web keeps its clean-only policy; the Agent resets hard. */
1038
+ force(target, channel) {
1039
+ if (target === 'webui')
1040
+ return this.apply(target, channel);
1041
+ const blocked = this.blockedResponse(target);
1042
+ if (blocked)
1043
+ return Promise.resolve(blocked);
1044
+ return this.locked(async () => {
1045
+ if (target !== 'agent')
1046
+ return { ok: false, message: `Unknown target: ${target}` };
1047
+ const result = await forceAgentUpdate(this.deps.agentDir(), this.git, this.deps.log);
1048
+ return result.ok ? this.finishAgent(result) : result;
1049
+ });
1050
+ }
1051
+ /** Python `apply_clear_lock`: never removes a lock; Web retries the clean path, the Agent gets the manual command. */
1052
+ clearLock(target) {
1053
+ if (target === 'webui')
1054
+ return this.apply(target).then((r) => ({ ...r, lock_recovery: { action: 'retry-only' } }));
1055
+ const blocked = this.blockedResponse(target);
1056
+ if (blocked)
1057
+ return Promise.resolve(blocked);
1058
+ return this.locked(async () => {
1059
+ if (target !== 'agent')
1060
+ return { ok: false, message: `Unknown target: ${target}` };
1061
+ const path = this.deps.agentDir();
1062
+ if (!path || !existsSync(join(path, '.git')))
1063
+ return { ok: false, message: 'Not a git repository' };
1064
+ const inv = inventoryLocks(path);
1065
+ const manual = `rm -f ${str(inv.well_known_lock_path)}`;
1066
+ if (!inv.well_known_lock_present) {
1067
+ this.cache.checked_at = 0;
1068
+ const retry = await this.applyInner(target, this.deps.channel());
1069
+ return { ...retry, lock_recovery: { action: 'no-lock-found', manual_command: manual, other_locks: inv.other_locks } };
1070
+ }
1071
+ return { ok: false, message: `A git lock file (.git/index.lock) is present. The server does not delete locks automatically -- git uses O_CREAT|O_EXCL locking, which cannot be detected with advisory probes. To recover: confirm no other git process is running against this checkout, then run: ${manual} Click "Retry update" once you have removed it.`, lock_held: true, target, manual_command: manual, well_known_lock_path: inv.well_known_lock_path, other_locks: inv.other_locks };
1072
+ });
1073
+ }
1074
+ /** Python `_commit_subjects_for_update_with_limit`. */
1075
+ async commitSubjects(target, info, limit = 24) {
1076
+ const path = target === 'webui' ? await checkoutRoot(this.deps.webRoot, this.git) : this.deps.agentDir();
1077
+ const current = str(info.current_sha).trim();
1078
+ const latest = str(info.latest_sha).trim();
1079
+ if (!path || !current || !latest)
1080
+ return [[], false];
1081
+ const args = ['log', '--format=%s', `${current}..${latest}`, `-n${String(limit + 1)}`];
1082
+ if (target === 'webui' && info.channel === 'experimental')
1083
+ args.push('--', ...WEB_UPDATE_PATHS);
1084
+ const out = await this.git(args, path, 5000);
1085
+ if (!out.ok || !out.out)
1086
+ return [[], false];
1087
+ const subjects = out.out.split('\n').map((l) => l.trim()).filter(Boolean);
1088
+ return [subjects.slice(0, limit), subjects.length > limit];
1089
+ }
1090
+ /** Python `summarize_update_payload`: What's New sections, LLM when available, cached per exact range. */
1091
+ async summarize(updates, targetRaw) {
1092
+ const target = targetRaw === 'webui' || targetRaw === 'agent' ? targetRaw : null;
1093
+ const details = [];
1094
+ for (const [key, label] of [['webui', 'WebUI'], ['agent', 'Agent']]) {
1095
+ if (target && key !== target)
1096
+ continue;
1097
+ const info = updates[key];
1098
+ if (!info || typeof info !== 'object' || Array.isArray(info))
1099
+ continue;
1100
+ const behind = Number.parseInt(str(info.behind ?? 0), 10) || 0;
1101
+ if (behind <= 0)
1102
+ continue;
1103
+ const [commits, truncated] = await this.commitSubjects(key, info);
1104
+ details.push({ name: key, label, behind, current_sha: info.current_sha ?? null, latest_sha: info.latest_sha ?? null, compare_url: info.compare_url ?? null, commits, commits_limit: 24, commits_truncated: truncated || (commits.length > 0 && behind > commits.length) });
1105
+ }
1106
+ const cacheKey = createHash('sha256').update(JSON.stringify(details.map((d) => sortKeys({ name: d.name, behind: d.behind, current_sha: d.current_sha, latest_sha: d.latest_sha, compare_url: d.compare_url, commits: d.commits })))).digest('hex');
1107
+ const cached = this.summaries.get(cacheKey);
1108
+ if (cached) {
1109
+ this.summaries.delete(cacheKey);
1110
+ this.summaries.set(cacheKey, cached);
1111
+ return { ...cached, cached: true };
1112
+ }
1113
+ let generatedBy = 'fallback';
1114
+ let candidate = '';
1115
+ if (details.length && this.deps.llm) {
1116
+ const [system, user] = summaryPrompt(details);
1117
+ try {
1118
+ candidate = (await this.deps.llm(system, user)).trim();
1119
+ if (candidate)
1120
+ generatedBy = 'llm';
1121
+ }
1122
+ catch {
1123
+ candidate = '';
1124
+ }
1125
+ }
1126
+ const [sections, summary] = formatSections(candidate, details);
1127
+ const result = { ok: true, summary, summary_sections: sections, generated_by: generatedBy, cached: false, cache_key: cacheKey, target, targets: details };
1128
+ if (this.summaries.size >= 16)
1129
+ this.summaries.delete(this.summaries.keys().next().value);
1130
+ this.summaries.set(cacheKey, result);
1131
+ return result;
1132
+ }
1133
+ }
1134
+ const ignoredAgent = () => ({ name: 'agent', behind: 0, ignored: true });
1135
+ /** Python `_wait_until_restart_safe`: poll until no chat work is active, bounded so a stuck run cannot jam the update forever. */
1136
+ export async function waitUntilRestartSafe(blockers, opts = {}) {
1137
+ const now = opts.now ?? (() => Date.now());
1138
+ const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
1139
+ const deadline = now() + (opts.maxWaitMs ?? RESTART_MAX_WAIT_S * 1000);
1140
+ let snapshot = blockers();
1141
+ while (snapshot.restart_blocked) {
1142
+ if (now() >= deadline) {
1143
+ opts.log?.(`[updates] restart-safety wait exceeded ${String((opts.maxWaitMs ?? RESTART_MAX_WAIT_S * 1000) / 1000)}s with work still in flight; proceeding with restart`);
1144
+ return { ...snapshot, wait_timed_out: true };
1145
+ }
1146
+ await sleep(Math.max(100, opts.pollMs ?? 2000));
1147
+ snapshot = blockers();
1148
+ }
1149
+ return snapshot;
1150
+ }
1151
+ //# sourceMappingURL=updates.js.map