@vantran-se/openchamber-web 1.23.1 → 1.24.4
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.
- package/bin/cli.test.js +29 -6
- package/bin/lib/cli-http.js +5 -1
- package/bin/lib/commands-status.js +5 -0
- package/dist/assets/{CodeMirrorCommentWidgets-BOpqXpFU.js → CodeMirrorCommentWidgets-B4a0JkUz.js} +1 -1
- package/dist/assets/DiffView-B2CD9wC8.js +4 -0
- package/dist/assets/FilesView-C4vMFclc.js +13 -0
- package/dist/assets/GitView-Byu2DY7s.js +6 -0
- package/dist/assets/GuestAttachDialog-B808E0-d.js +1 -0
- package/dist/assets/{JsonTreeView-nd_E8eVM.js → JsonTreeView-VW_7czo3.js} +1 -1
- package/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/assets/LinearIssuesView-EzGNCGrd.js +1 -0
- package/dist/assets/{MarkdownImageGallery-CVYds3sQ.js → MarkdownImageGallery-B2YUDFaB.js} +1 -1
- package/dist/assets/MarkdownRendererImpl-B4ikIzR3.js +12 -0
- package/dist/assets/{OnboardingScreen-Dd2IbPTn.js → OnboardingScreen-CQHBSTEi.js} +1 -1
- package/dist/assets/{PatchDiff-nUu5i4bG.js → PatchDiff-DCjGhlYV.js} +1 -1
- package/dist/assets/PierreDiffViewer-CEDZNkU2.js +210 -0
- package/dist/assets/PlanView-D3x-pTkZ.js +5 -0
- package/dist/assets/PluginPane-DEcgDQ9h.js +3 -0
- package/dist/assets/SettingsView-CSinuH-1.js +29 -0
- package/dist/assets/{SettingsWindow-BccxY81J.js → SettingsWindow-B5CHoJFZ.js} +1 -1
- package/dist/assets/SubmoduleDiffSummary-oxeACCWs.js +1 -0
- package/dist/assets/ToolOutputDialog-tLNWmfcW.js +15 -0
- package/dist/assets/{ToolPartDiffPreview-BFVgk0UK.js → ToolPartDiffPreview-CflzmK-x.js} +2 -2
- package/dist/assets/{VirtualizedFileDiff-z3_H74UR.js → VirtualizedFileDiff-NU0FHFhT.js} +3 -3
- package/dist/assets/{WalkthroughView-BqM9GFbJ.js → WalkthroughView-BZyjhqHv.js} +2 -2
- package/dist/assets/appThemeRegistry-DLicw4dH.js +1 -0
- package/dist/assets/commitAndPush-BDftrjr6.js +1 -0
- package/dist/assets/{computeVirtualFileMetrics-Bdazp9Qo.js → computeVirtualFileMetrics-DlWlEM3x.js} +1 -1
- package/dist/assets/de-Bro6_zyl.js +10 -0
- package/dist/assets/es-Bb9XQZvd.js +16 -0
- package/dist/assets/fr-Dgfzn-IL.js +14 -0
- package/dist/assets/{index-eo1-D_7z.js → index-CtQNmqUL.js} +1 -1
- package/dist/assets/index-DqaMWNrC.css +1 -0
- package/dist/assets/index-Dqc6USl3.js +40 -0
- package/dist/assets/{isDiffPlainText-BvKH712-.js → isDiffPlainText-CO4e5J_S.js} +1 -1
- package/dist/assets/{isFilePlainText-BdVVPukf.js → isFilePlainText-ue6kCou7.js} +1 -1
- package/dist/assets/ja-BYsakGFh.js +16 -0
- package/dist/assets/ko-BSaQz9aN.js +16 -0
- package/dist/assets/main-B62_pjL5.js +2 -0
- package/dist/assets/main-BEdcOI2P.js +896 -0
- package/dist/assets/{markdown-shiki.worker-D5fBU-lw.js → markdown-shiki.worker-CahLvHIq.js} +5 -5
- package/dist/assets/markdownCore-CK48LG0z.js +5 -0
- package/dist/assets/miniChat-LT8Rqofr.js +2 -0
- package/dist/assets/mobile-CqarEynh.js +2 -0
- package/dist/assets/{patchFileDiff-B7LjppSS.js → patchFileDiff-D7QVlovD.js} +3 -3
- package/dist/assets/pl-OIviPdoj.js +16 -0
- package/dist/assets/pt-BR-Cltg-E6s.js +16 -0
- package/dist/assets/renderElectronMiniChatApp-COyLTtZx.js +2 -0
- package/dist/assets/renderMobileApp-BC1MHg6g.js +25 -0
- package/dist/assets/runtimeEndpointReset-DdrazOVH.js +25 -0
- package/dist/assets/{scheduledTasksApi-hceovDei.js → scheduledTasksApi-B2SWMGEU.js} +1 -1
- package/dist/assets/shikiHighlight-BPu3JiQs.js +1 -0
- package/dist/assets/textMateThemeFromAppTheme-DWqRPo9A.js +1 -0
- package/dist/assets/tr-CQI-KPre.js +7 -0
- package/dist/assets/uk-CqW7R4DA.js +16 -0
- package/dist/assets/useAppFontEffects-ne84JBVL.js +7333 -0
- package/dist/assets/useInlineCommentController-CgS0fnw_.js +2 -0
- package/dist/assets/useRootScrollLock-Cpf1qoGp.js +2 -0
- package/dist/assets/{vendor-base-ui-BY_5qla_.js → vendor-base-ui-CsXYnR5c.js} +1 -1
- package/dist/assets/{vendor-codemirror-language-data-DWA1bm1F.js → vendor-codemirror-language-data-Bx2EHc1O.js} +2 -2
- package/dist/assets/vendor-framer-motion-Bq3iTZ6r.js +1 -0
- package/dist/assets/vendor-katex-Cp579UoJ.css +1 -0
- package/dist/assets/{vendor-motion-dom-D_o3BTI3.js → vendor-motion-dom-DcCgeG69.js} +1 -1
- package/dist/assets/{vendor-remixicon-react-Dil0zKKT.js → vendor-remixicon-react-BDmGmFCA.js} +1 -1
- package/dist/assets/vendor-strip-json-comments-5dJlOkP1.js +4 -0
- package/dist/assets/{vendor-tanstack-react-virtual-g05Cx3z9.js → vendor-tanstack-react-virtual-ClYN8CzB.js} +1 -1
- package/dist/assets/{vendor-tanstack-virtual-core-Dubg10g5.js → vendor-tanstack-virtual-core-BewVQryB.js} +1 -1
- package/dist/assets/{vendor-zod-B6551dwG.js → vendor-zod-CgAdXWZO.js} +4 -4
- package/dist/assets/{web-components-B_Z64So5.js → web-components-DxX8bZ1o.js} +2 -2
- package/dist/assets/zh-CN-CVZG_o_J.js +16 -0
- package/dist/assets/zh-TW-D5ZxzCZp.js +16 -0
- package/dist/index.html +6 -4
- package/dist/mini-chat.html +6 -4
- package/dist/mobile.html +6 -4
- package/package.json +12 -9
- package/server/built-in-extensions/registry.json +4 -0
- package/server/index.d.ts +2 -0
- package/server/index.js +44 -10
- package/server/lib/agent-tool/DOCUMENTATION.md +17 -4
- package/server/lib/agent-tool/runtime.js +62 -15
- package/server/lib/agent-tool/runtime.test.js +88 -2
- package/server/lib/changelog/update-notes.js +2 -1
- package/server/lib/changelog/update-notes.test.js +19 -0
- package/server/lib/event-stream/DOCUMENTATION.md +23 -0
- package/server/lib/event-stream/delta-coalescer.js +0 -0
- package/server/lib/event-stream/delta-coalescer.test.js +292 -0
- package/server/lib/event-stream/global-hub.js +53 -23
- package/server/lib/event-stream/global-hub.test.js +160 -0
- package/server/lib/event-stream/global-ws-bridge.js +1 -0
- package/server/lib/event-stream/index.js +4 -0
- package/server/lib/fs/DOCUMENTATION.md +10 -1
- package/server/lib/fs/git-process.test.js +77 -0
- package/server/lib/fs/routes.js +58 -5
- package/server/lib/fs/routes.test.js +116 -0
- package/server/lib/fs/search.js +2 -1
- package/server/lib/git/DOCUMENTATION.md +20 -5
- package/server/lib/git/routes.js +16 -3
- package/server/lib/git/serial-refresh.js +93 -0
- package/server/lib/git/serial-refresh.test.js +112 -0
- package/server/lib/git/service.js +429 -70
- package/server/lib/git/service.test.js +418 -0
- package/server/lib/github/pr-status.js +5 -5
- package/server/lib/github/pr-status.test.js +1 -1
- package/server/lib/github/routes.js +4 -4
- package/server/lib/guests/DOCUMENTATION.md +68 -0
- package/server/lib/guests/auth-store.js +184 -0
- package/server/lib/guests/auth-store.test.js +112 -0
- package/server/lib/guests/background.test.js +83 -0
- package/server/lib/guests/builtins.js +34 -0
- package/server/lib/guests/builtins.test.js +174 -0
- package/server/lib/guests/catalog.js +477 -0
- package/server/lib/guests/catalog.test.js +390 -0
- package/server/lib/guests/clone.js +297 -0
- package/server/lib/guests/extract-zip.js +136 -0
- package/server/lib/guests/extract-zip.test.js +109 -0
- package/server/lib/guests/files.js +308 -0
- package/server/lib/guests/files.test.js +262 -0
- package/server/lib/guests/grant-scope.js +81 -0
- package/server/lib/guests/grant-scope.test.js +75 -0
- package/server/lib/guests/host-session.js +73 -0
- package/server/lib/guests/host-session.test.js +30 -0
- package/server/lib/guests/html-styles.js +6 -0
- package/server/lib/guests/html-styles.test.js +45 -0
- package/server/lib/guests/html-tokens.js +73 -0
- package/server/lib/guests/html-tokens.test.js +53 -0
- package/server/lib/guests/install.js +406 -0
- package/server/lib/guests/install.test.js +338 -0
- package/server/lib/guests/oauth.js +501 -0
- package/server/lib/guests/oauth.test.js +481 -0
- package/server/lib/guests/persist.js +336 -0
- package/server/lib/guests/persist.test.js +288 -0
- package/server/lib/guests/request.js +112 -0
- package/server/lib/guests/request.test.js +206 -0
- package/server/lib/guests/routes.js +838 -0
- package/server/lib/guests/service.js +538 -0
- package/server/lib/guests/service.test.js +277 -0
- package/server/lib/guests/sockets.js +129 -0
- package/server/lib/guests/sockets.test.js +110 -0
- package/server/lib/guests/ssh-install.test.js +188 -0
- package/server/lib/guests/storage.js +68 -0
- package/server/lib/guests/storage.test.js +59 -0
- package/server/lib/guests/updates.js +294 -0
- package/server/lib/guests/updates.test.js +334 -0
- package/server/lib/guests/upload.js +50 -0
- package/server/lib/guests/upload.test.js +131 -0
- package/server/lib/linear/DOCUMENTATION.md +1 -1
- package/server/lib/message-queue/DOCUMENTATION.md +10 -1
- package/server/lib/message-queue/runtime.js +21 -1
- package/server/lib/message-queue/runtime.test.js +52 -5
- package/server/lib/notifications/routes.js +5 -0
- package/server/lib/openchamber-control/DOCUMENTATION.md +6 -0
- package/server/lib/openchamber-sessions/routes.js +62 -29
- package/server/lib/openchamber-sessions/routes.test.js +96 -0
- package/server/lib/opencode/DOCUMENTATION.md +55 -1
- package/server/lib/opencode/bootstrap-runtime.js +1 -0
- package/server/lib/opencode/core-routes.js +39 -1
- package/server/lib/opencode/feature-routes-runtime.js +15 -0
- package/server/lib/opencode/lifecycle-process.test.js +84 -0
- package/server/lib/opencode/lifecycle.js +54 -67
- package/server/lib/opencode/openchamber-routes.js +72 -14
- package/server/lib/opencode/openchamber-routes.test.js +71 -3
- package/server/lib/opencode/session-runtime.js +68 -0
- package/server/lib/opencode/session-runtime.test.js +43 -0
- package/server/lib/opencode/settings-helpers.js +8 -0
- package/server/lib/opencode/settings-helpers.test.js +13 -1
- package/server/lib/opencode/settings-normalization-runtime.js +2 -0
- package/server/lib/opencode/settings-normalization-runtime.test.js +13 -0
- package/server/lib/opencode/settings-registry.json +15 -0
- package/server/lib/opencode/shutdown-runtime.js +3 -0
- package/server/lib/opencode/shutdown-runtime.test.js +24 -0
- package/server/lib/opencode/theme-archive.js +53 -0
- package/server/lib/opencode/theme-catalog.js +171 -0
- package/server/lib/opencode/theme-catalog.test.js +125 -0
- package/server/lib/opencode/theme-import.test.js +144 -0
- package/server/lib/opencode/theme-runtime.js +100 -28
- package/server/lib/opencode/theme-runtime.test.js +15 -0
- package/server/lib/permission-auto-accept/DOCUMENTATION.md +8 -0
- package/server/lib/permission-auto-accept/runtime.js +13 -0
- package/server/lib/permission-auto-accept/runtime.test.js +37 -1
- package/server/lib/projects/project-config.js +2 -2
- package/server/lib/quota/DOCUMENTATION.md +0 -1
- package/server/lib/quota/providers/index.js +0 -7
- package/server/lib/realtime-proxy-terminal.test.js +150 -0
- package/server/lib/realtime-proxy.js +2 -0
- package/server/lib/routing/DOCUMENTATION.md +83 -0
- package/server/lib/routing/defaults.js +98 -0
- package/server/lib/routing/feature-flag.js +11 -0
- package/server/lib/routing/history.js +34 -0
- package/server/lib/routing/jev.js +98 -0
- package/server/lib/routing/routes.http.test.js +100 -0
- package/server/lib/routing/routes.js +81 -0
- package/server/lib/routing/runtime.js +217 -0
- package/server/lib/routing/runtime.test.js +188 -0
- package/server/lib/routing/store.js +249 -0
- package/server/lib/routing/store.test.js +96 -0
- package/server/lib/scheduled-tasks/runtime.js +2 -2
- package/server/lib/scheduled-tasks/runtime.test.js +14 -0
- package/server/lib/security/request-security.js +9 -5
- package/server/lib/security/request-security.test.js +37 -0
- package/server/lib/small-model/DOCUMENTATION.md +14 -2
- package/server/lib/small-model/call.js +37 -6
- package/server/lib/small-model/call.test.js +182 -0
- package/server/lib/terminal/DOCUMENTATION.md +23 -2
- package/server/lib/terminal/runtime.js +27 -5
- package/server/lib/terminal/runtime.test.js +67 -0
- package/server/lib/terminal/shutdown.js +106 -0
- package/server/lib/terminal/shutdown.test.js +84 -0
- package/server/lib/tts/service.test.js +78 -0
- package/server/lib/ui-auth/DOCUMENTATION.md +8 -0
- package/server/lib/ui-auth/session-cookie.js +51 -0
- package/server/lib/ui-auth/session-cookie.test.js +46 -0
- package/server/lib/ui-auth/ui-auth.js +56 -17
- package/server/lib/ui-auth/ui-auth.test.js +96 -0
- package/dist/assets/DiffView-CyLmb-wF.js +0 -4
- package/dist/assets/DirtyBranchSwitchDialog-pu5kcoir.js +0 -1
- package/dist/assets/FilesView-WtJB0y_l.js +0 -13
- package/dist/assets/GitView-DkNrV0BK.js +0 -6
- package/dist/assets/LinearIssuesView-B0H0Otii.js +0 -1
- package/dist/assets/MarkdownRendererImpl-DSqVN2d8.js +0 -12
- package/dist/assets/PierreDiffViewer-Bsq9z-sw.js +0 -161
- package/dist/assets/PlanView-CAFziKH5.js +0 -5
- package/dist/assets/SettingsView-BRittavZ.js +0 -28
- package/dist/assets/ToolOutputDialog-B0uYaJio.js +0 -15
- package/dist/assets/appThemeRegistry-BK0dHKa6.js +0 -1
- package/dist/assets/de-c7CYLCAW.js +0 -10
- package/dist/assets/es-BKAVPQmQ.js +0 -16
- package/dist/assets/fr-Bj1glqfV.js +0 -14
- package/dist/assets/index-BYFyOu_D.css +0 -1
- package/dist/assets/index-BfwRClDe.js +0 -40
- package/dist/assets/ja-5jwSIbK0.js +0 -16
- package/dist/assets/ko-BaDbg-Eb.js +0 -16
- package/dist/assets/main-CGG2_uHq.js +0 -2
- package/dist/assets/main-CcrSaL4J.js +0 -930
- package/dist/assets/markdownCore-DsmQr3bt.js +0 -5
- package/dist/assets/miniChat-DEaAhP4b.js +0 -2
- package/dist/assets/mobile-BC3rsvv0.js +0 -2
- package/dist/assets/pl-BFKVBDFu.js +0 -16
- package/dist/assets/pt-BR-qKfHvkDL.js +0 -16
- package/dist/assets/registerCustomTheme-BBXUCRnG.js +0 -1
- package/dist/assets/renderElectronMiniChatApp-CR9d1Mr0.js +0 -2
- package/dist/assets/renderMobileApp-Da5dwobZ.js +0 -25
- package/dist/assets/runtimeEndpointReset-CLYVRw2H.js +0 -41
- package/dist/assets/shikiHighlight-D1Z9G58W.js +0 -1
- package/dist/assets/tr-DYXPoEDG.js +0 -7
- package/dist/assets/uk-CwAoloR8.js +0 -16
- package/dist/assets/useAppFontEffects-DeStGcUT.js +0 -7282
- package/dist/assets/useGitComparison-CpxioduU.js +0 -1
- package/dist/assets/useInlineCommentController-gmUnJtrb.js +0 -2
- package/dist/assets/useRootScrollLock--a3cPz8s.js +0 -1
- package/dist/assets/vendor-framer-motion-livSKyyV.js +0 -1
- package/dist/assets/zh-CN-D9MG0lqF.js +0 -16
- package/dist/assets/zh-TW-1HNK7shh.js +0 -16
- package/server/lib/quota/providers/crof.js +0 -96
- package/server/lib/quota/providers/crof.test.js +0 -98
- /package/dist/assets/{vendor-katex-k3Ppq1Ha.js → vendor-katex-CHD9BdDO.js} +0 -0
package/dist/index.html
CHANGED
|
@@ -509,16 +509,18 @@
|
|
|
509
509
|
pointer-events: none;
|
|
510
510
|
}
|
|
511
511
|
</style>
|
|
512
|
-
<script type="module" crossorigin src="/assets/main-
|
|
512
|
+
<script type="module" crossorigin src="/assets/main-B62_pjL5.js"></script>
|
|
513
513
|
<link rel="modulepreload" crossorigin href="/assets/vendor-vite-runtime-DD1OZmLC.js">
|
|
514
|
-
<link rel="modulepreload" crossorigin href="/assets/vendor-zod-
|
|
514
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-zod-CgAdXWZO.js">
|
|
515
515
|
<link rel="modulepreload" crossorigin href="/assets/vendor-scheduler-7OC5HNn7.js">
|
|
516
516
|
<link rel="modulepreload" crossorigin href="/assets/vendor-react-BUCujlKS.js">
|
|
517
517
|
<link rel="modulepreload" crossorigin href="/assets/vendor-zustand-BAGL70zf.js">
|
|
518
518
|
<link rel="modulepreload" crossorigin href="/assets/vendor-opencode-sdk-BJ73u-bH.js">
|
|
519
|
-
<link rel="modulepreload" crossorigin href="/assets/index-
|
|
519
|
+
<link rel="modulepreload" crossorigin href="/assets/index-Dqc6USl3.js">
|
|
520
520
|
<link rel="modulepreload" crossorigin href="/assets/contextPanelEmbeddedChat-CirXEPJq.js">
|
|
521
|
-
<link rel="
|
|
521
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-katex-CHD9BdDO.js">
|
|
522
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DqaMWNrC.css">
|
|
523
|
+
<link rel="stylesheet" crossorigin href="/assets/vendor-katex-Cp579UoJ.css">
|
|
522
524
|
</head>
|
|
523
525
|
<body class="h-full bg-background text-foreground">
|
|
524
526
|
<div id="root" class="h-full">
|
package/dist/mini-chat.html
CHANGED
|
@@ -74,15 +74,17 @@
|
|
|
74
74
|
}
|
|
75
75
|
</style>
|
|
76
76
|
|
|
77
|
-
<script type="module" crossorigin src="/assets/miniChat-
|
|
77
|
+
<script type="module" crossorigin src="/assets/miniChat-LT8Rqofr.js"></script>
|
|
78
78
|
<link rel="modulepreload" crossorigin href="/assets/vendor-vite-runtime-DD1OZmLC.js">
|
|
79
|
-
<link rel="modulepreload" crossorigin href="/assets/vendor-zod-
|
|
79
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-zod-CgAdXWZO.js">
|
|
80
80
|
<link rel="modulepreload" crossorigin href="/assets/vendor-scheduler-7OC5HNn7.js">
|
|
81
81
|
<link rel="modulepreload" crossorigin href="/assets/vendor-react-BUCujlKS.js">
|
|
82
82
|
<link rel="modulepreload" crossorigin href="/assets/vendor-zustand-BAGL70zf.js">
|
|
83
83
|
<link rel="modulepreload" crossorigin href="/assets/vendor-opencode-sdk-BJ73u-bH.js">
|
|
84
|
-
<link rel="modulepreload" crossorigin href="/assets/index-
|
|
85
|
-
<link rel="
|
|
84
|
+
<link rel="modulepreload" crossorigin href="/assets/index-Dqc6USl3.js">
|
|
85
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-katex-CHD9BdDO.js">
|
|
86
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DqaMWNrC.css">
|
|
87
|
+
<link rel="stylesheet" crossorigin href="/assets/vendor-katex-Cp579UoJ.css">
|
|
86
88
|
</head>
|
|
87
89
|
<body class="h-full bg-background text-foreground">
|
|
88
90
|
<div id="root" class="h-full">
|
package/dist/mobile.html
CHANGED
|
@@ -63,15 +63,17 @@
|
|
|
63
63
|
})();
|
|
64
64
|
</script>
|
|
65
65
|
|
|
66
|
-
<script type="module" crossorigin src="/assets/mobile-
|
|
66
|
+
<script type="module" crossorigin src="/assets/mobile-CqarEynh.js"></script>
|
|
67
67
|
<link rel="modulepreload" crossorigin href="/assets/vendor-vite-runtime-DD1OZmLC.js">
|
|
68
|
-
<link rel="modulepreload" crossorigin href="/assets/vendor-zod-
|
|
68
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-zod-CgAdXWZO.js">
|
|
69
69
|
<link rel="modulepreload" crossorigin href="/assets/vendor-scheduler-7OC5HNn7.js">
|
|
70
70
|
<link rel="modulepreload" crossorigin href="/assets/vendor-react-BUCujlKS.js">
|
|
71
71
|
<link rel="modulepreload" crossorigin href="/assets/vendor-zustand-BAGL70zf.js">
|
|
72
72
|
<link rel="modulepreload" crossorigin href="/assets/vendor-opencode-sdk-BJ73u-bH.js">
|
|
73
|
-
<link rel="modulepreload" crossorigin href="/assets/index-
|
|
74
|
-
<link rel="
|
|
73
|
+
<link rel="modulepreload" crossorigin href="/assets/index-Dqc6USl3.js">
|
|
74
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-katex-CHD9BdDO.js">
|
|
75
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DqaMWNrC.css">
|
|
76
|
+
<link rel="stylesheet" crossorigin href="/assets/vendor-katex-Cp579UoJ.css">
|
|
75
77
|
</head>
|
|
76
78
|
<body class="h-full bg-background text-foreground">
|
|
77
79
|
<div id="root" class="h-full"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vantran-se/openchamber-web",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.24.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./server/index.js",
|
|
@@ -13,10 +13,11 @@
|
|
|
13
13
|
},
|
|
14
14
|
"scripts": {
|
|
15
15
|
"dev": "bun run build:watch",
|
|
16
|
-
"dev:server": "OPENCHAMBER_RELAY_HOST=${OPENCHAMBER_RELAY_HOST:-off} bun server/index.js --port ${OPENCHAMBER_PORT:-3001}",
|
|
17
|
-
"dev:server:watch": "node ./scripts/dev-server-watch.mjs",
|
|
18
|
-
"build": "vite build",
|
|
19
|
-
"build:watch": "vite build --watch",
|
|
16
|
+
"dev:server": "bun ../../scripts/build-builtin-extensions.mjs && OPENCHAMBER_RELAY_HOST=${OPENCHAMBER_RELAY_HOST:-off} bun server/index.js --port ${OPENCHAMBER_PORT:-3001}",
|
|
17
|
+
"dev:server:watch": "bun ../../scripts/build-builtin-extensions.mjs && node ./scripts/dev-server-watch.mjs",
|
|
18
|
+
"build": "bun ../../scripts/build-builtin-extensions.mjs && vite build",
|
|
19
|
+
"build:watch": "bun ../../scripts/build-builtin-extensions.mjs && vite build --watch",
|
|
20
|
+
"prepack": "bun ../../scripts/build-builtin-extensions.mjs",
|
|
20
21
|
"type-check": "tsc --noEmit",
|
|
21
22
|
"lint": "eslint \"./src/**/*.{ts,tsx}\" --config ../../eslint.config.js",
|
|
22
23
|
"test": "vitest run",
|
|
@@ -25,25 +26,27 @@
|
|
|
25
26
|
"dependencies": {
|
|
26
27
|
"@clack/prompts": "^1.1.0",
|
|
27
28
|
"@octokit/rest": "^22.0.1",
|
|
28
|
-
"@
|
|
29
|
+
"@openchamber/sdk": "1.24.2",
|
|
30
|
+
"@opencode-ai/sdk": "1.18.31",
|
|
29
31
|
"@simplewebauthn/server": "13.3.1",
|
|
30
32
|
"bun-pty": "^0.4.5",
|
|
31
33
|
"compression": "^1.8.1",
|
|
32
|
-
"cron-parser": "^
|
|
34
|
+
"cron-parser": "^5.10.1",
|
|
33
35
|
"express": "^5.1.0",
|
|
34
36
|
"http-proxy-middleware": "^3.0.5",
|
|
35
37
|
"jose": "^6.1.3",
|
|
36
38
|
"jsonc-parser": "^3.3.1",
|
|
37
39
|
"luxon": "^3.5.0",
|
|
38
40
|
"node-pty": "1.2.0-beta.12",
|
|
39
|
-
"openai": "^
|
|
41
|
+
"openai": "^7.18.0",
|
|
40
42
|
"qrcode-terminal": "^0.12.0",
|
|
41
43
|
"reflect-metadata": "^0.2.2",
|
|
42
44
|
"sherpa-onnx-node": "1.12.28",
|
|
43
45
|
"simple-git": "^3.36.0",
|
|
44
46
|
"web-push": "^3.6.7",
|
|
45
47
|
"ws": "^8.18.3",
|
|
46
|
-
"yaml": "^2.8.1"
|
|
48
|
+
"yaml": "^2.8.1",
|
|
49
|
+
"zod": "^4.3.6"
|
|
47
50
|
},
|
|
48
51
|
"devDependencies": {
|
|
49
52
|
"@base-ui/react": "^1.4.0",
|
package/server/index.d.ts
CHANGED
|
@@ -32,6 +32,8 @@ export interface StartWebUiServerOptions {
|
|
|
32
32
|
exitOnShutdown?: boolean;
|
|
33
33
|
uiPassword?: string | null;
|
|
34
34
|
desktopUpdater?: DesktopUpdater;
|
|
35
|
+
/** App-owned built-in resources outside Electron's ASAR archive. */
|
|
36
|
+
builtInExtensionsDir?: string;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
export declare function startWebUiServer(
|
package/server/index.js
CHANGED
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
createGlobalUiEventBroadcaster,
|
|
44
44
|
createGlobalMessageStreamHub,
|
|
45
45
|
createMessageStreamWsRuntime,
|
|
46
|
+
resolveDeltaCoalesceWindowMs,
|
|
46
47
|
DEFAULT_UPSTREAM_STALL_TIMEOUT_MS,
|
|
47
48
|
UPSTREAM_STALL_TIMEOUT_CONCURRENT_MS,
|
|
48
49
|
} from './lib/event-stream/index.js';
|
|
@@ -92,7 +93,9 @@ import { createApnsRuntime } from './lib/notifications/apns-runtime.js';
|
|
|
92
93
|
import { createNotificationTemplateRuntime } from './lib/notifications/template-runtime.js';
|
|
93
94
|
import { createPermissionAutoAcceptRuntime } from './lib/permission-auto-accept/runtime.js';
|
|
94
95
|
import { createMessageQueueRuntime } from './lib/message-queue/runtime.js';
|
|
96
|
+
import { createRoutingRuntime } from './lib/routing/runtime.js';
|
|
95
97
|
import { createGracefulShutdownRuntime } from './lib/opencode/shutdown-runtime.js';
|
|
98
|
+
import { stopAllGuestServices } from './lib/guests/service.js';
|
|
96
99
|
import { createProjectConfigRuntime } from './lib/projects/project-config.js';
|
|
97
100
|
import { migrateLegacyUserDirs } from './lib/data-dir-migration.js';
|
|
98
101
|
import { createProjectContextRuntime } from './lib/project-context/runtime.js';
|
|
@@ -297,6 +300,8 @@ const themeRuntime = createThemeRuntime({
|
|
|
297
300
|
});
|
|
298
301
|
|
|
299
302
|
const readCustomThemesFromDisk = (...args) => themeRuntime.readCustomThemesFromDisk(...args);
|
|
303
|
+
const saveImportedTheme = (...args) => themeRuntime.saveImportedTheme(...args);
|
|
304
|
+
const deleteImportedTheme = (...args) => themeRuntime.deleteImportedTheme(...args);
|
|
300
305
|
|
|
301
306
|
let notificationTemplateRuntime = null;
|
|
302
307
|
let agentToolRuntime = null;
|
|
@@ -889,6 +894,25 @@ const globalMessageStreamHub = createGlobalMessageStreamHub({
|
|
|
889
894
|
buildOpenCodeUrl,
|
|
890
895
|
getOpenCodeAuthHeaders,
|
|
891
896
|
upstreamStallTimeoutMs: getUpstreamStallTimeoutMs,
|
|
897
|
+
deltaCoalesceWindowMs: resolveDeltaCoalesceWindowMs(),
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
// OpenChamber-owned events for the UI control stream (SSE) plus the WS fan-out.
|
|
901
|
+
// OpenCode's /global/event proxy cannot carry them.
|
|
902
|
+
const broadcastOpenChamberUiEvent = createGlobalUiEventBroadcaster({
|
|
903
|
+
sseClients: uiOpenChamberEventClients,
|
|
904
|
+
wsClients: uiNotificationWsClients,
|
|
905
|
+
writeSseEvent,
|
|
906
|
+
});
|
|
907
|
+
|
|
908
|
+
// Jev model routing and the permission safety net. Dark unless
|
|
909
|
+
// OPENCHAMBER_ROUTING_ENABLE is set; every failure keeps the user's own model
|
|
910
|
+
// or the auto-accept reply it was asked about.
|
|
911
|
+
const routingRuntime = createRoutingRuntime({
|
|
912
|
+
dataDir: OPENCHAMBER_DATA_DIR,
|
|
913
|
+
buildOpenCodeUrl,
|
|
914
|
+
getOpenCodeAuthHeaders,
|
|
915
|
+
broadcastGlobalUiEvent: broadcastOpenChamberUiEvent,
|
|
892
916
|
});
|
|
893
917
|
|
|
894
918
|
const permissionAutoAcceptRuntime = createPermissionAutoAcceptRuntime({
|
|
@@ -898,6 +922,8 @@ const permissionAutoAcceptRuntime = createPermissionAutoAcceptRuntime({
|
|
|
898
922
|
readSettingsFromDiskMigrated,
|
|
899
923
|
persistSettings,
|
|
900
924
|
broadcastGlobalUiEvent,
|
|
925
|
+
evaluatePermission: (permission, directory) => routingRuntime.evaluatePermission(permission, directory),
|
|
926
|
+
onPermissionReplied: (permissionId) => routingRuntime.forgetPermission(permissionId),
|
|
901
927
|
});
|
|
902
928
|
permissionAutoAcceptRuntime.start();
|
|
903
929
|
notificationTriggerRuntime.setGetIsSessionAutoAccepting(
|
|
@@ -911,13 +937,8 @@ const messageQueueRuntime = createMessageQueueRuntime({
|
|
|
911
937
|
buildOpenCodeUrl,
|
|
912
938
|
getOpenCodeAuthHeaders,
|
|
913
939
|
sessionKnowledgeRuntime,
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
broadcastGlobalUiEvent: createGlobalUiEventBroadcaster({
|
|
917
|
-
sseClients: uiOpenChamberEventClients,
|
|
918
|
-
wsClients: uiNotificationWsClients,
|
|
919
|
-
writeSseEvent,
|
|
920
|
-
}),
|
|
940
|
+
broadcastGlobalUiEvent: broadcastOpenChamberUiEvent,
|
|
941
|
+
resolvePromptBody: (body, target) => routingRuntime.resolvePromptBody(body, target),
|
|
921
942
|
onPromptSent: (sessionId) => sessionRuntime.markUserMessageSent(sessionId),
|
|
922
943
|
dataDir: OPENCHAMBER_DATA_DIR,
|
|
923
944
|
});
|
|
@@ -1345,14 +1366,14 @@ const resolveMemoryProjectId = createMemoryProjectResolver({
|
|
|
1345
1366
|
});
|
|
1346
1367
|
|
|
1347
1368
|
/**
|
|
1348
|
-
* Tells open panels that the
|
|
1369
|
+
* Tells open panels that the service changed what it remembers, so what it just
|
|
1349
1370
|
* stored is visible without reopening anything.
|
|
1350
1371
|
*/
|
|
1351
1372
|
const emitAgentMemoryChangedEvent = (event) => {
|
|
1352
1373
|
for (const client of uiOpenChamberEventClients) {
|
|
1353
1374
|
try {
|
|
1354
1375
|
writeSseEvent(client, {
|
|
1355
|
-
type: 'openchamber:
|
|
1376
|
+
type: 'openchamber:service-memory-changed',
|
|
1356
1377
|
properties: {
|
|
1357
1378
|
scope: event.scope,
|
|
1358
1379
|
...(event.projectId ? { projectId: event.projectId } : {}),
|
|
@@ -1378,6 +1399,7 @@ const openChamberSessionService = createOpenChamberSessionService({
|
|
|
1378
1399
|
waitForOpenCodeReady,
|
|
1379
1400
|
emitSessionCreatedEvent,
|
|
1380
1401
|
sessionKnowledgeRuntime,
|
|
1402
|
+
resolvePromptBody: (body, target) => routingRuntime.resolvePromptBody(body, target),
|
|
1381
1403
|
});
|
|
1382
1404
|
// Browser actions are published to whichever OpenChamber clients are connected;
|
|
1383
1405
|
// the one owning the browser panel answers. `emitRequest` returns the number of
|
|
@@ -1526,6 +1548,8 @@ async function main(options = {}) {
|
|
|
1526
1548
|
const address = server?.address?.();
|
|
1527
1549
|
return typeof address === 'object' && address ? address.port : null;
|
|
1528
1550
|
},
|
|
1551
|
+
// A pipe listener reports a string here, which has no address to bind back to.
|
|
1552
|
+
getActiveHost: () => server?.address?.()?.address ?? null,
|
|
1529
1553
|
});
|
|
1530
1554
|
systemPromptRuntime = createSystemPromptRuntime({
|
|
1531
1555
|
fsPromises,
|
|
@@ -1933,6 +1957,8 @@ async function main(options = {}) {
|
|
|
1933
1957
|
resolveGitBinaryForSpawn,
|
|
1934
1958
|
createFsSearchRuntime: createFsSearchRuntimeFactory,
|
|
1935
1959
|
openchamberDataDir: OPENCHAMBER_DATA_DIR,
|
|
1960
|
+
openchamberVersion: OPENCHAMBER_VERSION,
|
|
1961
|
+
builtInExtensionsDir: options.builtInExtensionsDir,
|
|
1936
1962
|
openchamberUserConfigRoot: OPENCHAMBER_USER_CONFIG_ROOT,
|
|
1937
1963
|
managedChatsRoot: OPENCHAMBER_CHATS_DIR,
|
|
1938
1964
|
normalizeDirectoryPath,
|
|
@@ -1940,6 +1966,8 @@ async function main(options = {}) {
|
|
|
1940
1966
|
resolveOptionalProjectDirectory,
|
|
1941
1967
|
validateDirectoryPath,
|
|
1942
1968
|
readCustomThemesFromDisk,
|
|
1969
|
+
saveImportedTheme,
|
|
1970
|
+
deleteImportedTheme,
|
|
1943
1971
|
refreshOpenCodeAfterConfigChange,
|
|
1944
1972
|
getOpenCodeResolutionSnapshot,
|
|
1945
1973
|
getOpenCodeUpgradeCapability,
|
|
@@ -1973,6 +2001,7 @@ async function main(options = {}) {
|
|
|
1973
2001
|
writeSseEvent,
|
|
1974
2002
|
permissionAutoAcceptRuntime,
|
|
1975
2003
|
messageQueueRuntime,
|
|
2004
|
+
routingRuntime,
|
|
1976
2005
|
});
|
|
1977
2006
|
|
|
1978
2007
|
const startupPipelineResult = await startupPipelineRuntime.run({
|
|
@@ -2077,7 +2106,7 @@ async function main(options = {}) {
|
|
|
2077
2106
|
port: managed ? openCodePort : null,
|
|
2078
2107
|
};
|
|
2079
2108
|
},
|
|
2080
|
-
stop: (shutdownOptions = {}) => {
|
|
2109
|
+
stop: async (shutdownOptions = {}) => {
|
|
2081
2110
|
realtimeProxyRuntime.stop();
|
|
2082
2111
|
clearInterval(relayReconcileTimer);
|
|
2083
2112
|
try {
|
|
@@ -2090,6 +2119,11 @@ async function main(options = {}) {
|
|
|
2090
2119
|
} catch {
|
|
2091
2120
|
// best-effort shutdown of the dictation worker
|
|
2092
2121
|
}
|
|
2122
|
+
// Guest services are child processes; leaving before SIGTERM lands
|
|
2123
|
+
// (and the SIGKILL fallback fires) orphans them on the user's machine.
|
|
2124
|
+
await stopAllGuestServices().catch(() => {
|
|
2125
|
+
// best-effort teardown of guest service processes
|
|
2126
|
+
});
|
|
2093
2127
|
return gracefulShutdown({ exitProcess: shutdownOptions.exitProcess ?? false });
|
|
2094
2128
|
}
|
|
2095
2129
|
};
|
|
@@ -30,8 +30,10 @@ both settings are `false`.
|
|
|
30
30
|
2. `prepareManagedOpenCodeEnv()` materializes the plugin under
|
|
31
31
|
`<openchamber-data-dir>/agent-tool/` and appends its `file://` URL to
|
|
32
32
|
`OPENCODE_CONFIG_CONTENT` without replacing existing plugin entries.
|
|
33
|
-
3. A random per-child token and
|
|
34
|
-
|
|
33
|
+
3. A random per-child token and callback URL are added only to the managed
|
|
34
|
+
OpenCode child environment. The URL points at loopback, except when the
|
|
35
|
+
listener is bound to one concrete address (`--host <ip>`): that socket does
|
|
36
|
+
not answer on loopback, so the URL uses the bound address instead.
|
|
35
37
|
4. The plugin calls `POST /api/openchamber/agent-tool` with its typed input and
|
|
36
38
|
OpenCode's authoritative session directory.
|
|
37
39
|
5. The route delegates the fixed action allowlist directly to the shared
|
|
@@ -48,6 +50,9 @@ both settings are `false`.
|
|
|
48
50
|
- The tool exposes one shared parameter object rather than repeating parameters
|
|
49
51
|
in a large per-action union. Action descriptions carry only required inputs,
|
|
50
52
|
defaults, or one non-obvious semantic detail.
|
|
53
|
+
- The action schema carries `oneOf` and no `enum`. A node combining `enum` and
|
|
54
|
+
`oneOf` is valid JSON Schema, but some OpenAI-compatible gateways reject it
|
|
55
|
+
and answer with an empty completion instead of an error.
|
|
51
56
|
- Obvious fields rely on their names and JSON types. Parameter descriptions are
|
|
52
57
|
reserved for formats, dependencies, scope, and behavior that cannot be safely
|
|
53
58
|
inferred from the field name.
|
|
@@ -69,10 +74,18 @@ both settings are `false`.
|
|
|
69
74
|
|
|
70
75
|
## Security invariants
|
|
71
76
|
|
|
72
|
-
- The callback accepts
|
|
73
|
-
per-child bearer token using a timing-safe comparison.
|
|
77
|
+
- The callback accepts same-machine requests only and requires the current
|
|
78
|
+
per-child bearer token using a timing-safe comparison. Same-machine means a
|
|
79
|
+
loopback source, or, for a listener bound to one concrete address, a source
|
|
80
|
+
equal to that address: the OS sources a local connection to `<ip>` from
|
|
81
|
+
`<ip>`. A wildcard bind keeps the loopback-only rule, and another machine on
|
|
82
|
+
the network always arrives with its own address.
|
|
74
83
|
- The token is never persisted, logged, returned to the UI, or written into
|
|
75
84
|
the materialized plugin.
|
|
85
|
+
- The plugin adds the callback host to `NO_PROXY`/`no_proxy` inside the managed
|
|
86
|
+
child when it loads. Without that, an `HTTP_PROXY` in the child's environment
|
|
87
|
+
would receive a non-loopback callback, token included, because `fetch` has no
|
|
88
|
+
per-request way to skip the environment proxy.
|
|
76
89
|
- Inputs map to a fixed action and parameter allowlist. There is no arbitrary
|
|
77
90
|
CLI, shell, route, or URL forwarding.
|
|
78
91
|
- Session/worktree deletion and project-path registration are not exposed.
|
|
@@ -129,11 +129,24 @@ const createResult = ({ ok, action, data, error, exitCode }) => ({
|
|
|
129
129
|
...(Number.isInteger(exitCode) ? { exitCode } : {}),
|
|
130
130
|
});
|
|
131
131
|
|
|
132
|
+
// Node reports an IPv4 peer on a dual-stack socket as `::ffff:<ipv4>`.
|
|
133
|
+
const normalizeAddress = (value) => {
|
|
134
|
+
const address = (asNonEmptyString(value) || '').toLowerCase();
|
|
135
|
+
return address.startsWith('::ffff:') ? address.slice('::ffff:'.length) : address;
|
|
136
|
+
};
|
|
137
|
+
|
|
132
138
|
const isLoopbackAddress = (value) => {
|
|
133
|
-
const address =
|
|
134
|
-
return address === '127.0.0.1'
|
|
135
|
-
|
|
136
|
-
|
|
139
|
+
const address = normalizeAddress(value);
|
|
140
|
+
return address === '127.0.0.1' || address === '::1';
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const WILDCARD_ADDRESSES = new Set(['0.0.0.0', '::']);
|
|
144
|
+
|
|
145
|
+
// A wildcard listener answers on loopback. A listener bound to one concrete
|
|
146
|
+
// address answers only there, so that address is the only way back in.
|
|
147
|
+
const resolveConcreteBoundAddress = (value) => {
|
|
148
|
+
const address = normalizeAddress(value);
|
|
149
|
+
return address && !WILDCARD_ADDRESSES.has(address) ? address : null;
|
|
137
150
|
};
|
|
138
151
|
|
|
139
152
|
/**
|
|
@@ -143,11 +156,16 @@ const isLoopbackAddress = (value) => {
|
|
|
143
156
|
* set, the inputs and the description differ. Generating them from one template
|
|
144
157
|
* keeps the transport, metadata and failure handling identical, which is what
|
|
145
158
|
* the caller depends on.
|
|
159
|
+
*
|
|
160
|
+
* The action schema carries `oneOf` only. A node combining `enum` and `oneOf`
|
|
161
|
+
* is valid JSON Schema, but some OpenAI-compatible gateways reject it and
|
|
162
|
+
* answer with an empty completion instead of an error, and the `oneOf` branches
|
|
163
|
+
* are what carry the per-action descriptions the model reads.
|
|
146
164
|
*/
|
|
147
|
-
const createToolEntry = ({ name, description,
|
|
165
|
+
const createToolEntry = ({ name, description, definitions, parameters }) => String.raw` ${name}: {
|
|
148
166
|
description: ${JSON.stringify(description)},
|
|
149
167
|
args: {
|
|
150
|
-
action: { type: "string",
|
|
168
|
+
action: { type: "string", oneOf: ${JSON.stringify(definitions.map((entry) => ({ const: entry.action, description: entry.description })))}, description: "OpenChamber action to perform" },
|
|
151
169
|
parameters: { type: "object", properties: ${JSON.stringify(parameters)}, additionalProperties: false, description: "Inputs for the action; use an empty object when none are needed" },
|
|
152
170
|
},
|
|
153
171
|
async execute(input, context) {
|
|
@@ -221,7 +239,6 @@ const createPluginSource = ({ includeControl, includeWeb, includeMemory }) => {
|
|
|
221
239
|
entries.push(createToolEntry({
|
|
222
240
|
name: 'openchamber',
|
|
223
241
|
description: CONTROL_TOOL_DESCRIPTION,
|
|
224
|
-
actions: OPENCHAMBER_AGENT_TOOL_ACTIONS,
|
|
225
242
|
definitions: OPENCHAMBER_AGENT_TOOL_ACTION_DEFINITIONS,
|
|
226
243
|
parameters: CONTROL_PARAMETER_PROPERTIES,
|
|
227
244
|
}));
|
|
@@ -230,7 +247,6 @@ const createPluginSource = ({ includeControl, includeWeb, includeMemory }) => {
|
|
|
230
247
|
entries.push(createToolEntry({
|
|
231
248
|
name: 'openchamber_web',
|
|
232
249
|
description: WEB_TOOL_DESCRIPTION,
|
|
233
|
-
actions: OPENCHAMBER_WEB_ACTIONS,
|
|
234
250
|
definitions: OPENCHAMBER_WEB_ACTION_DEFINITIONS,
|
|
235
251
|
parameters: WEB_PARAMETER_PROPERTIES,
|
|
236
252
|
}));
|
|
@@ -239,16 +255,33 @@ const createPluginSource = ({ includeControl, includeWeb, includeMemory }) => {
|
|
|
239
255
|
entries.push(createToolEntry({
|
|
240
256
|
name: 'openchamber_memory',
|
|
241
257
|
description: MEMORY_TOOL_DESCRIPTION,
|
|
242
|
-
actions: OPENCHAMBER_MEMORY_ACTIONS,
|
|
243
258
|
definitions: OPENCHAMBER_MEMORY_ACTION_DEFINITIONS,
|
|
244
259
|
parameters: MEMORY_PARAMETER_PROPERTIES,
|
|
245
260
|
}));
|
|
246
261
|
}
|
|
247
262
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
263
|
+
// The callback carries the per-child token over plain HTTP. With a proxy in
|
|
264
|
+
// the child's environment, fetch would hand a non-loopback callback, token
|
|
265
|
+
// included, to that proxy, and no per-request option turns that off. The
|
|
266
|
+
// exemption is added inside the child because only there is the final
|
|
267
|
+
// NO_PROXY, merged from the shell and server environments, visible.
|
|
268
|
+
return `const exemptCallbackFromProxy = () => {
|
|
269
|
+
const endpoint = process.env.OPENCHAMBER_AGENT_TOOL_URL
|
|
270
|
+
if (!endpoint || !URL.canParse(endpoint)) return
|
|
271
|
+
const host = new URL(endpoint).hostname.replace(/^\\[|\\]$/g, "")
|
|
272
|
+
for (const key of ["NO_PROXY", "no_proxy"]) {
|
|
273
|
+
const entries = (process.env[key] || "").split(",").map((entry) => entry.trim()).filter(Boolean)
|
|
274
|
+
if (!entries.includes(host)) process.env[key] = [...entries, host].join(",")
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export const OpenChamberPlugin = async () => {
|
|
279
|
+
exemptCallbackFromProxy()
|
|
280
|
+
return {
|
|
281
|
+
tool: {
|
|
282
|
+
${entries.join('')} },
|
|
283
|
+
}
|
|
284
|
+
}
|
|
252
285
|
`;
|
|
253
286
|
};
|
|
254
287
|
|
|
@@ -259,6 +292,7 @@ export const createAgentToolRuntime = (dependencies) => {
|
|
|
259
292
|
path,
|
|
260
293
|
dataDir,
|
|
261
294
|
getActivePort,
|
|
295
|
+
getActiveHost = () => null,
|
|
262
296
|
executeAction,
|
|
263
297
|
env = process.env,
|
|
264
298
|
} = dependencies;
|
|
@@ -266,6 +300,8 @@ export const createAgentToolRuntime = (dependencies) => {
|
|
|
266
300
|
const pluginPath = path.join(pluginDirectory, 'openchamber-plugin.js');
|
|
267
301
|
let activeToken = null;
|
|
268
302
|
|
|
303
|
+
const getConcreteBoundAddress = () => resolveConcreteBoundAddress(getActiveHost());
|
|
304
|
+
|
|
269
305
|
const prepareManagedOpenCodeEnv = async ({ includeControl = true, includeWeb = true, includeMemory = true } = {}) => {
|
|
270
306
|
const port = getActivePort();
|
|
271
307
|
if (!Number.isInteger(port) || port <= 0) {
|
|
@@ -278,15 +314,26 @@ export const createAgentToolRuntime = (dependencies) => {
|
|
|
278
314
|
await fsPromises.writeFile(pluginPath, createPluginSource({ includeControl, includeWeb, includeMemory }), { mode: 0o600 });
|
|
279
315
|
activeToken = crypto.randomBytes(32).toString('base64url');
|
|
280
316
|
const pluginUrl = pathToFileURL(pluginPath).href;
|
|
317
|
+
const callbackAddress = getConcreteBoundAddress() || '127.0.0.1';
|
|
318
|
+
const callbackHost = callbackAddress.includes(':') ? `[${callbackAddress}]` : callbackAddress;
|
|
281
319
|
return {
|
|
282
320
|
OPENCODE_CONFIG_CONTENT: appendManagedPlugin(env.OPENCODE_CONFIG_CONTENT, pluginUrl, 'managed tool'),
|
|
283
|
-
OPENCHAMBER_AGENT_TOOL_URL: `http
|
|
321
|
+
OPENCHAMBER_AGENT_TOOL_URL: `http://${callbackHost}:${port}/api/openchamber/agent-tool`,
|
|
284
322
|
OPENCHAMBER_AGENT_TOOL_TOKEN: activeToken,
|
|
285
323
|
};
|
|
286
324
|
};
|
|
287
325
|
|
|
326
|
+
// The managed child runs on this machine. Reaching a listener bound to one
|
|
327
|
+
// concrete address makes the OS source the connection from that same address,
|
|
328
|
+
// so it stands in for loopback there; any other machine arrives as itself.
|
|
329
|
+
const isSameMachineAddress = (value) => {
|
|
330
|
+
if (isLoopbackAddress(value)) return true;
|
|
331
|
+
const boundAddress = getConcreteBoundAddress();
|
|
332
|
+
return boundAddress !== null && normalizeAddress(value) === boundAddress;
|
|
333
|
+
};
|
|
334
|
+
|
|
288
335
|
const authorize = (req) => {
|
|
289
|
-
if (!activeToken || !
|
|
336
|
+
if (!activeToken || !isSameMachineAddress(req.socket?.remoteAddress)) return false;
|
|
290
337
|
const header = asNonEmptyString(req.headers?.authorization);
|
|
291
338
|
if (!header?.startsWith('Bearer ')) return false;
|
|
292
339
|
const provided = Buffer.from(header.slice(7));
|
|
@@ -121,8 +121,8 @@ describe('managed agent tool runtime', () => {
|
|
|
121
121
|
const pluginModule = await import(`${pathToFileURL(pluginPath).href}?both=${Date.now()}`);
|
|
122
122
|
const { tool } = await pluginModule.OpenChamberPlugin();
|
|
123
123
|
|
|
124
|
-
const controlActions = tool.openchamber.args.action.
|
|
125
|
-
const webActions = tool.openchamber_web.args.action.
|
|
124
|
+
const controlActions = tool.openchamber.args.action.oneOf.map((entry) => entry.const);
|
|
125
|
+
const webActions = tool.openchamber_web.args.action.oneOf.map((entry) => entry.const);
|
|
126
126
|
expect(webActions).toContain('browser.open');
|
|
127
127
|
expect(controlActions).not.toContain('browser.open');
|
|
128
128
|
expect(webActions).not.toContain('session.create');
|
|
@@ -133,6 +133,23 @@ describe('managed agent tool runtime', () => {
|
|
|
133
133
|
expect(Object.keys(tool.openchamber.args.parameters.properties)).toContain('sessionId');
|
|
134
134
|
});
|
|
135
135
|
|
|
136
|
+
it('keeps the action schema to one validator keyword', async () => {
|
|
137
|
+
// A node carrying both `enum` and `oneOf` is valid JSON Schema, but some
|
|
138
|
+
// OpenAI-compatible gateways reject it and answer with an empty completion
|
|
139
|
+
// instead of an error. `oneOf` is the keyword that stayed. Its branches
|
|
140
|
+
// carry the per-action descriptions the model reads.
|
|
141
|
+
const { runtime, dataDir } = await createRuntime();
|
|
142
|
+
await runtime.prepareManagedOpenCodeEnv();
|
|
143
|
+
const pluginPath = path.join(dataDir, 'agent-tool', 'openchamber-plugin.js');
|
|
144
|
+
const pluginModule = await import(`${pathToFileURL(pluginPath).href}?validator=${Date.now()}`);
|
|
145
|
+
const { tool } = await pluginModule.OpenChamberPlugin();
|
|
146
|
+
|
|
147
|
+
for (const entry of Object.values(tool)) {
|
|
148
|
+
expect(entry.args.action.oneOf).toBeInstanceOf(Array);
|
|
149
|
+
expect(entry.args.action).not.toHaveProperty('enum');
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
136
153
|
it('accepts inputs passed beside the action, not only inside parameters', async () => {
|
|
137
154
|
const { runtime, dataDir } = await createRuntime();
|
|
138
155
|
const prepared = await runtime.prepareManagedOpenCodeEnv();
|
|
@@ -354,6 +371,75 @@ describe('managed agent tool runtime', () => {
|
|
|
354
371
|
expect(response.body).toEqual(expect.objectContaining({ ok: true, action: 'projects.list' }));
|
|
355
372
|
});
|
|
356
373
|
|
|
374
|
+
it.each([
|
|
375
|
+
['0.0.0.0', 'http://127.0.0.1:3901/api/openchamber/agent-tool'],
|
|
376
|
+
['::', 'http://127.0.0.1:3901/api/openchamber/agent-tool'],
|
|
377
|
+
[null, 'http://127.0.0.1:3901/api/openchamber/agent-tool'],
|
|
378
|
+
['127.0.0.1', 'http://127.0.0.1:3901/api/openchamber/agent-tool'],
|
|
379
|
+
['100.100.0.3', 'http://100.100.0.3:3901/api/openchamber/agent-tool'],
|
|
380
|
+
['fd7a:115c::3', 'http://[fd7a:115c::3]:3901/api/openchamber/agent-tool'],
|
|
381
|
+
])('points the callback at where a listener bound to %s answers', async (boundAddress, expectedUrl) => {
|
|
382
|
+
const { runtime } = await createRuntime({ getActiveHost: () => boundAddress });
|
|
383
|
+
const env = await runtime.prepareManagedOpenCodeEnv();
|
|
384
|
+
expect(env.OPENCHAMBER_AGENT_TOOL_URL).toBe(expectedUrl);
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
it.each([
|
|
388
|
+
['100.100.0.3', '100.100.0.3', 200],
|
|
389
|
+
['100.100.0.3', '::ffff:100.100.0.3', 200],
|
|
390
|
+
['100.100.0.3', '100.100.0.7', 401],
|
|
391
|
+
['fd7a:115c::3', 'fd7a:115c::3', 200],
|
|
392
|
+
['fd7a:115c::3', 'fd7a:115c::7', 401],
|
|
393
|
+
['0.0.0.0', '192.168.1.20', 401],
|
|
394
|
+
['0.0.0.0', '0.0.0.0', 401],
|
|
395
|
+
[null, '192.168.1.20', 401],
|
|
396
|
+
])('bound to %s, answers a token-bearing caller from %s with %i', async (boundAddress, remoteAddress, status) => {
|
|
397
|
+
const { runtime } = await createRuntime({ getActiveHost: () => boundAddress });
|
|
398
|
+
const env = await runtime.prepareManagedOpenCodeEnv();
|
|
399
|
+
const app = express();
|
|
400
|
+
app.use((req, _res, next) => {
|
|
401
|
+
Object.defineProperty(req.socket, 'remoteAddress', { value: remoteAddress, configurable: true });
|
|
402
|
+
next();
|
|
403
|
+
});
|
|
404
|
+
runtime.registerRoutes(app, express);
|
|
405
|
+
|
|
406
|
+
await request(app)
|
|
407
|
+
.post('/api/openchamber/agent-tool')
|
|
408
|
+
.set('authorization', `Bearer ${env.OPENCHAMBER_AGENT_TOOL_TOKEN}`)
|
|
409
|
+
.send({ input: { action: 'projects.list' } })
|
|
410
|
+
.expect(status);
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
it.each([
|
|
414
|
+
['http://100.100.0.3:3901/api/openchamber/agent-tool', 'localhost,127.0.0.1', 'localhost,127.0.0.1,100.100.0.3'],
|
|
415
|
+
['http://[fd7a:115c::3]:3901/api/openchamber/agent-tool', undefined, 'fd7a:115c::3'],
|
|
416
|
+
['http://100.100.0.3:3901/api/openchamber/agent-tool', '100.100.0.3', '100.100.0.3'],
|
|
417
|
+
['not a url', 'localhost', 'localhost'],
|
|
418
|
+
])('keeps the callback %s away from an environment proxy', async (callbackUrl, existing, expected) => {
|
|
419
|
+
const { runtime, dataDir } = await createRuntime();
|
|
420
|
+
await runtime.prepareManagedOpenCodeEnv();
|
|
421
|
+
const keys = ['OPENCHAMBER_AGENT_TOOL_URL', 'NO_PROXY', 'no_proxy'];
|
|
422
|
+
const previous = keys.map((key) => process.env[key]);
|
|
423
|
+
try {
|
|
424
|
+
process.env.OPENCHAMBER_AGENT_TOOL_URL = callbackUrl;
|
|
425
|
+
for (const key of ['NO_PROXY', 'no_proxy']) {
|
|
426
|
+
if (existing === undefined) delete process.env[key];
|
|
427
|
+
else process.env[key] = existing;
|
|
428
|
+
}
|
|
429
|
+
const pluginPath = path.join(dataDir, 'agent-tool', 'openchamber-plugin.js');
|
|
430
|
+
const pluginModule = await import(`${pathToFileURL(pluginPath).href}?test=${Date.now()}`);
|
|
431
|
+
await pluginModule.OpenChamberPlugin();
|
|
432
|
+
|
|
433
|
+
expect(process.env.NO_PROXY).toBe(expected);
|
|
434
|
+
expect(process.env.no_proxy).toBe(expected);
|
|
435
|
+
} finally {
|
|
436
|
+
keys.forEach((key, index) => {
|
|
437
|
+
if (previous[index] === undefined) delete process.env[key];
|
|
438
|
+
else process.env[key] = previous[index];
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
|
|
357
443
|
it('executes through the materialized plugin and authenticated callback', async () => {
|
|
358
444
|
let activePort = null;
|
|
359
445
|
const { runtime, dataDir } = await createRuntime({ getActivePort: () => activePort });
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
//
|
|
3
3
|
// The repo publishes `changelog/index.json` on `main`: one object per release,
|
|
4
4
|
// newest first, with the app notes grouped as New / Improvements / Fixes /
|
|
5
|
-
// Misc. This module fetches it and renders the releases between the installed
|
|
5
|
+
// SDK / Misc. This module fetches it and renders the releases between the installed
|
|
6
6
|
// version (exclusive) and the offered one (inclusive) as the Markdown the
|
|
7
7
|
// dialog already understands: a `## [x.y.z] - YYYY-MM-DD` header per release,
|
|
8
8
|
// the release title in bold, the intro, then the groups.
|
|
@@ -16,6 +16,7 @@ const GROUPS = [
|
|
|
16
16
|
['new', 'New'],
|
|
17
17
|
['improvements', 'Improvements'],
|
|
18
18
|
['fixes', 'Fixes'],
|
|
19
|
+
['sdk', 'SDK'],
|
|
19
20
|
['misc', 'Misc'],
|
|
20
21
|
];
|
|
21
22
|
|
|
@@ -37,6 +37,25 @@ A short intro.
|
|
|
37
37
|
- Faster.`);
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
+
it('shows SDK notes between Fixes and Misc and omits an empty SDK group', () => {
|
|
41
|
+
const withSdk = [{
|
|
42
|
+
...index[0],
|
|
43
|
+
app: { ...index[0].app, sdk: ['Actions: background execution.'], misc: ['Packaging update.'] },
|
|
44
|
+
}];
|
|
45
|
+
expect(renderUpdateNotes(withSdk, '1.2.2', '1.2.3', compare)).toContain(`### Fixes
|
|
46
|
+
|
|
47
|
+
- Chat: no freeze.
|
|
48
|
+
|
|
49
|
+
### SDK
|
|
50
|
+
|
|
51
|
+
- Actions: background execution.
|
|
52
|
+
|
|
53
|
+
### Misc
|
|
54
|
+
|
|
55
|
+
- Packaging update.`);
|
|
56
|
+
expect(renderUpdateNotes([{ ...index[0], app: { sdk: [] } }], '1.2.2', '1.2.3', compare)).not.toContain('### SDK');
|
|
57
|
+
});
|
|
58
|
+
|
|
40
59
|
it('returns null when nothing lies in the range or the payload is not an index', () => {
|
|
41
60
|
expect(renderUpdateNotes(index, '1.2.3', '1.2.3', compare)).toBe(null);
|
|
42
61
|
expect(renderUpdateNotes({ entries: [] }, '1.0.0', '9.9.9', compare)).toBe(null);
|