@xopcai/xopc 0.0.142 → 0.0.143
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/README.md +1 -1
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/activity-center-store-jITiX2vJ.js +1 -0
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BawPxiu5.js → agent-avatar-dicebear-DiME9u_P.js} +1 -1
- package/dist/gateway/static/root/assets/agents-DzBXhZXO.js +2 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-81xd1p9R.js → app-management-settings-panel-Cuo7SbUP.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-DYeQsYU8.js → appearance-settings-DUfdNQqk.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-CKuKK5AU.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-D_oa7oti.js → archive-plugin-B-Qk6cGr.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-Cd-bwI2N.js → attachment-load-Di6EEbQX.js} +1 -1
- package/dist/gateway/static/root/assets/automation-suggestion-card-DGxvRxtO.js +1 -0
- package/dist/gateway/static/root/assets/automations-page-D-FF_WKV.js +4 -0
- package/dist/gateway/static/root/assets/{binary-plugins-O8svLKWw.js → binary-plugins-ZaOZDH2I.js} +1 -1
- package/dist/gateway/static/root/assets/block-editor-BTFhjWfg.js +184 -0
- package/dist/gateway/static/root/assets/browser-settings-page-BvKLdEQt.js +8 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-dJy1Eqgx.js → capability-presets-api-BU-pVZiZ.js} +1 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-DgyeEwzh.js +2 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-Bfuhp2ty.js → channel-recipient-api-DuulnhIj.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-BbVsdD_I.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-B5lVrUsN.js +1 -0
- package/dist/gateway/static/root/assets/check-BODqo66o.js +1 -0
- package/dist/gateway/static/root/assets/chunk-QUQL4437-DXsxWP7r.js +4 -0
- package/dist/gateway/static/root/assets/circle-alert-RzVebuX2.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-B8QqVy3I.js +2 -0
- package/dist/gateway/static/root/assets/{desktop-pet-DFMfIb5F.js → desktop-pet---yzVxVR.js} +1 -1
- package/dist/gateway/static/root/assets/desktop-pet-settings-Dc3gqBJE.js +1 -0
- package/dist/gateway/static/root/assets/{directory-picker-path-field-BrYt1gAr.js → directory-picker-path-field-DCmOGLtK.js} +1 -1
- package/dist/gateway/static/root/assets/dreaming-settings-BgT5KZVe.js +3 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-Bh630pLD.js → extension-debug-page-ByaKTTq4.js} +1 -1
- package/dist/gateway/static/root/assets/extension-page-BmRzHAZr.js +1 -0
- package/dist/gateway/static/root/assets/extension-settings-page-JUtwIhbF.js +1 -0
- package/dist/gateway/static/root/assets/{fetch-B1WtuprY.js → fetch-8QNN25Sh.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-De2N821l.js → gateway-config-api-CxicF50_.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-settings-Bz2I_EO5.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-nEujFSDj.js → gateway-startup-retry-5YBnS9Fj.js} +1 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-VcoyuZGN.js +1 -0
- package/dist/gateway/static/root/assets/goal-detail-page-Cilkap2G.js +4 -0
- package/dist/gateway/static/root/assets/{goals-config-api-DUy3eEse.js → goals-config-api-CwcHRdC0.js} +1 -1
- package/dist/gateway/static/root/assets/goals-page-C6eoni4z.js +2 -0
- package/dist/gateway/static/root/assets/goals-settings-o4i-qAOS.js +1 -0
- package/dist/gateway/static/root/assets/heartbeat-settings-DQQkETX8.js +1 -0
- package/dist/gateway/static/root/assets/index-BKRqeRHm.js +257 -0
- package/dist/gateway/static/root/assets/index-CphxClbs.css +1 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-CVIwwM15.js → keyboard-shortcuts-settings-LT6qB-ua.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-Dli2e3fS.js +7 -0
- package/dist/gateway/static/root/assets/{markdown-split-B_6us9j7.js → markdown-split-Dw-yE2-y.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-D_fryIyj.js → media-plugins-D9NNNUgE.js} +1 -1
- package/dist/gateway/static/root/assets/messages-CzKxM6I4.js +5 -0
- package/dist/gateway/static/root/assets/models-hub-panel-DVn2Q1Ik.js +2 -0
- package/dist/gateway/static/root/assets/notes-page-CRgbJGgk.js +1 -0
- package/dist/gateway/static/root/assets/notes-workbench-BxZRHLWx.js +2 -0
- package/dist/gateway/static/root/assets/{page-tabs-D_8jGlqx.js → page-tabs-D4hkWVt_.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-BBLMK8Mp.js → preview-open-alternatives-CIckv0uy.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-Doz53xLn.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-DoMtcRLg.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-BeHVEgrm.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-DVS3FR5r.js → save-bar-controls-B0b42kB2.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-D6vKd6-T.js → schedule-field-BtjEkczK.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-BPy4lbIh.js → schema-form-Bf0bk3i6.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-Bk4bQsBe.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-DdFyaRMm.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-WzdikxPt.js → settings-collapsible-section-BTKTdTNX.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-CvfzhBV-.js → settings-form-section-DL4P0sAj.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-BxR-Ulhi.js → settings-loading-skeleton-BV6KFNj4.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-B_4DsX5W.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-layout-CKefvbYi.js → settings-page-layout-CyGlrInB.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-DJ1_MLgX.js +1 -0
- package/dist/gateway/static/root/assets/share-preview-page-BQBV7YrV.js +2 -0
- package/dist/gateway/static/root/assets/shares-settings-0VuFLBeU.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-DO87Ckeo.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-D3VdtxAn.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-BokgAgf7.js → system-settings-panel-D85fBBuI.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-BwHlNL3L.js → typed-models-lib-CwEuYrHX.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-DR11ap3A.js → use-channel-catalog-COXIfXcl.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-m9JVQ73F.js +1 -0
- package/dist/gateway/static/root/assets/user-profile-fields-editor-DtQiuY7E.js +1 -0
- package/dist/gateway/static/root/assets/user-profile-settings-panel-CWM0fEpb.js +1 -0
- package/dist/gateway/static/root/assets/{utils-BKUWB-TT.js → utils--BO6xT3u.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-LoT3wgZ9.js +1 -0
- package/dist/gateway/static/root/assets/with-selector-aYPsXwdl.js +1 -0
- package/dist/gateway/static/root/assets/work-item-detail-page-DSTMz_mO.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-CL_rnAUB.js → workflow-run-setup-panel-B35lJzvm.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-BfSm9oR8.js +11 -0
- package/dist/gateway/static/root/assets/workflows-page-DLioOiRN.css +1 -0
- package/dist/gateway/static/root/connector-icons/README.md +11 -0
- package/dist/gateway/static/root/connector-icons/airtable.svg +13 -0
- package/dist/gateway/static/root/connector-icons/asana.svg +15 -0
- package/dist/gateway/static/root/connector-icons/brave-search.svg +1 -0
- package/dist/gateway/static/root/connector-icons/clickup.svg +19 -0
- package/dist/gateway/static/root/connector-icons/composio.svg +266 -0
- package/dist/gateway/static/root/connector-icons/discord.svg +15 -0
- package/dist/gateway/static/root/connector-icons/dropbox.svg +152 -0
- package/dist/gateway/static/root/connector-icons/excel.svg +56 -0
- package/dist/gateway/static/root/connector-icons/fetch.svg +6 -0
- package/dist/gateway/static/root/connector-icons/figma.svg +178 -0
- package/dist/gateway/static/root/connector-icons/filesystem.svg +6 -0
- package/dist/gateway/static/root/connector-icons/github.svg +10 -0
- package/dist/gateway/static/root/connector-icons/gmail.svg +3 -0
- package/dist/gateway/static/root/connector-icons/google-calendar.svg +3 -0
- package/dist/gateway/static/root/connector-icons/google-docs.svg +25 -0
- package/dist/gateway/static/root/connector-icons/google-drive.svg +25 -0
- package/dist/gateway/static/root/connector-icons/google-sheets.svg +1 -0
- package/dist/gateway/static/root/connector-icons/hubspot.svg +142 -0
- package/dist/gateway/static/root/connector-icons/jira.svg +15 -0
- package/dist/gateway/static/root/connector-icons/linear.svg +5 -0
- package/dist/gateway/static/root/connector-icons/memory.svg +5 -0
- package/dist/gateway/static/root/connector-icons/microsoft-teams.svg +33 -0
- package/dist/gateway/static/root/connector-icons/notion.svg +5 -0
- package/dist/gateway/static/root/connector-icons/one-drive.svg +13 -0
- package/dist/gateway/static/root/connector-icons/outlook.svg +76 -0
- package/dist/gateway/static/root/connector-icons/playwright.svg +9 -0
- package/dist/gateway/static/root/connector-icons/salesforce.svg +17 -0
- package/dist/gateway/static/root/connector-icons/sequential-thinking.svg +8 -0
- package/dist/gateway/static/root/connector-icons/shopify.svg +5 -0
- package/dist/gateway/static/root/connector-icons/slack.svg +9 -0
- package/dist/gateway/static/root/connector-icons/spotify.svg +43 -0
- package/dist/gateway/static/root/connector-icons/stripe.svg +11 -0
- package/dist/gateway/static/root/connector-icons/telegram.svg +130 -0
- package/dist/gateway/static/root/connector-icons/time.svg +6 -0
- package/dist/gateway/static/root/connector-icons/todoist.svg +277 -0
- package/dist/gateway/static/root/connector-icons/trello.svg +19 -0
- package/dist/gateway/static/root/connector-icons/twitter.svg +128 -0
- package/dist/gateway/static/root/connector-icons/whatsapp.svg +61 -0
- package/dist/gateway/static/root/connector-icons/youtube.svg +11 -0
- package/dist/gateway/static/root/index.html +9 -6
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +2 -0
- package/dist/src/agent/agent-manager.js +8 -0
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/background-review/prompts.d.ts +1 -1
- package/dist/src/agent/background-review/prompts.js +3 -2
- package/dist/src/agent/background-review/prompts.js.map +1 -1
- package/dist/src/agent/embedded/session-tool-result-guard.js +1 -1
- package/dist/src/agent/embedded/xopc-tools-bridge.d.ts +9 -0
- package/dist/src/agent/embedded/xopc-tools-bridge.js +71 -3
- package/dist/src/agent/embedded/xopc-tools-bridge.js.map +1 -1
- package/dist/src/agent/goals/post-turn.js +5 -4
- package/dist/src/agent/goals/post-turn.js.map +1 -1
- package/dist/src/agent/mcp/mcp-transport.js +4 -1
- package/dist/src/agent/mcp/mcp-transport.js.map +1 -1
- package/dist/src/agent/memory/context/planner.d.ts +1 -0
- package/dist/src/agent/memory/context/planner.js +60 -14
- package/dist/src/agent/memory/context/planner.js.map +1 -1
- package/dist/src/agent/memory/context/types.d.ts +3 -1
- package/dist/src/agent/memory/lifecycle.d.ts +11 -0
- package/dist/src/agent/memory/lifecycle.js +50 -0
- package/dist/src/agent/memory/lifecycle.js.map +1 -0
- package/dist/src/agent/memory/source-origin.d.ts +3 -0
- package/dist/src/agent/memory/source-origin.js +19 -0
- package/dist/src/agent/memory/source-origin.js.map +1 -0
- package/dist/src/agent/memory/understanding/service.js +5 -0
- package/dist/src/agent/memory/understanding/service.js.map +1 -1
- package/dist/src/agent/memory/user-context-coordinator.js +7 -2
- package/dist/src/agent/memory/user-context-coordinator.js.map +1 -1
- package/dist/src/agent/prompt/sections/behavior.d.ts +2 -0
- package/dist/src/agent/prompt/sections/behavior.js +30 -1
- package/dist/src/agent/prompt/sections/behavior.js.map +1 -1
- package/dist/src/agent/prompt/sections/tooling.js +1 -1
- package/dist/src/agent/prompt/sections/tooling.js.map +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +8 -1
- package/dist/src/agent/prompt/service-prompt-builder.js.map +1 -1
- package/dist/src/agent/prompt/system-prompt.d.ts +2 -0
- package/dist/src/agent/prompt/system-prompt.js +6 -3
- package/dist/src/agent/prompt/system-prompt.js.map +1 -1
- package/dist/src/agent/service/process-direct-streaming.js +22 -0
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service.d.ts +2 -0
- package/dist/src/agent/service.js +9 -3
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/starter-agents.js +1 -1
- package/dist/src/agent/starter-agents.js.map +1 -1
- package/dist/src/agent/tool-manuals/xopc-use.d.ts +1 -1
- package/dist/src/agent/tool-manuals/xopc-use.js +1 -1
- package/dist/src/agent/tool-manuals/xopc-use.js.map +1 -1
- package/dist/src/agent/tools/composio-tool.d.ts +18 -5
- package/dist/src/agent/tools/composio-tool.js +252 -35
- package/dist/src/agent/tools/composio-tool.js.map +1 -1
- package/dist/src/agent/tools/factory.js +7 -3
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/index.d.ts +1 -1
- package/dist/src/agent/tools/index.js +2 -2
- package/dist/src/agent/tools/workflow-tool.d.ts +0 -1
- package/dist/src/agent/tools/workflow-tool.js +3 -16
- package/dist/src/agent/tools/workflow-tool.js.map +1 -1
- package/dist/src/agent/workflow/builtins/index.d.ts +2 -28
- package/dist/src/agent/workflow/builtins/index.js +226 -41
- package/dist/src/agent/workflow/builtins/index.js.map +1 -1
- package/dist/src/agent/workflow/catalog.d.ts +32 -34
- package/dist/src/agent/workflow/catalog.js +158 -154
- package/dist/src/agent/workflow/catalog.js.map +1 -1
- package/dist/src/agent/workflow/index.d.ts +4 -6
- package/dist/src/agent/workflow/index.js +2 -5
- package/dist/src/agent/workflow/snapshot.d.ts +2 -2
- package/dist/src/agent/workflow/snapshot.js +2 -2
- package/dist/src/agent/workflow/snapshot.js.map +1 -1
- package/dist/src/agent/workflow/structured-output-tool.d.ts +2 -2
- package/dist/src/agent/workflow/structured-output-tool.js +2 -2
- package/dist/src/agent/workflow/structured-output-tool.js.map +1 -1
- package/dist/src/agent/workflow/subagent-runner.js +1 -1
- package/dist/src/agent/workflow/types.d.ts +31 -26
- package/dist/src/agent-manifest/index.d.ts +1 -0
- package/dist/src/agent-manifest/index.js +3 -1
- package/dist/src/agent-manifest/index.js.map +1 -1
- package/dist/src/agent-manifest/preset-chain.d.ts +10 -0
- package/dist/src/agent-manifest/preset-chain.js +32 -0
- package/dist/src/agent-manifest/preset-chain.js.map +1 -0
- package/dist/src/agent-manifest/resolver.js +3 -10
- package/dist/src/agent-manifest/resolver.js.map +1 -1
- package/dist/src/agent-manifest/schema.d.ts +4 -4
- package/dist/src/automations/api/routes.js +13 -1
- package/dist/src/automations/api/routes.js.map +1 -1
- package/dist/src/automations/domain/validation.d.ts +14 -14
- package/dist/src/automations/draft/automation-draft-validator.d.ts +3 -3
- package/dist/src/browser/providers/browser-ext-install.d.ts +11 -1
- package/dist/src/browser/providers/browser-ext-install.js +39 -14
- package/dist/src/browser/providers/browser-ext-install.js.map +1 -1
- package/dist/src/capabilities/store-connector.d.ts +0 -1
- package/dist/src/capabilities/store-connector.js +3 -5
- package/dist/src/capabilities/store-connector.js.map +1 -1
- package/dist/src/chat-commands/builtins/review.js +72 -73
- package/dist/src/chat-commands/builtins/review.js.map +1 -1
- package/dist/src/chat-commands/builtins/workflow.js +9 -54
- package/dist/src/chat-commands/builtins/workflow.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/extension-create.js +2 -2
- package/dist/src/cli/commands/extension-create.js.map +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +42 -36
- package/dist/src/cli/commands/extension-marketplace.js.map +1 -1
- package/dist/src/cli/commands/extension-pack.d.ts +6 -0
- package/dist/src/cli/commands/extension-pack.js +3 -2
- package/dist/src/cli/commands/extension-pack.js.map +1 -1
- package/dist/src/commands/agents.config.d.ts +1 -0
- package/dist/src/commands/agents.config.js +1 -0
- package/dist/src/commands/agents.config.js.map +1 -1
- package/dist/src/config/schema.d.ts +6 -6
- package/dist/src/config/schema.js +6 -22
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/web-patch.d.ts +1 -1
- package/dist/src/connectors/approval.d.ts +2 -0
- package/dist/src/connectors/approval.js +33 -0
- package/dist/src/connectors/approval.js.map +1 -0
- package/dist/src/connectors/auth-provider-registry.d.ts +9 -0
- package/dist/src/connectors/auth-provider-registry.js +17 -0
- package/dist/src/connectors/auth-provider-registry.js.map +1 -0
- package/dist/src/connectors/builtin-catalog.js +55 -116
- package/dist/src/connectors/builtin-catalog.js.map +1 -1
- package/dist/src/connectors/catalog.js +7 -2
- package/dist/src/connectors/catalog.js.map +1 -1
- package/dist/src/connectors/composio-catalog.d.ts +19 -0
- package/dist/src/connectors/composio-catalog.js +237 -0
- package/dist/src/connectors/composio-catalog.js.map +1 -0
- package/dist/src/connectors/composio-logo.d.ts +1 -0
- package/dist/src/connectors/composio-logo.js +51 -0
- package/dist/src/connectors/composio-logo.js.map +1 -0
- package/dist/src/connectors/composio-sessions.d.ts +116 -0
- package/dist/src/connectors/composio-sessions.js +296 -0
- package/dist/src/connectors/composio-sessions.js.map +1 -0
- package/dist/src/connectors/composio-triggers.d.ts +17 -0
- package/dist/src/connectors/composio-triggers.js +48 -5
- package/dist/src/connectors/composio-triggers.js.map +1 -1
- package/dist/src/connectors/composio.d.ts +31 -2
- package/dist/src/connectors/composio.js +374 -151
- package/dist/src/connectors/composio.js.map +1 -1
- package/dist/src/connectors/connector-memory-sync.d.ts +15 -0
- package/dist/src/connectors/connector-memory-sync.js +90 -0
- package/dist/src/connectors/connector-memory-sync.js.map +1 -0
- package/dist/src/connectors/install.js +35 -92
- package/dist/src/connectors/install.js.map +1 -1
- package/dist/src/connectors/instances.js +6 -2
- package/dist/src/connectors/instances.js.map +1 -1
- package/dist/src/connectors/integration-strategy.d.ts +3 -0
- package/dist/src/connectors/integration-strategy.js +29 -0
- package/dist/src/connectors/integration-strategy.js.map +1 -0
- package/dist/src/connectors/policy.d.ts +13 -0
- package/dist/src/connectors/policy.js +48 -0
- package/dist/src/connectors/policy.js.map +1 -0
- package/dist/src/connectors/providers.js +1 -1
- package/dist/src/connectors/runtime-adapter-registry.d.ts +25 -0
- package/dist/src/connectors/runtime-adapter-registry.js +154 -0
- package/dist/src/connectors/runtime-adapter-registry.js.map +1 -0
- package/dist/src/connectors/types.d.ts +113 -4
- package/dist/src/connectors/workflow-preflight.d.ts +20 -0
- package/dist/src/connectors/workflow-preflight.js +70 -0
- package/dist/src/connectors/workflow-preflight.js.map +1 -0
- package/dist/src/extensions/install-transaction.d.ts +16 -0
- package/dist/src/extensions/install-transaction.js +76 -0
- package/dist/src/extensions/install-transaction.js.map +1 -0
- package/dist/src/extensions/install.d.ts +2 -0
- package/dist/src/extensions/install.js +23 -1
- package/dist/src/extensions/install.js.map +1 -1
- package/dist/src/gateway/agents-admin.d.ts +2 -0
- package/dist/src/gateway/agents-admin.js +7 -0
- package/dist/src/gateway/agents-admin.js.map +1 -1
- package/dist/src/gateway/capability-presets-admin.d.ts +11 -0
- package/dist/src/gateway/capability-presets-admin.js +11 -4
- package/dist/src/gateway/capability-presets-admin.js.map +1 -1
- package/dist/src/gateway/chat-stream/mapper.js +17 -0
- package/dist/src/gateway/chat-stream/mapper.js.map +1 -1
- package/dist/src/gateway/chat-stream/protocol.d.ts +18 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +3 -3
- package/dist/src/gateway/hono/routes/agents.js +3 -0
- package/dist/src/gateway/hono/routes/agents.js.map +1 -1
- package/dist/src/gateway/hono/routes/capability-presets.js +19 -1
- package/dist/src/gateway/hono/routes/capability-presets.js.map +1 -1
- package/dist/src/gateway/hono/routes/connectors.js +188 -25
- package/dist/src/gateway/hono/routes/connectors.js.map +1 -1
- package/dist/src/gateway/hono/routes/goals.js +22 -3
- package/dist/src/gateway/hono/routes/goals.js.map +1 -1
- package/dist/src/gateway/hono/routes/home.d.ts +60 -1
- package/dist/src/gateway/hono/routes/home.js +244 -18
- package/dist/src/gateway/hono/routes/home.js.map +1 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/memory.js +14 -1
- package/dist/src/gateway/hono/routes/memory.js.map +1 -1
- package/dist/src/gateway/hono/routes/projects.js +103 -2
- package/dist/src/gateway/hono/routes/projects.js.map +1 -1
- package/dist/src/gateway/hono/routes/public-gateway.js +93 -0
- package/dist/src/gateway/hono/routes/public-gateway.js.map +1 -1
- package/dist/src/gateway/hono/routes/workflows.js +137 -22
- package/dist/src/gateway/hono/routes/workflows.js.map +1 -1
- package/dist/src/gateway/hono/routes/you.d.ts +23 -0
- package/dist/src/gateway/hono/routes/you.js +538 -0
- package/dist/src/gateway/hono/routes/you.js.map +1 -0
- package/dist/src/gateway/hono/sse.d.ts +2 -1
- package/dist/src/gateway/hono/sse.js +2 -1
- package/dist/src/gateway/hono/sse.js.map +1 -1
- package/dist/src/gateway/service/marketplace-service.d.ts +13 -1
- package/dist/src/gateway/service/marketplace-service.js +96 -40
- package/dist/src/gateway/service/marketplace-service.js.map +1 -1
- package/dist/src/gateway/service.d.ts +2 -0
- package/dist/src/gateway/service.js +7 -1
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/goals/goal-service.d.ts +7 -5
- package/dist/src/goals/goal-service.js +25 -13
- package/dist/src/goals/goal-service.js.map +1 -1
- package/dist/src/goals/goal-store.js +46 -7
- package/dist/src/goals/goal-store.js.map +1 -1
- package/dist/src/goals/types.d.ts +24 -0
- package/dist/src/storage/sqlite/connector-repository.d.ts +49 -0
- package/dist/src/storage/sqlite/connector-repository.js +385 -0
- package/dist/src/storage/sqlite/connector-repository.js.map +1 -0
- package/dist/src/storage/sqlite/index.d.ts +3 -0
- package/dist/src/storage/sqlite/index.js +4 -1
- package/dist/src/storage/sqlite/migrations/030_connectors.sql +94 -0
- package/dist/src/storage/sqlite/migrations/031_connector_approvals.sql +24 -0
- package/dist/src/storage/sqlite/migrations/032_connector_webhook_deliveries.sql +15 -0
- package/dist/src/storage/sqlite/migrations/033_user_trust_policies.sql +6 -0
- package/dist/src/storage/sqlite/migrations/034_allow_global_auto_trust.sql +14 -0
- package/dist/src/storage/sqlite/migrations/035_user_profile_prompt_state.sql +7 -0
- package/dist/src/storage/sqlite/migrations/036_goal_outcome_metric.sql +12 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/storage/sqlite/user-profile-setup-repository.d.ts +3 -0
- package/dist/src/storage/sqlite/user-profile-setup-repository.js +34 -0
- package/dist/src/storage/sqlite/user-profile-setup-repository.js.map +1 -0
- package/dist/src/storage/sqlite/user-trust-repository.d.ts +3 -0
- package/dist/src/storage/sqlite/user-trust-repository.js +34 -0
- package/dist/src/storage/sqlite/user-trust-repository.js.map +1 -0
- package/dist/src/tui/components/assistant-message.js +15 -0
- package/dist/src/tui/components/assistant-message.js.map +1 -1
- package/dist/src/tui/tui-agent-events.js +85 -1
- package/dist/src/tui/tui-agent-events.js.map +1 -1
- package/dist/src/tui/tui-command-formatters.js +7 -7
- package/dist/src/tui/tui-command-formatters.js.map +1 -1
- package/dist/src/tui/tui-commands.js +1 -1
- package/dist/src/tui/tui-startup-resources.js +1 -1
- package/dist/src/user-context/import.d.ts +12 -0
- package/dist/src/user-context/import.js +48 -0
- package/dist/src/user-context/import.js.map +1 -0
- package/dist/src/user-context/profile.d.ts +37 -0
- package/dist/src/user-context/profile.js +165 -0
- package/dist/src/user-context/profile.js.map +1 -0
- package/dist/src/user-context/projection.d.ts +54 -0
- package/dist/src/user-context/projection.js +121 -0
- package/dist/src/user-context/projection.js.map +1 -0
- package/dist/src/user-context/source-recommendations.d.ts +13 -0
- package/dist/src/user-context/source-recommendations.js +86 -0
- package/dist/src/user-context/source-recommendations.js.map +1 -0
- package/dist/src/user-context/trust-policy.d.ts +11 -0
- package/dist/src/user-context/trust-policy.js +31 -0
- package/dist/src/user-context/trust-policy.js.map +1 -0
- package/dist/src/workflows/authoring/index.d.ts +1 -0
- package/dist/src/workflows/authoring/index.js +2 -0
- package/dist/src/workflows/authoring/workflow-draft-store.d.ts +33 -0
- package/dist/src/workflows/authoring/workflow-draft-store.js +74 -0
- package/dist/src/workflows/authoring/workflow-draft-store.js.map +1 -0
- package/dist/src/workflows/domain/definition-utils.d.ts +6 -4
- package/dist/src/workflows/domain/definition-utils.js +28 -26
- package/dist/src/workflows/domain/definition-utils.js.map +1 -1
- package/dist/src/workflows/domain/definition.d.ts +79 -6
- package/dist/src/workflows/domain/event.d.ts +18 -2
- package/dist/src/workflows/domain/index.js +3 -3
- package/dist/src/workflows/domain/run.d.ts +16 -2
- package/dist/src/workflows/domain/run.js.map +1 -1
- package/dist/src/workflows/domain/validation.d.ts +9 -5
- package/dist/src/workflows/domain/validation.js +183 -40
- package/dist/src/workflows/domain/validation.js.map +1 -1
- package/dist/src/workflows/draft/workflow-draft-prompt.d.ts +2 -3
- package/dist/src/workflows/draft/workflow-draft-prompt.js +31 -73
- package/dist/src/workflows/draft/workflow-draft-prompt.js.map +1 -1
- package/dist/src/workflows/draft/workflow-draft-service.js +4 -8
- package/dist/src/workflows/draft/workflow-draft-service.js.map +1 -1
- package/dist/src/workflows/draft/workflow-draft-validator.js +29 -37
- package/dist/src/workflows/draft/workflow-draft-validator.js.map +1 -1
- package/dist/src/workflows/draft/workflow-draft.types.d.ts +4 -4
- package/dist/src/workflows/engine/projector.js +43 -1
- package/dist/src/workflows/engine/projector.js.map +1 -1
- package/dist/src/workflows/engine/workflow-engine.d.ts +2 -3
- package/dist/src/workflows/engine/workflow-engine.js +24 -4
- package/dist/src/workflows/engine/workflow-engine.js.map +1 -1
- package/dist/src/workflows/index.js +4 -7
- package/dist/src/workflows/registry/catalog-workflow-definition-registry.js +1 -9
- package/dist/src/workflows/registry/catalog-workflow-definition-registry.js.map +1 -1
- package/dist/src/workflows/runtime/graph-workflow-runtime.d.ts +10 -0
- package/dist/src/workflows/runtime/graph-workflow-runtime.js +295 -0
- package/dist/src/workflows/runtime/graph-workflow-runtime.js.map +1 -0
- package/dist/src/workflows/runtime/index.d.ts +1 -2
- package/dist/src/workflows/runtime/index.js +2 -5
- package/dist/src/workflows/runtime/workflow-runtime-port.d.ts +5 -8
- package/dist/src/workflows/service/workflow-run-service.js +15 -1
- package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
- package/dist/src/workflows/service/workflow-run-service.types.d.ts +2 -1
- package/package.json +4 -3
- package/dist/gateway/static/root/assets/agents-CyvCIHnB.js +0 -2
- package/dist/gateway/static/root/assets/apps-page-DK_Vx6nl.js +0 -1
- package/dist/gateway/static/root/assets/automation-suggestion-card-B1LV3YYv.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-fzrovqhv.js +0 -4
- package/dist/gateway/static/root/assets/block-editor-Dhj5f4Bx.js +0 -184
- package/dist/gateway/static/root/assets/browser-settings-page-BDn-n-UB.js +0 -8
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-Co5ipo_Q.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-BWlpaxg9.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-D_jkIZLV.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-BcekbW4q.js +0 -2
- package/dist/gateway/static/root/assets/desktop-pet-settings-BJCUuL8Y.js +0 -1
- package/dist/gateway/static/root/assets/dreaming-settings-BN1Z2mIo.js +0 -3
- package/dist/gateway/static/root/assets/extension-page-B-1KxvVy.js +0 -1
- package/dist/gateway/static/root/assets/extension-settings-page-BF9NACI3.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-DN9sNREz.js +0 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-BpoQW8cD.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-CBRSPd0b.js +0 -4
- package/dist/gateway/static/root/assets/goals-page-BCcBi407.js +0 -2
- package/dist/gateway/static/root/assets/goals-settings-pkTXzXkh.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-ezsufgLQ.js +0 -1
- package/dist/gateway/static/root/assets/index-B8s8Pq5U.css +0 -1
- package/dist/gateway/static/root/assets/index-DcUaXYeb.js +0 -262
- package/dist/gateway/static/root/assets/logs-page-DQtTRXtj.js +0 -7
- package/dist/gateway/static/root/assets/messages-BXNELNBa.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-BP2M9n6Q.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-CspveYaO.js +0 -1
- package/dist/gateway/static/root/assets/notes-workbench-BHwzJ0OC.js +0 -2
- package/dist/gateway/static/root/assets/project-detail-page-Dy3rsobs.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-CWKpPE0L.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-CqNRyXEo.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-MEME7ivF.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-JVd0qaSF.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-DYEbB1EV.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-dWN8BJ3z.js +0 -1
- package/dist/gateway/static/root/assets/share-preview-page-D8foINzP.js +0 -2
- package/dist/gateway/static/root/assets/shares-settings-Tgbv1s7G.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-D_YK0b_Z.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-DGytfoZK.js +0 -2
- package/dist/gateway/static/root/assets/toast-z0toXu32.js +0 -1
- package/dist/gateway/static/root/assets/user-profile-settings-panel-8YtygcJp.js +0 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-BVH71EFf.js +0 -1
- package/dist/gateway/static/root/assets/work-item-detail-page-JeTE7XNM.js +0 -1
- package/dist/gateway/static/root/assets/workflow-start-dialog-_u8Uc1ze.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-ixgk_y1l.js +0 -18
- package/dist/src/agent/workflow/builtins/audit-repo.d.ts +0 -13
- package/dist/src/agent/workflow/builtins/audit-repo.js +0 -183
- package/dist/src/agent/workflow/builtins/audit-repo.js.map +0 -1
- package/dist/src/agent/workflow/builtins/client-proposal.d.ts +0 -12
- package/dist/src/agent/workflow/builtins/client-proposal.js +0 -164
- package/dist/src/agent/workflow/builtins/client-proposal.js.map +0 -1
- package/dist/src/agent/workflow/builtins/competitor-scan.d.ts +0 -12
- package/dist/src/agent/workflow/builtins/competitor-scan.js +0 -164
- package/dist/src/agent/workflow/builtins/competitor-scan.js.map +0 -1
- package/dist/src/agent/workflow/builtins/content-draft.d.ts +0 -13
- package/dist/src/agent/workflow/builtins/content-draft.js +0 -159
- package/dist/src/agent/workflow/builtins/content-draft.js.map +0 -1
- package/dist/src/agent/workflow/builtins/content-repurpose.d.ts +0 -11
- package/dist/src/agent/workflow/builtins/content-repurpose.js +0 -146
- package/dist/src/agent/workflow/builtins/content-repurpose.js.map +0 -1
- package/dist/src/agent/workflow/builtins/debug-incident.d.ts +0 -13
- package/dist/src/agent/workflow/builtins/debug-incident.js +0 -177
- package/dist/src/agent/workflow/builtins/debug-incident.js.map +0 -1
- package/dist/src/agent/workflow/builtins/decision-compare.d.ts +0 -13
- package/dist/src/agent/workflow/builtins/decision-compare.js +0 -187
- package/dist/src/agent/workflow/builtins/decision-compare.js.map +0 -1
- package/dist/src/agent/workflow/builtins/implementation-plan.d.ts +0 -12
- package/dist/src/agent/workflow/builtins/implementation-plan.js +0 -185
- package/dist/src/agent/workflow/builtins/implementation-plan.js.map +0 -1
- package/dist/src/agent/workflow/builtins/inbox-triage.d.ts +0 -11
- package/dist/src/agent/workflow/builtins/inbox-triage.js +0 -158
- package/dist/src/agent/workflow/builtins/inbox-triage.js.map +0 -1
- package/dist/src/agent/workflow/builtins/meeting-prep.d.ts +0 -12
- package/dist/src/agent/workflow/builtins/meeting-prep.js +0 -152
- package/dist/src/agent/workflow/builtins/meeting-prep.js.map +0 -1
- package/dist/src/agent/workflow/builtins/multi-perspective-review.d.ts +0 -14
- package/dist/src/agent/workflow/builtins/multi-perspective-review.js +0 -171
- package/dist/src/agent/workflow/builtins/multi-perspective-review.js.map +0 -1
- package/dist/src/agent/workflow/builtins/offer-design.d.ts +0 -12
- package/dist/src/agent/workflow/builtins/offer-design.js +0 -170
- package/dist/src/agent/workflow/builtins/offer-design.js.map +0 -1
- package/dist/src/agent/workflow/builtins/pr-review.d.ts +0 -12
- package/dist/src/agent/workflow/builtins/pr-review.js +0 -178
- package/dist/src/agent/workflow/builtins/pr-review.js.map +0 -1
- package/dist/src/agent/workflow/builtins/release-check.d.ts +0 -11
- package/dist/src/agent/workflow/builtins/release-check.js +0 -174
- package/dist/src/agent/workflow/builtins/release-check.js.map +0 -1
- package/dist/src/agent/workflow/builtins/research.d.ts +0 -13
- package/dist/src/agent/workflow/builtins/research.js +0 -188
- package/dist/src/agent/workflow/builtins/research.js.map +0 -1
- package/dist/src/agent/workflow/builtins/weekly-review.d.ts +0 -12
- package/dist/src/agent/workflow/builtins/weekly-review.js +0 -139
- package/dist/src/agent/workflow/builtins/weekly-review.js.map +0 -1
- package/dist/src/agent/workflow/last-run-memory.d.ts +0 -42
- package/dist/src/agent/workflow/last-run-memory.js +0 -60
- package/dist/src/agent/workflow/last-run-memory.js.map +0 -1
- package/dist/src/agent/workflow/lint.d.ts +0 -38
- package/dist/src/agent/workflow/lint.js +0 -74
- package/dist/src/agent/workflow/lint.js.map +0 -1
- package/dist/src/agent/workflow/meta-locale.d.ts +0 -12
- package/dist/src/agent/workflow/meta-locale.js +0 -62
- package/dist/src/agent/workflow/meta-locale.js.map +0 -1
- package/dist/src/agent/workflow/parser.d.ts +0 -20
- package/dist/src/agent/workflow/parser.js +0 -152
- package/dist/src/agent/workflow/parser.js.map +0 -1
- package/dist/src/agent/workflow/runtime.d.ts +0 -34
- package/dist/src/agent/workflow/runtime.js +0 -402
- package/dist/src/agent/workflow/runtime.js.map +0 -1
- package/dist/src/connectors/oauth.d.ts +0 -22
- package/dist/src/connectors/oauth.js +0 -99
- package/dist/src/connectors/oauth.js.map +0 -1
- package/dist/src/workflows/runtime/script-runtime.d.ts +0 -3
- package/dist/src/workflows/runtime/script-runtime.js +0 -3
- package/dist/src/workflows/runtime/script-workflow-runtime.d.ts +0 -5
- package/dist/src/workflows/runtime/script-workflow-runtime.js +0 -15
- package/dist/src/workflows/runtime/script-workflow-runtime.js.map +0 -1
|
@@ -283,26 +283,46 @@ function spawnDetached(command, args) {
|
|
|
283
283
|
detached: true
|
|
284
284
|
}).unref();
|
|
285
285
|
}
|
|
286
|
-
function
|
|
287
|
-
const
|
|
286
|
+
function windowsExtensionManagerCandidates(env) {
|
|
287
|
+
const programFiles = [
|
|
288
|
+
env.PROGRAMFILES,
|
|
289
|
+
env["PROGRAMFILES(X86)"],
|
|
290
|
+
env.LOCALAPPDATA
|
|
291
|
+
].filter((path) => Boolean(path?.trim()));
|
|
292
|
+
const candidates = [];
|
|
293
|
+
for (const root of programFiles) candidates.push({
|
|
294
|
+
browser: "chrome",
|
|
295
|
+
executablePath: join(root, "Google", "Chrome", "Application", "chrome.exe"),
|
|
296
|
+
url: "chrome://extensions/"
|
|
297
|
+
});
|
|
298
|
+
for (const root of programFiles) candidates.push({
|
|
299
|
+
browser: "edge",
|
|
300
|
+
executablePath: join(root, "Microsoft", "Edge", "Application", "msedge.exe"),
|
|
301
|
+
url: "edge://extensions/"
|
|
302
|
+
});
|
|
303
|
+
return candidates;
|
|
304
|
+
}
|
|
305
|
+
function resolveWindowsExtensionManager(env = process.env) {
|
|
306
|
+
return windowsExtensionManagerCandidates(env).find(({ executablePath }) => existsSync(executablePath)) ?? null;
|
|
307
|
+
}
|
|
308
|
+
function openBrowserExtensionManager() {
|
|
309
|
+
const chromeUrl = "chrome://extensions/";
|
|
288
310
|
if (process.platform === "darwin") {
|
|
289
311
|
spawnDetached("open", [
|
|
290
312
|
"-a",
|
|
291
313
|
"Google Chrome",
|
|
292
314
|
chromeUrl
|
|
293
315
|
]);
|
|
294
|
-
return;
|
|
316
|
+
return "chrome";
|
|
295
317
|
}
|
|
296
318
|
if (process.platform === "win32") {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
chromeUrl
|
|
302
|
-
]);
|
|
303
|
-
return;
|
|
319
|
+
const target = resolveWindowsExtensionManager();
|
|
320
|
+
if (!target) throw new Error("No compatible browser found. Install Google Chrome or Microsoft Edge, then try again.");
|
|
321
|
+
spawnDetached(target.executablePath, [target.url]);
|
|
322
|
+
return target.browser;
|
|
304
323
|
}
|
|
305
324
|
spawnDetached("xdg-open", [chromeUrl]);
|
|
325
|
+
return "chrome";
|
|
306
326
|
}
|
|
307
327
|
function revealFolderInFileManager(dir) {
|
|
308
328
|
if (process.platform === "darwin") {
|
|
@@ -316,16 +336,21 @@ function revealFolderInFileManager(dir) {
|
|
|
316
336
|
spawnDetached("xdg-open", [dir]);
|
|
317
337
|
}
|
|
318
338
|
/**
|
|
319
|
-
* Open
|
|
339
|
+
* Open the compatible browser's extension manager and/or reveal the installed extension folder
|
|
340
|
+
* on the gateway host.
|
|
320
341
|
*/
|
|
321
342
|
async function openBrowserExtensionInstallUi(opts) {
|
|
322
343
|
const dir = (await browserExtDoctor({ cacheDir: opts.cacheDir })).extensionDir;
|
|
323
344
|
if (!dir) throw new Error("Extension not installed. Run xopc browser extension install first.");
|
|
324
|
-
|
|
345
|
+
let browser;
|
|
346
|
+
if (opts.action === "chrome" || opts.action === "both") browser = openBrowserExtensionManager();
|
|
325
347
|
if (opts.action === "folder" || opts.action === "both") revealFolderInFileManager(dir);
|
|
326
|
-
return {
|
|
348
|
+
return {
|
|
349
|
+
extensionDir: dir,
|
|
350
|
+
browser
|
|
351
|
+
};
|
|
327
352
|
}
|
|
328
353
|
//#endregion
|
|
329
|
-
export { BROWSER_EXT_REQUIRED_FILES, browserExtDoctor, computeNeedsRefresh, ensureBrowserExtensionArtifacts, ensureBrowserExtensionOnStartup, openBrowserExtensionInstallUi, readInstalledExtensionDir, resolveBundledBrowserExtDir, resolveInstalledExtensionPath, validateBrowserExtLayout };
|
|
354
|
+
export { BROWSER_EXT_REQUIRED_FILES, browserExtDoctor, computeNeedsRefresh, ensureBrowserExtensionArtifacts, ensureBrowserExtensionOnStartup, openBrowserExtensionInstallUi, readInstalledExtensionDir, resolveBundledBrowserExtDir, resolveInstalledExtensionPath, resolveWindowsExtensionManager, validateBrowserExtLayout };
|
|
330
355
|
|
|
331
356
|
//# sourceMappingURL=browser-ext-install.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-ext-install.js","names":[],"sources":["../../../../src/browser/providers/browser-ext-install.ts"],"sourcesContent":["/**\n * Install bundled Chrome extension artifacts into {resolveBinDir()}/browser-ext/.\n * Fixed path — gateway upgrades overwrite in place so Chrome sideload paths stay stable.\n */\n\nimport {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n renameSync,\n rmSync,\n statSync,\n writeFileSync,\n} from 'node:fs';\nimport { readFile, readdir, rm } from 'node:fs/promises';\nimport { spawn } from 'node:child_process';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { PACKAGE_VERSION } from '../../package-version.js';\nimport { resolveBinDir } from '../../config/paths.js';\nimport { resolvePackageRoot } from '../../infra/update-check.js';\nimport { writeTextAtomic } from '../../infra/write-file-atomic.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { assertCacheDir } from '../cache-dir-policy.js';\n\nconst log = createLogger('BrowserExtInstall');\n\nconst META_FILENAME = '.meta.json';\nconst STAGING_MAX_AGE_MS = 60 * 60 * 1000;\nconst INSTALLED_ARTIFACT_NAMES = ['manifest.json', 'popup.html', 'dist', 'icons'] as const;\n\nexport const BROWSER_EXT_REQUIRED_FILES = [\n 'manifest.json',\n 'popup.html',\n 'dist/background.js',\n 'dist/content.js',\n 'dist/popup.js',\n] as const;\n\nexport type BrowserExtBundledFrom = 'npm-dist' | 'git-dev' | 'electron-asar' | 'env-override';\n\nexport interface BrowserExtInstallMeta {\n xopcVersion: string;\n manifestVersion: string;\n source: 'bundled';\n bundledFrom: BrowserExtBundledFrom;\n installedAt: string;\n installPath: string;\n}\n\nexport interface BrowserExtDoctor {\n bundledAvailable: boolean;\n installed: boolean;\n xopcVersion: string;\n installedVersion?: string;\n manifestVersion?: string;\n extensionDir?: string;\n cacheDir: string;\n needsRefresh: boolean;\n needsChromeReload?: boolean;\n bundledFrom?: BrowserExtBundledFrom;\n runtimeExtensionVersion?: string;\n}\n\nexport interface EnsureBrowserExtResult {\n extensionDir: string;\n xopcVersion: string;\n copied: boolean;\n}\n\nfunction moduleDir(): string {\n return dirname(fileURLToPath(import.meta.url));\n}\n\n/** Validate a directory contains a loadable extension tree. */\nexport function validateBrowserExtLayout(dir: string): boolean {\n return BROWSER_EXT_REQUIRED_FILES.every((rel) => existsSync(join(dir, rel)));\n}\n\nfunction readManifestVersion(dir: string): string | undefined {\n try {\n const raw = readFileSync(join(dir, 'manifest.json'), 'utf8');\n const parsed = JSON.parse(raw) as { version?: unknown };\n return typeof parsed.version === 'string' ? parsed.version : undefined;\n } catch {\n return undefined;\n }\n}\n\nasync function readMeta(metaPath: string): Promise<BrowserExtInstallMeta | null> {\n try {\n const raw = await readFile(metaPath, 'utf8');\n const parsed = JSON.parse(raw) as BrowserExtInstallMeta;\n if (parsed && typeof parsed === 'object' && typeof parsed.xopcVersion === 'string') {\n return parsed;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nfunction browserExtRoot(cacheDir: string): string {\n return join(cacheDir, 'browser-ext');\n}\n\nfunction resolveMetaPath(cacheDir: string): string {\n return join(browserExtRoot(cacheDir), META_FILENAME);\n}\n\n/** Resolve the installed extension directory (fixed `browser-ext/` root). */\nexport function resolveInstalledExtensionPath(\n cacheDir: string,\n _meta: BrowserExtInstallMeta | null,\n): string | null {\n const root = browserExtRoot(cacheDir);\n if (validateBrowserExtLayout(root)) {\n return root;\n }\n\n return null;\n}\n\nfunction walkAncestorsForGitDevBundled(start: string): string | null {\n let dir = start;\n for (let i = 0; i < 12; i++) {\n const candidate = join(dir, 'packages/browser-ext');\n if (validateBrowserExtLayout(candidate)) {\n return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\n/**\n * Resolve the bundled extension source directory (read-only).\n */\nexport async function resolveBundledBrowserExtDir(): Promise<{\n dir: string;\n bundledFrom: BrowserExtBundledFrom;\n} | null> {\n const envOverride = process.env.XOPC_BROWSER_EXT_BUNDLED_ROOT?.trim();\n if (envOverride && validateBrowserExtLayout(envOverride)) {\n return { dir: envOverride, bundledFrom: 'env-override' };\n }\n\n const fromModule = join(moduleDir(), '../../../browser-ext');\n if (validateBrowserExtLayout(fromModule)) {\n const root = await resolvePackageRoot();\n const bundledFrom: BrowserExtBundledFrom =\n process.versions.electron && root && root.includes('app.asar') ? 'electron-asar' : 'npm-dist';\n return { dir: fromModule, bundledFrom };\n }\n\n const gitDev = walkAncestorsForGitDevBundled(moduleDir());\n if (gitDev) {\n return { dir: gitDev, bundledFrom: 'git-dev' };\n }\n\n const root = await resolvePackageRoot();\n if (root) {\n const distBundled = join(root, 'dist/browser-ext');\n if (validateBrowserExtLayout(distBundled)) {\n const bundledFrom: BrowserExtBundledFrom =\n process.versions.electron && root.includes('app.asar') ? 'electron-asar' : 'npm-dist';\n return { dir: distBundled, bundledFrom };\n }\n }\n\n return null;\n}\n\nexport function computeNeedsRefresh(params: {\n force?: boolean;\n bundledManifestVersion: string;\n installedPath: string | null;\n meta: BrowserExtInstallMeta | null;\n}): boolean {\n if (params.force) return true;\n if (!params.installedPath || !validateBrowserExtLayout(params.installedPath)) return true;\n\n const installedManifest = readManifestVersion(params.installedPath);\n if (!installedManifest || installedManifest !== params.bundledManifestVersion) return true;\n\n if (!params.meta || params.meta.xopcVersion !== PACKAGE_VERSION) return true;\n\n return false;\n}\n\nasync function cleanupStaleStaging(root: string): Promise<void> {\n if (!existsSync(root)) return;\n let entries: string[];\n try {\n entries = await readdir(root);\n } catch {\n return;\n }\n const now = Date.now();\n for (const name of entries) {\n if (!name.startsWith('.staging-')) continue;\n const full = join(root, name);\n try {\n const st = statSync(full);\n if (now - st.mtimeMs > STAGING_MAX_AGE_MS) {\n await rm(full, { recursive: true, force: true });\n }\n } catch {\n /* */\n }\n }\n}\n\nfunction removeInstalledArtifacts(root: string): void {\n for (const name of INSTALLED_ARTIFACT_NAMES) {\n const full = join(root, name);\n if (existsSync(full)) {\n rmSync(full, { recursive: true, force: true });\n }\n }\n}\n\nfunction promoteStagingToRoot(stagingDir: string, root: string): void {\n removeInstalledArtifacts(root);\n for (const name of readdirSync(stagingDir)) {\n renameSync(join(stagingDir, name), join(root, name));\n }\n rmSync(stagingDir, { recursive: true, force: true });\n if (!validateBrowserExtLayout(root)) {\n throw new Error('Bundled browser extension copy failed validation');\n }\n}\n\n/** Copy one bundled file (read/write works when src is inside Electron app.asar). */\nfunction copyBundledFile(src: string, dest: string): void {\n mkdirSync(dirname(dest), { recursive: true });\n writeFileSync(dest, readFileSync(src));\n}\n\nconst BROWSER_EXT_DIST_FILES = ['background.js', 'content.js', 'popup.js'] as const;\nconst BROWSER_EXT_ICON_FILES = ['icon-16.png', 'icon-32.png', 'icon-48.png', 'icon-128.png'] as const;\n\nfunction copyBundledTree(src: string, dest: string): void {\n mkdirSync(dest, { recursive: true });\n for (const name of ['manifest.json', 'popup.html']) {\n copyBundledFile(join(src, name), join(dest, name));\n }\n for (const file of BROWSER_EXT_DIST_FILES) {\n copyBundledFile(join(src, 'dist', file), join(dest, 'dist', file));\n }\n for (const icon of BROWSER_EXT_ICON_FILES) {\n const iconSrc = join(src, 'icons', icon);\n if (existsSync(iconSrc)) {\n copyBundledFile(iconSrc, join(dest, 'icons', icon));\n }\n }\n if (!validateBrowserExtLayout(dest)) {\n throw new Error('Bundled browser extension copy failed validation');\n }\n}\n\nexport async function browserExtDoctor(opts?: {\n cacheDir?: string;\n runtimeExtensionVersion?: string;\n}): Promise<BrowserExtDoctor> {\n const resolvedCache = opts?.cacheDir?.trim()\n ? assertCacheDir(opts.cacheDir)\n : resolveBinDir();\n const cacheDir = resolvedCache || resolveBinDir();\n\n const bundled = await resolveBundledBrowserExtDir();\n const bundledManifestVersion = bundled ? readManifestVersion(bundled.dir) : undefined;\n const meta = await readMeta(resolveMetaPath(cacheDir));\n const installedPath = resolveInstalledExtensionPath(cacheDir, meta);\n\n const needsRefresh = bundled\n ? computeNeedsRefresh({\n force: false,\n bundledManifestVersion: bundledManifestVersion ?? PACKAGE_VERSION,\n installedPath,\n meta,\n })\n : false;\n\n const installed = Boolean(installedPath) && !needsRefresh;\n const manifestVersion = installedPath ? readManifestVersion(installedPath) : undefined;\n\n let needsChromeReload: boolean | undefined;\n const runtimeVer = opts?.runtimeExtensionVersion?.trim();\n if (runtimeVer && manifestVersion && runtimeVer !== manifestVersion) {\n needsChromeReload = true;\n }\n\n return {\n bundledAvailable: Boolean(bundled),\n installed,\n xopcVersion: PACKAGE_VERSION,\n installedVersion: meta?.xopcVersion,\n manifestVersion,\n extensionDir: installedPath ?? undefined,\n cacheDir,\n needsRefresh,\n needsChromeReload,\n bundledFrom: bundled?.bundledFrom,\n runtimeExtensionVersion: runtimeVer,\n };\n}\n\nexport async function ensureBrowserExtensionArtifacts(opts?: {\n force?: boolean;\n cacheDir?: string;\n}): Promise<EnsureBrowserExtResult> {\n const resolvedCache = opts?.cacheDir?.trim()\n ? assertCacheDir(opts.cacheDir)\n : resolveBinDir();\n const cacheDir = resolvedCache || resolveBinDir();\n\n const bundled = await resolveBundledBrowserExtDir();\n if (!bundled) {\n throw new Error(\n 'Bundled browser extension not found. Reinstall xopc or run from a built checkout (pnpm run build).',\n );\n }\n\n const bundledManifestVersion = readManifestVersion(bundled.dir) ?? PACKAGE_VERSION;\n const root = browserExtRoot(cacheDir);\n mkdirSync(root, { recursive: true });\n await cleanupStaleStaging(root);\n\n const meta = await readMeta(resolveMetaPath(cacheDir));\n const installedPath = resolveInstalledExtensionPath(cacheDir, meta);\n const needsRefresh = computeNeedsRefresh({\n force: opts?.force,\n bundledManifestVersion,\n installedPath,\n meta,\n });\n\n const extensionDir = root;\n\n if (!needsRefresh && installedPath) {\n return {\n extensionDir: installedPath,\n xopcVersion: PACKAGE_VERSION,\n copied: false,\n };\n }\n\n const stagingDir = join(root, `.staging-${process.pid}`);\n\n if (existsSync(stagingDir)) {\n rmSync(stagingDir, { recursive: true, force: true });\n }\n copyBundledTree(bundled.dir, stagingDir);\n promoteStagingToRoot(stagingDir, root);\n\n const nextMeta: BrowserExtInstallMeta = {\n xopcVersion: PACKAGE_VERSION,\n manifestVersion: bundledManifestVersion,\n source: 'bundled',\n bundledFrom: bundled.bundledFrom,\n installedAt: new Date().toISOString(),\n installPath: extensionDir,\n };\n await writeTextAtomic(resolveMetaPath(cacheDir), JSON.stringify(nextMeta, null, 2));\n\n log.info(\n { extensionDir, xopcVersion: PACKAGE_VERSION, bundledFrom: bundled.bundledFrom },\n 'Browser extension artifacts installed',\n );\n\n return {\n extensionDir,\n xopcVersion: PACKAGE_VERSION,\n copied: true,\n };\n}\n\n/** Gateway startup hook: ensure extension artifacts for the fixed extension backend. */\nexport async function ensureBrowserExtensionOnStartup(_config: unknown): Promise<void> {\n await ensureBrowserExtensionArtifacts();\n}\n\nexport async function readInstalledExtensionDir(cacheDir?: string): Promise<string | null> {\n const dir = cacheDir?.trim() ? assertCacheDir(cacheDir) : resolveBinDir();\n const resolved = dir || resolveBinDir();\n const meta = await readMeta(resolveMetaPath(resolved));\n return resolveInstalledExtensionPath(resolved, meta);\n}\n\nexport type BrowserExtensionOpenAction = 'chrome' | 'folder' | 'both';\n\nfunction spawnDetached(command: string, args: readonly string[]): void {\n spawn(command, [...args], { stdio: 'ignore', detached: true }).unref();\n}\n\nfunction openChromeExtensionsPage(): void {\n const chromeUrl = 'chrome://extensions';\n if (process.platform === 'darwin') {\n spawnDetached('open', ['-a', 'Google Chrome', chromeUrl]);\n return;\n }\n if (process.platform === 'win32') {\n spawnDetached('cmd', ['/c', 'start', 'chrome', chromeUrl]);\n return;\n }\n spawnDetached('xdg-open', [chromeUrl]);\n}\n\nfunction revealFolderInFileManager(dir: string): void {\n if (process.platform === 'darwin') {\n spawnDetached('open', [dir]);\n return;\n }\n if (process.platform === 'win32') {\n spawnDetached('explorer', [dir]);\n return;\n }\n spawnDetached('xdg-open', [dir]);\n}\n\n/**\n * Open chrome://extensions and/or reveal the installed extension folder on the gateway host.\n */\nexport async function openBrowserExtensionInstallUi(opts: {\n action: BrowserExtensionOpenAction;\n cacheDir?: string;\n}): Promise<{ extensionDir: string }> {\n const doctor = await browserExtDoctor({ cacheDir: opts.cacheDir });\n const dir = doctor.extensionDir;\n if (!dir) {\n throw new Error('Extension not installed. Run xopc browser extension install first.');\n }\n\n if (opts.action === 'chrome' || opts.action === 'both') {\n openChromeExtensionsPage();\n }\n if (opts.action === 'folder' || opts.action === 'both') {\n revealFolderInFileManager(dir);\n }\n\n return { extensionDir: dir };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;sBAoB2D;YACL;wBAEa;aACd;uBACG;AAExD,MAAM,MAAM,aAAa,oBAAoB;AAE7C,MAAM,gBAAgB;AACtB,MAAM,qBAAqB,OAAU;AACrC,MAAM,2BAA2B;CAAC;CAAiB;CAAc;CAAQ;CAAQ;AAEjF,MAAa,6BAA6B;CACxC;CACA;CACA;CACA;CACA;CACD;AAiCD,SAAS,YAAoB;AAC3B,QAAO,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;;;AAIhD,SAAgB,yBAAyB,KAAsB;AAC7D,QAAO,2BAA2B,OAAO,QAAQ,WAAW,KAAK,KAAK,IAAI,CAAC,CAAC;;AAG9E,SAAS,oBAAoB,KAAiC;AAC5D,KAAI;EACF,MAAM,MAAM,aAAa,KAAK,KAAK,gBAAgB,EAAE,OAAO;EAC5D,MAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,SAAO,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU,KAAA;SACvD;AACN;;;AAIJ,eAAe,SAAS,UAAyD;AAC/E,KAAI;EACF,MAAM,MAAM,MAAM,SAAS,UAAU,OAAO;EAC5C,MAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,MAAI,UAAU,OAAO,WAAW,YAAY,OAAO,OAAO,gBAAgB,SACxE,QAAO;AAET,SAAO;SACD;AACN,SAAO;;;AAIX,SAAS,eAAe,UAA0B;AAChD,QAAO,KAAK,UAAU,cAAc;;AAGtC,SAAS,gBAAgB,UAA0B;AACjD,QAAO,KAAK,eAAe,SAAS,EAAE,cAAc;;;AAItD,SAAgB,8BACd,UACA,OACe;CACf,MAAM,OAAO,eAAe,SAAS;AACrC,KAAI,yBAAyB,KAAK,CAChC,QAAO;AAGT,QAAO;;AAGT,SAAS,8BAA8B,OAA8B;CACnE,IAAI,MAAM;AACV,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;EAC3B,MAAM,YAAY,KAAK,KAAK,uBAAuB;AACnD,MAAI,yBAAyB,UAAU,CACrC,QAAO;EAET,MAAM,SAAS,QAAQ,IAAI;AAC3B,MAAI,WAAW,IAAK;AACpB,QAAM;;AAER,QAAO;;;;;AAMT,eAAsB,8BAGZ;CACR,MAAM,cAAc,QAAQ,IAAI,+BAA+B,MAAM;AACrE,KAAI,eAAe,yBAAyB,YAAY,CACtD,QAAO;EAAE,KAAK;EAAa,aAAa;EAAgB;CAG1D,MAAM,aAAa,KAAK,WAAW,EAAE,uBAAuB;AAC5D,KAAI,yBAAyB,WAAW,EAAE;EACxC,MAAM,OAAO,MAAM,oBAAoB;AAGvC,SAAO;GAAE,KAAK;GAAY,aADxB,QAAQ,SAAS,YAAY,QAAQ,KAAK,SAAS,WAAW,GAAG,kBAAkB;GAC9C;;CAGzC,MAAM,SAAS,8BAA8B,WAAW,CAAC;AACzD,KAAI,OACF,QAAO;EAAE,KAAK;EAAQ,aAAa;EAAW;CAGhD,MAAM,OAAO,MAAM,oBAAoB;AACvC,KAAI,MAAM;EACR,MAAM,cAAc,KAAK,MAAM,mBAAmB;AAClD,MAAI,yBAAyB,YAAY,CAGvC,QAAO;GAAE,KAAK;GAAa,aADzB,QAAQ,SAAS,YAAY,KAAK,SAAS,WAAW,GAAG,kBAAkB;GACrC;;AAI5C,QAAO;;AAGT,SAAgB,oBAAoB,QAKxB;AACV,KAAI,OAAO,MAAO,QAAO;AACzB,KAAI,CAAC,OAAO,iBAAiB,CAAC,yBAAyB,OAAO,cAAc,CAAE,QAAO;CAErF,MAAM,oBAAoB,oBAAoB,OAAO,cAAc;AACnE,KAAI,CAAC,qBAAqB,sBAAsB,OAAO,uBAAwB,QAAO;AAEtF,KAAI,CAAC,OAAO,QAAQ,OAAO,KAAK,gBAAgB,gBAAiB,QAAO;AAExE,QAAO;;AAGT,eAAe,oBAAoB,MAA6B;AAC9D,KAAI,CAAC,WAAW,KAAK,CAAE;CACvB,IAAI;AACJ,KAAI;AACF,YAAU,MAAM,QAAQ,KAAK;SACvB;AACN;;CAEF,MAAM,MAAM,KAAK,KAAK;AACtB,MAAK,MAAM,QAAQ,SAAS;AAC1B,MAAI,CAAC,KAAK,WAAW,YAAY,CAAE;EACnC,MAAM,OAAO,KAAK,MAAM,KAAK;AAC7B,MAAI;AAEF,OAAI,MADO,SAAS,KACR,CAAC,UAAU,mBACrB,OAAM,GAAG,MAAM;IAAE,WAAW;IAAM,OAAO;IAAM,CAAC;UAE5C;;;AAMZ,SAAS,yBAAyB,MAAoB;AACpD,MAAK,MAAM,QAAQ,0BAA0B;EAC3C,MAAM,OAAO,KAAK,MAAM,KAAK;AAC7B,MAAI,WAAW,KAAK,CAClB,QAAO,MAAM;GAAE,WAAW;GAAM,OAAO;GAAM,CAAC;;;AAKpD,SAAS,qBAAqB,YAAoB,MAAoB;AACpE,0BAAyB,KAAK;AAC9B,MAAK,MAAM,QAAQ,YAAY,WAAW,CACxC,YAAW,KAAK,YAAY,KAAK,EAAE,KAAK,MAAM,KAAK,CAAC;AAEtD,QAAO,YAAY;EAAE,WAAW;EAAM,OAAO;EAAM,CAAC;AACpD,KAAI,CAAC,yBAAyB,KAAK,CACjC,OAAM,IAAI,MAAM,mDAAmD;;;AAKvE,SAAS,gBAAgB,KAAa,MAAoB;AACxD,WAAU,QAAQ,KAAK,EAAE,EAAE,WAAW,MAAM,CAAC;AAC7C,eAAc,MAAM,aAAa,IAAI,CAAC;;AAGxC,MAAM,yBAAyB;CAAC;CAAiB;CAAc;CAAW;AAC1E,MAAM,yBAAyB;CAAC;CAAe;CAAe;CAAe;CAAe;AAE5F,SAAS,gBAAgB,KAAa,MAAoB;AACxD,WAAU,MAAM,EAAE,WAAW,MAAM,CAAC;AACpC,MAAK,MAAM,QAAQ,CAAC,iBAAiB,aAAa,CAChD,iBAAgB,KAAK,KAAK,KAAK,EAAE,KAAK,MAAM,KAAK,CAAC;AAEpD,MAAK,MAAM,QAAQ,uBACjB,iBAAgB,KAAK,KAAK,QAAQ,KAAK,EAAE,KAAK,MAAM,QAAQ,KAAK,CAAC;AAEpE,MAAK,MAAM,QAAQ,wBAAwB;EACzC,MAAM,UAAU,KAAK,KAAK,SAAS,KAAK;AACxC,MAAI,WAAW,QAAQ,CACrB,iBAAgB,SAAS,KAAK,MAAM,SAAS,KAAK,CAAC;;AAGvD,KAAI,CAAC,yBAAyB,KAAK,CACjC,OAAM,IAAI,MAAM,mDAAmD;;AAIvE,eAAsB,iBAAiB,MAGT;CAI5B,MAAM,YAHgB,MAAM,UAAU,MAAM,GACxC,eAAe,KAAK,SAAS,GAC7B,eAAe,KACe,eAAe;CAEjD,MAAM,UAAU,MAAM,6BAA6B;CACnD,MAAM,yBAAyB,UAAU,oBAAoB,QAAQ,IAAI,GAAG,KAAA;CAC5E,MAAM,OAAO,MAAM,SAAS,gBAAgB,SAAS,CAAC;CACtD,MAAM,gBAAgB,8BAA8B,UAAU,KAAK;CAEnE,MAAM,eAAe,UACjB,oBAAoB;EAClB,OAAO;EACP,wBAAwB,0BAA0B;EAClD;EACA;EACD,CAAC,GACF;CAEJ,MAAM,YAAY,QAAQ,cAAc,IAAI,CAAC;CAC7C,MAAM,kBAAkB,gBAAgB,oBAAoB,cAAc,GAAG,KAAA;CAE7E,IAAI;CACJ,MAAM,aAAa,MAAM,yBAAyB,MAAM;AACxD,KAAI,cAAc,mBAAmB,eAAe,gBAClD,qBAAoB;AAGtB,QAAO;EACL,kBAAkB,QAAQ,QAAQ;EAClC;EACA,aAAa;EACb,kBAAkB,MAAM;EACxB;EACA,cAAc,iBAAiB,KAAA;EAC/B;EACA;EACA;EACA,aAAa,SAAS;EACtB,yBAAyB;EAC1B;;AAGH,eAAsB,gCAAgC,MAGlB;CAIlC,MAAM,YAHgB,MAAM,UAAU,MAAM,GACxC,eAAe,KAAK,SAAS,GAC7B,eAAe,KACe,eAAe;CAEjD,MAAM,UAAU,MAAM,6BAA6B;AACnD,KAAI,CAAC,QACH,OAAM,IAAI,MACR,qGACD;CAGH,MAAM,yBAAyB,oBAAoB,QAAQ,IAAI,IAAI;CACnE,MAAM,OAAO,eAAe,SAAS;AACrC,WAAU,MAAM,EAAE,WAAW,MAAM,CAAC;AACpC,OAAM,oBAAoB,KAAK;CAE/B,MAAM,OAAO,MAAM,SAAS,gBAAgB,SAAS,CAAC;CACtD,MAAM,gBAAgB,8BAA8B,UAAU,KAAK;CACnE,MAAM,eAAe,oBAAoB;EACvC,OAAO,MAAM;EACb;EACA;EACA;EACD,CAAC;CAEF,MAAM,eAAe;AAErB,KAAI,CAAC,gBAAgB,cACnB,QAAO;EACL,cAAc;EACd,aAAa;EACb,QAAQ;EACT;CAGH,MAAM,aAAa,KAAK,MAAM,YAAY,QAAQ,MAAM;AAExD,KAAI,WAAW,WAAW,CACxB,QAAO,YAAY;EAAE,WAAW;EAAM,OAAO;EAAM,CAAC;AAEtD,iBAAgB,QAAQ,KAAK,WAAW;AACxC,sBAAqB,YAAY,KAAK;CAEtC,MAAM,WAAkC;EACtC,aAAa;EACb,iBAAiB;EACjB,QAAQ;EACR,aAAa,QAAQ;EACrB,8BAAa,IAAI,MAAM,EAAC,aAAa;EACrC,aAAa;EACd;AACD,OAAM,gBAAgB,gBAAgB,SAAS,EAAE,KAAK,UAAU,UAAU,MAAM,EAAE,CAAC;AAEnF,KAAI,KACF;EAAE;EAAc,aAAa;EAAiB,aAAa,QAAQ;EAAa,EAChF,wCACD;AAED,QAAO;EACL;EACA,aAAa;EACb,QAAQ;EACT;;;AAIH,eAAsB,gCAAgC,SAAiC;AACrF,OAAM,iCAAiC;;AAGzC,eAAsB,0BAA0B,UAA2C;CAEzF,MAAM,YADM,UAAU,MAAM,GAAG,eAAe,SAAS,GAAG,eAAe,KACjD,eAAe;AAEvC,QAAO,8BAA8B,UAAU,MAD5B,SAAS,gBAAgB,SAAS,CAAC,CACF;;AAKtD,SAAS,cAAc,SAAiB,MAA+B;AACrE,OAAM,SAAS,CAAC,GAAG,KAAK,EAAE;EAAE,OAAO;EAAU,UAAU;EAAM,CAAC,CAAC,OAAO;;AAGxE,SAAS,2BAAiC;CACxC,MAAM,YAAY;AAClB,KAAI,QAAQ,aAAa,UAAU;AACjC,gBAAc,QAAQ;GAAC;GAAM;GAAiB;GAAU,CAAC;AACzD;;AAEF,KAAI,QAAQ,aAAa,SAAS;AAChC,gBAAc,OAAO;GAAC;GAAM;GAAS;GAAU;GAAU,CAAC;AAC1D;;AAEF,eAAc,YAAY,CAAC,UAAU,CAAC;;AAGxC,SAAS,0BAA0B,KAAmB;AACpD,KAAI,QAAQ,aAAa,UAAU;AACjC,gBAAc,QAAQ,CAAC,IAAI,CAAC;AAC5B;;AAEF,KAAI,QAAQ,aAAa,SAAS;AAChC,gBAAc,YAAY,CAAC,IAAI,CAAC;AAChC;;AAEF,eAAc,YAAY,CAAC,IAAI,CAAC;;;;;AAMlC,eAAsB,8BAA8B,MAGd;CAEpC,MAAM,OAAM,MADS,iBAAiB,EAAE,UAAU,KAAK,UAAU,CAAC,EAC/C;AACnB,KAAI,CAAC,IACH,OAAM,IAAI,MAAM,qEAAqE;AAGvF,KAAI,KAAK,WAAW,YAAY,KAAK,WAAW,OAC9C,2BAA0B;AAE5B,KAAI,KAAK,WAAW,YAAY,KAAK,WAAW,OAC9C,2BAA0B,IAAI;AAGhC,QAAO,EAAE,cAAc,KAAK"}
|
|
1
|
+
{"version":3,"file":"browser-ext-install.js","names":[],"sources":["../../../../src/browser/providers/browser-ext-install.ts"],"sourcesContent":["/**\n * Install bundled Chrome extension artifacts into {resolveBinDir()}/browser-ext/.\n * Fixed path — gateway upgrades overwrite in place so Chrome sideload paths stay stable.\n */\n\nimport {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n renameSync,\n rmSync,\n statSync,\n writeFileSync,\n} from 'node:fs';\nimport { readFile, readdir, rm } from 'node:fs/promises';\nimport { spawn } from 'node:child_process';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { PACKAGE_VERSION } from '../../package-version.js';\nimport { resolveBinDir } from '../../config/paths.js';\nimport { resolvePackageRoot } from '../../infra/update-check.js';\nimport { writeTextAtomic } from '../../infra/write-file-atomic.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { assertCacheDir } from '../cache-dir-policy.js';\n\nconst log = createLogger('BrowserExtInstall');\n\nconst META_FILENAME = '.meta.json';\nconst STAGING_MAX_AGE_MS = 60 * 60 * 1000;\nconst INSTALLED_ARTIFACT_NAMES = ['manifest.json', 'popup.html', 'dist', 'icons'] as const;\n\nexport const BROWSER_EXT_REQUIRED_FILES = [\n 'manifest.json',\n 'popup.html',\n 'dist/background.js',\n 'dist/content.js',\n 'dist/popup.js',\n] as const;\n\nexport type BrowserExtBundledFrom = 'npm-dist' | 'git-dev' | 'electron-asar' | 'env-override';\n\nexport interface BrowserExtInstallMeta {\n xopcVersion: string;\n manifestVersion: string;\n source: 'bundled';\n bundledFrom: BrowserExtBundledFrom;\n installedAt: string;\n installPath: string;\n}\n\nexport interface BrowserExtDoctor {\n bundledAvailable: boolean;\n installed: boolean;\n xopcVersion: string;\n installedVersion?: string;\n manifestVersion?: string;\n extensionDir?: string;\n cacheDir: string;\n needsRefresh: boolean;\n needsChromeReload?: boolean;\n bundledFrom?: BrowserExtBundledFrom;\n runtimeExtensionVersion?: string;\n}\n\nexport interface EnsureBrowserExtResult {\n extensionDir: string;\n xopcVersion: string;\n copied: boolean;\n}\n\nfunction moduleDir(): string {\n return dirname(fileURLToPath(import.meta.url));\n}\n\n/** Validate a directory contains a loadable extension tree. */\nexport function validateBrowserExtLayout(dir: string): boolean {\n return BROWSER_EXT_REQUIRED_FILES.every((rel) => existsSync(join(dir, rel)));\n}\n\nfunction readManifestVersion(dir: string): string | undefined {\n try {\n const raw = readFileSync(join(dir, 'manifest.json'), 'utf8');\n const parsed = JSON.parse(raw) as { version?: unknown };\n return typeof parsed.version === 'string' ? parsed.version : undefined;\n } catch {\n return undefined;\n }\n}\n\nasync function readMeta(metaPath: string): Promise<BrowserExtInstallMeta | null> {\n try {\n const raw = await readFile(metaPath, 'utf8');\n const parsed = JSON.parse(raw) as BrowserExtInstallMeta;\n if (parsed && typeof parsed === 'object' && typeof parsed.xopcVersion === 'string') {\n return parsed;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nfunction browserExtRoot(cacheDir: string): string {\n return join(cacheDir, 'browser-ext');\n}\n\nfunction resolveMetaPath(cacheDir: string): string {\n return join(browserExtRoot(cacheDir), META_FILENAME);\n}\n\n/** Resolve the installed extension directory (fixed `browser-ext/` root). */\nexport function resolveInstalledExtensionPath(\n cacheDir: string,\n _meta: BrowserExtInstallMeta | null,\n): string | null {\n const root = browserExtRoot(cacheDir);\n if (validateBrowserExtLayout(root)) {\n return root;\n }\n\n return null;\n}\n\nfunction walkAncestorsForGitDevBundled(start: string): string | null {\n let dir = start;\n for (let i = 0; i < 12; i++) {\n const candidate = join(dir, 'packages/browser-ext');\n if (validateBrowserExtLayout(candidate)) {\n return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\n/**\n * Resolve the bundled extension source directory (read-only).\n */\nexport async function resolveBundledBrowserExtDir(): Promise<{\n dir: string;\n bundledFrom: BrowserExtBundledFrom;\n} | null> {\n const envOverride = process.env.XOPC_BROWSER_EXT_BUNDLED_ROOT?.trim();\n if (envOverride && validateBrowserExtLayout(envOverride)) {\n return { dir: envOverride, bundledFrom: 'env-override' };\n }\n\n const fromModule = join(moduleDir(), '../../../browser-ext');\n if (validateBrowserExtLayout(fromModule)) {\n const root = await resolvePackageRoot();\n const bundledFrom: BrowserExtBundledFrom =\n process.versions.electron && root && root.includes('app.asar') ? 'electron-asar' : 'npm-dist';\n return { dir: fromModule, bundledFrom };\n }\n\n const gitDev = walkAncestorsForGitDevBundled(moduleDir());\n if (gitDev) {\n return { dir: gitDev, bundledFrom: 'git-dev' };\n }\n\n const root = await resolvePackageRoot();\n if (root) {\n const distBundled = join(root, 'dist/browser-ext');\n if (validateBrowserExtLayout(distBundled)) {\n const bundledFrom: BrowserExtBundledFrom =\n process.versions.electron && root.includes('app.asar') ? 'electron-asar' : 'npm-dist';\n return { dir: distBundled, bundledFrom };\n }\n }\n\n return null;\n}\n\nexport function computeNeedsRefresh(params: {\n force?: boolean;\n bundledManifestVersion: string;\n installedPath: string | null;\n meta: BrowserExtInstallMeta | null;\n}): boolean {\n if (params.force) return true;\n if (!params.installedPath || !validateBrowserExtLayout(params.installedPath)) return true;\n\n const installedManifest = readManifestVersion(params.installedPath);\n if (!installedManifest || installedManifest !== params.bundledManifestVersion) return true;\n\n if (!params.meta || params.meta.xopcVersion !== PACKAGE_VERSION) return true;\n\n return false;\n}\n\nasync function cleanupStaleStaging(root: string): Promise<void> {\n if (!existsSync(root)) return;\n let entries: string[];\n try {\n entries = await readdir(root);\n } catch {\n return;\n }\n const now = Date.now();\n for (const name of entries) {\n if (!name.startsWith('.staging-')) continue;\n const full = join(root, name);\n try {\n const st = statSync(full);\n if (now - st.mtimeMs > STAGING_MAX_AGE_MS) {\n await rm(full, { recursive: true, force: true });\n }\n } catch {\n /* */\n }\n }\n}\n\nfunction removeInstalledArtifacts(root: string): void {\n for (const name of INSTALLED_ARTIFACT_NAMES) {\n const full = join(root, name);\n if (existsSync(full)) {\n rmSync(full, { recursive: true, force: true });\n }\n }\n}\n\nfunction promoteStagingToRoot(stagingDir: string, root: string): void {\n removeInstalledArtifacts(root);\n for (const name of readdirSync(stagingDir)) {\n renameSync(join(stagingDir, name), join(root, name));\n }\n rmSync(stagingDir, { recursive: true, force: true });\n if (!validateBrowserExtLayout(root)) {\n throw new Error('Bundled browser extension copy failed validation');\n }\n}\n\n/** Copy one bundled file (read/write works when src is inside Electron app.asar). */\nfunction copyBundledFile(src: string, dest: string): void {\n mkdirSync(dirname(dest), { recursive: true });\n writeFileSync(dest, readFileSync(src));\n}\n\nconst BROWSER_EXT_DIST_FILES = ['background.js', 'content.js', 'popup.js'] as const;\nconst BROWSER_EXT_ICON_FILES = ['icon-16.png', 'icon-32.png', 'icon-48.png', 'icon-128.png'] as const;\n\nfunction copyBundledTree(src: string, dest: string): void {\n mkdirSync(dest, { recursive: true });\n for (const name of ['manifest.json', 'popup.html']) {\n copyBundledFile(join(src, name), join(dest, name));\n }\n for (const file of BROWSER_EXT_DIST_FILES) {\n copyBundledFile(join(src, 'dist', file), join(dest, 'dist', file));\n }\n for (const icon of BROWSER_EXT_ICON_FILES) {\n const iconSrc = join(src, 'icons', icon);\n if (existsSync(iconSrc)) {\n copyBundledFile(iconSrc, join(dest, 'icons', icon));\n }\n }\n if (!validateBrowserExtLayout(dest)) {\n throw new Error('Bundled browser extension copy failed validation');\n }\n}\n\nexport async function browserExtDoctor(opts?: {\n cacheDir?: string;\n runtimeExtensionVersion?: string;\n}): Promise<BrowserExtDoctor> {\n const resolvedCache = opts?.cacheDir?.trim()\n ? assertCacheDir(opts.cacheDir)\n : resolveBinDir();\n const cacheDir = resolvedCache || resolveBinDir();\n\n const bundled = await resolveBundledBrowserExtDir();\n const bundledManifestVersion = bundled ? readManifestVersion(bundled.dir) : undefined;\n const meta = await readMeta(resolveMetaPath(cacheDir));\n const installedPath = resolveInstalledExtensionPath(cacheDir, meta);\n\n const needsRefresh = bundled\n ? computeNeedsRefresh({\n force: false,\n bundledManifestVersion: bundledManifestVersion ?? PACKAGE_VERSION,\n installedPath,\n meta,\n })\n : false;\n\n const installed = Boolean(installedPath) && !needsRefresh;\n const manifestVersion = installedPath ? readManifestVersion(installedPath) : undefined;\n\n let needsChromeReload: boolean | undefined;\n const runtimeVer = opts?.runtimeExtensionVersion?.trim();\n if (runtimeVer && manifestVersion && runtimeVer !== manifestVersion) {\n needsChromeReload = true;\n }\n\n return {\n bundledAvailable: Boolean(bundled),\n installed,\n xopcVersion: PACKAGE_VERSION,\n installedVersion: meta?.xopcVersion,\n manifestVersion,\n extensionDir: installedPath ?? undefined,\n cacheDir,\n needsRefresh,\n needsChromeReload,\n bundledFrom: bundled?.bundledFrom,\n runtimeExtensionVersion: runtimeVer,\n };\n}\n\nexport async function ensureBrowserExtensionArtifacts(opts?: {\n force?: boolean;\n cacheDir?: string;\n}): Promise<EnsureBrowserExtResult> {\n const resolvedCache = opts?.cacheDir?.trim()\n ? assertCacheDir(opts.cacheDir)\n : resolveBinDir();\n const cacheDir = resolvedCache || resolveBinDir();\n\n const bundled = await resolveBundledBrowserExtDir();\n if (!bundled) {\n throw new Error(\n 'Bundled browser extension not found. Reinstall xopc or run from a built checkout (pnpm run build).',\n );\n }\n\n const bundledManifestVersion = readManifestVersion(bundled.dir) ?? PACKAGE_VERSION;\n const root = browserExtRoot(cacheDir);\n mkdirSync(root, { recursive: true });\n await cleanupStaleStaging(root);\n\n const meta = await readMeta(resolveMetaPath(cacheDir));\n const installedPath = resolveInstalledExtensionPath(cacheDir, meta);\n const needsRefresh = computeNeedsRefresh({\n force: opts?.force,\n bundledManifestVersion,\n installedPath,\n meta,\n });\n\n const extensionDir = root;\n\n if (!needsRefresh && installedPath) {\n return {\n extensionDir: installedPath,\n xopcVersion: PACKAGE_VERSION,\n copied: false,\n };\n }\n\n const stagingDir = join(root, `.staging-${process.pid}`);\n\n if (existsSync(stagingDir)) {\n rmSync(stagingDir, { recursive: true, force: true });\n }\n copyBundledTree(bundled.dir, stagingDir);\n promoteStagingToRoot(stagingDir, root);\n\n const nextMeta: BrowserExtInstallMeta = {\n xopcVersion: PACKAGE_VERSION,\n manifestVersion: bundledManifestVersion,\n source: 'bundled',\n bundledFrom: bundled.bundledFrom,\n installedAt: new Date().toISOString(),\n installPath: extensionDir,\n };\n await writeTextAtomic(resolveMetaPath(cacheDir), JSON.stringify(nextMeta, null, 2));\n\n log.info(\n { extensionDir, xopcVersion: PACKAGE_VERSION, bundledFrom: bundled.bundledFrom },\n 'Browser extension artifacts installed',\n );\n\n return {\n extensionDir,\n xopcVersion: PACKAGE_VERSION,\n copied: true,\n };\n}\n\n/** Gateway startup hook: ensure extension artifacts for the fixed extension backend. */\nexport async function ensureBrowserExtensionOnStartup(_config: unknown): Promise<void> {\n await ensureBrowserExtensionArtifacts();\n}\n\nexport async function readInstalledExtensionDir(cacheDir?: string): Promise<string | null> {\n const dir = cacheDir?.trim() ? assertCacheDir(cacheDir) : resolveBinDir();\n const resolved = dir || resolveBinDir();\n const meta = await readMeta(resolveMetaPath(resolved));\n return resolveInstalledExtensionPath(resolved, meta);\n}\n\nexport type BrowserExtensionOpenAction = 'chrome' | 'folder' | 'both';\n\ntype ExtensionManagerBrowser = 'chrome' | 'edge';\n\ninterface ExtensionManagerTarget {\n browser: ExtensionManagerBrowser;\n executablePath: string;\n url: string;\n}\n\nfunction spawnDetached(command: string, args: readonly string[]): void {\n spawn(command, [...args], { stdio: 'ignore', detached: true }).unref();\n}\n\nfunction windowsExtensionManagerCandidates(env: NodeJS.ProcessEnv): ExtensionManagerTarget[] {\n const programFiles = [env.PROGRAMFILES, env['PROGRAMFILES(X86)'], env.LOCALAPPDATA].filter(\n (path): path is string => Boolean(path?.trim()),\n );\n const candidates: ExtensionManagerTarget[] = [];\n\n for (const root of programFiles) {\n candidates.push({\n browser: 'chrome',\n executablePath: join(root, 'Google', 'Chrome', 'Application', 'chrome.exe'),\n url: 'chrome://extensions/',\n });\n }\n for (const root of programFiles) {\n candidates.push({\n browser: 'edge',\n executablePath: join(root, 'Microsoft', 'Edge', 'Application', 'msedge.exe'),\n url: 'edge://extensions/',\n });\n }\n\n return candidates;\n}\n\nexport function resolveWindowsExtensionManager(\n env: NodeJS.ProcessEnv = process.env,\n): ExtensionManagerTarget | null {\n return windowsExtensionManagerCandidates(env).find(({ executablePath }) => existsSync(executablePath)) ?? null;\n}\n\nfunction openBrowserExtensionManager(): ExtensionManagerBrowser | undefined {\n const chromeUrl = 'chrome://extensions/';\n if (process.platform === 'darwin') {\n spawnDetached('open', ['-a', 'Google Chrome', chromeUrl]);\n return 'chrome';\n }\n if (process.platform === 'win32') {\n const target = resolveWindowsExtensionManager();\n if (!target) {\n throw new Error(\n 'No compatible browser found. Install Google Chrome or Microsoft Edge, then try again.',\n );\n }\n spawnDetached(target.executablePath, [target.url]);\n return target.browser;\n }\n spawnDetached('xdg-open', [chromeUrl]);\n return 'chrome';\n}\n\nfunction revealFolderInFileManager(dir: string): void {\n if (process.platform === 'darwin') {\n spawnDetached('open', [dir]);\n return;\n }\n if (process.platform === 'win32') {\n spawnDetached('explorer', [dir]);\n return;\n }\n spawnDetached('xdg-open', [dir]);\n}\n\n/**\n * Open the compatible browser's extension manager and/or reveal the installed extension folder\n * on the gateway host.\n */\nexport async function openBrowserExtensionInstallUi(opts: {\n action: BrowserExtensionOpenAction;\n cacheDir?: string;\n}): Promise<{ extensionDir: string; browser?: ExtensionManagerBrowser }> {\n const doctor = await browserExtDoctor({ cacheDir: opts.cacheDir });\n const dir = doctor.extensionDir;\n if (!dir) {\n throw new Error('Extension not installed. Run xopc browser extension install first.');\n }\n\n let browser: ExtensionManagerBrowser | undefined;\n if (opts.action === 'chrome' || opts.action === 'both') {\n browser = openBrowserExtensionManager();\n }\n if (opts.action === 'folder' || opts.action === 'both') {\n revealFolderInFileManager(dir);\n }\n\n return { extensionDir: dir, browser };\n}\n"],"mappings":"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"}
|
|
@@ -7,7 +7,6 @@ export type StoreConnectorInstallPlan = {
|
|
|
7
7
|
definition: ConnectorDefinition;
|
|
8
8
|
permissions: ConnectorPermissions;
|
|
9
9
|
requiresRestart: false;
|
|
10
|
-
requiresOAuth: boolean;
|
|
11
10
|
};
|
|
12
11
|
export declare function listStoreConnectors(config: Config, params: SkillsStoreListParams): Promise<import("../agent/skills/skills-marketplace.js").SkillsStoreListResponse>;
|
|
13
12
|
export declare function getStoreConnectorInstallPlan(config: Config, packageName: string, version?: string): Promise<StoreConnectorInstallPlan>;
|
|
@@ -79,7 +79,8 @@ function readConnectorManifest(value, packageName, version, sha256) {
|
|
|
79
79
|
const transport = serverTemplate.transport;
|
|
80
80
|
if (!localPackage && transport !== "streamable-http" && transport !== "sse") throw new Error("Store connectors must use streamable-http or sse transport.");
|
|
81
81
|
const authMode = asRecord(manifest.auth, "Connector auth").mode;
|
|
82
|
-
if (authMode !== "none" && authMode !== "apiKey"
|
|
82
|
+
if (authMode !== "none" && authMode !== "apiKey") throw new Error("Store connectors support only none or apiKey authentication.");
|
|
83
|
+
const normalizedAuth = { mode: authMode };
|
|
83
84
|
const category = asString(manifest.category, "Connector category");
|
|
84
85
|
if (![
|
|
85
86
|
"code",
|
|
@@ -97,7 +98,6 @@ function readConnectorManifest(value, packageName, version, sha256) {
|
|
|
97
98
|
"context",
|
|
98
99
|
"events",
|
|
99
100
|
"auth.apiKey",
|
|
100
|
-
"auth.oauth",
|
|
101
101
|
"runtime.mcp.stdio",
|
|
102
102
|
"runtime.mcp.sse",
|
|
103
103
|
"runtime.mcp.streamableHttp"
|
|
@@ -118,7 +118,7 @@ function readConnectorManifest(value, packageName, version, sha256) {
|
|
|
118
118
|
source: "store",
|
|
119
119
|
capabilities,
|
|
120
120
|
...Array.isArray(manifest.tags) ? { tags: asStringArray(manifest.tags, "Connector tags") } : {},
|
|
121
|
-
auth:
|
|
121
|
+
auth: normalizedAuth,
|
|
122
122
|
setup,
|
|
123
123
|
runtime: {
|
|
124
124
|
type: "mcp",
|
|
@@ -173,13 +173,11 @@ async function getStoreConnectorInstallPlan(config, packageName, version) {
|
|
|
173
173
|
version: detail.latestVersion.version,
|
|
174
174
|
permissions: definition.permissions ?? {},
|
|
175
175
|
requiresRestart: false,
|
|
176
|
-
requiresOAuth: definition.auth.mode === "oauth",
|
|
177
176
|
definition
|
|
178
177
|
};
|
|
179
178
|
}
|
|
180
179
|
async function installStoreConnector(config, packageName, input, version) {
|
|
181
180
|
const plan = await getStoreConnectorInstallPlan(config, packageName, version);
|
|
182
|
-
if (plan.requiresOAuth && plan.definition.id !== "github") throw new Error("OAuth installation for store connectors is not available yet. Use an API-key connector or the built-in GitHub connector.");
|
|
183
181
|
return {
|
|
184
182
|
instance: await installConnectorDefinition(config, plan.definition, input),
|
|
185
183
|
plan
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-connector.js","names":[],"sources":["../../../src/capabilities/store-connector.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { isIP } from 'node:net';\n\nimport AdmZip from 'adm-zip';\n\nimport type { Config } from '../config/schema.js';\nimport { installConnectorDefinition } from '../connectors/install.js';\nimport type {\n ConnectorDefinition,\n ConnectorInstallInput,\n ConnectorPermissions,\n} from '../connectors/types.js';\nimport {\n downloadConnectorStoreZipBuffer,\n fetchStoreConnectorPackageDetail,\n listConnectorPackages,\n resolveSkillsStoreBaseUrl,\n type SkillsStoreListParams,\n} from '../agent/skills/marketplace/adapters/store/store-api-client.js';\n\ntype JsonRecord = Record<string, unknown>;\n\nexport type StoreConnectorInstallPlan = {\n packageName: string;\n version: string;\n definition: ConnectorDefinition;\n permissions: ConnectorPermissions;\n requiresRestart: false;\n requiresOAuth: boolean;\n};\n\nfunction asRecord(value: unknown, label: string): JsonRecord {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error(`${label} must be an object.`);\n }\n return value as JsonRecord;\n}\n\nfunction asString(value: unknown, label: string): string {\n if (typeof value !== 'string' || !value.trim()) {\n throw new Error(`${label} must be a non-empty string.`);\n }\n return value.trim();\n}\n\nfunction asStringArray(value: unknown, label: string): string[] {\n if (!Array.isArray(value) || value.some((item) => typeof item !== 'string' || !item.trim())) {\n throw new Error(`${label} must be an array of non-empty strings.`);\n }\n return value.map((item) => item.trim());\n}\n\nconst NPM_PACKAGE_NAME = /^(?:@[a-z0-9][a-z0-9._-]*\\/)?[a-z0-9][a-z0-9._-]*$/;\nconst EXACT_SEMVER = /^v?(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$/;\n\nfunction assertSafeRemoteUrl(value: unknown): string {\n const urlString = asString(value, 'Connector MCP endpoint');\n let url: URL;\n try {\n url = new URL(urlString);\n } catch {\n throw new Error('Connector MCP endpoint must be a valid URL.');\n }\n const hostname = url.hostname.toLowerCase().replace(/^\\[|\\]$/g, '');\n if (\n url.protocol !== 'https:' ||\n url.username ||\n url.password ||\n hostname === 'localhost' ||\n hostname.endsWith('.localhost') ||\n isIP(hostname)\n ) {\n throw new Error('Store connectors must use a public HTTPS MCP endpoint.');\n }\n return url.toString();\n}\n\nfunction readPermissions(value: unknown, isLocal: boolean): ConnectorPermissions {\n const permissions = asRecord(value, 'Connector permissions');\n if (permissions.localExec !== isLocal) {\n if (isLocal) throw new Error('Local Store connectors must explicitly allow local command execution.');\n throw new Error('Store connectors must explicitly deny local command execution.');\n }\n const filesystem = permissions.filesystem === undefined\n ? []\n : asStringArray(permissions.filesystem, 'Connector filesystem permissions');\n if (filesystem.length > 0) {\n throw new Error('Store connectors cannot request filesystem access.');\n }\n const networkDomains = asStringArray(permissions.networkDomains, 'Connector network domains');\n if (!isLocal && networkDomains.length === 0) {\n throw new Error('Store connectors must declare at least one network domain.');\n }\n return {\n ...(permissions.data === undefined ? {} : { data: asStringArray(permissions.data, 'Connector data permissions') }),\n networkDomains,\n localExec: isLocal,\n filesystem,\n };\n}\n\nfunction readPinnedLocalRuntime(runtime: JsonRecord, template: JsonRecord): { registry: 'npm'; name: string; version: string } | null {\n if (runtime.localPackage === undefined) return null;\n const localPackage = asRecord(runtime.localPackage, 'Connector localPackage');\n if (localPackage.registry !== 'npm') {\n throw new Error('Local Store connectors must use the npm registry.');\n }\n const name = asString(localPackage.name, 'Connector local package name');\n const version = asString(localPackage.version, 'Connector local package version');\n if (!NPM_PACKAGE_NAME.test(name) || !EXACT_SEMVER.test(version)) {\n throw new Error('Local Store connectors must use a valid exact npm package version.');\n }\n if (template.command !== 'npx' ||\n JSON.stringify(asStringArray(template.args, 'Connector local MCP arguments')) !== JSON.stringify(['--yes', `${name}@${version}`])) {\n throw new Error('Local Store connectors must use the pinned npx launch form.');\n }\n for (const field of ['url', 'env', 'cwd', 'workingDirectory', 'headers', 'transport']) {\n if (field in template) throw new Error('Local Store connectors cannot define additional MCP process fields.');\n }\n return { registry: 'npm', name, version };\n}\n\nfunction readConnectorManifest(\n value: unknown,\n packageName: string,\n version: string,\n sha256: string,\n): ConnectorDefinition {\n const manifest = asRecord(value, 'Connector manifest');\n if (asString(manifest.id, 'Connector id') !== packageName) {\n throw new Error('Connector manifest id does not match the store package name.');\n }\n const runtime = asRecord(manifest.runtime, 'Connector runtime');\n if (runtime.type !== 'mcp') {\n throw new Error('Store connectors must use the MCP runtime.');\n }\n const serverTemplate = asRecord(runtime.serverTemplate, 'Connector MCP serverTemplate');\n const localPackage = readPinnedLocalRuntime(runtime, serverTemplate);\n const transport = serverTemplate.transport;\n if (!localPackage && transport !== 'streamable-http' && transport !== 'sse') {\n throw new Error('Store connectors must use streamable-http or sse transport.');\n }\n const auth = asRecord(manifest.auth, 'Connector auth');\n const authMode = auth.mode;\n if (authMode !== 'none' && authMode !== 'apiKey' && authMode !== 'oauth') {\n throw new Error('Connector auth mode must be none, apiKey, or oauth.');\n }\n const category = asString(manifest.category, 'Connector category');\n if (!['code', 'docs', 'browser', 'data', 'automation', 'custom'].includes(category)) {\n throw new Error(`Unsupported connector category: ${category}`);\n }\n const capabilities = asStringArray(manifest.capabilities, 'Connector capabilities');\n const allowedCapabilities = new Set([\n 'tools', 'resources', 'prompts', 'context', 'events', 'auth.apiKey', 'auth.oauth',\n 'runtime.mcp.stdio', 'runtime.mcp.sse', 'runtime.mcp.streamableHttp',\n ]);\n if (capabilities.some((capability) => !allowedCapabilities.has(capability))) {\n throw new Error('Connector manifest contains an unsupported capability.');\n }\n const setup = manifest.setup === undefined ? {} : asRecord(manifest.setup, 'Connector setup');\n const permissions = readPermissions(manifest.permissions, Boolean(localPackage));\n const endpoint = localPackage ? undefined : assertSafeRemoteUrl(serverTemplate.url);\n const hostname = endpoint ? new URL(endpoint).hostname : undefined;\n if (hostname && permissions.networkDomains?.length && !permissions.networkDomains.includes(hostname)) {\n throw new Error('Connector network permissions must include the MCP endpoint host.');\n }\n\n return {\n id: packageName,\n version,\n displayName: asString(manifest.displayName, 'Connector displayName'),\n description: asString(manifest.description, 'Connector description'),\n category: category as ConnectorDefinition['category'],\n kind: 'mcp',\n source: 'store',\n capabilities: capabilities as ConnectorDefinition['capabilities'],\n ...(Array.isArray(manifest.tags) ? { tags: asStringArray(manifest.tags, 'Connector tags') } : {}),\n auth: { mode: authMode },\n setup: setup as ConnectorDefinition['setup'],\n runtime: {\n type: 'mcp',\n serverId: asString(runtime.serverId, 'Connector MCP serverId'),\n serverTemplate: localPackage ? serverTemplate : { ...serverTemplate, url: endpoint },\n ...(localPackage ? { localPackage } : {}),\n },\n permissions,\n provenance: { packageName, sha256 },\n };\n}\n\nfunction readConnectorManifestFromArchive(buffer: Buffer): unknown {\n let archive: AdmZip;\n try {\n archive = new AdmZip(buffer);\n } catch {\n throw new Error('Store connector artifact is not a valid zip archive.');\n }\n const entry = archive.getEntries().find((candidate) => {\n const path = candidate.entryName.replace(/\\\\/g, '/').replace(/^\\/+/, '');\n return !candidate.isDirectory && (path === 'xopc.connector.json' || path.endsWith('/xopc.connector.json'));\n });\n if (!entry) {\n throw new Error('Store connector artifact is missing xopc.connector.json.');\n }\n try {\n return JSON.parse(entry.getData().toString('utf8'));\n } catch {\n throw new Error('Store connector manifest is not valid JSON.');\n }\n}\n\nexport async function listStoreConnectors(config: Config, params: SkillsStoreListParams) {\n return listConnectorPackages(resolveSkillsStoreBaseUrl(config), params);\n}\n\nexport async function getStoreConnectorInstallPlan(\n config: Config,\n packageName: string,\n version?: string,\n): Promise<StoreConnectorInstallPlan> {\n const storeBaseUrl = resolveSkillsStoreBaseUrl(config);\n const detail = await fetchStoreConnectorPackageDetail(storeBaseUrl, packageName, version);\n const sha256 = detail.latestVersion.sha256;\n if (!sha256 || !/^[a-f0-9]{64}$/i.test(sha256)) {\n throw new Error('Store connector version is missing a valid SHA-256 checksum.');\n }\n const archive = await downloadConnectorStoreZipBuffer(storeBaseUrl, detail.latestVersion.downloadUrl);\n const actualSha256 = createHash('sha256').update(archive).digest('hex');\n if (actualSha256 !== sha256.toLowerCase()) {\n throw new Error('Store connector artifact checksum verification failed.');\n }\n const artifactManifest = readConnectorManifestFromArchive(archive);\n const definition = readConnectorManifest(\n artifactManifest,\n detail.name,\n detail.latestVersion.version,\n actualSha256,\n );\n const storeManifest = readConnectorManifest(\n detail.latestVersion.manifest,\n detail.name,\n detail.latestVersion.version,\n actualSha256,\n );\n if (JSON.stringify(definition.runtime) !== JSON.stringify(storeManifest.runtime)) {\n throw new Error('Store connector metadata does not match its verified artifact.');\n }\n return {\n packageName: detail.name,\n version: detail.latestVersion.version,\n permissions: definition.permissions ?? {},\n requiresRestart: false,\n requiresOAuth: definition.auth.mode === 'oauth',\n definition,\n };\n}\n\nexport async function installStoreConnector(\n config: Config,\n packageName: string,\n input: ConnectorInstallInput,\n version?: string,\n) {\n const plan = await getStoreConnectorInstallPlan(config, packageName, version);\n if (plan.requiresOAuth && plan.definition.id !== 'github') {\n throw new Error('OAuth installation for store connectors is not available yet. Use an API-key connector or the built-in GitHub connector.');\n }\n const instance = await installConnectorDefinition(config, plan.definition, input);\n return { instance, plan };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"store-connector.js","names":[],"sources":["../../../src/capabilities/store-connector.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { isIP } from 'node:net';\n\nimport AdmZip from 'adm-zip';\n\nimport type { Config } from '../config/schema.js';\nimport { installConnectorDefinition } from '../connectors/install.js';\nimport type {\n ConnectorDefinition,\n ConnectorInstallInput,\n ConnectorPermissions,\n} from '../connectors/types.js';\nimport {\n downloadConnectorStoreZipBuffer,\n fetchStoreConnectorPackageDetail,\n listConnectorPackages,\n resolveSkillsStoreBaseUrl,\n type SkillsStoreListParams,\n} from '../agent/skills/marketplace/adapters/store/store-api-client.js';\n\ntype JsonRecord = Record<string, unknown>;\n\nexport type StoreConnectorInstallPlan = {\n packageName: string;\n version: string;\n definition: ConnectorDefinition;\n permissions: ConnectorPermissions;\n requiresRestart: false;\n};\n\nfunction asRecord(value: unknown, label: string): JsonRecord {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error(`${label} must be an object.`);\n }\n return value as JsonRecord;\n}\n\nfunction asString(value: unknown, label: string): string {\n if (typeof value !== 'string' || !value.trim()) {\n throw new Error(`${label} must be a non-empty string.`);\n }\n return value.trim();\n}\n\nfunction asStringArray(value: unknown, label: string): string[] {\n if (!Array.isArray(value) || value.some((item) => typeof item !== 'string' || !item.trim())) {\n throw new Error(`${label} must be an array of non-empty strings.`);\n }\n return value.map((item) => item.trim());\n}\n\nconst NPM_PACKAGE_NAME = /^(?:@[a-z0-9][a-z0-9._-]*\\/)?[a-z0-9][a-z0-9._-]*$/;\nconst EXACT_SEMVER = /^v?(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$/;\n\nfunction assertSafeRemoteUrl(value: unknown): string {\n const urlString = asString(value, 'Connector MCP endpoint');\n let url: URL;\n try {\n url = new URL(urlString);\n } catch {\n throw new Error('Connector MCP endpoint must be a valid URL.');\n }\n const hostname = url.hostname.toLowerCase().replace(/^\\[|\\]$/g, '');\n if (\n url.protocol !== 'https:' ||\n url.username ||\n url.password ||\n hostname === 'localhost' ||\n hostname.endsWith('.localhost') ||\n isIP(hostname)\n ) {\n throw new Error('Store connectors must use a public HTTPS MCP endpoint.');\n }\n return url.toString();\n}\n\nfunction readPermissions(value: unknown, isLocal: boolean): ConnectorPermissions {\n const permissions = asRecord(value, 'Connector permissions');\n if (permissions.localExec !== isLocal) {\n if (isLocal) throw new Error('Local Store connectors must explicitly allow local command execution.');\n throw new Error('Store connectors must explicitly deny local command execution.');\n }\n const filesystem = permissions.filesystem === undefined\n ? []\n : asStringArray(permissions.filesystem, 'Connector filesystem permissions');\n if (filesystem.length > 0) {\n throw new Error('Store connectors cannot request filesystem access.');\n }\n const networkDomains = asStringArray(permissions.networkDomains, 'Connector network domains');\n if (!isLocal && networkDomains.length === 0) {\n throw new Error('Store connectors must declare at least one network domain.');\n }\n return {\n ...(permissions.data === undefined ? {} : { data: asStringArray(permissions.data, 'Connector data permissions') }),\n networkDomains,\n localExec: isLocal,\n filesystem,\n };\n}\n\nfunction readPinnedLocalRuntime(runtime: JsonRecord, template: JsonRecord): { registry: 'npm'; name: string; version: string } | null {\n if (runtime.localPackage === undefined) return null;\n const localPackage = asRecord(runtime.localPackage, 'Connector localPackage');\n if (localPackage.registry !== 'npm') {\n throw new Error('Local Store connectors must use the npm registry.');\n }\n const name = asString(localPackage.name, 'Connector local package name');\n const version = asString(localPackage.version, 'Connector local package version');\n if (!NPM_PACKAGE_NAME.test(name) || !EXACT_SEMVER.test(version)) {\n throw new Error('Local Store connectors must use a valid exact npm package version.');\n }\n if (template.command !== 'npx' ||\n JSON.stringify(asStringArray(template.args, 'Connector local MCP arguments')) !== JSON.stringify(['--yes', `${name}@${version}`])) {\n throw new Error('Local Store connectors must use the pinned npx launch form.');\n }\n for (const field of ['url', 'env', 'cwd', 'workingDirectory', 'headers', 'transport']) {\n if (field in template) throw new Error('Local Store connectors cannot define additional MCP process fields.');\n }\n return { registry: 'npm', name, version };\n}\n\nfunction readConnectorManifest(\n value: unknown,\n packageName: string,\n version: string,\n sha256: string,\n): ConnectorDefinition {\n const manifest = asRecord(value, 'Connector manifest');\n if (asString(manifest.id, 'Connector id') !== packageName) {\n throw new Error('Connector manifest id does not match the store package name.');\n }\n const runtime = asRecord(manifest.runtime, 'Connector runtime');\n if (runtime.type !== 'mcp') {\n throw new Error('Store connectors must use the MCP runtime.');\n }\n const serverTemplate = asRecord(runtime.serverTemplate, 'Connector MCP serverTemplate');\n const localPackage = readPinnedLocalRuntime(runtime, serverTemplate);\n const transport = serverTemplate.transport;\n if (!localPackage && transport !== 'streamable-http' && transport !== 'sse') {\n throw new Error('Store connectors must use streamable-http or sse transport.');\n }\n const auth = asRecord(manifest.auth, 'Connector auth');\n const authMode = auth.mode;\n if (authMode !== 'none' && authMode !== 'apiKey') {\n throw new Error('Store connectors support only none or apiKey authentication.');\n }\n const normalizedAuth: ConnectorDefinition['auth'] = { mode: authMode };\n const category = asString(manifest.category, 'Connector category');\n if (!['code', 'docs', 'browser', 'data', 'automation', 'custom'].includes(category)) {\n throw new Error(`Unsupported connector category: ${category}`);\n }\n const capabilities = asStringArray(manifest.capabilities, 'Connector capabilities');\n const allowedCapabilities = new Set([\n 'tools', 'resources', 'prompts', 'context', 'events', 'auth.apiKey',\n 'runtime.mcp.stdio', 'runtime.mcp.sse', 'runtime.mcp.streamableHttp',\n ]);\n if (capabilities.some((capability) => !allowedCapabilities.has(capability))) {\n throw new Error('Connector manifest contains an unsupported capability.');\n }\n const setup = manifest.setup === undefined ? {} : asRecord(manifest.setup, 'Connector setup');\n const permissions = readPermissions(manifest.permissions, Boolean(localPackage));\n const endpoint = localPackage ? undefined : assertSafeRemoteUrl(serverTemplate.url);\n const hostname = endpoint ? new URL(endpoint).hostname : undefined;\n if (hostname && permissions.networkDomains?.length && !permissions.networkDomains.includes(hostname)) {\n throw new Error('Connector network permissions must include the MCP endpoint host.');\n }\n\n return {\n id: packageName,\n version,\n displayName: asString(manifest.displayName, 'Connector displayName'),\n description: asString(manifest.description, 'Connector description'),\n category: category as ConnectorDefinition['category'],\n kind: 'mcp',\n source: 'store',\n capabilities: capabilities as ConnectorDefinition['capabilities'],\n ...(Array.isArray(manifest.tags) ? { tags: asStringArray(manifest.tags, 'Connector tags') } : {}),\n auth: normalizedAuth,\n setup: setup as ConnectorDefinition['setup'],\n runtime: {\n type: 'mcp',\n serverId: asString(runtime.serverId, 'Connector MCP serverId'),\n serverTemplate: localPackage ? serverTemplate : { ...serverTemplate, url: endpoint },\n ...(localPackage ? { localPackage } : {}),\n },\n permissions,\n provenance: { packageName, sha256 },\n };\n}\n\nfunction readConnectorManifestFromArchive(buffer: Buffer): unknown {\n let archive: AdmZip;\n try {\n archive = new AdmZip(buffer);\n } catch {\n throw new Error('Store connector artifact is not a valid zip archive.');\n }\n const entry = archive.getEntries().find((candidate) => {\n const path = candidate.entryName.replace(/\\\\/g, '/').replace(/^\\/+/, '');\n return !candidate.isDirectory && (path === 'xopc.connector.json' || path.endsWith('/xopc.connector.json'));\n });\n if (!entry) {\n throw new Error('Store connector artifact is missing xopc.connector.json.');\n }\n try {\n return JSON.parse(entry.getData().toString('utf8'));\n } catch {\n throw new Error('Store connector manifest is not valid JSON.');\n }\n}\n\nexport async function listStoreConnectors(config: Config, params: SkillsStoreListParams) {\n return listConnectorPackages(resolveSkillsStoreBaseUrl(config), params);\n}\n\nexport async function getStoreConnectorInstallPlan(\n config: Config,\n packageName: string,\n version?: string,\n): Promise<StoreConnectorInstallPlan> {\n const storeBaseUrl = resolveSkillsStoreBaseUrl(config);\n const detail = await fetchStoreConnectorPackageDetail(storeBaseUrl, packageName, version);\n const sha256 = detail.latestVersion.sha256;\n if (!sha256 || !/^[a-f0-9]{64}$/i.test(sha256)) {\n throw new Error('Store connector version is missing a valid SHA-256 checksum.');\n }\n const archive = await downloadConnectorStoreZipBuffer(storeBaseUrl, detail.latestVersion.downloadUrl);\n const actualSha256 = createHash('sha256').update(archive).digest('hex');\n if (actualSha256 !== sha256.toLowerCase()) {\n throw new Error('Store connector artifact checksum verification failed.');\n }\n const artifactManifest = readConnectorManifestFromArchive(archive);\n const definition = readConnectorManifest(\n artifactManifest,\n detail.name,\n detail.latestVersion.version,\n actualSha256,\n );\n const storeManifest = readConnectorManifest(\n detail.latestVersion.manifest,\n detail.name,\n detail.latestVersion.version,\n actualSha256,\n );\n if (JSON.stringify(definition.runtime) !== JSON.stringify(storeManifest.runtime)) {\n throw new Error('Store connector metadata does not match its verified artifact.');\n }\n return {\n packageName: detail.name,\n version: detail.latestVersion.version,\n permissions: definition.permissions ?? {},\n requiresRestart: false,\n definition,\n };\n}\n\nexport async function installStoreConnector(\n config: Config,\n packageName: string,\n input: ConnectorInstallInput,\n version?: string,\n) {\n const plan = await getStoreConnectorInstallPlan(config, packageName, version);\n const instance = await installConnectorDefinition(config, plan.definition, input);\n return { instance, plan };\n}\n"],"mappings":"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"}
|
|
@@ -8,42 +8,62 @@ import { randomUUID } from "node:crypto";
|
|
|
8
8
|
//#region src/chat-commands/builtins/review.ts
|
|
9
9
|
const MAX_DIFF_CHARS = 6e4;
|
|
10
10
|
const REVIEW_JUDGE_MAX_TOKENS = 16384;
|
|
11
|
-
async function
|
|
11
|
+
async function emitReviewStart(ctx, reviewId, target, stage) {
|
|
12
12
|
await ctx.emitEvent?.({
|
|
13
|
-
type: "
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
type: "review_start",
|
|
14
|
+
reviewId,
|
|
15
|
+
target,
|
|
16
|
+
stage
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
|
-
async function
|
|
19
|
+
async function emitReviewEnd(ctx, reviewId, status, message) {
|
|
20
20
|
await ctx.emitEvent?.({
|
|
21
|
-
type: "
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
result: {
|
|
26
|
-
content: [{
|
|
27
|
-
type: "text",
|
|
28
|
-
text: resultText
|
|
29
|
-
}],
|
|
30
|
-
...details ? { details } : {}
|
|
31
|
-
}
|
|
21
|
+
type: "review_end",
|
|
22
|
+
reviewId,
|
|
23
|
+
status,
|
|
24
|
+
...message ? { message } : {}
|
|
32
25
|
});
|
|
33
26
|
}
|
|
34
|
-
async function
|
|
27
|
+
async function emitReviewDelta(ctx, reviewId, delta) {
|
|
35
28
|
if (!delta) return;
|
|
36
29
|
await ctx.emitEvent?.({
|
|
37
|
-
type: "
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
args: {},
|
|
41
|
-
partialResult: { content: [{
|
|
42
|
-
type: "text",
|
|
43
|
-
text: delta
|
|
44
|
-
}] }
|
|
30
|
+
type: "review_delta",
|
|
31
|
+
reviewId,
|
|
32
|
+
delta
|
|
45
33
|
});
|
|
46
34
|
}
|
|
35
|
+
function createReviewProgressExtractor() {
|
|
36
|
+
const open = "<review_progress>";
|
|
37
|
+
const close = "</review_progress>";
|
|
38
|
+
let buffer = "";
|
|
39
|
+
let inside = false;
|
|
40
|
+
return (delta) => {
|
|
41
|
+
buffer += delta;
|
|
42
|
+
let visible = "";
|
|
43
|
+
while (buffer) {
|
|
44
|
+
if (!inside) {
|
|
45
|
+
const start = buffer.indexOf(open);
|
|
46
|
+
if (start < 0) {
|
|
47
|
+
buffer = buffer.slice(-Math.max(0, 16));
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
buffer = buffer.slice(start + 17);
|
|
51
|
+
inside = true;
|
|
52
|
+
}
|
|
53
|
+
const end = buffer.indexOf(close);
|
|
54
|
+
if (end < 0) {
|
|
55
|
+
const safeLength = Math.max(0, buffer.length - 17);
|
|
56
|
+
visible += buffer.slice(0, safeLength);
|
|
57
|
+
buffer = buffer.slice(safeLength);
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
visible += buffer.slice(0, end);
|
|
61
|
+
buffer = buffer.slice(end + 18);
|
|
62
|
+
inside = false;
|
|
63
|
+
}
|
|
64
|
+
return visible;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
47
67
|
function truncateForPrompt(text) {
|
|
48
68
|
if (text.length <= MAX_DIFF_CHARS) return {
|
|
49
69
|
text,
|
|
@@ -111,10 +131,6 @@ function parseReviewJson(raw, target) {
|
|
|
111
131
|
source: "model"
|
|
112
132
|
};
|
|
113
133
|
}
|
|
114
|
-
function previewText(text, max = 500) {
|
|
115
|
-
const trimmed = text.trim();
|
|
116
|
-
return trimmed.length > max ? `${trimmed.slice(0, max)}…` : trimmed;
|
|
117
|
-
}
|
|
118
134
|
async function reviewModelRef(ctx) {
|
|
119
135
|
const sessionOverride = await ctx.getSessionConfigStore?.()?.get(ctx.sessionKey).then((config) => config?.modelOverride?.trim()).catch(() => void 0);
|
|
120
136
|
if (sessionOverride) return sessionOverride;
|
|
@@ -130,7 +146,9 @@ function buildReviewPrompt(params) {
|
|
|
130
146
|
"You are a senior code reviewer. Review the provided git diff for correctness bugs only.",
|
|
131
147
|
"Prioritize concrete regressions, broken behavior, missing required tests for changed behavior, data loss, security issues, and runtime/type errors.",
|
|
132
148
|
"Do not mention style, broad refactors, praise, or speculative improvements.",
|
|
133
|
-
"Return
|
|
149
|
+
"Return exactly two XML-delimited sections and nothing else.",
|
|
150
|
+
"First write a concise, user-facing Markdown review draft inside <review_progress>...</review_progress>. State the scope and concrete evidence only; do not reveal hidden chain-of-thought.",
|
|
151
|
+
"Then put strict JSON inside <review_result>...</review_result> using this shape:",
|
|
134
152
|
"{\"findings\":[{\"title\":\"...\",\"body\":\"...\",\"priority\":1,\"confidence_score\":0.9,\"code_location\":{\"file_path\":\"path\",\"line_range\":{\"start\":12,\"end\":12}}}],\"overall_correctness\":\"patch is correct\",\"overall_explanation\":\"...\",\"overall_confidence_score\":0.8,\"summary\":\"...\"}",
|
|
135
153
|
"Use priority 0 for release-blocking, 1 for high, 2 for medium, 3 for low.",
|
|
136
154
|
params.instructions ? `Extra reviewer instructions: ${params.instructions}` : "",
|
|
@@ -152,36 +170,33 @@ async function resolveWorkspace(ctx) {
|
|
|
152
170
|
async function buildReview(ctx, args) {
|
|
153
171
|
const cwd = await resolveGitRoot(await resolveWorkspace(ctx));
|
|
154
172
|
const reviewTarget = parseReviewTargetArgs(args);
|
|
155
|
-
const
|
|
156
|
-
await
|
|
157
|
-
target: args.trim() || "uncommitted",
|
|
158
|
-
cwd
|
|
159
|
-
});
|
|
173
|
+
const reviewId = `review_${randomUUID()}`;
|
|
174
|
+
await emitReviewStart(ctx, reviewId, args.trim() || "current workspace changes", "preparing");
|
|
160
175
|
let bundle;
|
|
161
176
|
try {
|
|
162
177
|
bundle = await buildReviewDiffBundle(cwd, reviewTarget);
|
|
163
|
-
await emitToolEnd(ctx, prepareToolCallId, "review.prepare_diff", [`Target: ${bundle.targetLabel}`, bundle.stat.trim() ? `Changed files:\n${bundle.stat.trim()}` : "No diff stat."].join("\n\n"), {
|
|
164
|
-
target: bundle.targetLabel,
|
|
165
|
-
status: bundle.status,
|
|
166
|
-
stat: bundle.stat
|
|
167
|
-
});
|
|
168
178
|
} catch (err) {
|
|
169
|
-
await
|
|
179
|
+
await emitReviewEnd(ctx, reviewId, "error", err instanceof Error ? err.message : String(err));
|
|
170
180
|
throw err;
|
|
171
181
|
}
|
|
172
182
|
const { text: diff, truncated } = truncateForPrompt(bundle.diff);
|
|
173
183
|
const target = bundle.targetLabel;
|
|
174
184
|
const instructions = reviewTarget.instructions ?? "";
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
+
await emitReviewStart(ctx, reviewId, target, "preparing");
|
|
186
|
+
if (!bundle.status.trim() && !bundle.diff.trim()) {
|
|
187
|
+
const review = {
|
|
188
|
+
type: "review",
|
|
189
|
+
target,
|
|
190
|
+
summary: "Working tree is clean.",
|
|
191
|
+
findings: [],
|
|
192
|
+
overallCorrectness: "patch is correct",
|
|
193
|
+
overallExplanation: "No uncommitted changes were found to review.",
|
|
194
|
+
generatedAt: Date.now(),
|
|
195
|
+
source: "local"
|
|
196
|
+
};
|
|
197
|
+
await emitReviewEnd(ctx, reviewId, "complete");
|
|
198
|
+
return review;
|
|
199
|
+
}
|
|
185
200
|
const prompt = buildReviewPrompt({
|
|
186
201
|
target,
|
|
187
202
|
status: bundle.status,
|
|
@@ -191,17 +206,12 @@ async function buildReview(ctx, args) {
|
|
|
191
206
|
instructions
|
|
192
207
|
});
|
|
193
208
|
const reviewerModelRef = await reviewModelRef(ctx);
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
target,
|
|
197
|
-
diffChars: diff.length,
|
|
198
|
-
truncated,
|
|
199
|
-
...reviewerModelRef ? { modelRef: reviewerModelRef } : {}
|
|
200
|
-
});
|
|
209
|
+
await emitReviewStart(ctx, reviewId, target, "reviewing");
|
|
210
|
+
const extractReviewProgress = createReviewProgressExtractor();
|
|
201
211
|
const answer = ctx.btwQuery ? await ctx.btwQuery(prompt, {
|
|
202
212
|
maxTokens: REVIEW_JUDGE_MAX_TOKENS,
|
|
203
213
|
includeSessionContext: false,
|
|
204
|
-
onTextDelta: (delta) =>
|
|
214
|
+
onTextDelta: (delta) => emitReviewDelta(ctx, reviewId, extractReviewProgress(delta)),
|
|
205
215
|
...reviewerModelRef ? { modelRef: reviewerModelRef } : {}
|
|
206
216
|
}) : {
|
|
207
217
|
text: "",
|
|
@@ -210,11 +220,7 @@ async function buildReview(ctx, args) {
|
|
|
210
220
|
let judgeFailure = answer.error ? { reason: `Reviewer model error: ${answer.error}` } : answer.text ? void 0 : { reason: "Reviewer model returned no text." };
|
|
211
221
|
if (answer?.text && !answer.error) try {
|
|
212
222
|
const parsed = parseReviewJson(answer.text, target);
|
|
213
|
-
await
|
|
214
|
-
target,
|
|
215
|
-
findings: parsed.findings.length,
|
|
216
|
-
overallCorrectness: parsed.overallCorrectness
|
|
217
|
-
});
|
|
223
|
+
await emitReviewEnd(ctx, reviewId, "complete");
|
|
218
224
|
return parsed;
|
|
219
225
|
} catch (err) {
|
|
220
226
|
judgeFailure = { reason: `Reviewer model output could not be parsed: ${err instanceof Error ? err.message : String(err)}` };
|
|
@@ -230,14 +236,7 @@ async function buildReview(ctx, args) {
|
|
|
230
236
|
generatedAt: Date.now(),
|
|
231
237
|
source: "local"
|
|
232
238
|
};
|
|
233
|
-
await
|
|
234
|
-
target,
|
|
235
|
-
findings: 0,
|
|
236
|
-
overallCorrectness: fallback.overallCorrectness,
|
|
237
|
-
fallback: true,
|
|
238
|
-
reason,
|
|
239
|
-
...answer.text ? { responsePreview: previewText(answer.text) } : {}
|
|
240
|
-
}, true);
|
|
239
|
+
await emitReviewEnd(ctx, reviewId, "error", reason);
|
|
241
240
|
return fallback;
|
|
242
241
|
}
|
|
243
242
|
const reviewCommand = {
|