@maudecode/talaria-web 1.17.2 → 1.18.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 (387) hide show
  1. package/_release.json +8 -8
  2. package/dist/api/auth-raw.d.ts +1 -1
  3. package/dist/api/auth-raw.js +4 -4
  4. package/dist/api/auth-raw.js.map +1 -1
  5. package/dist/api/automation-raw.d.ts +6 -0
  6. package/dist/api/automation-raw.js +53 -6
  7. package/dist/api/automation-raw.js.map +1 -1
  8. package/dist/api/automation-router.d.ts +26 -1
  9. package/dist/api/automation-router.js +16 -2
  10. package/dist/api/automation-router.js.map +1 -1
  11. package/dist/api/chat-router.d.ts +649 -15
  12. package/dist/api/chat-router.js +52 -50
  13. package/dist/api/chat-router.js.map +1 -1
  14. package/dist/api/git-router.d.ts +35 -1
  15. package/dist/api/git-router.js +18 -19
  16. package/dist/api/git-router.js.map +1 -1
  17. package/dist/api/raw-routes.d.ts +8 -0
  18. package/dist/api/raw-routes.js +247 -36
  19. package/dist/api/raw-routes.js.map +1 -1
  20. package/dist/api/router.d.ts +10 -0
  21. package/dist/api/router.js +10 -8
  22. package/dist/api/router.js.map +1 -1
  23. package/dist/api/sessions-router.d.ts +1492 -115
  24. package/dist/api/sessions-router.js +134 -8
  25. package/dist/api/sessions-router.js.map +1 -1
  26. package/dist/api/settings-router.d.ts +31 -0
  27. package/dist/api/settings-router.js +8 -3
  28. package/dist/api/settings-router.js.map +1 -1
  29. package/dist/api/sse-routes.d.ts +5 -0
  30. package/dist/api/sse-routes.js +50 -3
  31. package/dist/api/sse-routes.js.map +1 -1
  32. package/dist/api/tools-raw.js +6 -23
  33. package/dist/api/tools-raw.js.map +1 -1
  34. package/dist/api/tools-router.d.ts +356 -15
  35. package/dist/api/tools-router.js +148 -19
  36. package/dist/api/tools-router.js.map +1 -1
  37. package/dist/app.js +35 -15
  38. package/dist/app.js.map +1 -1
  39. package/dist/auth/gate.js +5 -2
  40. package/dist/auth/gate.js.map +1 -1
  41. package/dist/auth/oidc.d.ts +5 -2
  42. package/dist/auth/oidc.js +8 -7
  43. package/dist/auth/oidc.js.map +1 -1
  44. package/dist/bin/talaria-web.js +1 -1
  45. package/dist/bin/talaria-web.js.map +1 -1
  46. package/dist/cli/dotenv.js +1 -0
  47. package/dist/cli/dotenv.js.map +1 -1
  48. package/dist/config/agent-config.js +3 -2
  49. package/dist/config/agent-config.js.map +1 -1
  50. package/dist/config.d.ts +2 -0
  51. package/dist/config.js +5 -1
  52. package/dist/config.js.map +1 -1
  53. package/dist/http/context.d.ts +17 -3
  54. package/dist/http/context.js +31 -4
  55. package/dist/http/context.js.map +1 -1
  56. package/dist/http/csp.d.ts +2 -1
  57. package/dist/http/csp.js +3 -2
  58. package/dist/http/csp.js.map +1 -1
  59. package/dist/profiles/profiles.d.ts +10 -0
  60. package/dist/profiles/profiles.js +40 -2
  61. package/dist/profiles/profiles.js.map +1 -1
  62. package/dist/providers/catalog.d.ts +6 -2
  63. package/dist/providers/catalog.js +30 -11
  64. package/dist/providers/catalog.js.map +1 -1
  65. package/dist/raster-image.d.ts +7 -0
  66. package/dist/raster-image.js +267 -0
  67. package/dist/raster-image.js.map +1 -0
  68. package/dist/redact.js +327 -40
  69. package/dist/redact.js.map +1 -1
  70. package/dist/runtime.js +89 -23
  71. package/dist/runtime.js.map +1 -1
  72. package/dist/server.js +5 -0
  73. package/dist/server.js.map +1 -1
  74. package/dist/sessions/background-tasks.d.ts +2 -9
  75. package/dist/sessions/background-tasks.js +2 -12
  76. package/dist/sessions/background-tasks.js.map +1 -1
  77. package/dist/sessions/cli-sessions.d.ts +15 -4
  78. package/dist/sessions/cli-sessions.js +120 -29
  79. package/dist/sessions/cli-sessions.js.map +1 -1
  80. package/dist/sessions/completions.d.ts +48 -8
  81. package/dist/sessions/completions.js +222 -26
  82. package/dist/sessions/completions.js.map +1 -1
  83. package/dist/sessions/export.d.ts +5 -0
  84. package/dist/sessions/export.js +30 -0
  85. package/dist/sessions/export.js.map +1 -1
  86. package/dist/sessions/gateway-watcher.d.ts +7 -3
  87. package/dist/sessions/gateway-watcher.js +31 -19
  88. package/dist/sessions/gateway-watcher.js.map +1 -1
  89. package/dist/sessions/handoff.d.ts +32 -0
  90. package/dist/sessions/handoff.js +114 -0
  91. package/dist/sessions/handoff.js.map +1 -0
  92. package/dist/sessions/list.d.ts +7 -1
  93. package/dist/sessions/list.js +13 -5
  94. package/dist/sessions/list.js.map +1 -1
  95. package/dist/sessions/merge.d.ts +2 -4
  96. package/dist/sessions/merge.js +8 -15
  97. package/dist/sessions/merge.js.map +1 -1
  98. package/dist/sessions/recovery.d.ts +22 -0
  99. package/dist/sessions/recovery.js +506 -0
  100. package/dist/sessions/recovery.js.map +1 -0
  101. package/dist/sessions/relay.d.ts +21 -2
  102. package/dist/sessions/relay.js +156 -11
  103. package/dist/sessions/relay.js.map +1 -1
  104. package/dist/sessions/service.d.ts +108 -6
  105. package/dist/sessions/service.js +403 -29
  106. package/dist/sessions/service.js.map +1 -1
  107. package/dist/sessions/session.d.ts +6 -0
  108. package/dist/sessions/session.js +40 -2
  109. package/dist/sessions/session.js.map +1 -1
  110. package/dist/sessions/state-db-worker.d.ts +1 -0
  111. package/dist/sessions/state-db-worker.js +33 -0
  112. package/dist/sessions/state-db-worker.js.map +1 -0
  113. package/dist/sessions/state-db.d.ts +61 -0
  114. package/dist/sessions/state-db.js +291 -0
  115. package/dist/sessions/state-db.js.map +1 -1
  116. package/dist/sessions/store.d.ts +7 -0
  117. package/dist/sessions/store.js +31 -22
  118. package/dist/sessions/store.js.map +1 -1
  119. package/dist/sessions/titles.d.ts +2 -0
  120. package/dist/sessions/titles.js +4 -0
  121. package/dist/sessions/titles.js.map +1 -1
  122. package/dist/sessions/tool-display.d.ts +3 -3
  123. package/dist/sessions/tool-display.js +11 -37
  124. package/dist/sessions/tool-display.js.map +1 -1
  125. package/dist/sessions/turn-context.d.ts +1 -1
  126. package/dist/sessions/turn-context.js +11 -7
  127. package/dist/sessions/turn-context.js.map +1 -1
  128. package/dist/sessions/turn.d.ts +37 -2
  129. package/dist/sessions/turn.js +182 -49
  130. package/dist/sessions/turn.js.map +1 -1
  131. package/dist/sessions/wakeup-pause.d.ts +59 -0
  132. package/dist/sessions/wakeup-pause.js +181 -0
  133. package/dist/sessions/wakeup-pause.js.map +1 -0
  134. package/dist/settings.js +5 -7
  135. package/dist/settings.js.map +1 -1
  136. package/dist/sidecar/fake.d.ts +2 -2
  137. package/dist/sidecar/fake.js.map +1 -1
  138. package/dist/startup.d.ts +13 -5
  139. package/dist/startup.js +48 -0
  140. package/dist/startup.js.map +1 -1
  141. package/dist/test/ts-worker-hooks.d.ts +1 -0
  142. package/dist/test/ts-worker-hooks.js +24 -0
  143. package/dist/test/ts-worker-hooks.js.map +1 -0
  144. package/dist/text/diff.d.ts +9 -14
  145. package/dist/text/diff.js +74 -108
  146. package/dist/text/diff.js.map +1 -1
  147. package/dist/tools/crons.js +45 -8
  148. package/dist/tools/crons.js.map +1 -1
  149. package/dist/tools/dashboard-plugins.d.ts +53 -0
  150. package/dist/tools/dashboard-plugins.js +188 -0
  151. package/dist/tools/dashboard-plugins.js.map +1 -0
  152. package/dist/tools/extensions.d.ts +13 -1
  153. package/dist/tools/extensions.js +132 -60
  154. package/dist/tools/extensions.js.map +1 -1
  155. package/dist/tools/health.d.ts +32 -0
  156. package/dist/tools/health.js +111 -19
  157. package/dist/tools/health.js.map +1 -1
  158. package/dist/tools/mcp.d.ts +13 -0
  159. package/dist/tools/mcp.js +88 -0
  160. package/dist/tools/mcp.js.map +1 -1
  161. package/dist/tools/project-os.d.ts +11 -0
  162. package/dist/tools/project-os.js +267 -0
  163. package/dist/tools/project-os.js.map +1 -0
  164. package/dist/tools/skills.d.ts +5 -1
  165. package/dist/tools/skills.js +5 -3
  166. package/dist/tools/skills.js.map +1 -1
  167. package/dist/tools/updates.d.ts +27 -9
  168. package/dist/tools/updates.js +163 -51
  169. package/dist/tools/updates.js.map +1 -1
  170. package/dist/tools/wiki.d.ts +68 -0
  171. package/dist/tools/wiki.js +413 -0
  172. package/dist/tools/wiki.js.map +1 -0
  173. package/dist/workspace/escape.d.ts +61 -0
  174. package/dist/workspace/escape.js +149 -0
  175. package/dist/workspace/escape.js.map +1 -0
  176. package/dist/workspace/extract.d.ts +22 -0
  177. package/dist/workspace/extract.js +308 -0
  178. package/dist/workspace/extract.js.map +1 -0
  179. package/dist/workspace/fs.d.ts +12 -0
  180. package/dist/workspace/fs.js +92 -23
  181. package/dist/workspace/fs.js.map +1 -1
  182. package/dist/workspace/git.d.ts +18 -0
  183. package/dist/workspace/git.js +38 -25
  184. package/dist/workspace/git.js.map +1 -1
  185. package/dist/workspace/media.d.ts +4 -4
  186. package/dist/workspace/media.js +16 -45
  187. package/dist/workspace/media.js.map +1 -1
  188. package/dist/workspace/rollback.d.ts +34 -20
  189. package/dist/workspace/rollback.js +171 -265
  190. package/dist/workspace/rollback.js.map +1 -1
  191. package/dist/workspace/unzip.js +4 -1
  192. package/dist/workspace/unzip.js.map +1 -1
  193. package/dist/workspace/upload.d.ts +7 -4
  194. package/dist/workspace/upload.js +5 -2
  195. package/dist/workspace/upload.js.map +1 -1
  196. package/dist/workspace/worktrees.d.ts +2 -1
  197. package/dist/workspace/worktrees.js +14 -15
  198. package/dist/workspace/worktrees.js.map +1 -1
  199. package/package.json +4 -2
  200. package/sidecar/agent_dependency.json +4 -4
  201. package/sidecar/scripts/replay_sidecar.py +24 -0
  202. package/sidecar/talaria_sidecar/__init__.py +1 -1
  203. package/sidecar/talaria_sidecar/home.py +13 -2
  204. package/sidecar/talaria_sidecar/methods/__init__.py +2 -2
  205. package/sidecar/talaria_sidecar/methods/aux.py +39 -5
  206. package/sidecar/talaria_sidecar/methods/chat.py +9 -5
  207. package/sidecar/talaria_sidecar/methods/checkpoints.py +89 -0
  208. package/sidecar/talaria_sidecar/methods/commands.py +81 -0
  209. package/sidecar/talaria_sidecar/methods/cron.py +29 -2
  210. package/sidecar/talaria_sidecar/methods/gateway.py +32 -15
  211. package/sidecar/talaria_sidecar/methods/kanban.py +28 -7
  212. package/sidecar/talaria_sidecar/methods/mcp.py +1 -1
  213. package/sidecar/talaria_sidecar/methods/process.py +58 -4
  214. package/sidecar/talaria_sidecar/methods/profiles.py +77 -7
  215. package/sidecar/talaria_sidecar/methods/providers.py +27 -8
  216. package/sidecar/talaria_sidecar/methods/state_db.py +39 -5
  217. package/sidecar/talaria_sidecar/runtime.py +17 -1
  218. package/static/dist/FILES.txt +127 -126
  219. package/static/dist/assets/AppShell-g3bkgnvt.js +1 -0
  220. package/static/dist/assets/ChatPage-oo7bdan6.js +25 -0
  221. package/static/dist/assets/Dialog-g355qxhp.js +1 -0
  222. package/static/dist/assets/ExtensionRoute-i2y9fvjm.js +1 -0
  223. package/static/dist/assets/HubRoute-lmkrbw47.js +2 -0
  224. package/static/dist/assets/{Markdown-mdwlvj3w.js → Markdown-j4kut4j2.js} +114 -114
  225. package/static/dist/assets/{RightPanel-ftvrjlcp.js → RightPanel-ohlsdzfl.js} +1 -1
  226. package/static/dist/assets/Select-kddq75qc.js +1 -0
  227. package/static/dist/assets/SessionListPanel-lu3oy0hw.js +1 -0
  228. package/static/dist/assets/{SettingsLayout-jonjefmj.js → SettingsLayout-o9bv4mgb.js} +1 -1
  229. package/static/dist/assets/{States-nmejrwrm.js → States-eq6fe29m.js} +1 -1
  230. package/static/dist/assets/Toaster-pc247u9f.js +1 -0
  231. package/static/dist/assets/{_app-gdidzd94.js → _app-f8n1i0m1.js} +1 -1
  232. package/static/dist/assets/{_app.ext._extensionId-opyh9y0v.js → _app.ext._extensionId-gfbzpoou.js} +1 -1
  233. package/static/dist/assets/_app.index-bzzv80hk.js +1 -0
  234. package/static/dist/assets/_app.insights-dzixbryi.js +1 -0
  235. package/static/dist/assets/_app.kanban-c6hep2us.js +1 -0
  236. package/static/dist/assets/_app.logs-i69qds98.js +1 -0
  237. package/static/dist/assets/_app.memory-kl4vf0gd.js +1 -0
  238. package/static/dist/assets/_app.profiles-b8zinmyp.js +1 -0
  239. package/static/dist/assets/{_app.session._sessionId-bfd4h3id.js → _app.session._sessionId-fn1bhde6.js} +1 -1
  240. package/static/dist/assets/_app.settings-cg8plwmf.js +1 -0
  241. package/static/dist/assets/_app.settings._section-bkwbi9zn.js +3 -0
  242. package/static/dist/assets/_app.skills-cs47sbvs.js +1 -0
  243. package/static/dist/assets/_app.tasks-dwvk64tc.js +1 -0
  244. package/static/dist/assets/_app.todos-c8xjm8p3.js +1 -0
  245. package/static/dist/assets/_app.workspaces-ehvd1gds.js +1 -0
  246. package/static/dist/assets/{abnfDiagram-VCTEODGH-b2x1lqot.js → abnfDiagram-VCTEODGH-c8kdixke.js} +1 -1
  247. package/static/dist/assets/architecture-7GRP2DOG-6crvnylg.js +1 -0
  248. package/static/dist/assets/{architectureDiagram-5GKGNRK7-h38o5l7b.js → architectureDiagram-5GKGNRK7-cku06x1p.js} +1 -1
  249. package/static/dist/assets/{back-bemaer09.js → back-h7aun7ew.js} +1 -1
  250. package/static/dist/assets/{blockDiagram-I7D4REHJ-bqquxv2u.js → blockDiagram-I7D4REHJ-jzthp1wa.js} +1 -1
  251. package/static/dist/assets/{c4Diagram-7LVT6UL2-f3fb8w6z.js → c4Diagram-7LVT6UL2-mwr67mt8.js} +1 -1
  252. package/static/dist/assets/{cancel-drd0g6d9.js → cancel-fhi0vcnu.js} +1 -1
  253. package/static/dist/assets/channel-b2zo73z1.js +1 -0
  254. package/static/dist/assets/{chunk-4HAMMTFA-bzfyyzp3.js → chunk-4HAMMTFA-gpq1y228.js} +1 -1
  255. package/static/dist/assets/{chunk-75Z2AOVW-ly99rfx5.js → chunk-75Z2AOVW-ktje58c4.js} +1 -1
  256. package/static/dist/assets/{chunk-DU6HZSFF-bg6ecfqf.js → chunk-DU6HZSFF-ofajdixh.js} +3 -3
  257. package/static/dist/assets/{chunk-F27PBJKO-e8k7mmqw.js → chunk-F27PBJKO-cmev85ti.js} +1 -1
  258. package/static/dist/assets/{chunk-GMAD6QVW-cmalnoaj.js → chunk-GMAD6QVW-htjgt22y.js} +1 -1
  259. package/static/dist/assets/{chunk-GVQU2GXP-gmif5o01.js → chunk-GVQU2GXP-qndvoxl7.js} +1 -1
  260. package/static/dist/assets/{chunk-IMKFNOWR-f1nwwh6u.js → chunk-IMKFNOWR-e5bkd5q6.js} +1 -1
  261. package/static/dist/assets/{chunk-L3NEJ4N5-oktfh5v7.js → chunk-L3NEJ4N5-mj1155r6.js} +1 -1
  262. package/static/dist/assets/{chunk-OSK3NFVY-b1sdx96z.js → chunk-OSK3NFVY-e7gkikcw.js} +1 -1
  263. package/static/dist/assets/{chunk-P2QGCYS3-fhu4nzxt.js → chunk-P2QGCYS3-f7t54xfm.js} +1 -1
  264. package/static/dist/assets/{chunk-POPQ4Y6H-em31rnef.js → chunk-POPQ4Y6H-i927v9oa.js} +1 -1
  265. package/static/dist/assets/{chunk-PWAF6VOD-bxhhyftw.js → chunk-PWAF6VOD-m84lmnyt.js} +1 -1
  266. package/static/dist/assets/{chunk-SHT3W25Y-fmrvwcav.js → chunk-SHT3W25Y-mi0tlcu9.js} +1 -1
  267. package/static/dist/assets/{chunk-SVP7TREG-lymukl2j.js → chunk-SVP7TREG-dnau702j.js} +1 -1
  268. package/static/dist/assets/{chunk-TICWLB2K-lmza6k23.js → chunk-TICWLB2K-edem1gkg.js} +1 -1
  269. package/static/dist/assets/classDiagram-ZZMXUADV-oe99st8x.js +1 -0
  270. package/static/dist/assets/classDiagram-v2-VYDZK3BY-oe99st8x.js +1 -0
  271. package/static/dist/assets/{copied-ima3pysb.js → copied-hcplv46p.js} +1 -1
  272. package/static/dist/assets/{copy-fw5b1pc6.js → copy-magtofyp.js} +1 -1
  273. package/static/dist/assets/{cynefin-OW5HDTMX-czlhbyhs.js → cynefin-OW5HDTMX-siqlulkl.js} +1 -1
  274. package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-gq7mvswb.js → cynefinDiagram-5FMLGOSQ-i648tah9.js} +1 -1
  275. package/static/dist/assets/{dagre-GXQ25YYZ-cqdbf7dr.js → dagre-GXQ25YYZ-mwn6uc17.js} +1 -1
  276. package/static/dist/assets/{diagram-S7CK7UJ4-o6arxa58.js → diagram-S7CK7UJ4-l8abxaes.js} +1 -1
  277. package/static/dist/assets/{diagram-UQ7AKVKN-nhnd68tz.js → diagram-UQ7AKVKN-mekq7zgq.js} +1 -1
  278. package/static/dist/assets/{diagram-VSXAHHWV-dk2sclzn.js → diagram-VSXAHHWV-fnky6lvc.js} +1 -1
  279. package/static/dist/assets/{diagram-VX7I27RA-n3k5nyx3.js → diagram-VX7I27RA-xe6r5qfw.js} +1 -1
  280. package/static/dist/assets/{diagram-Z3DM3KII-m6q9cwdh.js → diagram-Z3DM3KII-nq07dg7k.js} +1 -1
  281. package/static/dist/assets/{ebnfDiagram-PWID7BFC-lsa5641p.js → ebnfDiagram-PWID7BFC-c62ipm3g.js} +1 -1
  282. package/static/dist/assets/endpoints-klbxod4t.js +64 -0
  283. package/static/dist/assets/{erDiagram-RLTQ6QDP-fo2ckbe6.js → erDiagram-RLTQ6QDP-h39kmnzy.js} +1 -1
  284. package/static/dist/assets/eventmodeling-NTZA5JFV-obfede4u.js +1 -0
  285. package/static/dist/assets/flowDiagram-HODETNUW-kdpsp1je.js +1 -0
  286. package/static/dist/assets/{ganttDiagram-EL5Y4UJY-nzqz6x9g.js → ganttDiagram-EL5Y4UJY-ngbsyp37.js} +1 -1
  287. package/static/dist/assets/{gitGraph-4MIJSDKK-gukvcxe6.js → gitGraph-4MIJSDKK-fr2i7caa.js} +1 -1
  288. package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-lqhdp8f0.js → gitGraphDiagram-WWUBYQGX-eravdti4.js} +1 -1
  289. package/static/dist/assets/{highlighted-body-KPVGNVTW-igw6cp39.js → highlighted-body-KPVGNVTW-jwpop9p8.js} +1 -1
  290. package/static/dist/assets/host-i828xuo7.js +1 -0
  291. package/static/dist/assets/index-eh8zilnv.css +2 -0
  292. package/static/dist/assets/{index-cxq58xb1.js → index-r648f4o1.js} +5 -5
  293. package/static/dist/assets/{info-A6RAGUB7-gvu7a93l.js → info-A6RAGUB7-h11x0dxo.js} +1 -1
  294. package/static/dist/assets/{infoDiagram-27XIBGKW-m8t8g6w1.js → infoDiagram-27XIBGKW-dfh47dw9.js} +1 -1
  295. package/static/dist/assets/{ishikawaDiagram-5VMMS53U-l07vkbgj.js → ishikawaDiagram-5VMMS53U-i6ypq351.js} +1 -1
  296. package/static/dist/assets/{journeyDiagram-3NMN7TZE-hybkgj8l.js → journeyDiagram-3NMN7TZE-lduf1z95.js} +1 -1
  297. package/static/dist/assets/{kanban-definition-UXKFOSKX-by13uvtn.js → kanban-definition-UXKFOSKX-e18bu4pg.js} +1 -1
  298. package/static/dist/assets/{lazyRouteComponent-af0lvgjx.js → lazyRouteComponent-e1y4t2i9.js} +1 -1
  299. package/static/dist/assets/{line-osxq6fq7.js → line-meizqsvn.js} +1 -1
  300. package/static/dist/assets/{link-jyxicdhg.js → link-oot2yn73.js} +1 -1
  301. package/static/dist/assets/login-gu28l9ou.js +1 -0
  302. package/static/dist/assets/mermaid-HWGCJPDP-mtwrj8fn.js +1 -0
  303. package/static/dist/assets/{mermaid-parser.core-i91oxmou.js → mermaid-parser.core-ntne45i9.js} +3 -3
  304. package/static/dist/assets/{mindmap-definition-YA3MSWOX-m82mx8ww.js → mindmap-definition-YA3MSWOX-27b26eok.js} +1 -1
  305. package/static/dist/assets/onboarding-lkphzu1s.js +1 -0
  306. package/static/dist/assets/{onboarding_model_label-dp7xffoh.js → onboarding_model_label-ftpjdwqk.js} +1 -1
  307. package/static/dist/assets/{packet-AYTQ26CC-nbtgge2o.js → packet-AYTQ26CC-l6jdka8p.js} +1 -1
  308. package/static/dist/assets/{pegDiagram-XKGWAZYB-f1zxzga1.js → pegDiagram-XKGWAZYB-g1er3bxj.js} +1 -1
  309. package/static/dist/assets/{pie-WAS4IAKB-of8vuhxs.js → pie-WAS4IAKB-i0ylcrt9.js} +1 -1
  310. package/static/dist/assets/{pieDiagram-E7YTZNPT-o7y8ftio.js → pieDiagram-E7YTZNPT-fbz1e55z.js} +1 -1
  311. package/static/dist/assets/{quadrantDiagram-AXDQQJYC-iqiwia1t.js → quadrantDiagram-AXDQQJYC-hhue7d8o.js} +1 -1
  312. package/static/dist/assets/{radar-RG4KPBEZ-delnsy2v.js → radar-RG4KPBEZ-f9b70aa4.js} +1 -1
  313. package/static/dist/assets/{railroad-74A4TZTK-nspnyq9u.js → railroad-74A4TZTK-lgsuoeda.js} +1 -1
  314. package/static/dist/assets/railroad-abnf-HS5TGJTU-nf9d6pdx.js +1 -0
  315. package/static/dist/assets/railroad-ebnf-LZEXJU2U-f7ummkt5.js +1 -0
  316. package/static/dist/assets/railroad-peg-WCYAUIDC-oczq5tqs.js +1 -0
  317. package/static/dist/assets/{railroadDiagram-O6MQD6OU-z41tqx5z.js → railroadDiagram-O6MQD6OU-eqpy9fnz.js} +1 -1
  318. package/static/dist/assets/{refresh-b4uams1i.js → refresh-abtu93ke.js} +1 -1
  319. package/static/dist/assets/{refresh-cw-nt1dtsx4.js → refresh-cw-hlwb02qv.js} +1 -1
  320. package/static/dist/assets/{requirementDiagram-BXWQKSXE-bdvif194.js → requirementDiagram-BXWQKSXE-ogf6puhi.js} +1 -1
  321. package/static/dist/assets/{sankeyDiagram-P5KCCOFB-h73e0rol.js → sankeyDiagram-P5KCCOFB-fqb8xcjf.js} +1 -1
  322. package/static/dist/assets/{saved-kg52csy7.js → saved-girnabkf.js} +1 -1
  323. package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-iv95mb1z.js → sequenceDiagram-WJ2MYXX4-dlcz6qjz.js} +1 -1
  324. package/static/dist/assets/{settings_section_extensions_title-ej0iapxe.js → settings_section_extensions_title-h14cwk6f.js} +1 -1
  325. package/static/dist/assets/share._token-kl0r7ido.js +2 -0
  326. package/static/dist/assets/{sliders-horizontal-fj18it47.js → sliders-horizontal-n1zm34qq.js} +1 -1
  327. package/static/dist/assets/sse-iwku0sjo.js +1 -0
  328. package/static/dist/assets/{stateDiagram-D77RDMKH-k417ixmf.js → stateDiagram-D77RDMKH-fyoznpcs.js} +1 -1
  329. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-ixhx8r46.js +1 -0
  330. package/static/dist/assets/{swimlanes-42K2YHIH-esola70w.js → swimlanes-42K2YHIH-oefldhfy.js} +1 -1
  331. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-h9ersk2e.js +8 -0
  332. package/static/dist/assets/{timeline-definition-24CTP7MA-getrz2y8.js → timeline-definition-24CTP7MA-b1vl2zil.js} +1 -1
  333. package/static/dist/assets/todoStore-jjr5yr78.js +1 -0
  334. package/static/dist/assets/{treeView-Q6P3EWNA-hc7ap1q7.js → treeView-Q6P3EWNA-f7hcci5o.js} +1 -1
  335. package/static/dist/assets/{treemap-WGGIJYW6-b7k1syy5.js → treemap-WGGIJYW6-nl85071a.js} +1 -1
  336. package/static/dist/assets/{tts-lxdxnmjd.js → units-kgxzxfhi.js} +1 -1
  337. package/static/dist/assets/{untitled-ovpfthg4.js → untitled-cikfjntn.js} +1 -1
  338. package/static/dist/assets/{useForm-bcblv1rx.js → useForm-kqoqg0k9.js} +1 -1
  339. package/static/dist/assets/useLocale-o59tbiea.js +1 -0
  340. package/static/dist/assets/{useParams-lhg566ew.js → useParams-b4dq6n4q.js} +1 -1
  341. package/static/dist/assets/{useSearch-lbrh6ejn.js → useSearch-ipfmv3he.js} +1 -1
  342. package/static/dist/assets/{vennDiagram-4TSXK5OY-n6pcy5qb.js → vennDiagram-4TSXK5OY-h5hzbk0n.js} +1 -1
  343. package/static/dist/assets/{wardley-WFR3VGLG-lpa18vz1.js → wardley-WFR3VGLG-jftvpm3e.js} +1 -1
  344. package/static/dist/assets/{wardleyDiagram-VM6X3IG4-kpclwwg7.js → wardleyDiagram-VM6X3IG4-hedh85ge.js} +1 -1
  345. package/static/dist/assets/{xychartDiagram-S5SC5T6Z-paa2n8y0.js → xychartDiagram-S5SC5T6Z-e49523ab.js} +1 -1
  346. package/static/dist/index.html +1 -1
  347. package/static/dist/sw.js +1 -1
  348. package/static/dist/assets/AppShell-fb2td9zi.js +0 -1
  349. package/static/dist/assets/ChatPage-cj96kiy9.js +0 -25
  350. package/static/dist/assets/Dialog-kxcg7ard.js +0 -1
  351. package/static/dist/assets/ExtensionRoute-jf7h0754.js +0 -1
  352. package/static/dist/assets/HubRoute-gmanpd5y.js +0 -2
  353. package/static/dist/assets/Select-bilaypej.js +0 -1
  354. package/static/dist/assets/SessionListPanel-og8n36qs.js +0 -1
  355. package/static/dist/assets/Toaster-nnl8zkt9.js +0 -1
  356. package/static/dist/assets/_app.index-hbarzbjx.js +0 -1
  357. package/static/dist/assets/_app.insights-luywlarz.js +0 -1
  358. package/static/dist/assets/_app.kanban-kincnbr8.js +0 -1
  359. package/static/dist/assets/_app.logs-oi2gr3gs.js +0 -1
  360. package/static/dist/assets/_app.memory-b6jfivt6.js +0 -1
  361. package/static/dist/assets/_app.profiles-lpvixmqp.js +0 -1
  362. package/static/dist/assets/_app.settings-vowx3iq0.js +0 -1
  363. package/static/dist/assets/_app.settings._section-cnntg1tu.js +0 -3
  364. package/static/dist/assets/_app.skills-fb57lpau.js +0 -1
  365. package/static/dist/assets/_app.tasks-eszpx1q7.js +0 -2
  366. package/static/dist/assets/_app.todos-nr05ac6w.js +0 -1
  367. package/static/dist/assets/_app.workspaces-d2luomu6.js +0 -1
  368. package/static/dist/assets/architecture-7GRP2DOG-hd0o7bde.js +0 -1
  369. package/static/dist/assets/channel-cpdgf867.js +0 -1
  370. package/static/dist/assets/classDiagram-ZZMXUADV-ko09sguk.js +0 -1
  371. package/static/dist/assets/classDiagram-v2-VYDZK3BY-ko09sguk.js +0 -1
  372. package/static/dist/assets/endpoints-d33siokx.js +0 -64
  373. package/static/dist/assets/eventmodeling-NTZA5JFV-emctlo64.js +0 -1
  374. package/static/dist/assets/flowDiagram-HODETNUW-bfi3moqa.js +0 -1
  375. package/static/dist/assets/index-hgtx08n5.css +0 -2
  376. package/static/dist/assets/login-ec21t39x.js +0 -1
  377. package/static/dist/assets/mermaid-HWGCJPDP-gfl8z3ep.js +0 -1
  378. package/static/dist/assets/onboarding-btnltvyz.js +0 -1
  379. package/static/dist/assets/railroad-abnf-HS5TGJTU-nst1qxyn.js +0 -1
  380. package/static/dist/assets/railroad-ebnf-LZEXJU2U-ci37x8qy.js +0 -1
  381. package/static/dist/assets/railroad-peg-WCYAUIDC-aimkk07z.js +0 -1
  382. package/static/dist/assets/share._token-f97e94r0.js +0 -2
  383. package/static/dist/assets/sse-fwpqtzbg.js +0 -1
  384. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-hwn4apct.js +0 -1
  385. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-d1h97oyg.js +0 -8
  386. package/static/dist/assets/todoStore-eginf9h4.js +0 -1
  387. package/static/dist/assets/useLocale-fi5jb8ma.js +0 -1
@@ -0,0 +1,413 @@
1
+ /**
2
+ * LLM wiki status, browse, and page reads (Python `_llm_wiki_*` handlers). Only allowlisted pages are ever read: a
3
+ * `*.md` file under one of the page sections whose resolved path stays inside that section, with no dot segment, and
4
+ * a single link. Every read reopens the allowlisted real path with `O_NOFOLLOW` and requires the open file's
5
+ * `(dev, ino)` to match the identity captured when the allowlist was built.
6
+ */
7
+ import { closeSync, constants, fstatSync, lstatSync, openSync, readdirSync, readFileSync, readSync, realpathSync, statSync } from 'node:fs';
8
+ import { basename, isAbsolute, join, relative, sep } from 'node:path';
9
+ import { parseDotenv } from '../cli/dotenv.js';
10
+ import { isDict } from '../config/agent-config.js';
11
+ import { HttpFailure } from '../sessions/service.js';
12
+ import { expandHome, isWithin, resolvePathLikePython } from '../workspace/paths.js';
13
+ export const WIKI_DOCS_URL = 'https://hermes-agent.nousresearch.com/docs/user-guide/skills/bundled/research/research-llm-wiki';
14
+ const SECTIONS = ['entities', 'concepts', 'comparisons', 'queries'];
15
+ /** Bounds a walk when `WIKI_PATH` points somewhere huge; real wikis hold a few thousand files. */
16
+ const MAX_FILES = 10_000;
17
+ export const MAX_PAGE_BYTES = 2 * 1024 * 1024;
18
+ const FORBIDDEN_ROOTS = new Set(['/', '/etc', '/usr', '/var', '/opt', '/sys', '/proc'].map((p) => resolvePathLikePython(p)));
19
+ const TOGGLE_REASON = 'Hermes Agent exposes WIKI_PATH/wiki.path for location, but no stable on/off config flag is currently available.';
20
+ const O_READ = constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0);
21
+ const sameFile = (st, entry) => st.dev === entry.dev && st.ino === entry.ino;
22
+ const isClean = (rel) => rel !== '' && !rel.split(sep).some((part) => part.startsWith('.'));
23
+ const realpath = (path) => { try {
24
+ return realpathSync.native(path);
25
+ }
26
+ catch {
27
+ return null;
28
+ } };
29
+ /** `stat` / `lstat` answering `undefined` for any failure (missing, unreadable, not a directory): such an entry is never listed or read. */
30
+ const stat = (path) => { try {
31
+ return statSync(path);
32
+ }
33
+ catch {
34
+ return undefined;
35
+ } };
36
+ const lstat = (path) => { try {
37
+ return lstatSync(path);
38
+ }
39
+ catch {
40
+ return undefined;
41
+ } };
42
+ /** Python `os.path.expandvars`: `$NAME` and `${NAME}` from `env`; unknown names stay as written. */
43
+ function expandVars(text, env) {
44
+ return text.replace(/\$(\w+|\{[^}]*\})/g, (match, name) => env[name.startsWith('{') ? name.slice(1, -1) : name] ?? match);
45
+ }
46
+ /** A dotted config key, accepted flat (`'wiki.path': …`) or nested. */
47
+ function configValue(config, dotted) {
48
+ let value = config[dotted];
49
+ if (!value) {
50
+ value = config;
51
+ for (const part of dotted.split('.'))
52
+ value = isDict(value) ? value[part] : undefined;
53
+ }
54
+ return value && (typeof value === 'string' || typeof value === 'number') ? String(value) : null;
55
+ }
56
+ /**
57
+ * Python `_llm_wiki_resolve_path`: `WIKI_PATH` from the env, then from `<profile home>/.env`, then config
58
+ * `skills.config.wiki.path` or `wiki.path`, else `~/wiki`; env vars and `~` expanded.
59
+ */
60
+ export function resolveWikiLocation(env, profileHome, config, home) {
61
+ let raw = env.WIKI_PATH || homeDotenvWikiPath(profileHome);
62
+ let source = raw ? 'WIKI_PATH' : 'default';
63
+ if (!raw) {
64
+ raw = configValue(config, 'skills.config.wiki.path') ?? configValue(config, 'wiki.path');
65
+ if (raw)
66
+ source = 'skills.config.wiki.path';
67
+ }
68
+ return { path: expandHome(expandVars(raw || '~/wiki', env), home), source, configured: source !== 'default' };
69
+ }
70
+ function homeDotenvWikiPath(profileHome) {
71
+ try {
72
+ return parseDotenv(readFileSync(join(profileHome, '.env'), 'utf8')).WIKI_PATH || null;
73
+ }
74
+ catch {
75
+ return null;
76
+ }
77
+ }
78
+ /** Python `datetime.fromtimestamp(ts, utc).isoformat()` with `Z`: microseconds only when nonzero. */
79
+ function isoSeconds(ms) {
80
+ const micros = Math.round(ms * 1000);
81
+ const base = new Date(Math.floor(micros / 1000)).toISOString().slice(0, 19);
82
+ const fraction = ((micros % 1_000_000) + 1_000_000) % 1_000_000;
83
+ return `${base}${fraction ? `.${String(fraction).padStart(6, '0')}` : ''}Z`;
84
+ }
85
+ /**
86
+ * Entries under `dir`, like `Path.rglob`: directory symlinks are not followed; dot directories (never listed) are
87
+ * skipped. Every entry spends one unit of `budget`, so a huge tree cannot hold the event loop.
88
+ */
89
+ function* walk(dir, budget) {
90
+ let names;
91
+ try {
92
+ names = readdirSync(dir, { withFileTypes: true });
93
+ }
94
+ catch {
95
+ return;
96
+ }
97
+ for (const d of names) {
98
+ if (budget.left-- <= 0)
99
+ return;
100
+ const path = join(dir, d.name);
101
+ yield { path, name: d.name, dir: d.isDirectory() };
102
+ if (d.isDirectory() && !d.name.startsWith('.'))
103
+ yield* walk(path, budget);
104
+ }
105
+ }
106
+ /** Python `_llm_wiki_count_files`: regular files under `raw/` outside dot segments. */
107
+ function countRawFiles(root) {
108
+ const real = realpath(root);
109
+ if (!real || FORBIDDEN_ROOTS.has(real) || !stat(real)?.isDirectory())
110
+ return 0;
111
+ let count = 0;
112
+ for (const item of walk(root, { left: MAX_FILES })) {
113
+ if (!item.dir && !item.name.startsWith('.') && stat(item.path)?.isFile())
114
+ count++;
115
+ }
116
+ return count;
117
+ }
118
+ export class WikiPages {
119
+ opts;
120
+ cache = new Map();
121
+ constructor(opts = {}) {
122
+ this.opts = opts;
123
+ }
124
+ /** Change signature over the section directories only: `(dev, ino, mtime_ns)` each, or missing. */
125
+ signature(root) {
126
+ return SECTIONS.map((s) => {
127
+ try {
128
+ const st = lstatSync(join(root, s), { bigint: true });
129
+ return `${s}:${String(st.dev)}:${String(st.ino)}:${String(st.mtimeNs)}`;
130
+ }
131
+ catch {
132
+ return `${s}:-`;
133
+ }
134
+ }).join('|');
135
+ }
136
+ /** Python `_llm_wiki_page_files_uncached`. */
137
+ pageFilesUncached(root) {
138
+ const pages = [];
139
+ const rootReal = realpath(root);
140
+ if (!rootReal || FORBIDDEN_ROOTS.has(rootReal))
141
+ return pages;
142
+ const budget = { left: this.opts.maxFiles ?? MAX_FILES };
143
+ for (const name of SECTIONS) {
144
+ const section = join(root, name);
145
+ const sectionReal = realpath(section);
146
+ // A symlinked section must still resolve under the wiki root, so it cannot expose an outside tree.
147
+ if (!sectionReal || !stat(sectionReal)?.isDirectory() || !isWithin(sectionReal, rootReal))
148
+ continue;
149
+ for (const item of walk(section, budget)) {
150
+ if (!item.name.endsWith('.md') || !isClean(relative(section, item.path)))
151
+ continue;
152
+ try {
153
+ // A hard link at a clean page name can carry any inode, and the identity check at read time cannot tell it apart.
154
+ if (!statSync(item.path).isFile() || lstatSync(item.path).nlink > 1)
155
+ continue;
156
+ const itemReal = realpathSync.native(item.path);
157
+ if (isWithin(itemReal, sectionReal) && isClean(relative(rootReal, itemReal)))
158
+ pages.push(item.path);
159
+ }
160
+ catch { /* vanished */ }
161
+ }
162
+ }
163
+ return pages;
164
+ }
165
+ /**
166
+ * Python `_llm_wiki_page_files`: the allowlisted page paths, cached 5 s per resolved root while no section's
167
+ * `(dev, ino, mtime_ns)` changes. A page swapped inside a nested directory leaves the signature unchanged, so every
168
+ * reader rechecks each cached path (`allowlistedEntries`). Trust boundary: a hard link created at a listed name
169
+ * before the snapshot carries that page's identity; the wiki directory is operator-controlled, so that is accepted.
170
+ */
171
+ pageFiles(root) {
172
+ const key = realpath(root) ?? root;
173
+ const signature = this.signature(key);
174
+ const now = (this.opts.now ?? Date.now)();
175
+ const cached = this.cache.get(key);
176
+ if (cached?.signature === signature && now < cached.expiresAt)
177
+ return [...cached.files];
178
+ const files = this.pageFilesUncached(key);
179
+ this.cache.set(key, { signature, expiresAt: now + (this.opts.ttlMs ?? 5000), files });
180
+ return [...files];
181
+ }
182
+ /** Python `_llm_wiki_allowlisted_entries`: listed relpaths (posix) mapped to their real path and identity, rechecked now. */
183
+ allowlistedEntries(root) {
184
+ const entries = new Map();
185
+ const rootReal = realpath(root);
186
+ if (!rootReal)
187
+ return entries;
188
+ for (const listed of this.pageFiles(rootReal)) {
189
+ try {
190
+ const rel = relative(rootReal, listed);
191
+ if (!isClean(rel) || rel.includes('\\'))
192
+ continue;
193
+ const sectionReal = realpathSync.native(join(rootReal, rel.split(sep)[0] ?? ''));
194
+ const target = realpathSync.native(listed);
195
+ if (!isWithin(sectionReal, rootReal) || !isWithin(target, sectionReal) || !isClean(relative(rootReal, target)))
196
+ continue;
197
+ const st = statSync(target);
198
+ if (!st.isFile() || st.nlink > 1 || realpathSync.native(listed) !== target)
199
+ continue;
200
+ entries.set(rel.split(sep).join('/'), { target, dev: st.dev, ino: st.ino });
201
+ }
202
+ catch { /* vanished */ }
203
+ }
204
+ return entries;
205
+ }
206
+ /** The single open used for every wiki read: no symlink at the final component, and a FIFO cannot block. */
207
+ openNoFollow(path) {
208
+ return openSync(path, O_READ);
209
+ }
210
+ /** Open `path` and require the open file to be `identity`; `null` when it changed or vanished. */
211
+ openVerified(path, identity) {
212
+ let fd;
213
+ try {
214
+ fd = this.openNoFollow(path);
215
+ }
216
+ catch {
217
+ return null;
218
+ }
219
+ try {
220
+ if (sameFile(fstatSync(fd), identity))
221
+ return fd;
222
+ }
223
+ catch { /* closed below */ }
224
+ closeSync(fd);
225
+ return null;
226
+ }
227
+ /** Lines from an open file (UTF-8 with replacement), at most `maxLines`, reading at most `MAX_PAGE_BYTES`. */
228
+ *lines(fd, maxLines) {
229
+ const decoder = new TextDecoder('utf-8', { ignoreBOM: true });
230
+ const buf = Buffer.alloc(64 * 1024);
231
+ let pending = '';
232
+ let read = 0;
233
+ let emitted = 0;
234
+ for (;;) {
235
+ const n = read < MAX_PAGE_BYTES ? readSync(fd, buf, 0, Math.min(buf.length, MAX_PAGE_BYTES - read), null) : 0;
236
+ read += n;
237
+ pending += n ? decoder.decode(buf.subarray(0, n), { stream: true }) : decoder.decode();
238
+ let nl;
239
+ while ((nl = pending.indexOf('\n')) >= 0) {
240
+ if (emitted++ >= maxLines)
241
+ return;
242
+ yield pending.slice(0, nl + 1);
243
+ pending = pending.slice(nl + 1);
244
+ }
245
+ if (!n) {
246
+ if (pending && emitted < maxLines)
247
+ yield pending;
248
+ return;
249
+ }
250
+ }
251
+ }
252
+ /** A top-level status file (`SCHEMA.md`, `index.md`, `log.md`), opened only while it is a regular file inside the wiki. */
253
+ openStatusFile(root, name) {
254
+ const path = join(root, name);
255
+ const real = realpath(path);
256
+ const rootReal = realpath(root);
257
+ if (!real || !rootReal || !isWithin(real, rootReal))
258
+ return null;
259
+ const entry = lstat(path);
260
+ return entry?.isFile() ? this.openVerified(path, entry) : null;
261
+ }
262
+ statusFileMtime(root, name) {
263
+ const fd = this.openStatusFile(root, name);
264
+ if (fd === null)
265
+ return undefined;
266
+ try {
267
+ return fstatSync(fd).mtimeMs;
268
+ }
269
+ finally {
270
+ closeSync(fd);
271
+ }
272
+ }
273
+ /**
274
+ * Python `_llm_wiki_last_writer`: `updated_by` / `writer` / `author` from the newest page's frontmatter (200 lines),
275
+ * else the first `## [date] action |` heading in `log.md` (5,000 lines) as `ai-agent (<action>)`, else `ai-agent`.
276
+ */
277
+ lastWriter(root, pages) {
278
+ const rootReal = realpath(root) ?? root;
279
+ let latest = null;
280
+ let latestMtime = -1;
281
+ for (const page of pages) {
282
+ const real = realpath(page.target);
283
+ const st = real && isWithin(real, rootReal) ? stat(page.target) : undefined;
284
+ if (st && sameFile(st, page) && st.mtimeMs > latestMtime) {
285
+ latest = page;
286
+ latestMtime = st.mtimeMs;
287
+ }
288
+ }
289
+ const fd = latest ? this.openVerified(latest.target, latest) : null;
290
+ if (fd !== null) {
291
+ try {
292
+ const lines = this.lines(fd, 201);
293
+ const first = lines.next();
294
+ if (!first.done && first.value.trim() === '---') {
295
+ for (const line of lines) {
296
+ const stripped = line.trim();
297
+ if (stripped === '---')
298
+ break;
299
+ const key = ['updated_by', 'writer', 'author'].find((k) => stripped.toLowerCase().startsWith(`${k}:`));
300
+ const value = key ? stripped.slice(stripped.indexOf(':') + 1).trim() : '';
301
+ if (value)
302
+ return value;
303
+ }
304
+ }
305
+ }
306
+ catch { /* unreadable */ }
307
+ finally {
308
+ closeSync(fd);
309
+ }
310
+ }
311
+ const logFd = this.openStatusFile(root, 'log.md');
312
+ if (logFd !== null) {
313
+ try {
314
+ for (const line of this.lines(logFd, 5000)) {
315
+ const stripped = line.trim();
316
+ if (!stripped.startsWith('## [') || !stripped.includes('|'))
317
+ continue;
318
+ const tail = stripped.includes(']') ? stripped.slice(stripped.indexOf(']') + 1).trim() : '';
319
+ return `ai-agent (${tail ? (tail.split(/\s+/)[0] ?? 'update') : 'update'})`;
320
+ }
321
+ }
322
+ catch { /* unreadable */ }
323
+ finally {
324
+ closeSync(logFd);
325
+ }
326
+ }
327
+ return 'ai-agent';
328
+ }
329
+ /** Python `_build_llm_wiki_status`: always answers, never with page bodies or the wiki path. */
330
+ status(location) {
331
+ const base = { available: false, enabled: false, status: 'missing', entry_count: 0, page_count: 0, raw_source_count: 0, last_updated: null, last_writer: 'ai-agent', path_configured: location.configured, path_source: location.source, toggle_available: false, toggle_reason: TOGGLE_REASON, docs_url: WIKI_DOCS_URL };
332
+ try {
333
+ const root = location.path;
334
+ const rootStat = stat(root);
335
+ if (!rootStat)
336
+ return base;
337
+ if (!rootStat.isDirectory())
338
+ return { ...base, status: 'not_directory' };
339
+ const verified = [];
340
+ for (const entry of this.allowlistedEntries(root).values()) {
341
+ const st = stat(entry.target);
342
+ if (st && sameFile(st, entry))
343
+ verified.push({ entry, st });
344
+ }
345
+ const mtimes = [...['SCHEMA.md', 'index.md', 'log.md'].map((n) => this.statusFileMtime(root, n)), ...verified.map((v) => v.st.mtimeMs)].filter((m) => m !== undefined);
346
+ const latest = mtimes.length ? Math.max(...mtimes) : 0;
347
+ return {
348
+ ...base, available: true, enabled: true, status: verified.length ? 'ready' : 'empty', entry_count: verified.length, page_count: verified.length,
349
+ raw_source_count: countRawFiles(join(root, 'raw')), last_updated: latest ? isoSeconds(latest) : null, last_writer: this.lastWriter(root, verified.map((v) => v.entry)),
350
+ };
351
+ }
352
+ catch (error) {
353
+ return { ...base, path_configured: false, path_source: 'unknown', toggle_reason: 'Unable to inspect LLM Wiki status safely.', status: 'error', error: error instanceof Error ? error.constructor.name : 'Error' };
354
+ }
355
+ }
356
+ /** `GET /api/wiki/browse`: listed pages sorted case-insensitively, skipping any whose identity changed. */
357
+ browse(location) {
358
+ if (!stat(location.path)?.isDirectory())
359
+ throw new HttpFailure(404, 'Wiki not configured or directory not found');
360
+ const pages = [];
361
+ const key = (rel) => rel.toLowerCase();
362
+ for (const [rel, entry] of [...this.allowlistedEntries(location.path)].sort(([a], [b]) => (key(a) < key(b) ? -1 : key(a) > key(b) ? 1 : 0))) {
363
+ const st = stat(entry.target);
364
+ if (st && sameFile(st, entry))
365
+ pages.push({ name: basename(rel), path: rel, size: st.size, mtime: Math.floor(st.mtimeMs / 1000) });
366
+ }
367
+ return { pages };
368
+ }
369
+ /** `GET /api/wiki/page`: one canonical, allowlisted relpath, read through the identity-checked open, cut at 2 MiB. */
370
+ page(location, path) {
371
+ const root = location.path;
372
+ if (!path)
373
+ throw new HttpFailure(400, 'Wiki not configured or path not provided');
374
+ const parts = path.split('/');
375
+ // A `..` or empty or `.` segment is refused; `v1..v2.md` is a legitimate name.
376
+ if (path.includes('\\') || isAbsolute(path) || parts.some((p) => p === '..' || p === '' || p === '.'))
377
+ throw new HttpFailure(400, 'Invalid path');
378
+ const resolved = resolvePathLikePython(join(root, path));
379
+ if (!isWithin(resolved, resolvePathLikePython(root)))
380
+ throw new HttpFailure(400, 'Invalid path');
381
+ const entry = this.allowlistedEntries(resolvePathLikePython(root)).get(path);
382
+ if (entry?.target !== resolved)
383
+ throw new HttpFailure(404, 'Page not found');
384
+ let fd;
385
+ try {
386
+ fd = this.openNoFollow(entry.target);
387
+ }
388
+ catch (error) {
389
+ const code = error.code;
390
+ throw new HttpFailure(404, code === 'ENOENT' || code === 'EISDIR' ? 'Page not found' : 'Could not read page');
391
+ }
392
+ try {
393
+ if (!sameFile(fstatSync(fd), entry))
394
+ throw new HttpFailure(404, 'Page not found');
395
+ const buf = Buffer.alloc(MAX_PAGE_BYTES);
396
+ let total = 0;
397
+ for (let n = 1; n > 0 && total < buf.length; total += n)
398
+ n = readSync(fd, buf, total, buf.length - total, null);
399
+ return { content: buf.subarray(0, total).toString('utf8'), path };
400
+ }
401
+ catch (error) {
402
+ if (error instanceof HttpFailure)
403
+ throw error;
404
+ throw new HttpFailure(404, 'Could not read page');
405
+ }
406
+ finally {
407
+ closeSync(fd);
408
+ }
409
+ }
410
+ }
411
+ /** The process-wide allowlist cache shared by the wiki routes. */
412
+ export const wikiPages = new WikiPages();
413
+ //# sourceMappingURL=wiki.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wiki.js","sourceRoot":"","sources":["../../src/tools/wiki.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import { type DirEntry } from './fs.js';
2
+ import { type FilePreview } from './preview.js';
3
+ export declare const ESCAPE_GRANT_TTL_SECONDS = 300;
4
+ /** Any failed re-check: the client asks for a new grant (403). */
5
+ export declare class EscapeGrantExpired extends Error {
6
+ constructor();
7
+ }
8
+ interface RootId {
9
+ dev: number;
10
+ ino: number;
11
+ }
12
+ export interface EscapeRequest {
13
+ surfacePath: string;
14
+ requestPath: string;
15
+ externalRoot: string;
16
+ rootId: RootId;
17
+ externalRel: string;
18
+ }
19
+ /** Run `fn` with every anchored open of the grant root held to the inode the grant was minted for. */
20
+ export declare function anchoredAt<T>(req: EscapeRequest, fn: () => T): T;
21
+ /** Python `_normalize_workspace_rel_path`: POSIX-normalised and workspace-relative; `..` and absolute paths fail. */
22
+ export declare function normalizeWorkspaceRelPath(rel: string): string;
23
+ export declare class EscapeGrants {
24
+ private readonly now;
25
+ private readonly grants;
26
+ constructor(now: () => number);
27
+ /** Mint a grant for one surfaced escape-target symlink. */
28
+ authorize(workspace: string, sessionId: string, profile: string | null, rel: string): {
29
+ token: string;
30
+ path: string;
31
+ is_dir: boolean;
32
+ expires_at: number;
33
+ expires_in: number;
34
+ read_only: true;
35
+ };
36
+ /**
37
+ * Python `resolve_authorized_escape_request`: re-check the grant, then re-root a request path under the link onto
38
+ * the grant root. A path outside the link answers "Path traversal blocked".
39
+ */
40
+ resolve(workspace: string, sessionId: string, profile: string | null, token: string, rel: string): EscapeRequest;
41
+ /** Python `list_authorized_escape_dir`: entries re-pathed under the link; a target outside the grant root is dropped. */
42
+ list(req: EscapeRequest): {
43
+ path: string;
44
+ entries: (DirEntry & {
45
+ escape_read_only: true;
46
+ })[];
47
+ signature: string;
48
+ virtual_root: string;
49
+ read_only: true;
50
+ };
51
+ /** Python `read_authorized_escape_file_content`, with the `/api/file` preview kind. */
52
+ read(req: EscapeRequest): FilePreview & {
53
+ escape_read_only: true;
54
+ };
55
+ /** Python `raw_authorized_escape_target`: the file to serve, anchored at the grant root. */
56
+ rawTarget(req: EscapeRequest): string;
57
+ /** Python `_escape_authorization_record`: the link must still escape to the same reachable, non-system target and root inode. */
58
+ private check;
59
+ private prune;
60
+ }
61
+ export {};
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Read-only escape grants (Python `workspace.py` `authorize_escape_target` and friends, TAL-263): a workspace symlink
3
+ * whose target sits outside the workspace opens through a short-lived token scoped to that one link. A directory
4
+ * target anchors the grant at the target; a file target anchors it at the parent with the file as the only reachable
5
+ * entry. Every use re-checks the link, and every read stays anchored at the grant root, so nested escaping links stay
6
+ * display-only.
7
+ */
8
+ import { randomBytes } from 'node:crypto';
9
+ import { lstatSync, statSync } from 'node:fs';
10
+ import { basename, dirname, join, posix, relative } from 'node:path';
11
+ import { stripSurroundingQuotes, isBlockedSystemPath } from './workspaces.js';
12
+ import { isWithin, resolvePathLikePython } from './paths.js';
13
+ import { dirSignature, listDir, NotFoundError, PathTraversalError, safeResolveWs, withPinnedRoot } from './fs.js';
14
+ import { readFilePreview } from './preview.js';
15
+ export const ESCAPE_GRANT_TTL_SECONDS = 300;
16
+ /** Any failed re-check: the client asks for a new grant (403). */
17
+ export class EscapeGrantExpired extends Error {
18
+ constructor() { super('Escape authorization expired'); }
19
+ }
20
+ /** Run `fn` with every anchored open of the grant root held to the inode the grant was minted for. */
21
+ export function anchoredAt(req, fn) {
22
+ return withPinnedRoot(req.externalRoot, req.rootId, fn);
23
+ }
24
+ /** Python `_normalize_workspace_rel_path`: POSIX-normalised and workspace-relative; `..` and absolute paths fail. */
25
+ export function normalizeWorkspaceRelPath(rel) {
26
+ const raw = stripSurroundingQuotes(rel).trim().replaceAll('\\', '/');
27
+ if (!raw || raw === '.')
28
+ return '.';
29
+ const norm = posix.normalize(raw).replace(/(.)\/+$/, '$1');
30
+ if (norm === '.')
31
+ return '.';
32
+ if (norm === '..' || norm.startsWith('../') || norm.startsWith('/'))
33
+ throw new PathTraversalError(`Path traversal blocked: ${rel}`);
34
+ return norm;
35
+ }
36
+ function virtualPath(root, rel) {
37
+ if (root === '.')
38
+ return rel;
39
+ return rel === '.' ? root : `${root}/${rel}`;
40
+ }
41
+ /** Python `_escape_surface_target`: the resolved target of an escaping, reachable, non-system workspace symlink. */
42
+ function surfaceTarget(workspaceRoot, rel) {
43
+ const surfaceRel = normalizeWorkspaceRelPath(rel);
44
+ const parentRel = posix.dirname(surfaceRel);
45
+ const parent = parentRel === '.' ? workspaceRoot : safeResolveWs(workspaceRoot, parentRel);
46
+ const surface = join(parent, posix.basename(surfaceRel));
47
+ let isLink = false;
48
+ try {
49
+ isLink = lstatSync(surface).isSymbolicLink();
50
+ }
51
+ catch { /* missing */ }
52
+ if (!isLink)
53
+ throw new NotFoundError(`Path is not an escape-target symlink: ${rel}`);
54
+ let target;
55
+ try {
56
+ target = resolvePathLikePython(surface);
57
+ statSync(target);
58
+ }
59
+ catch {
60
+ throw new NotFoundError(`Path is no longer reachable: ${rel}`);
61
+ }
62
+ if (isWithin(target, workspaceRoot))
63
+ throw new NotFoundError(`Path does not escape workspace: ${rel}`);
64
+ if (isBlockedSystemPath(target))
65
+ throw new NotFoundError(`Path points to a system directory: ${target}`);
66
+ return target;
67
+ }
68
+ export class EscapeGrants {
69
+ now;
70
+ grants = new Map();
71
+ constructor(now) {
72
+ this.now = now;
73
+ }
74
+ /** Mint a grant for one surfaced escape-target symlink. */
75
+ authorize(workspace, sessionId, profile, rel) {
76
+ const workspaceRoot = resolvePathLikePython(workspace);
77
+ const target = surfaceTarget(workspaceRoot, rel);
78
+ const isDir = statSync(target).isDirectory();
79
+ const externalRoot = isDir ? target : dirname(target);
80
+ const { dev, ino } = statSync(externalRoot);
81
+ const token = randomBytes(24).toString('base64url');
82
+ const expiresAt = this.now() + ESCAPE_GRANT_TTL_SECONDS;
83
+ const surfacePath = normalizeWorkspaceRelPath(rel);
84
+ this.prune();
85
+ this.grants.set(token, { sessionId, profile, workspaceRoot, surfacePath, externalRoot, rootId: { dev, ino }, externalEntryRel: isDir ? '.' : basename(target), surfaceTarget: target, expiresAt });
86
+ return { token, path: surfacePath, is_dir: isDir, expires_at: expiresAt, expires_in: ESCAPE_GRANT_TTL_SECONDS, read_only: true };
87
+ }
88
+ /**
89
+ * Python `resolve_authorized_escape_request`: re-check the grant, then re-root a request path under the link onto
90
+ * the grant root. A path outside the link answers "Path traversal blocked".
91
+ */
92
+ resolve(workspace, sessionId, profile, token, rel) {
93
+ const grant = this.check(workspace, sessionId, profile, token);
94
+ const requestPath = normalizeWorkspaceRelPath(rel);
95
+ const under = grant.surfacePath === '.' ? requestPath : requestPath === grant.surfacePath ? '.' : requestPath.startsWith(`${grant.surfacePath}/`) ? requestPath.slice(grant.surfacePath.length + 1) : null;
96
+ if (under === null)
97
+ throw new PathTraversalError(`Path traversal blocked: ${rel}`);
98
+ const externalRel = grant.externalEntryRel === '.' ? under : under === '.' ? grant.externalEntryRel : `${grant.externalEntryRel}/${under}`;
99
+ return { surfacePath: grant.surfacePath, requestPath, externalRoot: grant.externalRoot, rootId: grant.rootId, externalRel };
100
+ }
101
+ /** Python `list_authorized_escape_dir`: entries re-pathed under the link; a target outside the grant root is dropped. */
102
+ list(req) {
103
+ const entries = anchoredAt(req, () => listDir(req.externalRoot, req.externalRel)).map((entry) => {
104
+ const out = { ...entry, path: virtualPath(req.surfacePath, entry.path), escape_read_only: true };
105
+ if (entry.target === undefined)
106
+ return out;
107
+ delete out.target;
108
+ if (isWithin(entry.target, req.externalRoot))
109
+ out.target = virtualPath(req.surfacePath, relative(req.externalRoot, entry.target) || '.');
110
+ return out;
111
+ });
112
+ return { path: req.requestPath, entries, signature: dirSignature(req.externalRoot, req.externalRel, entries), virtual_root: req.surfacePath, read_only: true };
113
+ }
114
+ /** Python `read_authorized_escape_file_content`, with the `/api/file` preview kind. */
115
+ read(req) {
116
+ return { ...anchoredAt(req, () => readFilePreview(req.externalRoot, req.externalRel)), path: req.requestPath, escape_read_only: true };
117
+ }
118
+ /** Python `raw_authorized_escape_target`: the file to serve, anchored at the grant root. */
119
+ rawTarget(req) {
120
+ return safeResolveWs(req.externalRoot, req.externalRel);
121
+ }
122
+ /** Python `_escape_authorization_record`: the link must still escape to the same reachable, non-system target and root inode. */
123
+ check(workspace, sessionId, profile, token) {
124
+ this.prune();
125
+ const grant = this.grants.get(token);
126
+ if (grant?.sessionId !== sessionId || grant.profile !== profile || grant.workspaceRoot !== resolvePathLikePython(workspace))
127
+ throw new EscapeGrantExpired();
128
+ try {
129
+ if (surfaceTarget(grant.workspaceRoot, grant.surfacePath) !== grant.surfaceTarget)
130
+ throw new EscapeGrantExpired();
131
+ const root = statSync(grant.externalRoot);
132
+ if (root.dev !== grant.rootId.dev || root.ino !== grant.rootId.ino)
133
+ throw new EscapeGrantExpired();
134
+ }
135
+ catch {
136
+ // A retargeted link kills the grant for good, even if it later points back.
137
+ this.grants.delete(token);
138
+ throw new EscapeGrantExpired();
139
+ }
140
+ return grant;
141
+ }
142
+ prune() {
143
+ const now = this.now();
144
+ for (const [token, grant] of this.grants)
145
+ if (grant.expiresAt <= now)
146
+ this.grants.delete(token);
147
+ }
148
+ }
149
+ //# sourceMappingURL=escape.js.map