@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review.js","names":[],"sources":["../../../../src/chat-commands/builtins/review.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport type { CommandDefinition, CommandContext } from '../types.js';\nimport { commandRegistry } from '../registry.js';\nimport { effectiveWorkspacePathForSession } from '../../session/session-workspace.js';\nimport { resolveEffectiveAgentProfileForSession } from '../../config/agent-profile.js';\nimport { getProjectForSession } from '../../projects/workspace.js';\nimport {\n buildReviewDiffBundle,\n parseReviewTargetArgs,\n resolveGitRoot,\n} from '../../review/review-git.js';\nimport {\n formatReviewMarkdown,\n type ReviewFinding,\n type ReviewOutput,\n type ReviewPriority,\n} from '../../review/review-types.js';\n\nconst MAX_DIFF_CHARS = 60_000;\nconst REVIEW_JUDGE_MAX_TOKENS = 16_384;\n\nasync function emitToolStart(\n ctx: CommandContext,\n toolCallId: string,\n toolName: string,\n args: Record<string, unknown>,\n): Promise<void> {\n await ctx.emitEvent?.({\n type: 'tool_execution_start',\n toolCallId,\n toolName,\n args,\n });\n}\n\nasync function emitToolEnd(\n ctx: CommandContext,\n toolCallId: string,\n toolName: string,\n resultText: string,\n details?: Record<string, unknown>,\n isError = false,\n): Promise<void> {\n await ctx.emitEvent?.({\n type: 'tool_execution_end',\n toolCallId,\n toolName,\n isError,\n result: {\n content: [{ type: 'text', text: resultText }],\n ...(details ? { details } : {}),\n },\n });\n}\n\nasync function emitToolTextDelta(\n ctx: CommandContext,\n toolCallId: string,\n toolName: string,\n delta: string,\n): Promise<void> {\n if (!delta) return;\n await ctx.emitEvent?.({\n type: 'tool_execution_update',\n toolCallId,\n toolName,\n args: {},\n partialResult: {\n content: [{ type: 'text', text: delta }],\n },\n });\n}\n\nfunction truncateForPrompt(text: string): { text: string; truncated: boolean } {\n if (text.length <= MAX_DIFF_CHARS) return { text, truncated: false };\n return {\n text: text.slice(0, MAX_DIFF_CHARS) + '\\n\\n[diff truncated]',\n truncated: true,\n };\n}\n\nfunction extractJsonObject(raw: string): unknown {\n const fenced = raw.match(/```(?:json)?\\s*([\\s\\S]*?)```/i);\n const text = (fenced?.[1] ?? raw).trim();\n const start = text.indexOf('{');\n const end = text.lastIndexOf('}');\n if (start < 0 || end <= start) throw new Error('review response did not contain JSON');\n return JSON.parse(text.slice(start, end + 1));\n}\n\nfunction priorityFrom(raw: unknown): ReviewPriority {\n const n = typeof raw === 'number' ? raw : Number.parseInt(String(raw ?? ''), 10);\n if (n === 0 || n === 1 || n === 2 || n === 3) return n;\n return 2;\n}\n\nfunction numberFrom(raw: unknown): number | undefined {\n return typeof raw === 'number' && Number.isFinite(raw) ? raw : undefined;\n}\n\nfunction stringFrom(raw: unknown): string {\n return typeof raw === 'string' ? raw.trim() : '';\n}\n\nfunction parseReviewJson(raw: string, target: string): ReviewOutput {\n const parsed = extractJsonObject(raw);\n const rec = parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? parsed as Record<string, unknown>\n : {};\n const rawFindings = Array.isArray(rec.findings) ? rec.findings : [];\n const findings: ReviewFinding[] = rawFindings\n .map((item) => {\n const f = item && typeof item === 'object' && !Array.isArray(item)\n ? item as Record<string, unknown>\n : {};\n const loc = f.code_location && typeof f.code_location === 'object'\n ? f.code_location as Record<string, unknown>\n : {};\n const range = loc.line_range && typeof loc.line_range === 'object'\n ? loc.line_range as Record<string, unknown>\n : {};\n const title = stringFrom(f.title);\n const body = stringFrom(f.body);\n if (!title && !body) return undefined;\n const finding: ReviewFinding = {\n title: title || body.slice(0, 80),\n body,\n priority: priorityFrom(f.priority),\n };\n const confidenceScore = numberFrom(f.confidence_score ?? f.confidenceScore);\n const filePath = stringFrom(loc.file_path ?? f.filePath);\n const lineStart = numberFrom(range.start ?? f.lineStart);\n const lineEnd = numberFrom(range.end ?? f.lineEnd);\n if (confidenceScore !== undefined) finding.confidenceScore = confidenceScore;\n if (filePath) finding.filePath = filePath;\n if (lineStart !== undefined) finding.lineStart = lineStart;\n if (lineEnd !== undefined) finding.lineEnd = lineEnd;\n return finding;\n })\n .filter((item): item is ReviewFinding => Boolean(item));\n\n const correctness = stringFrom(rec.overall_correctness ?? rec.overallCorrectness);\n const overallCorrectness =\n correctness === 'patch is correct' || correctness === 'patch is incorrect'\n ? correctness\n : 'unknown';\n return {\n type: 'review',\n target,\n summary: stringFrom(rec.summary) || `${findings.length} finding${findings.length === 1 ? '' : 's'}`,\n findings,\n overallCorrectness,\n overallExplanation: stringFrom(rec.overall_explanation ?? rec.overallExplanation),\n overallConfidenceScore: numberFrom(rec.overall_confidence_score ?? rec.overallConfidenceScore),\n generatedAt: Date.now(),\n source: 'model',\n };\n}\n\nfunction previewText(text: string, max = 500): string {\n const trimmed = text.trim();\n return trimmed.length > max ? `${trimmed.slice(0, max)}…` : trimmed;\n}\n\nasync function reviewModelRef(ctx: CommandContext): Promise<string | undefined> {\n const sessionOverride = await ctx.getSessionConfigStore?.()\n ?.get(ctx.sessionKey)\n .then((config) => config?.modelOverride?.trim())\n .catch(() => undefined);\n if (sessionOverride) return sessionOverride;\n\n try {\n const profile = resolveEffectiveAgentProfileForSession(ctx.config, ctx.sessionKey);\n return profile.manifest.models.roles.review?.model?.trim() || profile.primaryModelRef;\n } catch {\n return undefined;\n }\n}\n\nfunction buildReviewPrompt(params: {\n target: string;\n status: string;\n stat: string;\n diff: string;\n truncated: boolean;\n instructions: string;\n}): string {\n return [\n 'You are a senior code reviewer. Review the provided git diff for correctness bugs only.',\n 'Prioritize concrete regressions, broken behavior, missing required tests for changed behavior, data loss, security issues, and runtime/type errors.',\n 'Do not mention style, broad refactors, praise, or speculative improvements.',\n 'Return strict JSON only with this shape:',\n '{\"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\":\"...\"}',\n 'Use priority 0 for release-blocking, 1 for high, 2 for medium, 3 for low.',\n params.instructions ? `Extra reviewer instructions: ${params.instructions}` : '',\n `Target: ${params.target}`,\n params.truncated ? 'The diff was truncated; only report findings supported by visible lines.' : '',\n 'Git status:',\n params.status || '(clean)',\n 'Diff stat:',\n params.stat || '(none)',\n 'Diff:',\n params.diff || '(none)',\n ].filter(Boolean).join('\\n\\n');\n}\n\nasync function resolveWorkspace(ctx: CommandContext): Promise<string> {\n const sessionConfigStore = ctx.getSessionConfigStore?.();\n const sessionConfig = sessionConfigStore\n ? await sessionConfigStore.get(ctx.sessionKey).catch(() => null)\n : null;\n return effectiveWorkspacePathForSession(\n ctx.config,\n ctx.sessionKey,\n sessionConfig,\n getProjectForSession(ctx.sessionKey),\n );\n}\n\nasync function buildReview(ctx: CommandContext, args: string): Promise<ReviewOutput> {\n const workspace = await resolveWorkspace(ctx);\n const cwd = await resolveGitRoot(workspace);\n const reviewTarget = parseReviewTargetArgs(args);\n const prepareToolCallId = `review_prepare_${randomUUID()}`;\n await emitToolStart(ctx, prepareToolCallId, 'review.prepare_diff', {\n target: args.trim() || 'uncommitted',\n cwd,\n });\n let bundle: Awaited<ReturnType<typeof buildReviewDiffBundle>>;\n try {\n bundle = await buildReviewDiffBundle(cwd, reviewTarget);\n await emitToolEnd(\n ctx,\n prepareToolCallId,\n 'review.prepare_diff',\n [\n `Target: ${bundle.targetLabel}`,\n bundle.stat.trim() ? `Changed files:\\n${bundle.stat.trim()}` : 'No diff stat.',\n ].join('\\n\\n'),\n {\n target: bundle.targetLabel,\n status: bundle.status,\n stat: bundle.stat,\n },\n );\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n await emitToolEnd(ctx, prepareToolCallId, 'review.prepare_diff', em, { cwd }, true);\n throw err;\n }\n const { text: diff, truncated } = truncateForPrompt(bundle.diff);\n const target = bundle.targetLabel;\n const instructions = reviewTarget.instructions ?? '';\n\n if (!bundle.status.trim() && !bundle.diff.trim()) {\n return {\n type: 'review',\n target,\n summary: 'Working tree is clean.',\n findings: [],\n overallCorrectness: 'patch is correct',\n overallExplanation: 'No uncommitted changes were found to review.',\n generatedAt: Date.now(),\n source: 'local',\n };\n }\n\n const prompt = buildReviewPrompt({\n target,\n status: bundle.status,\n stat: bundle.stat,\n diff,\n truncated,\n instructions,\n });\n const reviewerModelRef = await reviewModelRef(ctx);\n const judgeToolCallId = `review_judge_${randomUUID()}`;\n await emitToolStart(ctx, judgeToolCallId, 'review.model_judge', {\n target,\n diffChars: diff.length,\n truncated,\n ...(reviewerModelRef ? { modelRef: reviewerModelRef } : {}),\n });\n const answer = ctx.btwQuery\n ? await ctx.btwQuery(prompt, {\n maxTokens: REVIEW_JUDGE_MAX_TOKENS,\n includeSessionContext: false,\n onTextDelta: (delta) => emitToolTextDelta(ctx, judgeToolCallId, 'review.model_judge', delta),\n ...(reviewerModelRef ? { modelRef: reviewerModelRef } : {}),\n })\n : { text: '', error: 'Review model query is not available in this command context.' };\n let judgeFailure = answer.error\n ? { reason: `Reviewer model error: ${answer.error}` }\n : answer.text\n ? undefined\n : { reason: 'Reviewer model returned no text.' };\n if (answer?.text && !answer.error) {\n try {\n const parsed = parseReviewJson(answer.text, target);\n await emitToolEnd(\n ctx,\n judgeToolCallId,\n 'review.model_judge',\n parsed.summary || `${parsed.findings.length} findings`,\n {\n target,\n findings: parsed.findings.length,\n overallCorrectness: parsed.overallCorrectness,\n },\n );\n return parsed;\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n judgeFailure = {\n reason: `Reviewer model output could not be parsed: ${em}`,\n };\n }\n }\n\n const reason = judgeFailure?.reason ?? 'Reviewer model output could not be parsed.';\n const fallback: ReviewOutput = {\n type: 'review',\n target,\n summary: 'Review model did not complete; returned a local diff summary.',\n findings: [],\n overallCorrectness: 'unknown',\n overallExplanation: [\n reason,\n bundle.stat.trim() ? `Changed files:\\n${bundle.stat.trim()}` : 'No textual diff stat was available.',\n ].join('\\n\\n'),\n generatedAt: Date.now(),\n source: 'local',\n };\n await emitToolEnd(\n ctx,\n judgeToolCallId,\n 'review.model_judge',\n fallback.summary,\n {\n target,\n findings: 0,\n overallCorrectness: fallback.overallCorrectness,\n fallback: true,\n reason,\n ...(answer.text ? { responsePreview: previewText(answer.text) } : {}),\n },\n true,\n );\n return fallback;\n}\n\nconst reviewCommand: CommandDefinition = {\n id: 'coding.review',\n name: 'review',\n description: 'Review current workspace changes for correctness issues',\n category: 'tool',\n scope: ['global', 'private', 'group'],\n acceptsArgs: true,\n examples: ['/review', '/review focus on auth and persistence'],\n handler: async (ctx: CommandContext, args: string) => {\n await ctx.setTyping(true);\n const review = await buildReview(ctx, args);\n return {\n content: formatReviewMarkdown(review),\n success: true,\n metadata: { review },\n };\n },\n};\n\nexport function registerReviewCommand(): void {\n commandRegistry.register(reviewCommand);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"review.js","names":[],"sources":["../../../../src/chat-commands/builtins/review.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport type { CommandDefinition, CommandContext } from '../types.js';\nimport { commandRegistry } from '../registry.js';\nimport { effectiveWorkspacePathForSession } from '../../session/session-workspace.js';\nimport { resolveEffectiveAgentProfileForSession } from '../../config/agent-profile.js';\nimport { getProjectForSession } from '../../projects/workspace.js';\nimport {\n buildReviewDiffBundle,\n parseReviewTargetArgs,\n resolveGitRoot,\n} from '../../review/review-git.js';\nimport {\n formatReviewMarkdown,\n type ReviewFinding,\n type ReviewOutput,\n type ReviewPriority,\n} from '../../review/review-types.js';\n\nconst MAX_DIFF_CHARS = 60_000;\nconst REVIEW_JUDGE_MAX_TOKENS = 16_384;\n\nasync function emitReviewStart(\n ctx: CommandContext,\n reviewId: string,\n target: string,\n stage: 'preparing' | 'reviewing',\n): Promise<void> {\n await ctx.emitEvent?.({\n type: 'review_start',\n reviewId,\n target,\n stage,\n });\n}\n\nasync function emitReviewEnd(\n ctx: CommandContext,\n reviewId: string,\n status: 'complete' | 'error',\n message?: string,\n): Promise<void> {\n await ctx.emitEvent?.({\n type: 'review_end',\n reviewId,\n status,\n ...(message ? { message } : {}),\n });\n}\n\nasync function emitReviewDelta(\n ctx: CommandContext,\n reviewId: string,\n delta: string,\n): Promise<void> {\n if (!delta) return;\n await ctx.emitEvent?.({\n type: 'review_delta',\n reviewId,\n delta,\n });\n}\n\nfunction createReviewProgressExtractor(): (delta: string) => string {\n const open = '<review_progress>';\n const close = '</review_progress>';\n let buffer = '';\n let inside = false;\n\n return (delta) => {\n buffer += delta;\n let visible = '';\n\n while (buffer) {\n if (!inside) {\n const start = buffer.indexOf(open);\n if (start < 0) {\n buffer = buffer.slice(-Math.max(0, open.length - 1));\n break;\n }\n buffer = buffer.slice(start + open.length);\n inside = true;\n }\n\n const end = buffer.indexOf(close);\n if (end < 0) {\n const safeLength = Math.max(0, buffer.length - (close.length - 1));\n visible += buffer.slice(0, safeLength);\n buffer = buffer.slice(safeLength);\n break;\n }\n\n visible += buffer.slice(0, end);\n buffer = buffer.slice(end + close.length);\n inside = false;\n }\n\n return visible;\n };\n}\n\nfunction truncateForPrompt(text: string): { text: string; truncated: boolean } {\n if (text.length <= MAX_DIFF_CHARS) return { text, truncated: false };\n return {\n text: text.slice(0, MAX_DIFF_CHARS) + '\\n\\n[diff truncated]',\n truncated: true,\n };\n}\n\nfunction extractJsonObject(raw: string): unknown {\n const fenced = raw.match(/```(?:json)?\\s*([\\s\\S]*?)```/i);\n const text = (fenced?.[1] ?? raw).trim();\n const start = text.indexOf('{');\n const end = text.lastIndexOf('}');\n if (start < 0 || end <= start) throw new Error('review response did not contain JSON');\n return JSON.parse(text.slice(start, end + 1));\n}\n\nfunction priorityFrom(raw: unknown): ReviewPriority {\n const n = typeof raw === 'number' ? raw : Number.parseInt(String(raw ?? ''), 10);\n if (n === 0 || n === 1 || n === 2 || n === 3) return n;\n return 2;\n}\n\nfunction numberFrom(raw: unknown): number | undefined {\n return typeof raw === 'number' && Number.isFinite(raw) ? raw : undefined;\n}\n\nfunction stringFrom(raw: unknown): string {\n return typeof raw === 'string' ? raw.trim() : '';\n}\n\nfunction parseReviewJson(raw: string, target: string): ReviewOutput {\n const parsed = extractJsonObject(raw);\n const rec = parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? parsed as Record<string, unknown>\n : {};\n const rawFindings = Array.isArray(rec.findings) ? rec.findings : [];\n const findings: ReviewFinding[] = rawFindings\n .map((item) => {\n const f = item && typeof item === 'object' && !Array.isArray(item)\n ? item as Record<string, unknown>\n : {};\n const loc = f.code_location && typeof f.code_location === 'object'\n ? f.code_location as Record<string, unknown>\n : {};\n const range = loc.line_range && typeof loc.line_range === 'object'\n ? loc.line_range as Record<string, unknown>\n : {};\n const title = stringFrom(f.title);\n const body = stringFrom(f.body);\n if (!title && !body) return undefined;\n const finding: ReviewFinding = {\n title: title || body.slice(0, 80),\n body,\n priority: priorityFrom(f.priority),\n };\n const confidenceScore = numberFrom(f.confidence_score ?? f.confidenceScore);\n const filePath = stringFrom(loc.file_path ?? f.filePath);\n const lineStart = numberFrom(range.start ?? f.lineStart);\n const lineEnd = numberFrom(range.end ?? f.lineEnd);\n if (confidenceScore !== undefined) finding.confidenceScore = confidenceScore;\n if (filePath) finding.filePath = filePath;\n if (lineStart !== undefined) finding.lineStart = lineStart;\n if (lineEnd !== undefined) finding.lineEnd = lineEnd;\n return finding;\n })\n .filter((item): item is ReviewFinding => Boolean(item));\n\n const correctness = stringFrom(rec.overall_correctness ?? rec.overallCorrectness);\n const overallCorrectness =\n correctness === 'patch is correct' || correctness === 'patch is incorrect'\n ? correctness\n : 'unknown';\n return {\n type: 'review',\n target,\n summary: stringFrom(rec.summary) || `${findings.length} finding${findings.length === 1 ? '' : 's'}`,\n findings,\n overallCorrectness,\n overallExplanation: stringFrom(rec.overall_explanation ?? rec.overallExplanation),\n overallConfidenceScore: numberFrom(rec.overall_confidence_score ?? rec.overallConfidenceScore),\n generatedAt: Date.now(),\n source: 'model',\n };\n}\n\nasync function reviewModelRef(ctx: CommandContext): Promise<string | undefined> {\n const sessionOverride = await ctx.getSessionConfigStore?.()\n ?.get(ctx.sessionKey)\n .then((config) => config?.modelOverride?.trim())\n .catch(() => undefined);\n if (sessionOverride) return sessionOverride;\n\n try {\n const profile = resolveEffectiveAgentProfileForSession(ctx.config, ctx.sessionKey);\n return profile.manifest.models.roles.review?.model?.trim() || profile.primaryModelRef;\n } catch {\n return undefined;\n }\n}\n\nfunction buildReviewPrompt(params: {\n target: string;\n status: string;\n stat: string;\n diff: string;\n truncated: boolean;\n instructions: string;\n}): string {\n return [\n 'You are a senior code reviewer. Review the provided git diff for correctness bugs only.',\n 'Prioritize concrete regressions, broken behavior, missing required tests for changed behavior, data loss, security issues, and runtime/type errors.',\n 'Do not mention style, broad refactors, praise, or speculative improvements.',\n 'Return exactly two XML-delimited sections and nothing else.',\n '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.',\n 'Then put strict JSON inside <review_result>...</review_result> using this shape:',\n '{\"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\":\"...\"}',\n 'Use priority 0 for release-blocking, 1 for high, 2 for medium, 3 for low.',\n params.instructions ? `Extra reviewer instructions: ${params.instructions}` : '',\n `Target: ${params.target}`,\n params.truncated ? 'The diff was truncated; only report findings supported by visible lines.' : '',\n 'Git status:',\n params.status || '(clean)',\n 'Diff stat:',\n params.stat || '(none)',\n 'Diff:',\n params.diff || '(none)',\n ].filter(Boolean).join('\\n\\n');\n}\n\nasync function resolveWorkspace(ctx: CommandContext): Promise<string> {\n const sessionConfigStore = ctx.getSessionConfigStore?.();\n const sessionConfig = sessionConfigStore\n ? await sessionConfigStore.get(ctx.sessionKey).catch(() => null)\n : null;\n return effectiveWorkspacePathForSession(\n ctx.config,\n ctx.sessionKey,\n sessionConfig,\n getProjectForSession(ctx.sessionKey),\n );\n}\n\nasync function buildReview(ctx: CommandContext, args: string): Promise<ReviewOutput> {\n const workspace = await resolveWorkspace(ctx);\n const cwd = await resolveGitRoot(workspace);\n const reviewTarget = parseReviewTargetArgs(args);\n const reviewId = `review_${randomUUID()}`;\n await emitReviewStart(ctx, reviewId, args.trim() || 'current workspace changes', 'preparing');\n let bundle: Awaited<ReturnType<typeof buildReviewDiffBundle>>;\n try {\n bundle = await buildReviewDiffBundle(cwd, reviewTarget);\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n await emitReviewEnd(ctx, reviewId, 'error', em);\n throw err;\n }\n const { text: diff, truncated } = truncateForPrompt(bundle.diff);\n const target = bundle.targetLabel;\n const instructions = reviewTarget.instructions ?? '';\n await emitReviewStart(ctx, reviewId, target, 'preparing');\n\n if (!bundle.status.trim() && !bundle.diff.trim()) {\n const review: ReviewOutput = {\n type: 'review',\n target,\n summary: 'Working tree is clean.',\n findings: [],\n overallCorrectness: 'patch is correct',\n overallExplanation: 'No uncommitted changes were found to review.',\n generatedAt: Date.now(),\n source: 'local',\n };\n await emitReviewEnd(ctx, reviewId, 'complete');\n return review;\n }\n\n const prompt = buildReviewPrompt({\n target,\n status: bundle.status,\n stat: bundle.stat,\n diff,\n truncated,\n instructions,\n });\n const reviewerModelRef = await reviewModelRef(ctx);\n await emitReviewStart(ctx, reviewId, target, 'reviewing');\n const extractReviewProgress = createReviewProgressExtractor();\n const answer = ctx.btwQuery\n ? await ctx.btwQuery(prompt, {\n maxTokens: REVIEW_JUDGE_MAX_TOKENS,\n includeSessionContext: false,\n onTextDelta: (delta) => emitReviewDelta(ctx, reviewId, extractReviewProgress(delta)),\n ...(reviewerModelRef ? { modelRef: reviewerModelRef } : {}),\n })\n : { text: '', error: 'Review model query is not available in this command context.' };\n let judgeFailure = answer.error\n ? { reason: `Reviewer model error: ${answer.error}` }\n : answer.text\n ? undefined\n : { reason: 'Reviewer model returned no text.' };\n if (answer?.text && !answer.error) {\n try {\n const parsed = parseReviewJson(answer.text, target);\n await emitReviewEnd(ctx, reviewId, 'complete');\n return parsed;\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n judgeFailure = {\n reason: `Reviewer model output could not be parsed: ${em}`,\n };\n }\n }\n\n const reason = judgeFailure?.reason ?? 'Reviewer model output could not be parsed.';\n const fallback: ReviewOutput = {\n type: 'review',\n target,\n summary: 'Review model did not complete; returned a local diff summary.',\n findings: [],\n overallCorrectness: 'unknown',\n overallExplanation: [\n reason,\n bundle.stat.trim() ? `Changed files:\\n${bundle.stat.trim()}` : 'No textual diff stat was available.',\n ].join('\\n\\n'),\n generatedAt: Date.now(),\n source: 'local',\n };\n await emitReviewEnd(ctx, reviewId, 'error', reason);\n return fallback;\n}\n\nconst reviewCommand: CommandDefinition = {\n id: 'coding.review',\n name: 'review',\n description: 'Review current workspace changes for correctness issues',\n category: 'tool',\n scope: ['global', 'private', 'group'],\n acceptsArgs: true,\n examples: ['/review', '/review focus on auth and persistence'],\n handler: async (ctx: CommandContext, args: string) => {\n await ctx.setTyping(true);\n const review = await buildReview(ctx, args);\n return {\n content: formatReviewMarkdown(review),\n success: true,\n metadata: { review },\n };\n },\n};\n\nexport function registerReviewCommand(): void {\n commandRegistry.register(reviewCommand);\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { extractProfileAgentId } from "../../config/agent-profile.js";
|
|
2
2
|
import { createWorkflowCatalog } from "../../agent/workflow/catalog.js";
|
|
3
|
-
import { getLastWorkflowMemory } from "../../agent/workflow/last-run-memory.js";
|
|
4
3
|
import { commandRegistry } from "../registry.js";
|
|
5
4
|
import { bulletList, code, joinBlocks, section } from "../format-output.js";
|
|
6
5
|
//#region src/chat-commands/builtins/workflow.ts
|
|
@@ -19,13 +18,12 @@ import { bulletList, code, joinBlocks, section } from "../format-output.js";
|
|
|
19
18
|
* `/workflows` and `/workflow view` make discovery cheap, which is the missing
|
|
20
19
|
* piece.
|
|
21
20
|
*/
|
|
22
|
-
const VIEW_MAX_LINES = 200;
|
|
23
21
|
function formatEntryDetail(entry) {
|
|
24
22
|
const tags = entry.tags?.length ? `[${entry.tags.join(", ")}] ` : "";
|
|
25
23
|
const agents = entry.estimatedAgents ? ` (~${entry.estimatedAgents.min}–${entry.estimatedAgents.max} agents)` : "";
|
|
26
24
|
return `${tags}${entry.description}${agents}`;
|
|
27
25
|
}
|
|
28
|
-
function formatWorkflowListContent(entries
|
|
26
|
+
function formatWorkflowListContent(entries) {
|
|
29
27
|
const grouped = {
|
|
30
28
|
builtin: entries.filter((e) => e.source === "builtin"),
|
|
31
29
|
user: entries.filter((e) => e.source === "user")
|
|
@@ -42,8 +40,8 @@ function formatWorkflowListContent(entries, userDir) {
|
|
|
42
40
|
})))));
|
|
43
41
|
blocks.push(joinBlocks(section("How to run"), bulletList([
|
|
44
42
|
`Plain language: "run the ${exampleName} workflow"`,
|
|
45
|
-
`Inspect
|
|
46
|
-
|
|
43
|
+
`Inspect its visual structure: ${code(`/workflow view ${exampleName}`)}`,
|
|
44
|
+
"Create and edit workflows in the Workflow Studio."
|
|
47
45
|
])));
|
|
48
46
|
return joinBlocks(...blocks);
|
|
49
47
|
}
|
|
@@ -58,14 +56,13 @@ const workflowsCommand = {
|
|
|
58
56
|
"group"
|
|
59
57
|
],
|
|
60
58
|
handler: async (_ctx) => {
|
|
61
|
-
const
|
|
62
|
-
const entries = catalog.list();
|
|
59
|
+
const entries = createWorkflowCatalog().list();
|
|
63
60
|
if (entries.length === 0) return {
|
|
64
|
-
content:
|
|
61
|
+
content: "No workflows found. Create one in the Workflow Studio.",
|
|
65
62
|
success: true
|
|
66
63
|
};
|
|
67
64
|
return {
|
|
68
|
-
content: formatWorkflowListContent(entries
|
|
65
|
+
content: formatWorkflowListContent(entries),
|
|
69
66
|
success: true
|
|
70
67
|
};
|
|
71
68
|
}
|
|
@@ -96,11 +93,9 @@ const workflowCommand = {
|
|
|
96
93
|
const catalog = createWorkflowCatalog();
|
|
97
94
|
try {
|
|
98
95
|
const loaded = catalog.load(target);
|
|
99
|
-
const
|
|
100
|
-
const visible = lines.length > VIEW_MAX_LINES ? [...lines.slice(0, VIEW_MAX_LINES), `… (truncated; ${lines.length - VIEW_MAX_LINES} more lines)`] : lines;
|
|
101
|
-
const source = loaded.source === "user" ? loaded.path ?? "user" : "built-in";
|
|
96
|
+
const nodeSummary = loaded.graph.nodes.map((node) => `${node.title} (${node.kind})`).join(" → ");
|
|
102
97
|
return {
|
|
103
|
-
content: joinBlocks(`**${loaded.
|
|
98
|
+
content: joinBlocks(`**${loaded.title}** (${loaded.metadata.source}) — ${loaded.description}`, `Flow: ${nodeSummary}`, `Revision: ${loaded.revision}`),
|
|
104
99
|
success: true
|
|
105
100
|
};
|
|
106
101
|
} catch (e) {
|
|
@@ -111,33 +106,8 @@ const workflowCommand = {
|
|
|
111
106
|
}
|
|
112
107
|
}
|
|
113
108
|
if (subLower === "run" || subLower === "start") return runWorkflowFromCommand(ctx, target);
|
|
114
|
-
if (subLower === "save") {
|
|
115
|
-
if (!target) return {
|
|
116
|
-
content: `usage: ${code("/workflow save <name>")}`,
|
|
117
|
-
success: false
|
|
118
|
-
};
|
|
119
|
-
const last = getLastWorkflowMemory().get(ctx.sessionKey);
|
|
120
|
-
if (!last) return {
|
|
121
|
-
content: "No workflow has run successfully in this session yet. Run one first (e.g. ask \"run the audit_repo workflow\"), then `/workflow save <name>`.",
|
|
122
|
-
success: false
|
|
123
|
-
};
|
|
124
|
-
const catalog = createWorkflowCatalog();
|
|
125
|
-
try {
|
|
126
|
-
const script = last.metaName === target ? last.script : rewriteMetaName(last.script, target);
|
|
127
|
-
const { path } = catalog.save(target, script);
|
|
128
|
-
return {
|
|
129
|
-
content: joinBlocks(`✓ Saved workflow **${target}** → ${code(path)}`, bulletList([`Trigger with ${code(`/${target}`)} or "run the ${target} workflow"`, `Inspect with ${code(`/workflow view ${target}`)}`])),
|
|
130
|
-
success: true
|
|
131
|
-
};
|
|
132
|
-
} catch (e) {
|
|
133
|
-
return {
|
|
134
|
-
content: `error: ${e instanceof Error ? e.message : String(e)}`,
|
|
135
|
-
success: false
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
109
|
return {
|
|
140
|
-
content: joinBlocks(`Unknown subcommand "${sub}". Available: list, view ${code("<name>")},
|
|
110
|
+
content: joinBlocks(`Unknown subcommand "${sub}". Available: list, view ${code("<name>")}, run ${code("<name>")}.`, `Run directly with ${code("/workflow run <name> [--goal \"...\"] [--json '{...}']")}.`),
|
|
141
111
|
success: false
|
|
142
112
|
};
|
|
143
113
|
}
|
|
@@ -271,21 +241,6 @@ function tokenizeArgs(raw) {
|
|
|
271
241
|
}
|
|
272
242
|
return tokens;
|
|
273
243
|
}
|
|
274
|
-
/**
|
|
275
|
-
* Replace the `name` field inside the FIRST `export const meta = { ... }` literal.
|
|
276
|
-
*
|
|
277
|
-
* Why text-level (not AST re-emit)? The parser already accepted the script
|
|
278
|
-
* once (the runtime ran it), so the surrounding code is unchanged. A targeted
|
|
279
|
-
* regex on the `name: '...'` slot inside the first object literal keeps the
|
|
280
|
-
* user's formatting / comments / quote style intact, which an AST round-trip
|
|
281
|
-
* would smash. The match anchors to the first `name:` after `export const meta`
|
|
282
|
-
* and only touches that single value.
|
|
283
|
-
*/
|
|
284
|
-
function rewriteMetaName(script, newName) {
|
|
285
|
-
const re = /(export\s+const\s+meta\s*=\s*\{[^}]*?\bname\s*:\s*)(['"`])([^'"`]*)\2/;
|
|
286
|
-
if (!re.test(script)) throw new Error("could not locate meta.name in the recorded script to rewrite");
|
|
287
|
-
return script.replace(re, (_m, prefix, quote) => `${prefix}${quote}${newName}${quote}`);
|
|
288
|
-
}
|
|
289
244
|
function registerWorkflowCommands() {
|
|
290
245
|
commandRegistry.register(workflowsCommand);
|
|
291
246
|
commandRegistry.register(workflowCommand);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow.js","names":[],"sources":["../../../../src/chat-commands/builtins/workflow.ts"],"sourcesContent":["/**\n * `/workflows` and `/workflow <subcommand>` — read-only commands for browsing\n * saved workflows.\n *\n * Why only read commands here? Slash command results are sent to the user; they\n * are NOT injected back into the agent's turn. Triggering a workflow run from\n * the slash layer would require a non-trivial cross-cutting \"inject this as the\n * next user message\" hook that doesn't exist yet. Instead, the workflow tool\n * understands `name`, and its description tells the model to prefer that route\n * whenever a user mentions a saved workflow by name. Plain text — \"run the\n * audit_repo workflow\" — works end-to-end.\n *\n * `/workflows` and `/workflow view` make discovery cheap, which is the missing\n * piece.\n */\n\nimport { commandRegistry } from '../registry.js';\nimport type { CommandContext, CommandDefinition } from '../types.js';\nimport { bulletList, code, joinBlocks, section } from '../format-output.js';\n\nimport { createWorkflowCatalog } from '../../agent/workflow/catalog.js';\nimport { getLastWorkflowMemory } from '../../agent/workflow/last-run-memory.js';\nimport type { CatalogEntry } from '../../agent/workflow/catalog.js';\nimport { extractProfileAgentId } from '../../config/agent-profile.js';\n\nconst VIEW_MAX_LINES = 200;\n\nfunction formatEntryDetail(entry: CatalogEntry): string {\n const tags = entry.tags?.length ? `[${entry.tags.join(', ')}] ` : '';\n const agents = entry.estimatedAgents\n ? ` (~${entry.estimatedAgents.min}–${entry.estimatedAgents.max} agents)`\n : '';\n return `${tags}${entry.description}${agents}`;\n}\n\nfunction formatWorkflowListContent(entries: CatalogEntry[], userDir: string): string {\n const grouped = {\n builtin: entries.filter((e) => e.source === 'builtin'),\n user: entries.filter((e) => e.source === 'user'),\n };\n const exampleName = entries[0]?.name ?? 'audit_repo';\n const blocks: string[] = [];\n\n if (grouped.user.length > 0) {\n blocks.push(\n joinBlocks(\n section('User workflows'),\n bulletList(grouped.user.map((e) => ({ label: e.name, detail: formatEntryDetail(e) }))),\n ),\n );\n }\n if (grouped.builtin.length > 0) {\n blocks.push(\n joinBlocks(\n section('Built-in workflows'),\n bulletList(grouped.builtin.map((e) => ({ label: e.name, detail: formatEntryDetail(e) }))),\n ),\n );\n }\n\n blocks.push(\n joinBlocks(\n section('How to run'),\n bulletList([\n `Plain language: \"run the ${exampleName} workflow\"`,\n `Inspect source: ${code(`/workflow view ${exampleName}`)}`,\n `Add your own: drop a ${code('.js')} at ${code(userDir)}`,\n ]),\n ),\n );\n\n return joinBlocks(...blocks);\n}\n\nconst workflowsCommand: CommandDefinition = {\n id: 'system.workflows',\n name: 'workflows',\n description: 'List saved workflows (built-in + ~/.xopc/workflows/)',\n category: 'system',\n scope: ['global', 'private', 'group'],\n handler: async (_ctx: CommandContext) => {\n const catalog = createWorkflowCatalog();\n const entries = catalog.list();\n if (entries.length === 0) {\n return {\n content: `No workflows found. Drop a script at ${code(`${catalog.userDir}/<name>.js`)} to add one.`,\n success: true,\n };\n }\n return { content: formatWorkflowListContent(entries, catalog.userDir), success: true };\n },\n};\n\nexport const workflowCommand: CommandDefinition = {\n id: 'system.workflow',\n name: 'workflow',\n description: 'Inspect or manage saved workflows. Subcommands: list, view <name>',\n category: 'system',\n scope: ['global', 'private', 'group'],\n acceptsArgs: true,\n examples: ['/workflow list', '/workflow view audit_repo'],\n handler: async (ctx: CommandContext, args: string) => {\n const trimmed = args.trim();\n if (!trimmed || trimmed.toLowerCase() === 'list') {\n return workflowsCommand.handler(ctx, '');\n }\n const [sub, ...rest] = trimmed.split(/\\s+/);\n const subLower = sub.toLowerCase();\n const target = rest.join(' ').trim();\n\n if (subLower === 'view' || subLower === 'show' || subLower === 'cat') {\n if (!target) {\n return { content: `usage: ${code('/workflow view <name>')}`, success: false };\n }\n const catalog = createWorkflowCatalog();\n try {\n const loaded = catalog.load(target);\n const lines = loaded.script.split('\\n');\n const visible =\n lines.length > VIEW_MAX_LINES\n ? [...lines.slice(0, VIEW_MAX_LINES), `… (truncated; ${lines.length - VIEW_MAX_LINES} more lines)`]\n : lines;\n const source = loaded.source === 'user' ? loaded.path ?? 'user' : 'built-in';\n return {\n content: joinBlocks(\n `**${loaded.name}** (${source}) — ${loaded.meta.description}`,\n '```js\\n' + visible.join('\\n') + '\\n```',\n ),\n success: true,\n };\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e);\n return { content: `error: ${message}`, success: false };\n }\n }\n\n if (subLower === 'run' || subLower === 'start') {\n return runWorkflowFromCommand(ctx, target);\n }\n\n if (subLower === 'save') {\n if (!target) {\n return { content: `usage: ${code('/workflow save <name>')}`, success: false };\n }\n const last = getLastWorkflowMemory().get(ctx.sessionKey);\n if (!last) {\n return {\n content:\n 'No workflow has run successfully in this session yet. Run one first (e.g. ask \"run the audit_repo workflow\"), then `/workflow save <name>`.',\n success: false,\n };\n }\n const catalog = createWorkflowCatalog();\n try {\n // Allow the user to rename: if target differs from meta.name, rewrite it\n // before saving so the file is addressable as `target`.\n const script =\n last.metaName === target ? last.script : rewriteMetaName(last.script, target);\n const { path } = catalog.save(target, script);\n return {\n content: joinBlocks(\n `✓ Saved workflow **${target}** → ${code(path)}`,\n bulletList([\n `Trigger with ${code(`/${target}`)} or \"run the ${target} workflow\"`,\n `Inspect with ${code(`/workflow view ${target}`)}`,\n ]),\n ),\n success: true,\n };\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e);\n return { content: `error: ${message}`, success: false };\n }\n }\n\n return {\n content: joinBlocks(\n `Unknown subcommand \"${sub}\". Available: list, view ${code('<name>')}, save ${code('<name>')}.`,\n `Run directly with ${code('/workflow run <name> [--goal \"...\"] [--json \\'{...}\\']')}.`,\n ),\n success: false,\n };\n },\n};\n\nasync function runWorkflowFromCommand(ctx: CommandContext, args: string) {\n if (!ctx.workflowRunApis) {\n return {\n content: 'Workflow runs are not available in this context.',\n success: false,\n };\n }\n\n let parsed: { name: string; goal?: string; input?: unknown };\n try {\n parsed = parseWorkflowRunArgs(args);\n } catch (err) {\n return {\n content: `error: ${err instanceof Error ? err.message : String(err)}`,\n success: false,\n };\n }\n if (!parsed.name) {\n return {\n content: `usage: ${code('/workflow run <name> [--goal \"...\"] [--json \\'{...}\\']')}`,\n success: false,\n };\n }\n\n const catalog = createWorkflowCatalog();\n try {\n catalog.load(parsed.name);\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e);\n return { content: `error: ${message}`, success: false };\n }\n\n const agentId = extractProfileAgentId(ctx.sessionKey, ctx.config);\n const source =\n ctx.source === 'webui' || ctx.channelId === 'webchat'\n ? ({ kind: 'webui' as const, sessionKey: ctx.sessionKey })\n : ({ kind: 'chat' as const, sessionKey: ctx.sessionKey });\n const result = await ctx.workflowRunApis.startWorkflowRun({\n agentId,\n definitionId: parsed.name,\n goal: parsed.goal,\n input: parsed.input,\n parentSessionKey: ctx.sessionKey,\n source,\n });\n\n if (result.ok === false) {\n return {\n content: `error: ${result.message}`,\n success: false,\n metadata: {\n workflowRun: {\n ok: false,\n definitionId: parsed.name,\n code: result.code,\n message: result.message,\n },\n },\n };\n }\n\n const content = joinBlocks(\n `Started workflow **${parsed.name}**.`,\n bulletList([\n { label: 'runId', detail: code(result.runId) },\n { label: 'sessionKey', detail: code(result.sessionKey) },\n ]),\n );\n\n return {\n content,\n success: true,\n metadata: {\n workflowRun: {\n ok: true,\n definitionId: parsed.name,\n runId: result.runId,\n sessionKey: result.sessionKey,\n parentSessionKey: ctx.sessionKey,\n },\n },\n };\n}\n\nfunction parseWorkflowRunArgs(raw: string): { name: string; goal?: string; input?: unknown } {\n const tokens = tokenizeArgs(raw);\n const name = tokens.shift()?.trim() ?? '';\n let goal: string | undefined;\n let input: unknown;\n\n for (let i = 0; i < tokens.length; i += 1) {\n const token = tokens[i];\n if (token === '--goal' || token === '-g') {\n goal = tokens[++i]?.trim() || undefined;\n continue;\n }\n if (token.startsWith('--goal=')) {\n goal = token.slice('--goal='.length).trim() || undefined;\n continue;\n }\n if (token === '--json' || token === '--input') {\n const value = tokens[++i];\n input = parseJsonArg(value, token);\n continue;\n }\n if (token.startsWith('--json=')) {\n input = parseJsonArg(token.slice('--json='.length), '--json');\n continue;\n }\n if (token.startsWith('--input=')) {\n input = parseJsonArg(token.slice('--input='.length), '--input');\n continue;\n }\n if (!goal) {\n goal = [token, ...tokens.slice(i + 1)].join(' ').trim() || undefined;\n break;\n }\n }\n\n return { name, goal, input };\n}\n\nfunction parseJsonArg(value: string | undefined, flag: string): unknown {\n if (!value?.trim()) {\n throw new Error(`${flag} requires a JSON value`);\n }\n try {\n return JSON.parse(value);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`${flag} is not valid JSON: ${message}`);\n }\n}\n\nfunction tokenizeArgs(raw: string): string[] {\n const tokens: string[] = [];\n const re = /\"([^\"\\\\]*(?:\\\\.[^\"\\\\]*)*)\"|'([^'\\\\]*(?:\\\\.[^'\\\\]*)*)'|(\\S+)/g;\n let match: RegExpExecArray | null;\n while ((match = re.exec(raw)) !== null) {\n const value = match[1] ?? match[2] ?? match[3] ?? '';\n tokens.push(value.replace(/\\\\([\"'\\\\])/g, '$1'));\n }\n return tokens;\n}\n\n/**\n * Replace the `name` field inside the FIRST `export const meta = { ... }` literal.\n *\n * Why text-level (not AST re-emit)? The parser already accepted the script\n * once (the runtime ran it), so the surrounding code is unchanged. A targeted\n * regex on the `name: '...'` slot inside the first object literal keeps the\n * user's formatting / comments / quote style intact, which an AST round-trip\n * would smash. The match anchors to the first `name:` after `export const meta`\n * and only touches that single value.\n */\nfunction rewriteMetaName(script: string, newName: string): string {\n const re = /(export\\s+const\\s+meta\\s*=\\s*\\{[^}]*?\\bname\\s*:\\s*)(['\"`])([^'\"`]*)\\2/;\n if (!re.test(script)) {\n throw new Error('could not locate meta.name in the recorded script to rewrite');\n }\n return script.replace(re, (_m, prefix, quote) => `${prefix}${quote}${newName}${quote}`);\n}\n\nexport function registerWorkflowCommands(): void {\n commandRegistry.register(workflowsCommand);\n commandRegistry.register(workflowCommand);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"workflow.js","names":[],"sources":["../../../../src/chat-commands/builtins/workflow.ts"],"sourcesContent":["/**\n * `/workflows` and `/workflow <subcommand>` — read-only commands for browsing\n * saved workflows.\n *\n * Why only read commands here? Slash command results are sent to the user; they\n * are NOT injected back into the agent's turn. Triggering a workflow run from\n * the slash layer would require a non-trivial cross-cutting \"inject this as the\n * next user message\" hook that doesn't exist yet. Instead, the workflow tool\n * understands `name`, and its description tells the model to prefer that route\n * whenever a user mentions a saved workflow by name. Plain text — \"run the\n * audit_repo workflow\" — works end-to-end.\n *\n * `/workflows` and `/workflow view` make discovery cheap, which is the missing\n * piece.\n */\n\nimport { commandRegistry } from '../registry.js';\nimport type { CommandContext, CommandDefinition } from '../types.js';\nimport { bulletList, code, joinBlocks, section } from '../format-output.js';\n\nimport { createWorkflowCatalog } from '../../agent/workflow/catalog.js';\nimport type { CatalogEntry } from '../../agent/workflow/catalog.js';\nimport { extractProfileAgentId } from '../../config/agent-profile.js';\n\nfunction formatEntryDetail(entry: CatalogEntry): string {\n const tags = entry.tags?.length ? `[${entry.tags.join(', ')}] ` : '';\n const agents = entry.estimatedAgents\n ? ` (~${entry.estimatedAgents.min}–${entry.estimatedAgents.max} agents)`\n : '';\n return `${tags}${entry.description}${agents}`;\n}\n\nfunction formatWorkflowListContent(entries: CatalogEntry[]): string {\n const grouped = {\n builtin: entries.filter((e) => e.source === 'builtin'),\n user: entries.filter((e) => e.source === 'user'),\n };\n const exampleName = entries[0]?.name ?? 'audit_repo';\n const blocks: string[] = [];\n\n if (grouped.user.length > 0) {\n blocks.push(\n joinBlocks(\n section('User workflows'),\n bulletList(grouped.user.map((e) => ({ label: e.name, detail: formatEntryDetail(e) }))),\n ),\n );\n }\n if (grouped.builtin.length > 0) {\n blocks.push(\n joinBlocks(\n section('Built-in workflows'),\n bulletList(grouped.builtin.map((e) => ({ label: e.name, detail: formatEntryDetail(e) }))),\n ),\n );\n }\n\n blocks.push(\n joinBlocks(\n section('How to run'),\n bulletList([\n `Plain language: \"run the ${exampleName} workflow\"`,\n `Inspect its visual structure: ${code(`/workflow view ${exampleName}`)}`,\n 'Create and edit workflows in the Workflow Studio.',\n ]),\n ),\n );\n\n return joinBlocks(...blocks);\n}\n\nconst workflowsCommand: CommandDefinition = {\n id: 'system.workflows',\n name: 'workflows',\n description: 'List saved workflows (built-in + ~/.xopc/workflows/)',\n category: 'system',\n scope: ['global', 'private', 'group'],\n handler: async (_ctx: CommandContext) => {\n const catalog = createWorkflowCatalog();\n const entries = catalog.list();\n if (entries.length === 0) {\n return {\n content: 'No workflows found. Create one in the Workflow Studio.',\n success: true,\n };\n }\n return { content: formatWorkflowListContent(entries), success: true };\n },\n};\n\nexport const workflowCommand: CommandDefinition = {\n id: 'system.workflow',\n name: 'workflow',\n description: 'Inspect or manage saved workflows. Subcommands: list, view <name>',\n category: 'system',\n scope: ['global', 'private', 'group'],\n acceptsArgs: true,\n examples: ['/workflow list', '/workflow view audit_repo'],\n handler: async (ctx: CommandContext, args: string) => {\n const trimmed = args.trim();\n if (!trimmed || trimmed.toLowerCase() === 'list') {\n return workflowsCommand.handler(ctx, '');\n }\n const [sub, ...rest] = trimmed.split(/\\s+/);\n const subLower = sub.toLowerCase();\n const target = rest.join(' ').trim();\n\n if (subLower === 'view' || subLower === 'show' || subLower === 'cat') {\n if (!target) {\n return { content: `usage: ${code('/workflow view <name>')}`, success: false };\n }\n const catalog = createWorkflowCatalog();\n try {\n const loaded = catalog.load(target);\n const nodeSummary = loaded.graph.nodes.map((node) => `${node.title} (${node.kind})`).join(' → ');\n return {\n content: joinBlocks(\n `**${loaded.title}** (${loaded.metadata.source}) — ${loaded.description}`,\n `Flow: ${nodeSummary}`,\n `Revision: ${loaded.revision}`,\n ),\n success: true,\n };\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e);\n return { content: `error: ${message}`, success: false };\n }\n }\n\n if (subLower === 'run' || subLower === 'start') {\n return runWorkflowFromCommand(ctx, target);\n }\n\n return {\n content: joinBlocks(\n `Unknown subcommand \"${sub}\". Available: list, view ${code('<name>')}, run ${code('<name>')}.`,\n `Run directly with ${code('/workflow run <name> [--goal \"...\"] [--json \\'{...}\\']')}.`,\n ),\n success: false,\n };\n },\n};\n\nasync function runWorkflowFromCommand(ctx: CommandContext, args: string) {\n if (!ctx.workflowRunApis) {\n return {\n content: 'Workflow runs are not available in this context.',\n success: false,\n };\n }\n\n let parsed: { name: string; goal?: string; input?: unknown };\n try {\n parsed = parseWorkflowRunArgs(args);\n } catch (err) {\n return {\n content: `error: ${err instanceof Error ? err.message : String(err)}`,\n success: false,\n };\n }\n if (!parsed.name) {\n return {\n content: `usage: ${code('/workflow run <name> [--goal \"...\"] [--json \\'{...}\\']')}`,\n success: false,\n };\n }\n\n const catalog = createWorkflowCatalog();\n try {\n catalog.load(parsed.name);\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e);\n return { content: `error: ${message}`, success: false };\n }\n\n const agentId = extractProfileAgentId(ctx.sessionKey, ctx.config);\n const source =\n ctx.source === 'webui' || ctx.channelId === 'webchat'\n ? ({ kind: 'webui' as const, sessionKey: ctx.sessionKey })\n : ({ kind: 'chat' as const, sessionKey: ctx.sessionKey });\n const result = await ctx.workflowRunApis.startWorkflowRun({\n agentId,\n definitionId: parsed.name,\n goal: parsed.goal,\n input: parsed.input,\n parentSessionKey: ctx.sessionKey,\n source,\n });\n\n if (result.ok === false) {\n return {\n content: `error: ${result.message}`,\n success: false,\n metadata: {\n workflowRun: {\n ok: false,\n definitionId: parsed.name,\n code: result.code,\n message: result.message,\n },\n },\n };\n }\n\n const content = joinBlocks(\n `Started workflow **${parsed.name}**.`,\n bulletList([\n { label: 'runId', detail: code(result.runId) },\n { label: 'sessionKey', detail: code(result.sessionKey) },\n ]),\n );\n\n return {\n content,\n success: true,\n metadata: {\n workflowRun: {\n ok: true,\n definitionId: parsed.name,\n runId: result.runId,\n sessionKey: result.sessionKey,\n parentSessionKey: ctx.sessionKey,\n },\n },\n };\n}\n\nfunction parseWorkflowRunArgs(raw: string): { name: string; goal?: string; input?: unknown } {\n const tokens = tokenizeArgs(raw);\n const name = tokens.shift()?.trim() ?? '';\n let goal: string | undefined;\n let input: unknown;\n\n for (let i = 0; i < tokens.length; i += 1) {\n const token = tokens[i];\n if (token === '--goal' || token === '-g') {\n goal = tokens[++i]?.trim() || undefined;\n continue;\n }\n if (token.startsWith('--goal=')) {\n goal = token.slice('--goal='.length).trim() || undefined;\n continue;\n }\n if (token === '--json' || token === '--input') {\n const value = tokens[++i];\n input = parseJsonArg(value, token);\n continue;\n }\n if (token.startsWith('--json=')) {\n input = parseJsonArg(token.slice('--json='.length), '--json');\n continue;\n }\n if (token.startsWith('--input=')) {\n input = parseJsonArg(token.slice('--input='.length), '--input');\n continue;\n }\n if (!goal) {\n goal = [token, ...tokens.slice(i + 1)].join(' ').trim() || undefined;\n break;\n }\n }\n\n return { name, goal, input };\n}\n\nfunction parseJsonArg(value: string | undefined, flag: string): unknown {\n if (!value?.trim()) {\n throw new Error(`${flag} requires a JSON value`);\n }\n try {\n return JSON.parse(value);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`${flag} is not valid JSON: ${message}`);\n }\n}\n\nfunction tokenizeArgs(raw: string): string[] {\n const tokens: string[] = [];\n const re = /\"([^\"\\\\]*(?:\\\\.[^\"\\\\]*)*)\"|'([^'\\\\]*(?:\\\\.[^'\\\\]*)*)'|(\\S+)/g;\n let match: RegExpExecArray | null;\n while ((match = re.exec(raw)) !== null) {\n const value = match[1] ?? match[2] ?? match[3] ?? '';\n tokens.push(value.replace(/\\\\([\"'\\\\])/g, '$1'));\n }\n return tokens;\n}\n\nexport function registerWorkflowCommands(): void {\n commandRegistry.register(workflowsCommand);\n commandRegistry.register(workflowCommand);\n}\n"],"mappings":"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"}
|
|
@@ -52,7 +52,7 @@ async function checkDatabaseSchema(ctx) {
|
|
|
52
52
|
id: "database-schema",
|
|
53
53
|
label: "Database schema",
|
|
54
54
|
status: "pass",
|
|
55
|
-
message: `SQLite schema v${status.dbVersion} (current release
|
|
55
|
+
message: `SQLite schema v${status.dbVersion} (current release v36).`,
|
|
56
56
|
hints: []
|
|
57
57
|
};
|
|
58
58
|
}
|
|
@@ -109,8 +109,8 @@ function sourceFor(id, template) {
|
|
|
109
109
|
const toolName = `${id.replace(/-/g, "_")}_echo`;
|
|
110
110
|
if (template === "provider") return `import type { ExtensionApi } from '@xopcai/xopc/extension-sdk';\n\nexport default function register(api: ExtensionApi) {\n api.registerProvider({\n id: '${id}',\n name: '${id}',\n models: [],\n createStream: async function* () {\n yield { type: 'text', text: 'Provider template: implement createStream().' };\n },\n } as any);\n}\n`;
|
|
111
111
|
if (template === "ui") return `import type { ExtensionApi } from '@xopcai/xopc/extension-sdk';\n\nexport default function register(api: ExtensionApi) {\n api.logger.info('${id} UI extension loaded');\n}\n`;
|
|
112
|
-
if (template === "channel") return `import type { ExtensionApi } from '@xopcai/xopc/extension-sdk';\
|
|
113
|
-
return `import type { ExtensionApi } from '@xopcai/xopc/extension-sdk';\n\nexport default function register(api: ExtensionApi) {\n api.registerTool({\n name: '${toolName}',\n description: 'Echo input text',\n parameters: {\n type: 'object',\n properties: { text: { type: 'string' } },\n required: ['text'],\n },\n async execute(_toolCallId, params) {\n return {
|
|
112
|
+
if (template === "channel") return `import type { ChannelPlugin, ExtensionApi } from '@xopcai/xopc/extension-sdk';\n\nconst plugin: ChannelPlugin = {\n id: '${id}' as any,\n meta: { id: '${id}' as any, name: '${id}', description: '${id} channel' } as any,\n capabilities: { inbound: true, outbound: true } as any,\n async init() {},\n async start() {},\n async stop() {},\n config: {\n resolveAccounts() { return []; },\n } as any,\n};\n\nexport default function register(api: ExtensionApi) {\n api.registerChannel({ plugin });\n}\n`;
|
|
113
|
+
return `import type { ExtensionApi } from '@xopcai/xopc/extension-sdk';\n\nexport default function register(api: ExtensionApi) {\n api.registerTool({\n name: '${toolName}',\n label: 'Echo text',\n description: 'Echo input text',\n parameters: {\n type: 'object',\n properties: { text: { type: 'string' } },\n required: ['text'],\n },\n async execute(_toolCallId, params) {\n return {\n content: [{ type: 'text', text: String((params as any).text) }],\n details: {},\n };\n },\n });\n}\n`;
|
|
114
114
|
}
|
|
115
115
|
function createExtensionCreateCommand() {
|
|
116
116
|
return new Command("create").description("Create a new independent extension package").argument("<name>", "Extension id / package suffix").option("--template <type>", `Template: ${TEMPLATE_TYPES.join(", ")}`, "tool").option("--dir <path>", "Output directory (default: ./<name>)").action((name, opts) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension-create.js","names":[],"sources":["../../../../src/cli/commands/extension-create.ts"],"sourcesContent":["import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\n\nimport { Command } from 'commander';\n\nimport { PACKAGE_VERSION } from '../../package-version.js';\nimport { colors } from '../utils/colors.js';\n\nconst TEMPLATE_TYPES = ['tool', 'ui', 'provider', 'channel'] as const;\ntype TemplateType = (typeof TEMPLATE_TYPES)[number];\n\nfunction toPackageName(name: string): string {\n return name.trim().toLowerCase().replace(/[^a-z0-9._-]+/g, '-').replace(/^-+|-+$/g, '');\n}\n\nfunction writeJson(path: string, value: unknown): void {\n writeFileSync(path, `${JSON.stringify(value, null, 2)}\\n`);\n}\n\nfunction basePackageJson(id: string, template: TemplateType): Record<string, unknown> {\n const scripts: Record<string, string> = {\n build: template === 'ui' ? 'tsc -p tsconfig.json && npm run build:ui' : 'tsc -p tsconfig.json',\n prepack: 'npm run build',\n };\n if (template === 'ui') scripts['build:ui'] = 'node scripts/build-ui.mjs';\n const devDependencies: Record<string, string> = {\n '@xopcai/xopc': `^${PACKAGE_VERSION}`,\n typescript: '^6.0.0',\n };\n if (template === 'ui') {\n devDependencies['@xopcai/extension-ui-sdk'] = `^${PACKAGE_VERSION}`;\n devDependencies.esbuild = '^0.28.1';\n }\n return {\n name: `xopc-extension-${id}`,\n version: '0.1.0',\n type: 'module',\n main: 'dist/index.js',\n files: ['dist', 'ui', 'xopc.extension.json', 'README.md', 'LICENSE'],\n keywords: ['xopc', 'xopc-extension'],\n license: 'MIT',\n scripts,\n devDependencies,\n peerDependencies: {\n '@xopcai/xopc': `>=${PACKAGE_VERSION} <1.0.0`,\n },\n peerDependenciesMeta: {\n '@xopcai/xopc': { optional: true },\n },\n };\n}\n\nfunction manifestFor(id: string, template: TemplateType): Record<string, unknown> {\n const base: Record<string, unknown> = {\n id,\n name: id.split('-').map((s) => s[0]?.toUpperCase() + s.slice(1)).join(' '),\n description: `xopc ${template} extension`,\n version: '0.1.0',\n kind: template === 'provider' ? 'provider' : template === 'channel' ? 'channel' : template === 'tool' ? 'tool' : 'utility',\n main: 'dist/index.js',\n engines: { xopc: `>=${PACKAGE_VERSION} <1.0.0` },\n };\n if (template === 'tool') {\n base.contracts = { tools: [`${id.replace(/-/g, '_')}_echo`] };\n } else if (template === 'provider') {\n base.providers = [id];\n base.contracts = { providers: [id] };\n } else if (template === 'channel') {\n base.channels = [id];\n base.contracts = { channels: [id] };\n base.activation = { onChannels: [id] };\n base.channelContributions = {\n [id]: {\n label: base.name,\n description: `Channel integration for ${base.name}`,\n configPath: `channels.${id}`,\n capabilities: { multiAccount: false, streaming: false, media: false },\n configSchema: { type: 'object', additionalProperties: true },\n },\n };\n } else {\n base.contracts = {};\n base.ui = {\n main: 'ui/panel.html',\n permissions: ['theme'],\n contributions: {\n pages: [{ id: `${id}.page`, title: base.name, path: id, entrypoint: 'ui/panel.html', showInNav: true }],\n },\n };\n }\n return base;\n}\n\nfunction buildUiScriptSource(): string {\n return `import { build } from 'esbuild';\\n\\nawait build({\\n entryPoints: ['ui/panel-entry.ts'],\\n outfile: 'ui/panel.bundle.js',\\n bundle: true,\\n format: 'esm',\\n platform: 'browser',\\n target: ['es2022'],\\n sourcemap: false,\\n});\\n`;\n}\n\nfunction uiPanelEntrySource(id: string): string {\n return `import { createExtensionClient } from '@xopcai/extension-ui-sdk';\\n\\nconst root = document.getElementById('root');\\nconst client = createExtensionClient();\\n\\nasync function main() {\\n await client.whenReady();\\n const theme = await client.theme.getTheme();\\n if (root) {\\n root.innerHTML = \\`<main style=\"font-family: system-ui; padding: 16px\">\\n <h1>${id}</h1>\\n <p>Theme mode: \\${theme.mode}</p>\\n <button id=\"notify\">Show notification</button>\\n </main>\\`;\\n document.getElementById('notify')?.addEventListener('click', () => {\\n void client.ui.showNotification({ type: 'info', message: '${id} is ready' });\\n });\\n }\\n}\\n\\nvoid main();\\n`;\n}\n\nfunction sourceFor(id: string, template: TemplateType): string {\n const toolName = `${id.replace(/-/g, '_')}_echo`;\n if (template === 'provider') {\n return `import type { ExtensionApi } from '@xopcai/xopc/extension-sdk';\\n\\nexport default function register(api: ExtensionApi) {\\n api.registerProvider({\\n id: '${id}',\\n name: '${id}',\\n models: [],\\n createStream: async function* () {\\n yield { type: 'text', text: 'Provider template: implement createStream().' };\\n },\\n } as any);\\n}\\n`;\n }\n if (template === 'ui') {\n return `import type { ExtensionApi } from '@xopcai/xopc/extension-sdk';\\n\\nexport default function register(api: ExtensionApi) {\\n api.logger.info('${id} UI extension loaded');\\n}\\n`;\n }\n if (template === 'channel') {\n return `import type { ExtensionApi } from '@xopcai/xopc/extension-sdk';\\nimport type { ChannelPlugin } from '@xopcai/xopc/extension-sdk/channel';\\n\\nconst plugin: ChannelPlugin = {\\n id: '${id}' as any,\\n meta: { id: '${id}' as any, name: '${id}', description: '${id} channel' } as any,\\n capabilities: { inbound: true, outbound: true } as any,\\n async init() {},\\n async start() {},\\n async stop() {},\\n config: {\\n resolveAccounts() { return []; },\\n } as any,\\n};\\n\\nexport default function register(api: ExtensionApi) {\\n api.registerChannel({ plugin });\\n}\\n`;\n }\n return `import type { ExtensionApi } from '@xopcai/xopc/extension-sdk';\\n\\nexport default function register(api: ExtensionApi) {\\n api.registerTool({\\n name: '${toolName}',\\n description: 'Echo input text',\\n parameters: {\\n type: 'object',\\n properties: { text: { type: 'string' } },\\n required: ['text'],\\n },\\n async execute(_toolCallId, params) {\\n return { content: [{ type: 'text', text: String((params as any).text) }] };\\n },\\n });\\n}\\n`;\n}\n\nexport function createExtensionCreateCommand(): Command {\n return new Command('create')\n .description('Create a new independent extension package')\n .argument('<name>', 'Extension id / package suffix')\n .option('--template <type>', `Template: ${TEMPLATE_TYPES.join(', ')}`, 'tool')\n .option('--dir <path>', 'Output directory (default: ./<name>)')\n .action((name: string, opts: { template: string; dir?: string }) => {\n const id = toPackageName(name);\n if (!id) {\n console.error(colors.red('error:'), 'Invalid extension name');\n process.exit(1);\n }\n const template = opts.template as TemplateType;\n if (!TEMPLATE_TYPES.includes(template)) {\n console.error(colors.red('error:'), `Unknown template: ${opts.template}`);\n process.exit(1);\n }\n const root = resolve(opts.dir?.trim() || id);\n if (existsSync(root)) {\n console.error(colors.red('error:'), `Directory already exists: ${root}`);\n process.exit(1);\n }\n mkdirSync(join(root, 'src'), { recursive: true });\n writeJson(join(root, 'package.json'), basePackageJson(id, template));\n writeJson(join(root, 'xopc.extension.json'), manifestFor(id, template));\n writeJson(join(root, 'tsconfig.json'), {\n compilerOptions: {\n target: 'ES2022',\n module: 'NodeNext',\n moduleResolution: 'NodeNext',\n declaration: true,\n outDir: 'dist',\n rootDir: 'src',\n strict: true,\n skipLibCheck: true,\n },\n include: ['src/**/*.ts'],\n });\n writeFileSync(join(root, 'src', 'index.ts'), sourceFor(id, template));\n if (template === 'ui') {\n mkdirSync(join(root, 'ui'), { recursive: true });\n mkdirSync(join(root, 'scripts'), { recursive: true });\n writeFileSync(join(root, 'ui', 'panel.html'), '<!doctype html><html><body><div id=\"root\"></div><script type=\"module\" src=\"./panel.bundle.js\"></script></body></html>\\n');\n writeFileSync(join(root, 'ui', 'panel-entry.ts'), uiPanelEntrySource(id));\n writeFileSync(join(root, 'scripts', 'build-ui.mjs'), buildUiScriptSource());\n }\n writeFileSync(join(root, 'README.md'), `# ${id}\\n\\nGenerated xopc extension.\\n`);\n writeFileSync(join(root, 'LICENSE'), 'MIT\\n');\n console.log(colors.green('✓'), `Created extension package at ${root}`);\n console.log(colors.cyan('Next:'), `cd ${root} && npm install && npm run build && xopc extensions pack . --dry-run`);\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"extension-create.js","names":[],"sources":["../../../../src/cli/commands/extension-create.ts"],"sourcesContent":["import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\n\nimport { Command } from 'commander';\n\nimport { PACKAGE_VERSION } from '../../package-version.js';\nimport { colors } from '../utils/colors.js';\n\nconst TEMPLATE_TYPES = ['tool', 'ui', 'provider', 'channel'] as const;\ntype TemplateType = (typeof TEMPLATE_TYPES)[number];\n\nfunction toPackageName(name: string): string {\n return name.trim().toLowerCase().replace(/[^a-z0-9._-]+/g, '-').replace(/^-+|-+$/g, '');\n}\n\nfunction writeJson(path: string, value: unknown): void {\n writeFileSync(path, `${JSON.stringify(value, null, 2)}\\n`);\n}\n\nfunction basePackageJson(id: string, template: TemplateType): Record<string, unknown> {\n const scripts: Record<string, string> = {\n build: template === 'ui' ? 'tsc -p tsconfig.json && npm run build:ui' : 'tsc -p tsconfig.json',\n prepack: 'npm run build',\n };\n if (template === 'ui') scripts['build:ui'] = 'node scripts/build-ui.mjs';\n const devDependencies: Record<string, string> = {\n '@xopcai/xopc': `^${PACKAGE_VERSION}`,\n typescript: '^6.0.0',\n };\n if (template === 'ui') {\n devDependencies['@xopcai/extension-ui-sdk'] = `^${PACKAGE_VERSION}`;\n devDependencies.esbuild = '^0.28.1';\n }\n return {\n name: `xopc-extension-${id}`,\n version: '0.1.0',\n type: 'module',\n main: 'dist/index.js',\n files: ['dist', 'ui', 'xopc.extension.json', 'README.md', 'LICENSE'],\n keywords: ['xopc', 'xopc-extension'],\n license: 'MIT',\n scripts,\n devDependencies,\n peerDependencies: {\n '@xopcai/xopc': `>=${PACKAGE_VERSION} <1.0.0`,\n },\n peerDependenciesMeta: {\n '@xopcai/xopc': { optional: true },\n },\n };\n}\n\nfunction manifestFor(id: string, template: TemplateType): Record<string, unknown> {\n const base: Record<string, unknown> = {\n id,\n name: id.split('-').map((s) => s[0]?.toUpperCase() + s.slice(1)).join(' '),\n description: `xopc ${template} extension`,\n version: '0.1.0',\n kind: template === 'provider' ? 'provider' : template === 'channel' ? 'channel' : template === 'tool' ? 'tool' : 'utility',\n main: 'dist/index.js',\n engines: { xopc: `>=${PACKAGE_VERSION} <1.0.0` },\n };\n if (template === 'tool') {\n base.contracts = { tools: [`${id.replace(/-/g, '_')}_echo`] };\n } else if (template === 'provider') {\n base.providers = [id];\n base.contracts = { providers: [id] };\n } else if (template === 'channel') {\n base.channels = [id];\n base.contracts = { channels: [id] };\n base.activation = { onChannels: [id] };\n base.channelContributions = {\n [id]: {\n label: base.name,\n description: `Channel integration for ${base.name}`,\n configPath: `channels.${id}`,\n capabilities: { multiAccount: false, streaming: false, media: false },\n configSchema: { type: 'object', additionalProperties: true },\n },\n };\n } else {\n base.contracts = {};\n base.ui = {\n main: 'ui/panel.html',\n permissions: ['theme'],\n contributions: {\n pages: [{ id: `${id}.page`, title: base.name, path: id, entrypoint: 'ui/panel.html', showInNav: true }],\n },\n };\n }\n return base;\n}\n\nfunction buildUiScriptSource(): string {\n return `import { build } from 'esbuild';\\n\\nawait build({\\n entryPoints: ['ui/panel-entry.ts'],\\n outfile: 'ui/panel.bundle.js',\\n bundle: true,\\n format: 'esm',\\n platform: 'browser',\\n target: ['es2022'],\\n sourcemap: false,\\n});\\n`;\n}\n\nfunction uiPanelEntrySource(id: string): string {\n return `import { createExtensionClient } from '@xopcai/extension-ui-sdk';\\n\\nconst root = document.getElementById('root');\\nconst client = createExtensionClient();\\n\\nasync function main() {\\n await client.whenReady();\\n const theme = await client.theme.getTheme();\\n if (root) {\\n root.innerHTML = \\`<main style=\"font-family: system-ui; padding: 16px\">\\n <h1>${id}</h1>\\n <p>Theme mode: \\${theme.mode}</p>\\n <button id=\"notify\">Show notification</button>\\n </main>\\`;\\n document.getElementById('notify')?.addEventListener('click', () => {\\n void client.ui.showNotification({ type: 'info', message: '${id} is ready' });\\n });\\n }\\n}\\n\\nvoid main();\\n`;\n}\n\nfunction sourceFor(id: string, template: TemplateType): string {\n const toolName = `${id.replace(/-/g, '_')}_echo`;\n if (template === 'provider') {\n return `import type { ExtensionApi } from '@xopcai/xopc/extension-sdk';\\n\\nexport default function register(api: ExtensionApi) {\\n api.registerProvider({\\n id: '${id}',\\n name: '${id}',\\n models: [],\\n createStream: async function* () {\\n yield { type: 'text', text: 'Provider template: implement createStream().' };\\n },\\n } as any);\\n}\\n`;\n }\n if (template === 'ui') {\n return `import type { ExtensionApi } from '@xopcai/xopc/extension-sdk';\\n\\nexport default function register(api: ExtensionApi) {\\n api.logger.info('${id} UI extension loaded');\\n}\\n`;\n }\n if (template === 'channel') {\n return `import type { ChannelPlugin, ExtensionApi } from '@xopcai/xopc/extension-sdk';\\n\\nconst plugin: ChannelPlugin = {\\n id: '${id}' as any,\\n meta: { id: '${id}' as any, name: '${id}', description: '${id} channel' } as any,\\n capabilities: { inbound: true, outbound: true } as any,\\n async init() {},\\n async start() {},\\n async stop() {},\\n config: {\\n resolveAccounts() { return []; },\\n } as any,\\n};\\n\\nexport default function register(api: ExtensionApi) {\\n api.registerChannel({ plugin });\\n}\\n`;\n }\n return `import type { ExtensionApi } from '@xopcai/xopc/extension-sdk';\\n\\nexport default function register(api: ExtensionApi) {\\n api.registerTool({\\n name: '${toolName}',\\n label: 'Echo text',\\n description: 'Echo input text',\\n parameters: {\\n type: 'object',\\n properties: { text: { type: 'string' } },\\n required: ['text'],\\n },\\n async execute(_toolCallId, params) {\\n return {\\n content: [{ type: 'text', text: String((params as any).text) }],\\n details: {},\\n };\\n },\\n });\\n}\\n`;\n}\n\nexport function createExtensionCreateCommand(): Command {\n return new Command('create')\n .description('Create a new independent extension package')\n .argument('<name>', 'Extension id / package suffix')\n .option('--template <type>', `Template: ${TEMPLATE_TYPES.join(', ')}`, 'tool')\n .option('--dir <path>', 'Output directory (default: ./<name>)')\n .action((name: string, opts: { template: string; dir?: string }) => {\n const id = toPackageName(name);\n if (!id) {\n console.error(colors.red('error:'), 'Invalid extension name');\n process.exit(1);\n }\n const template = opts.template as TemplateType;\n if (!TEMPLATE_TYPES.includes(template)) {\n console.error(colors.red('error:'), `Unknown template: ${opts.template}`);\n process.exit(1);\n }\n const root = resolve(opts.dir?.trim() || id);\n if (existsSync(root)) {\n console.error(colors.red('error:'), `Directory already exists: ${root}`);\n process.exit(1);\n }\n mkdirSync(join(root, 'src'), { recursive: true });\n writeJson(join(root, 'package.json'), basePackageJson(id, template));\n writeJson(join(root, 'xopc.extension.json'), manifestFor(id, template));\n writeJson(join(root, 'tsconfig.json'), {\n compilerOptions: {\n target: 'ES2022',\n module: 'NodeNext',\n moduleResolution: 'NodeNext',\n declaration: true,\n outDir: 'dist',\n rootDir: 'src',\n strict: true,\n skipLibCheck: true,\n },\n include: ['src/**/*.ts'],\n });\n writeFileSync(join(root, 'src', 'index.ts'), sourceFor(id, template));\n if (template === 'ui') {\n mkdirSync(join(root, 'ui'), { recursive: true });\n mkdirSync(join(root, 'scripts'), { recursive: true });\n writeFileSync(join(root, 'ui', 'panel.html'), '<!doctype html><html><body><div id=\"root\"></div><script type=\"module\" src=\"./panel.bundle.js\"></script></body></html>\\n');\n writeFileSync(join(root, 'ui', 'panel-entry.ts'), uiPanelEntrySource(id));\n writeFileSync(join(root, 'scripts', 'build-ui.mjs'), buildUiScriptSource());\n }\n writeFileSync(join(root, 'README.md'), `# ${id}\\n\\nGenerated xopc extension.\\n`);\n writeFileSync(join(root, 'LICENSE'), 'MIT\\n');\n console.log(colors.green('✓'), `Created extension package at ${root}`);\n console.log(colors.cyan('Next:'), `cd ${root} && npm install && npm run build && xopc extensions pack . --dry-run`);\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { init_paths, resolveExtensionsDir } from "../../config/paths.js";
|
|
2
2
|
import { init_loader, loadConfig } from "../../config/loader.js";
|
|
3
|
-
import { downloadExtensionStoreZipBuffer, resolveExtensionZipDownloadUrl, resolveExtensionsStoreBaseUrl } from "../../agent/skills/marketplace/adapters/store/store-api-client.js";
|
|
3
|
+
import { downloadExtensionStoreZipBuffer, resolveExtensionZipDownloadUrl, resolveExtensionsStoreBaseUrl, verifyStoreArtifactSha256 } from "../../agent/skills/marketplace/adapters/store/store-api-client.js";
|
|
4
4
|
import { getContextWithOpts } from "../context.js";
|
|
5
5
|
import { getExtensionLockfileManager } from "../../extensions/lockfile.js";
|
|
6
|
-
import {
|
|
6
|
+
import { installFromLocal, installFromNpm, peekExtensionManifestFromStoreZip } from "../../extensions/install.js";
|
|
7
|
+
import { commitStagedExtensionInstall, finalizeStagedExtensionInstall, rollbackStagedExtensionInstall, stageExtensionStoreZip } from "../../extensions/install-transaction.js";
|
|
7
8
|
import { fetchRegistry, findExtension, getExtensionMarketplaceStoreBaseUrl, listExtensions, searchExtensions } from "../../extensions/marketplace.js";
|
|
8
9
|
import { colors } from "../utils/colors.js";
|
|
9
10
|
import { validateExtensionPackageDirectory } from "./extension-pack.js";
|
|
@@ -36,13 +37,6 @@ function readInstalledSnapshots(targetDir, extensionId) {
|
|
|
36
37
|
function sha256Integrity(buffer) {
|
|
37
38
|
return `sha256-${createHash("sha256").update(buffer).digest("base64")}`;
|
|
38
39
|
}
|
|
39
|
-
function normalizeIntegrity(raw) {
|
|
40
|
-
const value = raw?.trim();
|
|
41
|
-
if (!value) return void 0;
|
|
42
|
-
if (value.startsWith("sha256-")) return value;
|
|
43
|
-
if (/^[a-f0-9]{64}$/i.test(value)) return `sha256-${Buffer.from(value, "hex").toString("base64")}`;
|
|
44
|
-
return value;
|
|
45
|
-
}
|
|
46
40
|
function printManifestSummary(params) {
|
|
47
41
|
const manifest = params.manifest;
|
|
48
42
|
console.log("");
|
|
@@ -122,15 +116,11 @@ async function upsertNpmExtensionLock(lock, targetDir, result, spec) {
|
|
|
122
116
|
}
|
|
123
117
|
async function installExtensionFromStoreWithLock(params) {
|
|
124
118
|
try {
|
|
125
|
-
const { downloadUrl, version,
|
|
119
|
+
const { downloadUrl, version, sha256 } = await resolveExtensionZipDownloadUrl(params.storeBase, params.packageName, params.version);
|
|
126
120
|
console.log(colors.cyan("📦"), `Downloading ${params.packageName}@${version} from xopc-store (${params.storeBase})…`);
|
|
127
121
|
const buf = await downloadExtensionStoreZipBuffer(params.storeBase, downloadUrl);
|
|
122
|
+
verifyStoreArtifactSha256(buf, sha256);
|
|
128
123
|
const actualIntegrity = sha256Integrity(buf);
|
|
129
|
-
const expectedIntegrity = normalizeIntegrity(expectedIntegrityRaw);
|
|
130
|
-
if (expectedIntegrity && expectedIntegrity !== actualIntegrity) return {
|
|
131
|
-
ok: false,
|
|
132
|
-
error: `Extension artifact checksum mismatch: expected ${expectedIntegrity}, got ${actualIntegrity}`
|
|
133
|
-
};
|
|
134
124
|
const manifest = peekExtensionManifestFromStoreZip(buf);
|
|
135
125
|
if (!await confirmInstall({
|
|
136
126
|
source: "store",
|
|
@@ -143,30 +133,46 @@ async function installExtensionFromStoreWithLock(params) {
|
|
|
143
133
|
ok: false,
|
|
144
134
|
error: "Install cancelled"
|
|
145
135
|
};
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
136
|
+
const transaction = await stageExtensionStoreZip(buf, params.targetDir);
|
|
137
|
+
const lockSnapshot = await params.lock.load();
|
|
138
|
+
let lockWriteStarted = false;
|
|
139
|
+
try {
|
|
140
|
+
commitStagedExtensionInstall(transaction, params.force ?? false);
|
|
141
|
+
lockWriteStarted = true;
|
|
142
|
+
await params.lock.upsert(transaction.extensionId, {
|
|
143
|
+
name: transaction.extensionId,
|
|
144
|
+
version,
|
|
145
|
+
resolved: params.packageName,
|
|
146
|
+
source: "store",
|
|
147
|
+
artifactUrl: downloadUrl,
|
|
148
|
+
integrity: actualIntegrity,
|
|
149
|
+
...readInstalledSnapshots(params.targetDir, transaction.extensionId)
|
|
151
150
|
});
|
|
151
|
+
} catch (err) {
|
|
152
|
+
const rollbackErrors = [];
|
|
153
|
+
try {
|
|
154
|
+
rollbackStagedExtensionInstall(transaction);
|
|
155
|
+
} catch (rollbackErr) {
|
|
156
|
+
rollbackErrors.push(`files: ${rollbackErr instanceof Error ? rollbackErr.message : String(rollbackErr)}`);
|
|
157
|
+
}
|
|
158
|
+
if (lockWriteStarted) try {
|
|
159
|
+
await params.lock.save(lockSnapshot);
|
|
160
|
+
} catch (rollbackErr) {
|
|
161
|
+
rollbackErrors.push(`lockfile: ${rollbackErr instanceof Error ? rollbackErr.message : String(rollbackErr)}`);
|
|
162
|
+
}
|
|
163
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
164
|
+
const suffix = rollbackErrors.length > 0 ? ` Rollback incomplete (${rollbackErrors.join("; ")}).` : "";
|
|
165
|
+
throw new Error(`${message}${suffix}`, { cause: err });
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
finalizeStagedExtensionInstall(transaction);
|
|
169
|
+
} catch (cleanupErr) {
|
|
170
|
+
const message = cleanupErr instanceof Error ? cleanupErr.message : String(cleanupErr);
|
|
171
|
+
console.warn(colors.yellow("warning:"), `Installed extension, but temporary backup cleanup failed: ${message}`);
|
|
152
172
|
}
|
|
153
|
-
const result = await installExtensionFromStoreZip(buf, params.targetDir);
|
|
154
|
-
if (!result.ok || !result.extensionId) return {
|
|
155
|
-
ok: false,
|
|
156
|
-
error: result.error ?? "install failed"
|
|
157
|
-
};
|
|
158
|
-
await params.lock.upsert(result.extensionId, {
|
|
159
|
-
name: result.extensionId,
|
|
160
|
-
version,
|
|
161
|
-
resolved: params.packageName,
|
|
162
|
-
source: "store",
|
|
163
|
-
artifactUrl: downloadUrl,
|
|
164
|
-
integrity: actualIntegrity,
|
|
165
|
-
...readInstalledSnapshots(params.targetDir, result.extensionId)
|
|
166
|
-
});
|
|
167
173
|
return {
|
|
168
174
|
ok: true,
|
|
169
|
-
extensionId:
|
|
175
|
+
extensionId: transaction.extensionId,
|
|
170
176
|
version
|
|
171
177
|
};
|
|
172
178
|
} catch (e) {
|
|
@@ -177,7 +183,7 @@ async function installExtensionFromStoreWithLock(params) {
|
|
|
177
183
|
}
|
|
178
184
|
}
|
|
179
185
|
function createExtensionInstallCommand() {
|
|
180
|
-
return new Command("install").description("Install extension from xopc-store (store.xopc.ai), npm, or a local directory into ~/.xopc/extensions").argument("<target>", "Explicit source spec: store:<id>, npm:<package>, or a local extension directory").option("-f, --force", "
|
|
186
|
+
return new Command("install").description("Install extension from xopc-store (store.xopc.ai), npm, or a local directory into ~/.xopc/extensions").argument("<target>", "Explicit source spec: store:<id>, npm:<package>, or a local extension directory").option("-f, --force", "Replace an existing store or local extension with the same manifest id", false).option("-y, --yes", "Skip interactive install confirmation", false).action(async (target, opts) => {
|
|
181
187
|
const cfg = loadConfig(getContextWithOpts().configPath);
|
|
182
188
|
const targetDir = resolveExtensionsDir();
|
|
183
189
|
const lock = getExtensionLockfileManager();
|