@xopcai/xopc 0.0.105 → 0.0.107
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/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/dashscope/xopc.extension.json +7 -2
- package/dist/extensions/fal/xopc.extension.json +7 -2
- package/dist/extensions/feishu/src/adapters/gateway-setup.js +22 -26
- package/dist/extensions/feishu/src/adapters/gateway-setup.js.map +1 -1
- package/dist/extensions/feishu/src/directory/directory-adapter.js +1 -1
- package/dist/extensions/feishu/src/directory/directory-adapter.js.map +1 -1
- package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
- package/dist/extensions/feishu/src/outbound/outbound-adapter.js +4 -3
- package/dist/extensions/feishu/src/outbound/outbound-adapter.js.map +1 -1
- package/dist/extensions/feishu/src/plugin.d.ts +6 -3
- package/dist/extensions/feishu/src/plugin.js +59 -40
- package/dist/extensions/feishu/src/plugin.js.map +1 -1
- package/dist/extensions/feishu/src/streaming/streaming-adapter.js +20 -16
- package/dist/extensions/feishu/src/streaming/streaming-adapter.js.map +1 -1
- package/dist/extensions/feishu/src/transport/socket-mode/monitor.js +1 -1
- package/dist/extensions/feishu/src/transport/webhook/monitor.js +1 -1
- package/dist/extensions/feishu/src/workflow-progress.d.ts +1 -1
- package/dist/extensions/feishu/src/workflow-progress.js +3 -3
- package/dist/extensions/feishu/src/workflow-progress.js.map +1 -1
- package/dist/extensions/feishu/xopc.extension.json +458 -26
- package/dist/extensions/google/xopc.extension.json +7 -2
- package/dist/extensions/minimax/xopc.extension.json +8 -2
- package/dist/extensions/openai/xopc.extension.json +7 -2
- package/dist/extensions/telegram/src/adapters/gateway-setup.js +8 -6
- package/dist/extensions/telegram/src/adapters/gateway-setup.js.map +1 -1
- package/dist/extensions/telegram/src/adapters/streaming-adapter.js +1 -1
- package/dist/extensions/telegram/src/command-handler.d.ts +1 -1
- package/dist/extensions/telegram/src/command-handler.js +11 -9
- package/dist/extensions/telegram/src/command-handler.js.map +1 -1
- package/dist/extensions/telegram/src/inbound-processor.js +2 -3
- package/dist/extensions/telegram/src/inbound-processor.js.map +1 -1
- package/dist/extensions/telegram/src/plugin.d.ts +1 -0
- package/dist/extensions/telegram/src/plugin.js +7 -7
- package/dist/extensions/telegram/src/plugin.js.map +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +2 -2
- package/dist/extensions/telegram/src/update-offset-store.js +1 -1
- package/dist/extensions/telegram/src/workflow-progress.d.ts +1 -1
- package/dist/extensions/telegram/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/src/workflow-progress.js.map +1 -1
- package/dist/extensions/telegram/xopc.extension.json +10 -2
- package/dist/extensions/weixin/src/api/api.js +2 -2
- package/dist/extensions/weixin/src/auth/accounts.js +1 -1
- package/dist/extensions/weixin/src/cdn/upload.js +1 -1
- package/dist/extensions/weixin/src/cli/gateway-qr-login.d.ts +4 -0
- package/dist/extensions/weixin/src/cli/gateway-qr-login.js +34 -5
- package/dist/extensions/weixin/src/cli/gateway-qr-login.js.map +1 -1
- package/dist/extensions/weixin/src/cli/qr-login.js +4 -3
- package/dist/extensions/weixin/src/cli/qr-login.js.map +1 -1
- package/dist/extensions/weixin/src/media/data-url.js +1 -1
- package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
- package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
- package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
- package/dist/extensions/weixin/src/plugin.d.ts +1 -0
- package/dist/extensions/weixin/src/plugin.js +8 -7
- package/dist/extensions/weixin/src/plugin.js.map +1 -1
- package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
- package/dist/extensions/weixin/src/workflow-progress.d.ts +1 -1
- package/dist/extensions/weixin/src/workflow-progress.js +1 -1
- package/dist/extensions/weixin/src/workflow-progress.js.map +1 -1
- package/dist/extensions/weixin/xopc.extension.json +57 -14
- package/dist/gateway/static/root/apple-touch-icon.png +0 -0
- package/dist/gateway/static/root/assets/agents-BXg2_mE4.js +78 -0
- package/dist/gateway/static/root/assets/apps-page-CJqQ-7Ss.js +1 -0
- package/dist/gateway/static/root/assets/channels-settings-DvMZ6NAd.js +1 -0
- package/dist/gateway/static/root/assets/cron-page-BPBlvSl5.js +1 -0
- package/dist/gateway/static/root/assets/{dist-DJDkNhu5.js → dist-CZh0c-s8.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-DI1XJTJi.js → extension-debug-page-DyJQR0SR.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-SuafGTT_.js → extension-page-CDTuUr9B.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-cKmGax9v.js → extension-settings-page-DszZ8zHD.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-CkvRO30i.js → fetch-CFdKBnE6.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-BkKyRDrF.js → gateway-startup-retry-DdngdObI.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-CRiDcxtt.js → heartbeat-config-api-U10wnPdc.js} +1 -1
- package/dist/gateway/static/root/assets/index-DBc-bVOQ.js +4845 -0
- package/dist/gateway/static/root/assets/index-DI5_GsZt.css +1 -0
- package/dist/gateway/static/root/assets/{logs-page-DM8o5-Bm.js → logs-page-B6js8Bfi.js} +2 -2
- package/dist/gateway/static/root/assets/{note-detail-page-j53jtvq9.js → note-detail-page-DFzAXR35.js} +4 -4
- package/dist/gateway/static/root/assets/{note-time-Ck2H2Qpw.js → note-time-DOiSU-10.js} +1 -1
- package/dist/gateway/static/root/assets/notes-page-DAuZJMT8.js +1 -0
- package/dist/gateway/static/root/assets/{schema-form-BvmGNxiJ.js → schema-form-zM36dvbY.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-CAsV03BY.js +1 -0
- package/dist/gateway/static/root/assets/{settings-advanced-gate-DRdayl8P.js → settings-advanced-gate-BCvObK1y.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-BlIYg2gZ.js → settings-form-section-Bvl-RInc.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-DuCJDd74.js +3 -0
- package/dist/gateway/static/root/assets/{share-preview-page-BlT6Akvk.js → share-preview-page-rpL4DDTO.js} +1 -1
- package/dist/gateway/static/root/assets/skills-page--BioR9J4.js +2 -0
- package/dist/gateway/static/root/assets/{theme-store-DYgVdRB4.js → theme-store-BZozwAeK.js} +1 -1
- package/dist/gateway/static/root/assets/url-DQRqHuL-.js +3 -0
- package/dist/gateway/static/root/assets/voice-api-key-field-D2RJaoj_.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-page.utils-_sjXCMvi.js → workflow-page.utils-BxacHYen.js} +1 -1
- package/dist/gateway/static/root/assets/workflows-page-B1B-est-.js +18 -0
- package/dist/gateway/static/root/favicon-16.png +0 -0
- package/dist/gateway/static/root/favicon-32.png +0 -0
- package/dist/gateway/static/root/favicon.ico +0 -0
- package/dist/gateway/static/root/favicon.svg +18 -0
- package/dist/gateway/static/root/index.html +11 -10
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.js +7 -7
- package/dist/src/agent/agent-scope.js +1 -1
- package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
- package/dist/src/agent/context/workspace-seed.js +2 -2
- package/dist/src/agent/context/workspace-state.js +1 -1
- package/dist/src/agent/goals/goal-run-store.js +4 -4
- package/dist/src/agent/goals/persistent-goal-service.js +1 -1
- package/dist/src/agent/goals/post-turn.js +2 -2
- package/dist/src/agent/image/load-image-media.js +2 -2
- package/dist/src/agent/ipc/bus.js +1 -1
- package/dist/src/agent/ipc/inbox.js +2 -2
- package/dist/src/agent/ipc/socket.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-config.js +16 -8
- package/dist/src/agent/mcp/bundle-mcp-config.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-policy.js +2 -2
- package/dist/src/agent/mcp/bundle-mcp-policy.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js +2 -2
- package/dist/src/agent/mcp/mcp-http.js +1 -1
- package/dist/src/agent/mcp/mcp-http.js.map +1 -1
- package/dist/src/agent/mcp/mcp-transport-config.js +3 -7
- package/dist/src/agent/mcp/mcp-transport-config.js.map +1 -1
- package/dist/src/agent/mcp/mcp-transport.js +1 -1
- package/dist/src/agent/memory/builtin-memory-store.js +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
- package/dist/src/agent/memory/dreaming/events.js +1 -1
- package/dist/src/agent/memory/dreaming/last-run.js +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
- package/dist/src/agent/memory/dreaming/preview.js +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
- package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
- package/dist/src/agent/memory/dreaming/utils.js +1 -1
- package/dist/src/agent/memory/memory-flush.js +1 -1
- package/dist/src/agent/memory/plugin-discovery.js +1 -1
- package/dist/src/agent/models/manager.js +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
- package/dist/src/agent/reply/post-compaction-context.js +1 -1
- package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
- package/dist/src/agent/sandbox/path-policy.js +2 -2
- package/dist/src/agent/service.js +4 -4
- package/dist/src/agent/session/session-inspector.js +1 -1
- package/dist/src/agent/skills/config.js +1 -1
- package/dist/src/agent/skills/hub-hash.js +2 -2
- package/dist/src/agent/skills/hub-lock.js +1 -1
- package/dist/src/agent/skills/hub-pull.js +2 -2
- package/dist/src/agent/skills/index.js +1 -1
- package/dist/src/agent/skills/managed-store.js +1 -1
- package/dist/src/agent/skills/marketplace/adapters/store/store-api-client.d.ts +4 -0
- package/dist/src/agent/skills/marketplace/adapters/store/store-api-client.js +4 -2
- package/dist/src/agent/skills/marketplace/adapters/store/store-api-client.js.map +1 -1
- package/dist/src/agent/skills/scanner.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +1 -1
- package/dist/src/agent/skills/skill-manager.js +1 -1
- package/dist/src/agent/starter-agents.d.ts +19 -0
- package/dist/src/agent/starter-agents.js +190 -0
- package/dist/src/agent/starter-agents.js.map +1 -0
- package/dist/src/agent/tools/dreaming-tool.js +1 -1
- package/dist/src/agent/tools/factory.js +1 -1
- package/dist/src/agent/tools/image-generate-tool.js +1 -1
- package/dist/src/agent/tools/send-media.js +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js +1 -1
- package/dist/src/agent/tools/workflow-tool.js +1 -1
- package/dist/src/agent/tools/write.js +1 -1
- package/dist/src/agent/workflow/catalog.js +1 -1
- package/dist/src/agent/workflow/index.js +2 -1
- package/dist/src/agent/workflow/runtime.d.ts +2 -2
- package/dist/src/agent/workflow/runtime.js +50 -29
- package/dist/src/agent/workflow/runtime.js.map +1 -1
- package/dist/src/agent/workflow/snapshot-empty.d.ts +2 -0
- package/dist/src/agent/workflow/snapshot-empty.js +19 -0
- package/dist/src/agent/workflow/snapshot-empty.js.map +1 -0
- package/dist/src/agent/workflow/snapshot.js +1 -1
- package/dist/src/agent/workflow/snapshot.js.map +1 -1
- package/dist/src/agent/workflow/types.d.ts +11 -0
- package/dist/src/auth/credentials.js +3 -3
- package/dist/src/auth/profiles/store.js +2 -2
- package/dist/src/auth/sync-provider-auth.js +1 -1
- package/dist/src/browser/cache-dir-policy.js +1 -1
- package/dist/src/browser/cdp-local-launcher.js +2 -2
- package/dist/src/browser/providers/browser-ext-install.js +3 -3
- package/dist/src/browser/providers/cloakbrowser.js +4 -4
- package/dist/src/browser/providers/playwright-doctor.js +1 -1
- package/dist/src/browser/stealth.js +1 -1
- package/dist/src/channels/catalog/channel-catalog-service.js +13 -0
- package/dist/src/channels/catalog/channel-catalog-service.js.map +1 -1
- package/dist/src/channels/outbound/persist-store.js +1 -1
- package/dist/src/channels/pairing/allow-from-file.js +1 -1
- package/dist/src/channels/pairing/pairing-store.js +2 -2
- package/dist/src/channels/plugins/types.adapters.d.ts +2 -0
- package/dist/src/chat-commands/agent-edit.js +2 -2
- package/dist/src/chat-commands/builtins/config.js +2 -2
- package/dist/src/chat-commands/context.js +1 -1
- package/dist/src/cli/commands/config.js +1 -1
- package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
- package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
- package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
- package/dist/src/cli/commands/extension-create.d.ts +2 -0
- package/dist/src/cli/commands/extension-create.js +165 -0
- package/dist/src/cli/commands/extension-create.js.map +1 -0
- package/dist/src/cli/commands/extension-dev.js +1 -3
- package/dist/src/cli/commands/extension-dev.js.map +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +105 -81
- package/dist/src/cli/commands/extension-marketplace.js.map +1 -1
- package/dist/src/cli/commands/extension-pack.d.ts +13 -0
- package/dist/src/cli/commands/extension-pack.js +159 -91
- package/dist/src/cli/commands/extension-pack.js.map +1 -1
- package/dist/src/cli/commands/extension.d.ts +2 -0
- package/dist/src/cli/commands/extension.js +375 -3
- package/dist/src/cli/commands/extension.js.map +1 -1
- package/dist/src/cli/commands/gateway/logs.js +1 -1
- package/dist/src/cli/commands/gateway/run-foreground.js +1 -2
- package/dist/src/cli/commands/gateway/run-foreground.js.map +1 -1
- package/dist/src/cli/commands/image.js +1 -1
- package/dist/src/cli/commands/init.js +3 -3
- package/dist/src/cli/commands/models.js +1 -1
- package/dist/src/cli/commands/onboard/model.js +2 -2
- package/dist/src/cli/commands/onboard.js +0 -2
- package/dist/src/cli/commands/onboard.js.map +1 -1
- package/dist/src/cli/commands/setup.js +0 -2
- package/dist/src/cli/commands/setup.js.map +1 -1
- package/dist/src/cli/utils/init-workspace-core.js +10 -7
- package/dist/src/cli/utils/init-workspace-core.js.map +1 -1
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/config/agent-typed-models.js +1 -1
- package/dist/src/config/gateway-bind.js +1 -1
- package/dist/src/config/index.js +5 -5
- package/dist/src/config/loader.js +2 -2
- package/dist/src/config/models-json.js +2 -2
- package/dist/src/config/paths-state.js +1 -1
- package/dist/src/config/paths.d.ts +2 -2
- package/dist/src/config/paths.js +6 -5
- package/dist/src/config/paths.js.map +1 -1
- package/dist/src/config/profile.js +2 -2
- package/dist/src/config/schema.d.ts +2 -0
- package/dist/src/config/schema.js +3 -1
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/workspace-path.js +1 -1
- package/dist/src/connectors/health.js +1 -1
- package/dist/src/connectors/install.js +1 -1
- package/dist/src/cron/executor.js +2 -2
- package/dist/src/cron/persistence.js +1 -1
- package/dist/src/daemon/constants.js +1 -1
- package/dist/src/daemon/install-plan.js +2 -2
- package/dist/src/daemon/launchd.js +2 -2
- package/dist/src/daemon/schtasks.js +2 -2
- package/dist/src/daemon/systemd.js +2 -2
- package/dist/src/extensions/api.d.ts +4 -2
- package/dist/src/extensions/api.js +31 -12
- package/dist/src/extensions/api.js.map +1 -1
- package/dist/src/extensions/bundle-mcp.js +1 -1
- package/dist/src/extensions/discover-extensions.js +2 -1
- package/dist/src/extensions/discover-extensions.js.map +1 -1
- package/dist/src/extensions/health.js +1 -1
- package/dist/src/extensions/install.d.ts +1 -0
- package/dist/src/extensions/install.js +51 -8
- package/dist/src/extensions/install.js.map +1 -1
- package/dist/src/extensions/loader.d.ts +0 -4
- package/dist/src/extensions/loader.js +55 -88
- package/dist/src/extensions/loader.js.map +1 -1
- package/dist/src/extensions/lockfile.d.ts +9 -1
- package/dist/src/extensions/lockfile.js +2 -2
- package/dist/src/extensions/lockfile.js.map +1 -1
- package/dist/src/extensions/normalize-manifest.js +20 -4
- package/dist/src/extensions/normalize-manifest.js.map +1 -1
- package/dist/src/extensions/package-contract.d.ts +12 -0
- package/dist/src/extensions/package-contract.js +59 -0
- package/dist/src/extensions/package-contract.js.map +1 -0
- package/dist/src/extensions/sdk/core.d.ts +1 -1
- package/dist/src/extensions/sdk/index.d.ts +1 -1
- package/dist/src/extensions/sdk/index.js.map +1 -1
- package/dist/src/extensions/types/manifest.d.ts +15 -0
- package/dist/src/extensions/update.js +1 -1
- package/dist/src/gateway/agents-admin.d.ts +0 -8
- package/dist/src/gateway/agents-admin.js +3 -28
- package/dist/src/gateway/agents-admin.js.map +1 -1
- package/dist/src/gateway/file-path-classifier.js +2 -2
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/lib/config-payload.js +1 -1
- package/dist/src/gateway/hono/lib/extension-store.js +2 -2
- package/dist/src/gateway/hono/lib/static-ui.js +2 -2
- package/dist/src/gateway/hono/oauth-async.js +1 -1
- package/dist/src/gateway/hono/oauth.js +1 -1
- package/dist/src/gateway/hono/routes/agents.js +2 -56
- package/dist/src/gateway/hono/routes/agents.js.map +1 -1
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
- package/dist/src/gateway/hono/routes/channels.js +10 -1
- package/dist/src/gateway/hono/routes/channels.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
- package/dist/src/gateway/hono/routes/dreaming.js +1 -1
- package/dist/src/gateway/hono/routes/host-fs.js +2 -2
- package/dist/src/gateway/hono/routes/mcp.js +1 -1
- package/dist/src/gateway/hono/routes/models.js +1 -1
- package/dist/src/gateway/hono/routes/shares.js +1 -1
- package/dist/src/gateway/hono/routes/workflows.js +130 -0
- package/dist/src/gateway/hono/routes/workflows.js.map +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +2 -2
- package/dist/src/gateway/lock.js +3 -3
- package/dist/src/gateway/ports.js +1 -1
- package/dist/src/gateway/service/agent-runner.js +2 -2
- package/dist/src/gateway/service/marketplace-service.js +2 -2
- package/dist/src/gateway/service.d.ts +2 -0
- package/dist/src/gateway/service.js +45 -1
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/workspace-fs-file-list.js +1 -1
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/infra/brew.js +1 -1
- package/dist/src/infra/package-json.js +1 -1
- package/dist/src/infra/package-update-steps.js +1 -1
- package/dist/src/infra/path-env.js +2 -2
- package/dist/src/infra/restart.js +2 -2
- package/dist/src/infra/stable-node-path.js +1 -1
- package/dist/src/infra/update-check.js +1 -1
- package/dist/src/infra/update-global.js +1 -1
- package/dist/src/infra/update-lock.js +3 -3
- package/dist/src/infra/update-runner.js +1 -1
- package/dist/src/infra/update-startup.js +2 -2
- package/dist/src/infra/write-file-atomic.js +2 -2
- package/dist/src/media/store.js +1 -1
- package/dist/src/notes/agent-context.d.ts +12 -4
- package/dist/src/notes/agent-context.js +1 -1
- package/dist/src/notes/agent-context.js.map +1 -1
- package/dist/src/notes/store.js +2 -2
- package/dist/src/project-trust/trust-store.js +2 -2
- package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
- package/dist/src/providers/index.js +2 -2
- package/dist/src/providers/model-registry.js +1 -1
- package/dist/src/session/init-session-turn.js +2 -2
- package/dist/src/session/resolve-session.js +3 -3
- package/dist/src/session/session-title.js +2 -2
- package/dist/src/session/store.js +2 -2
- package/dist/src/share/share-auto.js +2 -2
- package/dist/src/share/share-store.js +3 -3
- package/dist/src/share/share-thumbnail.js +2 -2
- package/dist/src/share/share-zip.js +1 -1
- package/dist/src/share/site-share-store.js +3 -3
- package/dist/src/share/site-static-serve.js +1 -1
- package/dist/src/storage/sqlite/connection.js +2 -2
- package/dist/src/storage/sqlite/memory-index-repository.js +2 -2
- package/dist/src/storage/sqlite/migrations/discover.js +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/tui/backends/embedded-backend.js +1 -8
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.js +0 -7
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/clipboard-image.js +3 -3
- package/dist/src/tui/theme-manager.js +1 -1
- package/dist/src/tui/tui-backend.d.ts +0 -1
- package/dist/src/tui/tui-command-formatters.js +3 -3
- package/dist/src/tui/tui-commands.js +3 -3
- package/dist/src/tui/tui-commands.js.map +1 -1
- package/dist/src/tui/tui-keybindings-file.js +1 -1
- package/dist/src/tui/tui-picker-overlay.js +1 -1
- package/dist/src/tui/tui-picker-overlay.js.map +1 -1
- package/dist/src/tui/tui-scoped-models.js +2 -2
- package/dist/src/tui/tui-settings.js +1 -1
- package/dist/src/tui/tui-startup-resources.js +2 -2
- package/dist/src/tui/tui.js +5 -5
- package/dist/src/tunnel/frpc-binary.js +3 -3
- package/dist/src/tunnel/frpc-config.js +1 -1
- package/dist/src/tunnel/frpc-extract.js +1 -1
- package/dist/src/tunnel/tunnel-state.js +1 -1
- package/dist/src/utils/logger/audit.js +1 -1
- package/dist/src/utils/logger/log-store.js +1 -1
- package/dist/src/utils/logger/rotation.js +1 -1
- package/dist/src/voice/stt/availability.d.ts +6 -0
- package/dist/src/voice/stt/availability.js +14 -6
- package/dist/src/voice/stt/availability.js.map +1 -1
- package/dist/src/voice/stt/index.js +2 -1
- package/dist/src/voice/stt/index.js.map +1 -1
- package/dist/src/voice/stt/mention.d.ts +2 -0
- package/dist/src/voice/stt/mention.js +20 -0
- package/dist/src/voice/stt/mention.js.map +1 -0
- package/dist/src/voice/stt/preflight.d.ts +1 -4
- package/dist/src/voice/stt/preflight.js +1 -18
- package/dist/src/voice/stt/preflight.js.map +1 -1
- package/dist/src/voice/tts/audio.js +1 -1
- package/dist/src/voice/tts/providers/edge-speech.js +2 -2
- package/dist/src/workflows/domain/definition-utils.d.ts +1 -0
- package/dist/src/workflows/domain/definition-utils.js +32 -2
- package/dist/src/workflows/domain/definition-utils.js.map +1 -1
- package/dist/src/workflows/domain/definition.d.ts +2 -0
- package/dist/src/workflows/domain/event.d.ts +2 -1
- package/dist/src/workflows/domain/index.d.ts +1 -0
- package/dist/src/workflows/domain/index.js +3 -2
- package/dist/src/workflows/domain/run.d.ts +27 -1
- package/dist/src/workflows/domain/run.js.map +1 -1
- package/dist/src/workflows/domain/schema-validation.d.ts +8 -0
- package/dist/src/workflows/domain/schema-validation.js +28 -0
- package/dist/src/workflows/domain/schema-validation.js.map +1 -0
- package/dist/src/workflows/draft/index.d.ts +3 -0
- package/dist/src/workflows/draft/index.js +3 -0
- package/dist/src/workflows/draft/workflow-draft-prompt.d.ts +23 -0
- package/dist/src/workflows/draft/workflow-draft-prompt.js +98 -0
- package/dist/src/workflows/draft/workflow-draft-prompt.js.map +1 -0
- package/dist/src/workflows/draft/workflow-draft-service.d.ts +12 -0
- package/dist/src/workflows/draft/workflow-draft-service.js +131 -0
- package/dist/src/workflows/draft/workflow-draft-service.js.map +1 -0
- package/dist/src/workflows/draft/workflow-draft-validator.d.ts +4 -0
- package/dist/src/workflows/draft/workflow-draft-validator.js +133 -0
- package/dist/src/workflows/draft/workflow-draft-validator.js.map +1 -0
- package/dist/src/workflows/draft/workflow-draft.types.d.ts +44 -0
- package/dist/src/workflows/draft/workflow-draft.types.js +1 -0
- package/dist/src/workflows/engine/projector.js +1 -0
- package/dist/src/workflows/engine/projector.js.map +1 -1
- package/dist/src/workflows/engine/workflow-engine.d.ts +18 -0
- package/dist/src/workflows/engine/workflow-engine.js +320 -11
- package/dist/src/workflows/engine/workflow-engine.js.map +1 -1
- package/dist/src/workflows/index.js +4 -3
- package/dist/src/workflows/service/workflow-run-service.d.ts +14 -3
- package/dist/src/workflows/service/workflow-run-service.js +227 -6
- package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
- package/dist/src/workflows/service/workflow-run-service.types.d.ts +7 -2
- package/dist/src/workflows/store/event-store.js +1 -1
- package/dist/src/workflows/store/run-store.js +1 -1
- package/package.json +5 -3
- package/dist/gateway/static/root/assets/agents-XzgIVKcI.js +0 -396
- package/dist/gateway/static/root/assets/apps-page-B7Us3RMl.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-BgeV6fzw.js +0 -1
- package/dist/gateway/static/root/assets/cron-page-DKGHEeAU.js +0 -1
- package/dist/gateway/static/root/assets/index-50FVtgXU.js +0 -4845
- package/dist/gateway/static/root/assets/index-BPYKW7FB.css +0 -1
- package/dist/gateway/static/root/assets/notes-page-CsWIw35Q.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-CLPsbyOW.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-CRGHT_bm.js +0 -3
- package/dist/gateway/static/root/assets/skills-page-Ce-RIH2y.js +0 -2
- package/dist/gateway/static/root/assets/url-DPEStU4M.js +0 -3
- package/dist/gateway/static/root/assets/voice-api-key-field-CJGTidqc.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-o63aaARK.js +0 -27
- package/dist/src/agent/builtin-agent-ids.d.ts +0 -2
- package/dist/src/agent/builtin-agent-ids.js +0 -17
- package/dist/src/agent/builtin-agent-ids.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.js","names":["resolveGlobalExtensionsDir"],"sources":["../../../src/extensions/install.ts"],"sourcesContent":["/**\n * Extension Installation Module\n * Supports installing from npm packages, local directories, and xopc-store zips\n * Supports three-tier storage: workspace, global, bundled\n */\n\nimport { execSync } from 'child_process';\nimport AdmZip from 'adm-zip';\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n cpSync,\n rmSync,\n readdirSync,\n mkdtempSync,\n writeFileSync,\n} from 'fs';\nimport { dirname, join, isAbsolute, resolve, sep } from 'path';\nimport { tmpdir } from 'os';\nimport {\n resolveExtensionsDir as resolveGlobalExtensionsDir,\n resolveBundledExtensionsDir,\n} from '../config/paths.js';\nimport { createLogger } from '../utils/logger.js';\nimport { MAX_EXTENSION_STORE_ZIP_BYTES } from './store-zip-limits.js';\n\nconst log = createLogger('ExtensionInstall');\n\nconst NPM_INSTALL_ENV = process.env.XOPC_EXTENSION_NPM_INSTALL?.trim().toLowerCase();\n\nfunction extractExecSyncOutput(error: unknown): string {\n if (!error || typeof error !== 'object') return '';\n const o = error as { stderr?: Buffer | string; stdout?: Buffer | string; message?: string };\n const read = (x?: Buffer | string | null) => {\n if (x == null) return '';\n return Buffer.isBuffer(x) ? x.toString('utf8') : x;\n };\n const stderr = read(o.stderr).trim();\n const stdout = read(o.stdout).trim();\n if (stderr) return stderr;\n if (stdout) return stdout;\n return typeof o.message === 'string' ? o.message.trim() : '';\n}\n\nfunction truncateOutput(text: string, max = 4500): string {\n const t = text.trim();\n if (t.length <= max) return t;\n return `…${t.slice(-max)}`;\n}\n\n/**\n * Install production `node_modules` for an unpacked extension (package.json dependencies).\n * Uses pnpm when `pnpm-lock.yaml` is present, otherwise npm. Set `XOPC_EXTENSION_NPM_INSTALL=skip`\n * to skip (extensions must ship runnable code or you install deps manually).\n */\nfunction installExtensionProdDependencies(extensionDir: string): { ok: true } | { ok: false; error: string } {\n if (NPM_INSTALL_ENV === 'skip' || NPM_INSTALL_ENV === '0' || NPM_INSTALL_ENV === 'false') {\n log.warn(\n { extensionDir, XOPC_EXTENSION_NPM_INSTALL: process.env.XOPC_EXTENSION_NPM_INSTALL },\n 'Skipping extension dependency install (XOPC_EXTENSION_NPM_INSTALL)',\n );\n return { ok: true };\n }\n\n const execOpts = {\n cwd: extensionDir,\n timeout: 300_000,\n encoding: 'utf-8' as const,\n stdio: ['ignore', 'pipe', 'pipe'] as ('ignore' | 'pipe')[],\n maxBuffer: 20 * 1024 * 1024,\n env: process.env,\n ...(process.platform === 'win32'\n ? { shell: (process.env.ComSpec && process.env.ComSpec.trim()) || 'cmd.exe' }\n : {}),\n };\n\n const run = (label: string, command: string): { ok: true } | { ok: false; error: string } => {\n try {\n execSync(command, execOpts);\n return { ok: true };\n } catch (err) {\n const out = truncateOutput(extractExecSyncOutput(err));\n const hint =\n label === 'npm'\n ? ' Check that Node.js/npm is on PATH, the registry is reachable, and peer/engine rules allow install.'\n : ' Check that pnpm is on PATH or remove pnpm-lock.yaml to use npm instead.';\n return {\n ok: false,\n error: `${label} install failed.${hint}${out ? `\\n\\n${out}` : ''}`,\n };\n }\n };\n\n const usePnpm = existsSync(join(extensionDir, 'pnpm-lock.yaml'));\n if (usePnpm) {\n const pnpm = run('pnpm', 'pnpm install --prod --no-frozen-lockfile');\n if (pnpm.ok) return pnpm;\n const npmFallback = run('npm', 'npm install --omit=dev --no-audit --no-fund');\n if (npmFallback.ok) {\n log.warn({ extensionDir }, 'pnpm failed; extension dependencies installed with npm instead');\n return { ok: true };\n }\n return npmFallback;\n }\n\n return run('npm', 'npm install --omit=dev --no-audit --no-fund');\n}\n\nexport interface InstallOptions {\n source: 'npm' | 'local';\n targetDir: string;\n timeoutMs?: number;\n global?: boolean;\n}\n\nexport interface InstallResult {\n ok: boolean;\n extensionId?: string;\n targetDir?: string;\n origin?: 'workspace' | 'global';\n error?: string;\n}\n\nexport interface ListedExtension {\n id: string;\n name?: string;\n version?: string;\n kind?: string;\n path: string;\n origin: 'workspace' | 'global' | 'bundled';\n}\n\ninterface ExtensionManifest {\n id: string;\n name?: string;\n version?: string;\n main?: string;\n}\n\nfunction isSafeZipPath(name: string): boolean {\n if (!name) return false;\n const normalized = name.replace(/\\\\/g, '/');\n if (normalized.includes('..')) return false;\n if (normalized.startsWith('/') || /^\\w:/.test(normalized)) return false;\n for (const p of normalized.split('/')) {\n if (p === '..') return false;\n }\n return true;\n}\n\nfunction isIgnorableZipEntry(name: string): boolean {\n const n = name.replace(/\\\\/g, '/');\n if (n.startsWith('__MACOSX/')) return true;\n const segments = n.split('/').filter(Boolean);\n for (const s of segments) {\n if (s === '.DS_Store' || s === 'Thumbs.db' || s === 'desktop.ini') return true;\n if (s.startsWith('._')) return true;\n }\n return false;\n}\n\nfunction inferExtensionStripPrefix(primaryManifestPath: string): string {\n const norm = primaryManifestPath.replace(/\\\\/g, '/');\n const lower = norm.toLowerCase();\n const suff = 'xopc.extension.json';\n if (lower === suff) return '';\n if (!lower.endsWith(suff)) return '';\n return norm.slice(0, norm.length - suff.length);\n}\n\n/** Read `id` from the shallowest xopc.extension.json in a store zip (for --force / preflight). */\nexport function peekExtensionIdFromStoreZip(buffer: Buffer): string | undefined {\n if (buffer.length > MAX_EXTENSION_STORE_ZIP_BYTES) return undefined;\n let zip: AdmZip;\n try {\n zip = new AdmZip(buffer);\n } catch {\n return undefined;\n }\n const entries = zip\n .getEntries()\n .filter((e) => !e.isDirectory && e.entryName && !isIgnorableZipEntry(e.entryName));\n const safeEntries = entries.filter((e) => isSafeZipPath(e.entryName));\n const names = safeEntries.map((e) => e.entryName.replace(/\\\\/g, '/'));\n const manifestPaths = names.filter((n) => /(^|\\/)xopc\\.extension\\.json$/i.test(n));\n const shallow = manifestPaths.filter((n) => n.split('/').filter(Boolean).length <= 2);\n if (shallow.length === 0) return undefined;\n shallow.sort((a, b) => a.length - b.length);\n const path = shallow[0];\n const entry = safeEntries.find((e) => e.entryName.replace(/\\\\/g, '/') === path);\n if (!entry) return undefined;\n try {\n const raw = entry.getData().toString('utf8');\n const m = JSON.parse(raw) as { id?: string };\n const id = typeof m.id === 'string' ? m.id.trim() : '';\n if (!id || id.includes('/') || id.includes('\\\\')) return undefined;\n return id;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Install an extension from an xopc-store zip buffer (layout: manifest at archive root\n * or under a single top-level folder).\n */\nexport async function installExtensionFromStoreZip(\n buffer: Buffer,\n extensionsDir: string,\n): Promise<InstallResult> {\n if (buffer.length > MAX_EXTENSION_STORE_ZIP_BYTES) {\n return {\n ok: false,\n error: `Extension zip exceeds maximum size (${MAX_EXTENSION_STORE_ZIP_BYTES} bytes)`,\n };\n }\n\n const zip = new AdmZip(buffer);\n const entries = zip\n .getEntries()\n .filter((e) => !e.isDirectory && e.entryName && !isIgnorableZipEntry(e.entryName));\n const safeEntries = entries.filter((e) => isSafeZipPath(e.entryName));\n if (safeEntries.length === 0) {\n return { ok: false, error: 'Zip is empty or invalid' };\n }\n\n const names = safeEntries.map((e) => e.entryName.replace(/\\\\/g, '/'));\n const manifestPaths = names.filter((n) => /(^|\\/)xopc\\.extension\\.json$/i.test(n));\n if (manifestPaths.length === 0) {\n return { ok: false, error: 'Zip must contain xopc.extension.json' };\n }\n const shallow = manifestPaths.filter((n) => n.split('/').filter(Boolean).length <= 2);\n if (shallow.length === 0) {\n return {\n ok: false,\n error:\n 'xopc.extension.json is nested too deeply; use a zip with manifest at archive root or one folder (e.g. my-ext/xopc.extension.json)',\n };\n }\n shallow.sort((a, b) => a.length - b.length);\n const stripPrefix = inferExtensionStripPrefix(shallow[0]);\n if (stripPrefix) {\n const prefixNorm = stripPrefix.replace(/\\\\/g, '/');\n const outside = names.filter((n) => !n.startsWith(prefixNorm) && !isIgnorableZipEntry(n));\n if (outside.length > 0) {\n return {\n ok: false,\n error: `Invalid zip: expected all files under \"${prefixNorm.replace(/\\/$/, '')}/\", but found \"${outside[0]}\".`,\n };\n }\n }\n\n const tmpRoot = mkdtempSync(join(tmpdir(), 'xopc-ext-zip-'));\n const destResolved = resolve(tmpRoot);\n try {\n for (const e of safeEntries) {\n const norm = e.entryName.replace(/\\\\/g, '/');\n let rel: string;\n if (stripPrefix) {\n const prefixNorm = stripPrefix.replace(/\\\\/g, '/');\n if (!norm.startsWith(prefixNorm)) {\n return {\n ok: false,\n error: `Zip entry outside extension prefix \"${prefixNorm.replace(/\\/$/, '')}\": ${norm}`,\n };\n }\n rel = norm.slice(prefixNorm.length).replace(/^\\//, '');\n } else {\n rel = norm;\n }\n if (!rel || rel.includes('..')) {\n return { ok: false, error: `Refusing unsafe zip entry path: ${e.entryName}` };\n }\n const targetPath = join(tmpRoot, rel);\n const resolvedTarget = resolve(targetPath);\n if (!resolvedTarget.startsWith(destResolved + sep) && resolvedTarget !== destResolved) {\n return {\n ok: false,\n error: `Refusing unsafe zip path (possible traversal): ${e.entryName}`,\n };\n }\n mkdirSync(dirname(targetPath), { recursive: true });\n writeFileSync(targetPath, e.getData());\n }\n\n if (!existsSync(join(tmpRoot, 'xopc.extension.json'))) {\n return { ok: false, error: 'Extracted content is missing xopc.extension.json' };\n }\n\n return await installFromDirectory(tmpRoot, extensionsDir);\n } finally {\n try {\n rmSync(tmpRoot, { recursive: true, force: true });\n } catch {\n // ignore\n }\n }\n}\n\n/**\n * Resolve target extensions directory based on options\n */\nexport function resolveExtensionsDir(\n workspaceDir: string,\n global = false,\n): string {\n if (global) {\n const globalDir = resolveGlobalExtensionsDir();\n mkdirSync(globalDir, { recursive: true });\n return globalDir;\n }\n return join(workspaceDir, '.extensions');\n}\n\n/**\n * Install extension from npm package\n */\nexport async function installFromNpm(\n packageSpec: string,\n extensionsDir: string,\n timeoutMs = 120000,\n): Promise<InstallResult> {\n const tmpDir = join(tmpdir(), `xopc-install-${Date.now()}`);\n\n try {\n console.log(`📦 Downloading ${packageSpec} from npm...`);\n\n // Create temp directory\n mkdirSync(tmpDir, { recursive: true });\n\n // Use npm pack to download package\n const result = execSync(`npm pack ${packageSpec} --pack-destination ${tmpDir}`, {\n timeout: timeoutMs,\n encoding: 'utf-8',\n stdio: 'pipe',\n });\n\n const packedFile = result.trim().split('\\n').pop()?.trim();\n if (!packedFile) {\n return { ok: false, error: 'Failed to download package from npm' };\n }\n\n const archivePath = join(tmpDir, packedFile);\n\n // Extract tarball\n console.log(`📂 Extracting ${packedFile}...`);\n execSync(`tar -xzf ${archivePath} -C ${tmpDir}`, {\n timeout: 30000,\n stdio: 'pipe',\n });\n\n // npm pack extracts to 'package' directory\n const extractDir = join(tmpDir, 'package');\n\n // Validate and install\n return await installFromDirectory(extractDir, extensionsDir);\n } catch (error) {\n return {\n ok: false,\n error: `Failed to install from npm: ${error instanceof Error ? error.message : String(error)}`,\n };\n } finally {\n // Cleanup temp directory\n try {\n rmSync(tmpDir, { recursive: true, force: true });\n } catch {\n // Ignore cleanup errors\n }\n }\n}\n\n/**\n * Install extension from local directory\n */\nexport async function installFromLocal(\n localPath: string,\n extensionsDir: string,\n): Promise<InstallResult> {\n // Resolve to absolute path\n const sourceDir = isAbsolute(localPath) ? localPath : resolve(process.cwd(), localPath);\n\n if (!existsSync(sourceDir)) {\n return { ok: false, error: `Directory not found: ${sourceDir}` };\n }\n\n console.log(`📂 Installing from local directory: ${sourceDir}...`);\n\n return await installFromDirectory(sourceDir, extensionsDir);\n}\n\n/**\n * Install extension from extracted directory\n */\nasync function installFromDirectory(\n sourceDir: string,\n extensionsDir: string,\n): Promise<InstallResult> {\n // Validate manifest\n const manifestPath = join(sourceDir, 'xopc.extension.json');\n const packagePath = join(sourceDir, 'package.json');\n\n let manifest: ExtensionManifest | null = null;\n let packageJson: { name?: string; version?: string; dependencies?: Record<string, string> } | null =\n null;\n\n // Try to load xopc.extension.json first\n if (existsSync(manifestPath)) {\n try {\n manifest = JSON.parse(readFileSync(manifestPath, 'utf-8')) as ExtensionManifest;\n } catch {\n return { ok: false, error: 'Invalid xopc.extension.json manifest file' };\n }\n }\n\n // Also try package.json for metadata\n if (existsSync(packagePath)) {\n try {\n packageJson = JSON.parse(readFileSync(packagePath, 'utf-8')) as typeof packageJson;\n } catch {\n // Ignore package.json parse errors\n }\n }\n\n // Determine extension ID\n const extensionId = manifest?.id || packageJson?.name;\n if (!extensionId) {\n return {\n ok: false,\n error: 'Extension must have an id in xopc.extension.json or name in package.json',\n };\n }\n\n // Validate extension ID (no path separators)\n if (extensionId.includes('/') || extensionId.includes('\\\\')) {\n return { ok: false, error: 'Extension ID cannot contain path separators' };\n }\n\n // Check if already exists\n const targetDir = join(extensionsDir, extensionId);\n if (existsSync(targetDir)) {\n return { ok: false, error: `Extension already exists at ${targetDir}. Use update instead.` };\n }\n\n // Validate main entry exists\n const mainFile = manifest?.main || 'index.js';\n const mainPath = join(sourceDir, mainFile);\n if (!existsSync(mainPath)) {\n return { ok: false, error: `Main entry not found: ${mainFile}` };\n }\n\n console.log(`📋 Extension: ${manifest?.name || extensionId} (${extensionId})`);\n if (manifest?.version || packageJson?.version) {\n console.log(`🔖 Version: ${manifest?.version || packageJson?.version}`);\n }\n\n // Create target directory\n mkdirSync(targetDir, { recursive: true });\n\n // Copy files\n console.log(`📂 Copying files to ${targetDir}...`);\n cpSync(sourceDir, targetDir, { recursive: true, force: true });\n\n // Install dependencies if package.json exists and has dependencies\n if (packageJson?.dependencies && Object.keys(packageJson.dependencies).length > 0) {\n console.log(`📦 Installing dependencies...`);\n const depResult = installExtensionProdDependencies(targetDir);\n if (depResult.ok === false) {\n rmSync(targetDir, { recursive: true, force: true });\n return { ok: false, error: depResult.error };\n }\n }\n\n const origin = extensionsDir.includes('.xopc/extensions') ? 'global' : 'workspace';\n\n console.log(`✅ Extension ${extensionId} installed successfully!`);\n console.log(`\\nTo enable the extension, add to your config:`);\n console.log(` extensions:`);\n console.log(` enabled: [${extensionId}]`);\n console.log(` ${extensionId}:`);\n console.log(` # your extension options here\\n`);\n\n return { ok: true, extensionId, targetDir, origin };\n}\n\n/**\n * Remove installed extension from all tiers\n */\nexport function removeExtension(\n extensionId: string,\n workspaceDir: string,\n): { ok: boolean; removedFrom?: string; error?: string } {\n // Try workspace first\n const workspaceDir_ = join(workspaceDir, '.extensions');\n const workspaceExtension = join(workspaceDir_, extensionId);\n\n if (existsSync(workspaceExtension)) {\n try {\n rmSync(workspaceExtension, { recursive: true, force: true });\n return { ok: true, removedFrom: 'workspace' };\n } catch (error) {\n return {\n ok: false,\n error: `Failed to remove from workspace: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n }\n\n // Try global\n const globalDir = resolveGlobalExtensionsDir();\n const globalExtension = join(globalDir, extensionId);\n\n if (existsSync(globalExtension)) {\n try {\n rmSync(globalExtension, { recursive: true, force: true });\n return { ok: true, removedFrom: 'global' };\n } catch (error) {\n return {\n ok: false,\n error: `Failed to remove from global: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n }\n\n return { ok: false, error: `Extension not found: ${extensionId}` };\n}\n\n/**\n * List installed extensions from all tiers\n */\nexport function listAllExtensions(workspaceDir: string): ListedExtension[] {\n const extensions: ListedExtension[] = [];\n const seen = new Set<string>();\n\n // Priority 1: Workspace (highest)\n const workspaceExtensionsDir = join(workspaceDir, '.extensions');\n if (existsSync(workspaceExtensionsDir)) {\n for (const entry of readdirSync(workspaceExtensionsDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n\n const extensionDir = join(workspaceExtensionsDir, entry.name);\n const manifest = readManifest(extensionDir);\n\n if (manifest) {\n seen.add(entry.name);\n extensions.push({\n id: entry.name,\n name: manifest.name,\n version: manifest.version,\n path: extensionDir,\n origin: 'workspace',\n });\n }\n }\n }\n\n // Priority 2: Global\n const globalDir = resolveGlobalExtensionsDir();\n if (existsSync(globalDir)) {\n for (const entry of readdirSync(globalDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n if (seen.has(entry.name)) continue; // Skip if already in workspace\n\n const extensionDir = join(globalDir, entry.name);\n const manifest = readManifest(extensionDir);\n\n if (manifest) {\n seen.add(entry.name);\n extensions.push({\n id: entry.name,\n name: manifest.name,\n version: manifest.version,\n path: extensionDir,\n origin: 'global',\n });\n }\n }\n }\n\n // Priority 3: Bundled (lowest)\n const bundledDir = resolveBundledExtensionsDir();\n if (bundledDir && existsSync(bundledDir)) {\n for (const entry of readdirSync(bundledDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n if (seen.has(entry.name)) continue;\n\n const extensionDir = join(bundledDir, entry.name);\n const manifest = readManifest(extensionDir);\n\n if (manifest) {\n extensions.push({\n id: entry.name,\n name: manifest.name,\n version: manifest.version,\n path: extensionDir,\n origin: 'bundled',\n });\n }\n }\n }\n\n return extensions;\n}\n\nfunction readManifest(extensionDir: string): ExtensionManifest | null {\n const manifestPath = join(extensionDir, 'xopc.extension.json');\n\n if (!existsSync(manifestPath)) {\n // Try package.json\n const packagePath = join(extensionDir, 'package.json');\n if (existsSync(packagePath)) {\n try {\n const pkg = JSON.parse(readFileSync(packagePath, 'utf-8'));\n return {\n id: pkg.name,\n name: pkg.xopc?.extension?.name || pkg.name,\n version: pkg.version,\n };\n } catch {\n return null;\n }\n }\n return null;\n }\n\n try {\n return JSON.parse(readFileSync(manifestPath, 'utf-8')) as ExtensionManifest;\n } catch {\n return null;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"install.js","names":["resolveGlobalExtensionsDir"],"sources":["../../../src/extensions/install.ts"],"sourcesContent":["/**\n * Extension Installation Module\n * Supports installing from npm packages, local directories, and xopc-store zips\n * Supports three-tier storage: workspace, global, bundled\n */\n\nimport { execSync } from 'child_process';\nimport AdmZip from 'adm-zip';\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n cpSync,\n rmSync,\n readdirSync,\n mkdtempSync,\n writeFileSync,\n} from 'fs';\nimport { dirname, join, isAbsolute, resolve, sep } from 'path';\nimport { tmpdir } from 'os';\nimport {\n resolveExtensionsDir as resolveGlobalExtensionsDir,\n resolveBundledExtensionsDir,\n} from '../config/paths.js';\nimport { PACKAGE_VERSION } from '../package-version.js';\nimport { createLogger } from '../utils/logger.js';\nimport { checkEngineCompatibility } from './engine-check.js';\nimport { collectExtensionPackageDependencyIssues } from './package-contract.js';\nimport { MAX_EXTENSION_STORE_ZIP_BYTES } from './store-zip-limits.js';\n\nconst log = createLogger('ExtensionInstall');\n\nconst NPM_INSTALL_ENV = process.env.XOPC_EXTENSION_NPM_INSTALL?.trim().toLowerCase();\n\nfunction extractExecSyncOutput(error: unknown): string {\n if (!error || typeof error !== 'object') return '';\n const o = error as { stderr?: Buffer | string; stdout?: Buffer | string; message?: string };\n const read = (x?: Buffer | string | null) => {\n if (x == null) return '';\n return Buffer.isBuffer(x) ? x.toString('utf8') : x;\n };\n const stderr = read(o.stderr).trim();\n const stdout = read(o.stdout).trim();\n if (stderr) return stderr;\n if (stdout) return stdout;\n return typeof o.message === 'string' ? o.message.trim() : '';\n}\n\nfunction truncateOutput(text: string, max = 4500): string {\n const t = text.trim();\n if (t.length <= max) return t;\n return `…${t.slice(-max)}`;\n}\n\n/**\n * Install production `node_modules` for an unpacked extension (package.json dependencies).\n * Uses pnpm when `pnpm-lock.yaml` is present, otherwise npm. Set `XOPC_EXTENSION_NPM_INSTALL=skip`\n * to skip (extensions must ship runnable code or you install deps manually).\n */\nfunction installExtensionProdDependencies(extensionDir: string): { ok: true } | { ok: false; error: string } {\n if (NPM_INSTALL_ENV === 'skip' || NPM_INSTALL_ENV === '0' || NPM_INSTALL_ENV === 'false') {\n log.warn(\n { extensionDir, XOPC_EXTENSION_NPM_INSTALL: process.env.XOPC_EXTENSION_NPM_INSTALL },\n 'Skipping extension dependency install (XOPC_EXTENSION_NPM_INSTALL)',\n );\n return { ok: true };\n }\n\n const execOpts = {\n cwd: extensionDir,\n timeout: 300_000,\n encoding: 'utf-8' as const,\n stdio: ['ignore', 'pipe', 'pipe'] as ('ignore' | 'pipe')[],\n maxBuffer: 20 * 1024 * 1024,\n env: process.env,\n ...(process.platform === 'win32'\n ? { shell: (process.env.ComSpec && process.env.ComSpec.trim()) || 'cmd.exe' }\n : {}),\n };\n\n const run = (label: string, command: string): { ok: true } | { ok: false; error: string } => {\n try {\n execSync(command, execOpts);\n return { ok: true };\n } catch (err) {\n const out = truncateOutput(extractExecSyncOutput(err));\n const hint =\n label === 'npm'\n ? ' Check that Node.js/npm is on PATH, the registry is reachable, and peer/engine rules allow install.'\n : ' Check that pnpm is on PATH or remove pnpm-lock.yaml to use npm instead.';\n return {\n ok: false,\n error: `${label} install failed.${hint}${out ? `\\n\\n${out}` : ''}`,\n };\n }\n };\n\n const usePnpm = existsSync(join(extensionDir, 'pnpm-lock.yaml'));\n if (usePnpm) {\n const pnpm = run('pnpm', 'pnpm install --prod --no-frozen-lockfile');\n if (pnpm.ok) return pnpm;\n const npmFallback = run('npm', 'npm install --omit=dev --no-audit --no-fund');\n if (npmFallback.ok) {\n log.warn({ extensionDir }, 'pnpm failed; extension dependencies installed with npm instead');\n return { ok: true };\n }\n return npmFallback;\n }\n\n return run('npm', 'npm install --omit=dev --no-audit --no-fund');\n}\n\nexport interface InstallOptions {\n source: 'npm' | 'local';\n targetDir: string;\n timeoutMs?: number;\n global?: boolean;\n}\n\nexport interface InstallResult {\n ok: boolean;\n extensionId?: string;\n targetDir?: string;\n origin?: 'workspace' | 'global';\n error?: string;\n}\n\nexport interface ListedExtension {\n id: string;\n name?: string;\n version?: string;\n kind?: string;\n path: string;\n origin: 'workspace' | 'global' | 'bundled';\n}\n\ninterface ExtensionManifest {\n id: string;\n name?: string;\n version?: string;\n main?: string;\n engines?: {\n xopc?: string;\n extensionApi?: string;\n extensionUiApi?: string;\n };\n}\n\nfunction isSafeZipPath(name: string): boolean {\n if (!name) return false;\n const normalized = name.replace(/\\\\/g, '/');\n if (normalized.includes('..')) return false;\n if (normalized.startsWith('/') || /^\\w:/.test(normalized)) return false;\n for (const p of normalized.split('/')) {\n if (p === '..') return false;\n }\n return true;\n}\n\nfunction isIgnorableZipEntry(name: string): boolean {\n const n = name.replace(/\\\\/g, '/');\n if (n.startsWith('__MACOSX/')) return true;\n const segments = n.split('/').filter(Boolean);\n for (const s of segments) {\n if (s === '.DS_Store' || s === 'Thumbs.db' || s === 'desktop.ini') return true;\n if (s.startsWith('._')) return true;\n }\n return false;\n}\n\nfunction inferExtensionStripPrefix(primaryManifestPath: string): string {\n const norm = primaryManifestPath.replace(/\\\\/g, '/');\n const lower = norm.toLowerCase();\n const suff = 'xopc.extension.json';\n if (lower === suff) return '';\n if (!lower.endsWith(suff)) return '';\n return norm.slice(0, norm.length - suff.length);\n}\n\nfunction readShallowestExtensionManifestFromZip(buffer: Buffer): Record<string, unknown> | undefined {\n if (buffer.length > MAX_EXTENSION_STORE_ZIP_BYTES) return undefined;\n let zip: AdmZip;\n try {\n zip = new AdmZip(buffer);\n } catch {\n return undefined;\n }\n const entries = zip\n .getEntries()\n .filter((e) => !e.isDirectory && e.entryName && !isIgnorableZipEntry(e.entryName));\n const safeEntries = entries.filter((e) => isSafeZipPath(e.entryName));\n const names = safeEntries.map((e) => e.entryName.replace(/\\\\/g, '/'));\n const manifestPaths = names.filter((n) => /(^|\\/)xopc\\.extension\\.json$/i.test(n));\n const shallow = manifestPaths.filter((n) => n.split('/').filter(Boolean).length <= 2);\n if (shallow.length === 0) return undefined;\n shallow.sort((a, b) => a.length - b.length);\n const path = shallow[0];\n const entry = safeEntries.find((e) => e.entryName.replace(/\\\\/g, '/') === path);\n if (!entry) return undefined;\n try {\n const raw = entry.getData().toString('utf8');\n const parsed = JSON.parse(raw) as unknown;\n return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function peekExtensionManifestFromStoreZip(buffer: Buffer): Record<string, unknown> | undefined {\n return readShallowestExtensionManifestFromZip(buffer);\n}\n\n/** Read `id` from the shallowest xopc.extension.json in a store zip (for --force / preflight). */\nexport function peekExtensionIdFromStoreZip(buffer: Buffer): string | undefined {\n const m = readShallowestExtensionManifestFromZip(buffer) as { id?: string } | undefined;\n const id = typeof m?.id === 'string' ? m.id.trim() : '';\n if (!id || id.includes('/') || id.includes('\\\\')) return undefined;\n return id;\n}\n\n/**\n * Install an extension from an xopc-store zip buffer (layout: manifest at archive root\n * or under a single top-level folder).\n */\nexport async function installExtensionFromStoreZip(\n buffer: Buffer,\n extensionsDir: string,\n): Promise<InstallResult> {\n if (buffer.length > MAX_EXTENSION_STORE_ZIP_BYTES) {\n return {\n ok: false,\n error: `Extension zip exceeds maximum size (${MAX_EXTENSION_STORE_ZIP_BYTES} bytes)`,\n };\n }\n\n const zip = new AdmZip(buffer);\n const entries = zip\n .getEntries()\n .filter((e) => !e.isDirectory && e.entryName && !isIgnorableZipEntry(e.entryName));\n const safeEntries = entries.filter((e) => isSafeZipPath(e.entryName));\n if (safeEntries.length === 0) {\n return { ok: false, error: 'Zip is empty or invalid' };\n }\n\n const names = safeEntries.map((e) => e.entryName.replace(/\\\\/g, '/'));\n const manifestPaths = names.filter((n) => /(^|\\/)xopc\\.extension\\.json$/i.test(n));\n if (manifestPaths.length === 0) {\n return { ok: false, error: 'Zip must contain xopc.extension.json' };\n }\n const shallow = manifestPaths.filter((n) => n.split('/').filter(Boolean).length <= 2);\n if (shallow.length === 0) {\n return {\n ok: false,\n error:\n 'xopc.extension.json is nested too deeply; use a zip with manifest at archive root or one folder (e.g. my-ext/xopc.extension.json)',\n };\n }\n shallow.sort((a, b) => a.length - b.length);\n const stripPrefix = inferExtensionStripPrefix(shallow[0]);\n if (stripPrefix) {\n const prefixNorm = stripPrefix.replace(/\\\\/g, '/');\n const outside = names.filter((n) => !n.startsWith(prefixNorm) && !isIgnorableZipEntry(n));\n if (outside.length > 0) {\n return {\n ok: false,\n error: `Invalid zip: expected all files under \"${prefixNorm.replace(/\\/$/, '')}/\", but found \"${outside[0]}\".`,\n };\n }\n }\n\n const tmpRoot = mkdtempSync(join(tmpdir(), 'xopc-ext-zip-'));\n const destResolved = resolve(tmpRoot);\n try {\n for (const e of safeEntries) {\n const norm = e.entryName.replace(/\\\\/g, '/');\n let rel: string;\n if (stripPrefix) {\n const prefixNorm = stripPrefix.replace(/\\\\/g, '/');\n if (!norm.startsWith(prefixNorm)) {\n return {\n ok: false,\n error: `Zip entry outside extension prefix \"${prefixNorm.replace(/\\/$/, '')}\": ${norm}`,\n };\n }\n rel = norm.slice(prefixNorm.length).replace(/^\\//, '');\n } else {\n rel = norm;\n }\n if (!rel || rel.includes('..')) {\n return { ok: false, error: `Refusing unsafe zip entry path: ${e.entryName}` };\n }\n const targetPath = join(tmpRoot, rel);\n const resolvedTarget = resolve(targetPath);\n if (!resolvedTarget.startsWith(destResolved + sep) && resolvedTarget !== destResolved) {\n return {\n ok: false,\n error: `Refusing unsafe zip path (possible traversal): ${e.entryName}`,\n };\n }\n mkdirSync(dirname(targetPath), { recursive: true });\n writeFileSync(targetPath, e.getData());\n }\n\n if (!existsSync(join(tmpRoot, 'xopc.extension.json'))) {\n return { ok: false, error: 'Extracted content is missing xopc.extension.json' };\n }\n\n return await installFromDirectory(tmpRoot, extensionsDir);\n } finally {\n try {\n rmSync(tmpRoot, { recursive: true, force: true });\n } catch {\n // ignore\n }\n }\n}\n\n/**\n * Resolve target extensions directory based on options\n */\nexport function resolveExtensionsDir(\n workspaceDir: string,\n global = false,\n): string {\n if (global) {\n const globalDir = resolveGlobalExtensionsDir();\n mkdirSync(globalDir, { recursive: true });\n return globalDir;\n }\n return join(workspaceDir, '.extensions');\n}\n\n/**\n * Install extension from npm package\n */\nexport async function installFromNpm(\n packageSpec: string,\n extensionsDir: string,\n timeoutMs = 120000,\n): Promise<InstallResult> {\n const tmpDir = join(tmpdir(), `xopc-install-${Date.now()}`);\n\n try {\n console.log(`📦 Downloading ${packageSpec} from npm...`);\n\n // Create temp directory\n mkdirSync(tmpDir, { recursive: true });\n\n // Use npm pack to download package\n const result = execSync(`npm pack ${packageSpec} --pack-destination ${tmpDir}`, {\n timeout: timeoutMs,\n encoding: 'utf-8',\n stdio: 'pipe',\n });\n\n const packedFile = result.trim().split('\\n').pop()?.trim();\n if (!packedFile) {\n return { ok: false, error: 'Failed to download package from npm' };\n }\n\n const archivePath = join(tmpDir, packedFile);\n\n // Extract tarball\n console.log(`📂 Extracting ${packedFile}...`);\n execSync(`tar -xzf ${archivePath} -C ${tmpDir}`, {\n timeout: 30000,\n stdio: 'pipe',\n });\n\n // npm pack extracts to 'package' directory\n const extractDir = join(tmpDir, 'package');\n\n // Validate and install\n return await installFromDirectory(extractDir, extensionsDir);\n } catch (error) {\n return {\n ok: false,\n error: `Failed to install from npm: ${error instanceof Error ? error.message : String(error)}`,\n };\n } finally {\n // Cleanup temp directory\n try {\n rmSync(tmpDir, { recursive: true, force: true });\n } catch {\n // Ignore cleanup errors\n }\n }\n}\n\n/**\n * Install extension from local directory\n */\nexport async function installFromLocal(\n localPath: string,\n extensionsDir: string,\n): Promise<InstallResult> {\n // Resolve to absolute path\n const sourceDir = isAbsolute(localPath) ? localPath : resolve(process.cwd(), localPath);\n\n if (!existsSync(sourceDir)) {\n return { ok: false, error: `Directory not found: ${sourceDir}` };\n }\n\n console.log(`📂 Installing from local directory: ${sourceDir}...`);\n\n return await installFromDirectory(sourceDir, extensionsDir);\n}\n\n/**\n * Install extension from extracted directory\n */\nasync function installFromDirectory(\n sourceDir: string,\n extensionsDir: string,\n): Promise<InstallResult> {\n // Validate manifest\n const manifestPath = join(sourceDir, 'xopc.extension.json');\n const packagePath = join(sourceDir, 'package.json');\n\n let manifest: ExtensionManifest | null = null;\n let packageJson: { name?: string; version?: string; dependencies?: Record<string, string> } | null =\n null;\n\n // Try to load xopc.extension.json first\n if (existsSync(manifestPath)) {\n try {\n manifest = JSON.parse(readFileSync(manifestPath, 'utf-8')) as ExtensionManifest;\n } catch {\n return { ok: false, error: 'Invalid xopc.extension.json manifest file' };\n }\n }\n\n // Also try package.json for metadata\n if (existsSync(packagePath)) {\n try {\n packageJson = JSON.parse(readFileSync(packagePath, 'utf-8')) as typeof packageJson;\n } catch {\n // Ignore package.json parse errors\n }\n }\n\n if (packageJson) {\n const packageIssues = collectExtensionPackageDependencyIssues(\n packageJson as Record<string, unknown>,\n { strictRuntimeSdkDeps: true },\n );\n if (packageIssues.length > 0) {\n return {\n ok: false,\n error: `Extension package is not installable as an independent package:\\n${packageIssues\n .map((issue) => `- ${issue.message}`)\n .join('\\n')}`,\n };\n }\n }\n\n // Determine extension ID\n const extensionId = manifest?.id || packageJson?.name;\n if (!extensionId) {\n return {\n ok: false,\n error: 'Extension must have an id in xopc.extension.json or name in package.json',\n };\n }\n\n // Validate extension ID (no path separators)\n if (extensionId.includes('/') || extensionId.includes('\\\\')) {\n return { ok: false, error: 'Extension ID cannot contain path separators' };\n }\n\n // Check if already exists\n const targetDir = join(extensionsDir, extensionId);\n if (existsSync(targetDir)) {\n return { ok: false, error: `Extension already exists at ${targetDir}. Use update instead.` };\n }\n\n if (!manifest) {\n return { ok: false, error: 'Extension must include xopc.extension.json' };\n }\n\n if (!manifest.engines?.xopc) {\n return { ok: false, error: 'Extension manifest must declare engines.xopc' };\n }\n const engineCheck = checkEngineCompatibility(PACKAGE_VERSION, manifest.engines.xopc);\n if (engineCheck.parseWarning) {\n return {\n ok: false,\n error: engineCheck.reason ?? `Could not parse engines.xopc ${manifest.engines.xopc}`,\n };\n }\n if (!engineCheck.compatible) {\n return {\n ok: false,\n error: engineCheck.reason ?? `xopc ${PACKAGE_VERSION} does not satisfy engines.xopc ${manifest.engines.xopc}`,\n };\n }\n\n if (!manifest.main) {\n return { ok: false, error: 'Extension manifest must declare main' };\n }\n\n if (!/\\.(mjs|cjs|js)$/i.test(manifest.main)) {\n return {\n ok: false,\n error: `Extension main must point at built JavaScript (.js/.mjs/.cjs), got: ${manifest.main}`,\n };\n }\n\n // Validate main entry exists\n const mainFile = manifest.main;\n const mainPath = join(sourceDir, mainFile);\n if (!existsSync(mainPath)) {\n return { ok: false, error: `Main entry not found: ${mainFile}` };\n }\n\n console.log(`📋 Extension: ${manifest?.name || extensionId} (${extensionId})`);\n if (manifest?.version || packageJson?.version) {\n console.log(`🔖 Version: ${manifest?.version || packageJson?.version}`);\n }\n\n // Create target directory\n mkdirSync(targetDir, { recursive: true });\n\n // Copy files\n console.log(`📂 Copying files to ${targetDir}...`);\n cpSync(sourceDir, targetDir, { recursive: true, force: true });\n\n // Install dependencies if package.json exists and has dependencies\n if (packageJson?.dependencies && Object.keys(packageJson.dependencies).length > 0) {\n console.log(`📦 Installing dependencies...`);\n const depResult = installExtensionProdDependencies(targetDir);\n if (depResult.ok === false) {\n rmSync(targetDir, { recursive: true, force: true });\n return { ok: false, error: depResult.error };\n }\n }\n\n const origin = extensionsDir.includes('.xopc/extensions') ? 'global' : 'workspace';\n\n console.log(`✅ Extension ${extensionId} installed successfully!`);\n console.log(`\\nTo enable the extension, add to your config:`);\n console.log(` extensions:`);\n console.log(` enabled: [${extensionId}]`);\n console.log(` ${extensionId}:`);\n console.log(` # your extension options here\\n`);\n\n return { ok: true, extensionId, targetDir, origin };\n}\n\n/**\n * Remove installed extension from all tiers\n */\nexport function removeExtension(\n extensionId: string,\n workspaceDir: string,\n): { ok: boolean; removedFrom?: string; error?: string } {\n // Try workspace first\n const workspaceDir_ = join(workspaceDir, '.extensions');\n const workspaceExtension = join(workspaceDir_, extensionId);\n\n if (existsSync(workspaceExtension)) {\n try {\n rmSync(workspaceExtension, { recursive: true, force: true });\n return { ok: true, removedFrom: 'workspace' };\n } catch (error) {\n return {\n ok: false,\n error: `Failed to remove from workspace: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n }\n\n // Try global\n const globalDir = resolveGlobalExtensionsDir();\n const globalExtension = join(globalDir, extensionId);\n\n if (existsSync(globalExtension)) {\n try {\n rmSync(globalExtension, { recursive: true, force: true });\n return { ok: true, removedFrom: 'global' };\n } catch (error) {\n return {\n ok: false,\n error: `Failed to remove from global: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n }\n\n return { ok: false, error: `Extension not found: ${extensionId}` };\n}\n\n/**\n * List installed extensions from all tiers\n */\nexport function listAllExtensions(workspaceDir: string): ListedExtension[] {\n const extensions: ListedExtension[] = [];\n const seen = new Set<string>();\n\n // Priority 1: Workspace (highest)\n const workspaceExtensionsDir = join(workspaceDir, '.extensions');\n if (existsSync(workspaceExtensionsDir)) {\n for (const entry of readdirSync(workspaceExtensionsDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n\n const extensionDir = join(workspaceExtensionsDir, entry.name);\n const manifest = readManifest(extensionDir);\n\n if (manifest) {\n seen.add(entry.name);\n extensions.push({\n id: entry.name,\n name: manifest.name,\n version: manifest.version,\n path: extensionDir,\n origin: 'workspace',\n });\n }\n }\n }\n\n // Priority 2: Global\n const globalDir = resolveGlobalExtensionsDir();\n if (existsSync(globalDir)) {\n for (const entry of readdirSync(globalDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n if (seen.has(entry.name)) continue; // Skip if already in workspace\n\n const extensionDir = join(globalDir, entry.name);\n const manifest = readManifest(extensionDir);\n\n if (manifest) {\n seen.add(entry.name);\n extensions.push({\n id: entry.name,\n name: manifest.name,\n version: manifest.version,\n path: extensionDir,\n origin: 'global',\n });\n }\n }\n }\n\n // Priority 3: Bundled (lowest)\n const bundledDir = resolveBundledExtensionsDir();\n if (bundledDir && existsSync(bundledDir)) {\n for (const entry of readdirSync(bundledDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n if (seen.has(entry.name)) continue;\n\n const extensionDir = join(bundledDir, entry.name);\n const manifest = readManifest(extensionDir);\n\n if (manifest) {\n extensions.push({\n id: entry.name,\n name: manifest.name,\n version: manifest.version,\n path: extensionDir,\n origin: 'bundled',\n });\n }\n }\n }\n\n return extensions;\n}\n\nfunction readManifest(extensionDir: string): ExtensionManifest | null {\n const manifestPath = join(extensionDir, 'xopc.extension.json');\n\n if (!existsSync(manifestPath)) {\n // Try package.json\n const packagePath = join(extensionDir, 'package.json');\n if (existsSync(packagePath)) {\n try {\n const pkg = JSON.parse(readFileSync(packagePath, 'utf-8'));\n return {\n id: pkg.name,\n name: pkg.xopc?.extension?.name || pkg.name,\n version: pkg.version,\n };\n } catch {\n return null;\n }\n }\n return null;\n }\n\n try {\n return JSON.parse(readFileSync(manifestPath, 'utf-8')) as ExtensionManifest;\n } catch {\n return null;\n }\n}\n"],"mappings":"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"}
|
|
@@ -119,10 +119,6 @@ export declare class ExtensionLoader {
|
|
|
119
119
|
*/
|
|
120
120
|
private claimExtensionSlots;
|
|
121
121
|
loadManifest(extensionPath: string): ExtensionManifest | null;
|
|
122
|
-
/**
|
|
123
|
-
* Build candidate extension entry paths. After `tsdown`, manifests may still
|
|
124
|
-
* point at `*.ts` while the shipped tree only contains the emitted `*.js`.
|
|
125
|
-
*/
|
|
126
122
|
private moduleEntryCandidates;
|
|
127
123
|
private loadModule;
|
|
128
124
|
private createExtensionApi;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PACKAGE_VERSION, init_package_version } from "../package-version.js";
|
|
2
|
+
import { init_agent_scope, resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agent/agent-scope.js";
|
|
2
3
|
import { createLogger, createServiceLogger } from "../utils/logger/index.js";
|
|
3
4
|
import { init_logger } from "../utils/logger.js";
|
|
4
|
-
import { init_agent_scope, resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agent/agent-scope.js";
|
|
5
5
|
import { init_paths, resolveBundledExtensionsDir, resolveExtensionSdkPath, resolveExtensionsDir, resolveWorkspaceExtensionsDir } from "../config/paths.js";
|
|
6
6
|
import { init_normalize_manifest, normalizeExtensionManifest } from "./normalize-manifest.js";
|
|
7
7
|
import { areExtensionsGloballyDisabled, discoverExtensionsFromDisk, init_discover_extensions } from "./discover-extensions.js";
|
|
@@ -18,10 +18,9 @@ import { validateMediaUnderstandingProviderContracts } from "./media-provider-co
|
|
|
18
18
|
import { DEFAULT_SECURITY_CONFIG, checkExtensionPathSafety, isExtensionAllowed, logSecurityIssue, provenanceTracker } from "./security.js";
|
|
19
19
|
import { getSlotRegistry } from "./slots.js";
|
|
20
20
|
import { getExtensionCache, getExtensionDiagnostics } from "./diagnostics.js";
|
|
21
|
-
import { createRequire } from "node:module";
|
|
22
21
|
import { dirname, isAbsolute, join } from "path";
|
|
23
22
|
import { existsSync, readFileSync } from "fs";
|
|
24
|
-
import { fileURLToPath } from "node:url";
|
|
23
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
25
24
|
import { createJiti } from "jiti";
|
|
26
25
|
//#region src/extensions/loader.ts
|
|
27
26
|
/**
|
|
@@ -90,17 +89,21 @@ var ExtensionLoader = class {
|
|
|
90
89
|
const alias = {};
|
|
91
90
|
const sdkPath = resolveExtensionSdkPath();
|
|
92
91
|
if (sdkPath) {
|
|
93
|
-
alias["xopc/extension-sdk"] = sdkPath;
|
|
94
92
|
const sdkDir = dirname(sdkPath);
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
93
|
+
const sdkSubpaths = [
|
|
94
|
+
"core",
|
|
95
|
+
"lazy",
|
|
96
|
+
"provider",
|
|
97
|
+
"channel",
|
|
98
|
+
"hooks",
|
|
99
|
+
"tools",
|
|
100
|
+
"testing",
|
|
101
|
+
"speech",
|
|
102
|
+
"media"
|
|
103
|
+
];
|
|
104
|
+
const prefix = "@xopcai/xopc/extension-sdk";
|
|
105
|
+
alias[prefix] = sdkPath;
|
|
106
|
+
for (const subpath of sdkSubpaths) alias[`${prefix}/${subpath}`] = join(sdkDir, `${subpath}.ts`);
|
|
104
107
|
}
|
|
105
108
|
this.jiti = createJiti(fileURLToPath(import.meta.url), {
|
|
106
109
|
interopDefault: true,
|
|
@@ -333,23 +336,41 @@ var ExtensionLoader = class {
|
|
|
333
336
|
this.diagnostics.error(config.id, `Failed to load manifest`);
|
|
334
337
|
return null;
|
|
335
338
|
}
|
|
336
|
-
if (manifest.
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
|
|
339
|
+
if (!manifest.main || !/\.(js|mjs|cjs)$/i.test(manifest.main)) {
|
|
340
|
+
const reason = `Extension manifest main must point at built JavaScript (.js/.mjs/.cjs): ${manifest.main ?? "(missing)"}`;
|
|
341
|
+
log.warn({
|
|
342
|
+
extensionId: config.id,
|
|
343
|
+
main: manifest.main
|
|
344
|
+
}, reason);
|
|
345
|
+
this.diagnostics.error(config.id, reason);
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
if (!manifest.engines?.xopc) {
|
|
349
|
+
const reason = "Extension manifest must declare engines.xopc";
|
|
350
|
+
log.warn({ extensionId: config.id }, reason);
|
|
351
|
+
this.diagnostics.error(config.id, reason);
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
const range = manifest.engines.xopc;
|
|
355
|
+
const engineResult = checkEngineCompatibility(PACKAGE_VERSION, range);
|
|
356
|
+
if (engineResult.parseWarning) {
|
|
357
|
+
const reason = engineResult.reason ?? `Could not parse engines.xopc: ${range}`;
|
|
358
|
+
log.warn({
|
|
340
359
|
extensionId: config.id,
|
|
341
360
|
range,
|
|
342
|
-
reason
|
|
343
|
-
}, "
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
}
|
|
361
|
+
reason
|
|
362
|
+
}, "Extension engine range parse failure — skipping load");
|
|
363
|
+
this.diagnostics.error(config.id, reason);
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
if (!engineResult.compatible) {
|
|
367
|
+
log.warn({
|
|
368
|
+
extensionId: config.id,
|
|
369
|
+
range,
|
|
370
|
+
currentVersion: PACKAGE_VERSION
|
|
371
|
+
}, "Extension engine requirement not met (engines.xopc) — skipping load");
|
|
372
|
+
this.diagnostics.error(config.id, engineResult.reason ?? "Incompatible xopc version (engines.xopc)");
|
|
373
|
+
return null;
|
|
353
374
|
}
|
|
354
375
|
if (manifest.configSchema) try {
|
|
355
376
|
const schema = manifest.configSchema;
|
|
@@ -480,69 +501,19 @@ var ExtensionLoader = class {
|
|
|
480
501
|
}, `Failed to parse manifest`);
|
|
481
502
|
return null;
|
|
482
503
|
}
|
|
483
|
-
const packagePath = join(extensionPath, "package.json");
|
|
484
|
-
if (existsSync(packagePath)) try {
|
|
485
|
-
const packageJson = JSON.parse(readFileSync(packagePath, "utf-8"));
|
|
486
|
-
if (packageJson.xopc?.extension) {
|
|
487
|
-
const xopcConfig = packageJson.xopc;
|
|
488
|
-
return normalizeExtensionManifest({
|
|
489
|
-
id: xopcConfig.id || packageJson.name,
|
|
490
|
-
name: xopcConfig.name || packageJson.name,
|
|
491
|
-
description: xopcConfig.description || packageJson.description,
|
|
492
|
-
version: xopcConfig.version || packageJson.version || "1.0.0",
|
|
493
|
-
kind: xopcConfig.kind || "utility",
|
|
494
|
-
main: xopcConfig.main || packageJson.main || "index.js",
|
|
495
|
-
configSchema: xopcConfig.configSchema
|
|
496
|
-
});
|
|
497
|
-
}
|
|
498
|
-
if (packageJson.name?.startsWith("xopc-extension-")) return normalizeExtensionManifest({
|
|
499
|
-
id: packageJson.name.replace("xopc-extension-", ""),
|
|
500
|
-
name: packageJson.name,
|
|
501
|
-
description: packageJson.description,
|
|
502
|
-
version: packageJson.version || "1.0.0",
|
|
503
|
-
kind: "utility",
|
|
504
|
-
main: packageJson.main || "index.js"
|
|
505
|
-
});
|
|
506
|
-
} catch (error) {
|
|
507
|
-
log.error({
|
|
508
|
-
err: error,
|
|
509
|
-
packagePath
|
|
510
|
-
}, `Failed to parse package.json`);
|
|
511
|
-
}
|
|
512
504
|
return null;
|
|
513
505
|
}
|
|
514
|
-
/**
|
|
515
|
-
* Build candidate extension entry paths. After `tsdown`, manifests may still
|
|
516
|
-
* point at `*.ts` while the shipped tree only contains the emitted `*.js`.
|
|
517
|
-
*/
|
|
518
506
|
moduleEntryCandidates(manifest) {
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
"index.ts",
|
|
522
|
-
"index.js",
|
|
523
|
-
"extension.ts",
|
|
524
|
-
"extension.js"
|
|
525
|
-
].filter(Boolean);
|
|
526
|
-
const out = [];
|
|
527
|
-
for (const entry of raw) {
|
|
528
|
-
out.push(entry);
|
|
529
|
-
if (entry.endsWith(".tsx")) out.push(`${entry.slice(0, -4)}.js`);
|
|
530
|
-
else if (entry.endsWith(".ts")) out.push(`${entry.slice(0, -3)}.js`);
|
|
531
|
-
else if (entry.endsWith(".mts")) out.push(`${entry.slice(0, -4)}.mjs`);
|
|
532
|
-
else if (entry.endsWith(".cts")) out.push(`${entry.slice(0, -4)}.cjs`);
|
|
533
|
-
}
|
|
534
|
-
return [...new Set(out)];
|
|
507
|
+
if (!manifest.main) return [];
|
|
508
|
+
return [manifest.main];
|
|
535
509
|
}
|
|
536
510
|
async loadModule(extensionPath, manifest) {
|
|
537
511
|
const entryPoints = this.moduleEntryCandidates(manifest);
|
|
538
512
|
for (const entry of entryPoints) {
|
|
539
513
|
const fullPath = isAbsolute(entry) ? entry : join(extensionPath, entry);
|
|
540
514
|
if (existsSync(fullPath)) try {
|
|
541
|
-
if (
|
|
542
|
-
|
|
543
|
-
return mod.default || mod;
|
|
544
|
-
}
|
|
545
|
-
const mod = this.jiti(fullPath);
|
|
515
|
+
if (!/\.(js|mjs|cjs)$/.test(fullPath)) throw new Error(`Extension runtime entry must be built JavaScript: ${entry}`);
|
|
516
|
+
const mod = await import(pathToFileURL(fullPath).href);
|
|
546
517
|
return mod.default || mod;
|
|
547
518
|
} catch (error) {
|
|
548
519
|
log.warn({
|
|
@@ -572,7 +543,7 @@ var ExtensionLoader = class {
|
|
|
572
543
|
config: this._appConfig,
|
|
573
544
|
log: logger
|
|
574
545
|
} : void 0;
|
|
575
|
-
const api = new ExtensionApiImpl(manifest.id, manifest.name, manifest.version, extensionDir, appConfig, extensionOnly, logger, resolvePath, this.registry, runtime);
|
|
546
|
+
const api = new ExtensionApiImpl(manifest.id, manifest.name, manifest.version, extensionDir, appConfig, extensionOnly, logger, resolvePath, this.registry, manifest.contracts ?? {}, runtime);
|
|
576
547
|
if (manifest.reload?.configPrefixes?.length) api._setReloadConfigPrefixes(manifest.reload.configPrefixes);
|
|
577
548
|
const manifestCommands = manifest.ui?.contributions?.commands;
|
|
578
549
|
if (manifestCommands?.length) api._setManifestCommands(manifestCommands);
|
|
@@ -629,11 +600,7 @@ function resolveExtensionPath(id, _options) {
|
|
|
629
600
|
const bundledPath = join(bundledDir, id);
|
|
630
601
|
if (existsSync(bundledPath)) return bundledPath;
|
|
631
602
|
}
|
|
632
|
-
|
|
633
|
-
return dirname(createRequire(import.meta.url).resolve(id));
|
|
634
|
-
} catch {
|
|
635
|
-
return null;
|
|
636
|
-
}
|
|
603
|
+
return null;
|
|
637
604
|
}
|
|
638
605
|
function normalizeExtensionConfig(rawConfig) {
|
|
639
606
|
const extensions = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","names":["apiImpl"],"sources":["../../../src/extensions/loader.ts"],"sourcesContent":["/**\n * Extension Loader and Registry\n * \n * Supports three-tier extension storage:\n * 1. Workspace level (workspace/.extensions/) - highest priority\n * 2. Global level (~/.xopc/extensions/) - shared across workspaces\n * 3. Bundled level (xopc/extensions/) - shipped with xopc\n */\n\nimport { existsSync, readFileSync } from 'fs';\nimport { join, dirname, isAbsolute } from 'path';\nimport { fileURLToPath } from 'node:url';\nimport { createRequire } from 'node:module';\nimport { createJiti } from 'jiti';\nimport { resolveDefaultAgentId } from '../agent/agent-scope.js';\nimport { loadConfig } from '../config/loader.js';\nimport {\n resolveAgentWorkspaceDir,\n resolveExtensionsDir,\n resolveWorkspaceExtensionsDir,\n resolveBundledExtensionsDir,\n resolveExtensionSdkPath,\n} from '../config/paths.js';\nimport type { Config } from '../config/config-surface.js';\nimport type { MessageBus } from '../infra/bus/index.js';\nimport type { SessionIndex } from '../session/manager.js';\nimport type { AgentTool } from '@earendil-works/pi-agent-core';\nimport type {\n ExtensionApi,\n ExtensionModule,\n ExtensionManifest,\n ResolvedExtensionConfig,\n DiscoveredExtension,\n} from './types/index.js';\nimport type { ActivationContext } from './activation-planner.js';\nimport { ActivationPlanner, type ActivationLoadPhase } from './activation-planner.js';\nimport { mergeActivationContext } from './activation-context.js';\nimport {\n areExtensionsGloballyDisabled,\n discoverExtensionsFromDisk,\n type DiscoverConfig,\n type ExtensionLoaderOptions,\n} from './discover-extensions.js';\nimport type { ExtensionMetadataSnapshot } from './extension-metadata-snapshot.js';\nimport { ManifestRegistry } from './manifest-registry.js';\nimport { normalizeExtensionManifest } from './normalize-manifest.js';\nimport { checkEngineCompatibility } from './engine-check.js';\nimport { PACKAGE_VERSION } from '../package-version.js';\nimport { ExtensionApiImpl, createExtensionLogger, createPathResolver } from './api.js';\nimport { validateSpeechProviderContracts } from './speech-provider-contracts.js';\nimport { validateMediaUnderstandingProviderContracts } from './media-provider-contracts.js';\nimport { createLogger, createServiceLogger } from '../utils/logger.js';\n\n// Security imports\nimport {\n checkExtensionPathSafety,\n isExtensionAllowed,\n provenanceTracker,\n logSecurityIssue,\n DEFAULT_SECURITY_CONFIG,\n type SecurityConfig,\n // Note: ExtensionSourceOrigin is defined locally in this file\n} from './security.js';\n\n// Provider imports\nimport { getProviderRegistry, type ProviderPluginRegistry } from '../providers/plugin-registry.js';\n\n// Slot imports\nimport {\n getSlotRegistry,\n type SlotRegistry,\n type SlotKey,\n} from './slots.js';\n\n// Diagnostics imports\nimport {\n getExtensionCache,\n getExtensionDiagnostics,\n type ExtensionLoaderCache,\n type ExtensionDiagnostics,\n} from './diagnostics.js';\n\nconst EXTENSION_MANIFEST_FILE = 'xopc.extension.json';\n\nconst log = createLogger('ExtensionLoader');\n\nconst DEFAULT_EXTENSION_LOAD_CONCURRENCY = 4;\n\nasync function mapWithConcurrency<T>(\n items: readonly T[],\n concurrency: number,\n fn: (item: T) => Promise<void>,\n): Promise<void> {\n if (items.length === 0) {\n return;\n }\n const queue = [...items];\n const workerCount = Math.min(Math.max(1, concurrency), queue.length);\n await Promise.all(\n Array.from({ length: workerCount }, async () => {\n while (queue.length > 0) {\n const item = queue.shift();\n if (item === undefined) {\n break;\n }\n await fn(item);\n }\n }),\n );\n}\n\nexport type { ExtensionLoaderOptions, ExtensionSourceOrigin } from './discover-extensions.js';\nexport { areExtensionsGloballyDisabled } from './discover-extensions.js';\n\n// ============================================================================\n// Extension Registry\n// ============================================================================\n\n// `ExtensionRegistryImpl` moved to `./extension-registry-impl.ts` so `api.ts`\n// can use the class without going through loader.ts (which imports back from\n// api.ts and formed a circular cycle). Re-exported here for backward-compat.\nexport { ExtensionRegistryImpl } from './extension-registry-impl.js';\nimport { ExtensionRegistryImpl } from './extension-registry-impl.js';\n\n// ============================================================================\n// Extension Loader\n// ============================================================================\n\nexport interface ActivationPlanLoadOptions extends Partial<ActivationContext> {\n phase?: ActivationLoadPhase | 'all';\n}\n\nexport class ExtensionLoader {\n private registry: ExtensionRegistryImpl;\n private options: ExtensionLoaderOptions;\n private extensionInstances: Map<string, ExtensionApi> = new Map();\n private jiti: ReturnType<typeof createJiti>;\n private _appConfig?: Config;\n private _runtimeContext?: {\n bus?: MessageBus;\n sessionManager?: SessionIndex;\n scheduleWebchatContinuation?: (sessionKey: string, message: string) => void;\n setLabel?: (entryId: string, label: string | undefined) => void;\n sendUserMessage?: import('./types/index.js').ExtensionRuntime['sendUserMessage'];\n appendEntry?: import('./types/index.js').ExtensionRuntime['appendEntry'];\n sendMessage?: import('./types/index.js').ExtensionRuntime['sendMessage'];\n };\n \n // Security\n private securityConfig: SecurityConfig;\n \n // Provider Registry\n private providerRegistry: ProviderPluginRegistry;\n \n // Slot Registry & Config\n private slotRegistry: SlotRegistry;\n private slotsConfig: Partial<Record<SlotKey, string>> = {};\n \n // Cache and Diagnostics\n private cache: ExtensionLoaderCache;\n private diagnostics: ExtensionDiagnostics;\n\n /** Manifest-only registry cache (no runtime module load). */\n private manifestRegistry: ManifestRegistry | null = null;\n private manifestSnapshot: ExtensionMetadataSnapshot | null = null;\n\n constructor(options?: ExtensionLoaderOptions) {\n this.registry = new ExtensionRegistryImpl();\n this.options = options || (() => {\n const c = loadConfig();\n const aid = resolveDefaultAgentId(c);\n return {\n workspaceDir: resolveAgentWorkspaceDir(c, aid),\n extensionsDir: resolveWorkspaceExtensionsDir(c, aid),\n };\n })();\n\n // Initialize security config\n this.securityConfig = DEFAULT_SECURITY_CONFIG;\n \n // Initialize provider registry\n this.providerRegistry = getProviderRegistry();\n \n // Initialize slot registry\n this.slotRegistry = getSlotRegistry();\n \n // Initialize cache and diagnostics \n this.cache = getExtensionCache();\n this.diagnostics = getExtensionDiagnostics();\n\n // Build jiti alias for extension-sdk (+ subpath entry points)\n const alias: Record<string, string> = {};\n const sdkPath = resolveExtensionSdkPath();\n if (sdkPath) {\n alias['xopc/extension-sdk'] = sdkPath;\n const sdkDir = dirname(sdkPath);\n alias['xopc/extension-sdk/core'] = join(sdkDir, 'core.ts');\n alias['xopc/extension-sdk/lazy'] = join(sdkDir, 'lazy.ts');\n alias['xopc/extension-sdk/provider'] = join(sdkDir, 'provider.ts');\n alias['xopc/extension-sdk/channel'] = join(sdkDir, 'channel.ts');\n alias['xopc/extension-sdk/hooks'] = join(sdkDir, 'hooks.ts');\n alias['xopc/extension-sdk/tools'] = join(sdkDir, 'tools.ts');\n alias['xopc/extension-sdk/testing'] = join(sdkDir, 'testing.ts');\n alias['xopc/extension-sdk/speech'] = join(sdkDir, 'speech.ts');\n alias['xopc/extension-sdk/media'] = join(sdkDir, 'media.ts');\n }\n\n // Initialize jiti with TypeScript support and SDK alias\n this.jiti = createJiti(fileURLToPath(import.meta.url), {\n interopDefault: true,\n extensions: ['.ts', '.tsx', '.mts', '.cts', '.js', '.mjs', '.cjs', '.json'],\n alias,\n });\n }\n\n /**\n * Reuse a pre-built metadata snapshot (avoids duplicate filesystem discovery).\n */\n setManifestSnapshot(snapshot: ExtensionMetadataSnapshot | null): void {\n this.manifestSnapshot = snapshot;\n this.manifestRegistry = snapshot?.manifestRegistry ?? null;\n }\n\n getManifestSnapshot(): ExtensionMetadataSnapshot | null {\n return this.manifestSnapshot;\n }\n\n /**\n * Set security configuration \n */\n setSecurityConfig(config: Partial<SecurityConfig>): void {\n this.securityConfig = { ...this.securityConfig, ...config };\n }\n\n /**\n * Get security configuration \n */\n getSecurityConfig(): SecurityConfig {\n return this.securityConfig;\n }\n\n /**\n * Get provider registry \n */\n getProviderRegistry(): ProviderPluginRegistry {\n return this.providerRegistry;\n }\n\n /**\n * Get slot registry \n */\n getSlotRegistry(): SlotRegistry {\n return this.slotRegistry;\n }\n\n /**\n * Get diagnostics \n */\n getDiagnostics(): ExtensionDiagnostics {\n return this.diagnostics;\n }\n\n /**\n * Set configuration from main Config object \n */\n setConfig(config: Config): void {\n this._appConfig = config;\n // Wire slot config\n const slots = (config.extensions as any)?.slots || {};\n this.slotsConfig = {\n memory: slots.memory,\n tts: slots.tts,\n imageGeneration: slots.imageGeneration,\n webSearch: slots.webSearch,\n };\n\n // Wire security config\n const security = (config.extensions as any)?.security;\n if (security) {\n this.securityConfig = {\n checkPermissions: security.checkPermissions ?? true,\n allowUntrusted: security.allowUntrusted ?? false,\n allow: security.allow ?? [],\n trackProvenance: security.trackProvenance ?? true,\n allowPromptInjection: security.allowPromptInjection ?? false,\n };\n }\n }\n\n /**\n * Inject MessageBus and optional SessionManager for ExtensionApi.runtime (Gateway).\n */\n setRuntimeContext(ctx: {\n bus?: MessageBus;\n sessionManager?: SessionIndex;\n scheduleWebchatContinuation?: (sessionKey: string, message: string) => void;\n setLabel?: (entryId: string, label: string | undefined) => void;\n sendUserMessage?: import('./types/index.js').ExtensionRuntime['sendUserMessage'];\n appendEntry?: import('./types/index.js').ExtensionRuntime['appendEntry'];\n sendMessage?: import('./types/index.js').ExtensionRuntime['sendMessage'];\n }): void {\n this._runtimeContext = ctx;\n // ExtensionApi snapshots `runtime` at construction and is tied to this loader's registry.\n // CLI startup loads extensions with `{ bus }` first; a global cache hit would reuse that\n // api for the gateway loader (no sessionManager, wrong registry) — breaks extensions that need SessionManager.\n this.cache.invalidate();\n }\n\n getRegistry(): ExtensionRegistryImpl {\n return this.registry;\n }\n\n /**\n * Phase 1: build manifest registry (filesystem manifests only, no extension code load).\n */\n buildManifestRegistry(): ManifestRegistry {\n if (this.manifestRegistry) {\n return this.manifestRegistry;\n }\n const discovered = this.discoverExtensions();\n this.manifestRegistry = ManifestRegistry.fromDiscovered(discovered);\n return this.manifestRegistry;\n }\n\n /**\n * Phase 2: activation planner over the manifest registry (pure logic).\n */\n planActivation(_context?: Partial<ActivationContext>): ActivationPlanner {\n return new ActivationPlanner(this.buildManifestRegistry());\n }\n\n /**\n * Phase 3: load only extensions selected by the activation plan.\n */\n async loadByActivationPlan(context?: ActivationPlanLoadOptions): Promise<void> {\n if (areExtensionsGloballyDisabled(this._appConfig as DiscoverConfig | undefined)) {\n log.debug('Extension loading skipped (extensions globally disabled)');\n return;\n }\n\n const registry = this.buildManifestRegistry();\n const planner = new ActivationPlanner(registry);\n const fullContext = mergeActivationContext(this._appConfig, context);\n let activatedIds = planner.getActivatedIds(fullContext).sort((a, b) => a.localeCompare(b));\n\n const phase = context?.phase ?? 'all';\n if (phase === 'startup' || phase === 'deferred') {\n activatedIds = planner.filterActivatedIdsByLoadPhase(activatedIds, phase);\n }\n\n const concurrency = Number.parseInt(\n process.env.XOPC_EXTENSION_LOAD_CONCURRENCY ?? '',\n 10,\n );\n const loadConcurrency = Number.isFinite(concurrency) && concurrency > 0\n ? concurrency\n : DEFAULT_EXTENSION_LOAD_CONCURRENCY;\n\n await mapWithConcurrency(activatedIds, loadConcurrency, async (extensionId) => {\n if (this.extensionInstances.has(extensionId)) {\n return;\n }\n const entry = registry.getEntry(extensionId);\n if (!entry) {\n log.debug(\n { extensionId },\n 'Activation plan references extension id that was not discovered on disk',\n );\n return;\n }\n\n const config: ResolvedExtensionConfig = {\n id: extensionId,\n name: entry.manifest.name || extensionId,\n source: entry.source,\n path: entry.path,\n enabled: true,\n config: this.resolveExtensionConfig(extensionId),\n };\n\n await this.loadExtension(config);\n });\n }\n\n getManifestRegistry(): ManifestRegistry {\n return this.buildManifestRegistry();\n }\n\n invalidateManifestCache(): void {\n this.manifestRegistry = this.manifestSnapshot?.manifestRegistry ?? null;\n }\n\n private resolveExtensionConfig(extensionId: string): Record<string, unknown> {\n if (!this._appConfig) return {};\n const extensionsConfig = (this._appConfig as Record<string, unknown>).extensions as\n | Record<string, unknown>\n | undefined;\n if (!extensionsConfig || typeof extensionsConfig !== 'object') return {};\n const raw = extensionsConfig[extensionId];\n if (raw && typeof raw === 'object' && !Array.isArray(raw)) {\n return raw as Record<string, unknown>;\n }\n return {};\n }\n\n /**\n * Discover extensions from all three tiers:\n * 1. Workspace (.extensions/) - highest priority\n * 2. Global (~/.xopc/extensions/) - shared\n * 3. Bundled (xopc/extensions/) - lowest priority\n */\n discoverExtensions(): DiscoveredExtension[] {\n if (this.manifestSnapshot) {\n return this.manifestSnapshot.discovered;\n }\n return discoverExtensionsFromDisk(this.options, this._appConfig as DiscoverConfig | undefined);\n }\n\n /**\n * Load all discovered extensions\n */\n async loadAllExtensions(enabledIds?: string[]): Promise<void> {\n const extensions = this.discoverExtensions();\n\n for (const extension of extensions) {\n // If enabledIds specified, only load those\n if (enabledIds && !enabledIds.includes(extension.id)) {\n continue;\n }\n\n const config: ResolvedExtensionConfig = {\n id: extension.id,\n name: extension.manifest.name || extension.id,\n source: extension.source,\n path: extension.path,\n enabled: true,\n config: {},\n };\n\n await this.loadExtension(config);\n }\n }\n\n async loadExtensions(configs: ResolvedExtensionConfig[]): Promise<void> {\n for (const extensionConfig of configs) {\n if (extensionConfig.enabled) {\n await this.loadExtension(extensionConfig);\n }\n }\n }\n\n async loadExtension(config: ResolvedExtensionConfig): Promise<ExtensionApi | null> {\n try {\n // Check cache first\n const cacheKey = this.cache.buildKey(this.options, [config.id]);\n const cached = this.cache.get<ExtensionApi>(cacheKey);\n if (cached) {\n log.debug({ extensionId: config.id }, 'Extension loaded from cache');\n return cached;\n }\n\n // Check if already loaded\n if (this.extensionInstances.has(config.id)) {\n return this.extensionInstances.get(config.id)!;\n }\n\n // Resolve extension path using resolveExtensionPath\n let extensionPath: string | null;\n if (isAbsolute(config.path)) {\n extensionPath = config.path;\n } else {\n // Try to resolve extension ID to actual path\n extensionPath = resolveExtensionPath(config.path, this.options) ||\n resolveExtensionPath(config.id, this.options);\n }\n \n if (!extensionPath) {\n log.error({ extensionId: config.id, path: config.path }, `Could not resolve extension path`);\n this.diagnostics.error(config.id, `Could not resolve extension path: ${config.path}`);\n return null;\n }\n\n log.debug({ extensionId: config.id, extensionPath }, 'Resolved extension path');\n\n // Security check\n const source = config.source || 'bundled';\n const safetyResult = checkExtensionPathSafety(extensionPath, extensionPath, source);\n \n if (!safetyResult.safe) {\n logSecurityIssue(config.id, safetyResult);\n \n if (this.securityConfig.checkPermissions && source !== 'bundled') {\n // Check allowlist\n if (!isExtensionAllowed(config.id, this.securityConfig)) {\n this.diagnostics.error(config.id, `Extension not allowed: ${safetyResult.detail}`);\n log.error({ extensionId: config.id, reason: safetyResult.reason }, 'Extension blocked by security policy');\n return null;\n }\n }\n }\n\n // Track provenance \n provenanceTracker.track(config.id, source);\n\n const manifest = this.loadManifest(extensionPath);\n if (!manifest) {\n log.error({ extensionId: config.id, extensionPath }, `Failed to load manifest for extension`);\n this.diagnostics.error(config.id, `Failed to load manifest`);\n return null;\n }\n\n if (manifest.engines?.xopc) {\n const range = manifest.engines.xopc;\n const engineResult = checkEngineCompatibility(PACKAGE_VERSION, range);\n if (engineResult.parseWarning) {\n log.warn(\n { extensionId: config.id, range, reason: engineResult.reason },\n 'Engine range parse warning — loading anyway',\n );\n } else if (!engineResult.compatible) {\n log.warn(\n { extensionId: config.id, range, currentVersion: PACKAGE_VERSION },\n 'Extension engine requirement not met (engines.xopc) — skipping load',\n );\n this.diagnostics.error(\n config.id,\n engineResult.reason ?? 'Incompatible xopc version (engines.xopc)',\n );\n return null;\n }\n }\n\n // Validate extension config against schema (basic validation)\n if (manifest.configSchema) {\n try {\n const schema = manifest.configSchema as Record<string, unknown>;\n const extensionConfig = config.config as Record<string, unknown>;\n \n // Basic validation: check required fields and types\n if (schema.type === 'object' && schema.properties) {\n const props = schema.properties as Record<string, Record<string, unknown>>;\n const required = (schema.required as string[]) || [];\n \n for (const field of required) {\n if (extensionConfig[field] === undefined) {\n log.error({ \n extensionId: config.id, \n field \n }, 'Extension config validation failed: missing required field');\n return null;\n }\n }\n \n for (const [key, value] of Object.entries(extensionConfig)) {\n const propSchema = props[key];\n if (propSchema) {\n if (propSchema.type && !this.validateType(value, propSchema.type as string)) {\n log.error({ \n extensionId: config.id, \n field: key,\n expected: propSchema.type,\n actual: typeof value\n }, 'Extension config validation failed: type mismatch');\n return null;\n }\n }\n }\n }\n \n log.debug({ extensionId: config.id }, 'Extension config validated');\n } catch (err) {\n log.warn({ err, extensionId: config.id }, 'Config schema validation skipped');\n }\n }\n\n // Create extension API\n const extensionDir = dirname(extensionPath);\n const api = this.createExtensionApi(manifest, config, extensionDir);\n\n // Load extension module\n const module = await this.loadModule(extensionPath, manifest);\n if (!module) {\n log.error({ extensionId: config.id }, `Failed to load module for extension`);\n this.diagnostics.error(config.id, `Failed to load module`);\n return null;\n }\n\n // Check and claim slots\n const slotClaimed = this.claimExtensionSlots(config.id, manifest);\n if (!slotClaimed) {\n log.warn({ extensionId: config.id }, 'Failed to claim required slots');\n }\n\n // Initialize extension\n await this.initializeExtension(module, api, manifest);\n\n validateSpeechProviderContracts({\n extensionId: config.id,\n manifest,\n registeredProviderIds: (api as ExtensionApiImpl).getRegisteredSpeechProviderIds(),\n logger: api.logger,\n });\n\n validateMediaUnderstandingProviderContracts({\n extensionId: config.id,\n manifest,\n registeredProviderIds: (api as ExtensionApiImpl).getRegisteredMediaUnderstandingProviderIds(),\n logger: api.logger,\n });\n\n // Register to registry\n this.registry.addExtension({\n id: config.id,\n name: manifest.name,\n version: manifest.version,\n path: extensionPath,\n module,\n config: config.config,\n enabled: true,\n source: config.source,\n });\n\n // Register extension tools to registry (so AgentManager can access them)\n // Note: api is actually ExtensionApiImpl at runtime\n const apiImpl = api as unknown as { _getTools: () => Map<string, AgentTool> };\n const extensionTools = apiImpl._getTools();\n for (const tool of extensionTools.values()) {\n this.registry.addTool(tool);\n }\n\n this.extensionInstances.set(config.id, api);\n \n // Cache the loaded extension\n this.cache.set(cacheKey, api);\n\n this.diagnostics.info(config.id, `Loaded extension: ${manifest.name}`);\n log.info({ name: manifest.name, id: manifest.id, source: config.source }, `Loaded extension`);\n\n return api;\n } catch (error) {\n log.error({ err: error, extensionId: config.id }, `Error loading extension`);\n this.diagnostics.error(config.id, `Error loading extension: ${error}`);\n return null;\n }\n }\n\n /**\n * Claim extension slots based on manifest kind\n * Respects configured preferred plugin from config.extensions.slots\n */\n private claimExtensionSlots(extensionId: string, manifest: ExtensionManifest): boolean {\n const kind = manifest.kind as string;\n \n // Map extension kind to slot\n const slotMap: Record<string, SlotKey> = {\n 'memory': 'memory',\n 'tts': 'tts',\n 'speech-provider': 'tts',\n 'web-search': 'webSearch',\n };\n \n const slotKey = slotMap[kind];\n if (!slotKey) {\n return true; // No slot required\n }\n \n // Check if slot is reserved for a different plugin in config\n const preferredPlugin = this.slotsConfig[slotKey];\n if (preferredPlugin && preferredPlugin !== extensionId) {\n log.info(\n { extensionId, slotKey, preferredPlugin },\n `Skipping slot claim: slot \"${slotKey}\" is reserved for \"${preferredPlugin}\"`\n );\n this.diagnostics.info(\n extensionId,\n `Slot \"${slotKey}\" is reserved for \"${preferredPlugin}\", skipping claim`\n );\n return false;\n }\n \n const claimed = this.slotRegistry.claim(slotKey, extensionId, null);\n if (!claimed) {\n this.diagnostics.warn(extensionId, `Slot \"${slotKey}\" already claimed by another extension`);\n }\n return claimed;\n }\n\n loadManifest(extensionPath: string): ExtensionManifest | null {\n const manifestPath = join(extensionPath, EXTENSION_MANIFEST_FILE);\n\n // First try to load xopc.extension.json\n if (existsSync(manifestPath)) {\n try {\n const raw = JSON.parse(readFileSync(manifestPath, 'utf-8'));\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n log.error({ manifestPath }, 'Manifest root must be a JSON object');\n return null;\n }\n return normalizeExtensionManifest(raw as Record<string, unknown>);\n } catch (error) {\n log.error({ err: error, manifestPath }, `Failed to parse manifest`);\n return null;\n }\n }\n\n // Fallback to package.json\n const packagePath = join(extensionPath, 'package.json');\n if (existsSync(packagePath)) {\n try {\n const packageJson = JSON.parse(readFileSync(packagePath, 'utf-8'));\n \n // Check for xopc.extension marker\n if (packageJson.xopc?.extension) {\n const xopcConfig = packageJson.xopc;\n return normalizeExtensionManifest({\n id: xopcConfig.id || packageJson.name,\n name: xopcConfig.name || packageJson.name,\n description: xopcConfig.description || packageJson.description,\n version: xopcConfig.version || packageJson.version || '1.0.0',\n kind: xopcConfig.kind || 'utility',\n main: xopcConfig.main || packageJson.main || 'index.js',\n configSchema: xopcConfig.configSchema,\n });\n }\n\n // Also support xopc-extension-* naming convention\n if (packageJson.name?.startsWith('xopc-extension-')) {\n const id = packageJson.name.replace('xopc-extension-', '');\n return normalizeExtensionManifest({\n id,\n name: packageJson.name,\n description: packageJson.description,\n version: packageJson.version || '1.0.0',\n kind: 'utility',\n main: packageJson.main || 'index.js',\n });\n }\n } catch (error) {\n log.error({ err: error, packagePath }, `Failed to parse package.json`);\n }\n }\n\n return null;\n }\n\n /**\n * Build candidate extension entry paths. After `tsdown`, manifests may still\n * point at `*.ts` while the shipped tree only contains the emitted `*.js`.\n */\n private moduleEntryCandidates(manifest: ExtensionManifest): string[] {\n const raw = [\n manifest.main,\n 'index.ts',\n 'index.js',\n 'extension.ts',\n 'extension.js',\n ].filter(Boolean) as string[];\n\n const out: string[] = [];\n for (const entry of raw) {\n out.push(entry);\n if (entry.endsWith('.tsx')) {\n out.push(`${entry.slice(0, -4)}.js`);\n } else if (entry.endsWith('.ts')) {\n out.push(`${entry.slice(0, -3)}.js`);\n } else if (entry.endsWith('.mts')) {\n out.push(`${entry.slice(0, -4)}.mjs`);\n } else if (entry.endsWith('.cts')) {\n out.push(`${entry.slice(0, -4)}.cjs`);\n }\n }\n return [...new Set(out)];\n }\n\n private async loadModule(\n extensionPath: string,\n manifest: ExtensionManifest,\n ): Promise<ExtensionModule | null> {\n const entryPoints = this.moduleEntryCandidates(manifest);\n\n for (const entry of entryPoints) {\n const fullPath = isAbsolute(entry) ? entry : join(extensionPath, entry);\n\n if (existsSync(fullPath)) {\n try {\n if (/\\.(js|mjs|cjs)$/.test(fullPath)) {\n const require = createRequire(import.meta.url);\n const mod = require(fullPath);\n return mod.default || mod;\n }\n const mod = this.jiti(fullPath);\n return mod.default || mod;\n } catch (error) {\n log.warn({ err: error, path: fullPath }, `Failed to load module`);\n }\n }\n }\n\n return null;\n }\n\n private createExtensionApi(\n manifest: ExtensionManifest,\n resolved: ResolvedExtensionConfig,\n extensionDir: string,\n ): ExtensionApi {\n const logger = createExtensionLogger(`[${manifest.id}]`);\n const resolvePath = createPathResolver(extensionDir, this.options.workspaceDir || '');\n\n const appConfig = this._appConfig ?? ({} as Config);\n const extensionOnly = (resolved.config ?? {}) as Record<string, unknown>;\n\n const runtime =\n this._appConfig && this._runtimeContext\n ? {\n config: this._appConfig,\n bus: this._runtimeContext.bus,\n log: logger,\n sessionManager: this._runtimeContext.sessionManager,\n scheduleWebchatContinuation: this._runtimeContext.scheduleWebchatContinuation,\n setLabel: this._runtimeContext.setLabel,\n sendUserMessage: this._runtimeContext.sendUserMessage,\n appendEntry: this._runtimeContext.appendEntry,\n sendMessage: this._runtimeContext.sendMessage,\n }\n : this._appConfig\n ? {\n config: this._appConfig,\n log: logger,\n }\n : undefined;\n\n const api = new ExtensionApiImpl(\n manifest.id,\n manifest.name,\n manifest.version,\n extensionDir,\n appConfig,\n extensionOnly,\n logger,\n resolvePath,\n this.registry,\n runtime,\n );\n if (manifest.reload?.configPrefixes?.length) {\n api._setReloadConfigPrefixes(manifest.reload.configPrefixes);\n }\n const manifestCommands = manifest.ui?.contributions?.commands;\n if (manifestCommands?.length) {\n (api as ExtensionApiImpl)._setManifestCommands(manifestCommands);\n }\n return api;\n }\n\n private async initializeExtension(\n module: ExtensionModule,\n api: ExtensionApi,\n _manifest: ExtensionManifest,\n ): Promise<void> {\n if (typeof module === 'function') {\n // Module is a function that receives the API\n await module(api);\n } else if (typeof module === 'object' && module.register) {\n // Module is a ExtensionDefinition with register method\n await module.register(api);\n }\n }\n\n async startServices(): Promise<void> {\n const services = Array.from(this.registry.services.values());\n\n for (const service of services) {\n const serviceLog = createServiceLogger(service.id);\n try {\n await service.start?.();\n serviceLog.info(`Started service`);\n } catch (error) {\n serviceLog.error({ err: error }, `Failed to start service`);\n }\n }\n }\n\n async stopServices(): Promise<void> {\n const services = Array.from(this.registry.services.values()).reverse();\n\n for (const service of services) {\n if (service.stop) {\n const serviceLog = createServiceLogger(service.id);\n try {\n await service.stop();\n serviceLog.info(`Stopped service`);\n } catch (error) {\n serviceLog.error({ err: error }, `Failed to stop service`);\n }\n }\n }\n }\n\n /**\n * Basic type validation for config values\n */\n private validateType(value: unknown, expectedType: string): boolean {\n if (expectedType === 'string') return typeof value === 'string';\n if (expectedType === 'number' || expectedType === 'integer') return typeof value === 'number';\n if (expectedType === 'boolean') return typeof value === 'boolean';\n if (expectedType === 'array') return Array.isArray(value);\n if (expectedType === 'object') return typeof value === 'object' && value !== null && !Array.isArray(value);\n return true;\n }\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\nexport function resolveExtensionPath(id: string, _options: ExtensionLoaderOptions): string | null {\n const c = loadConfig();\n const aid = resolveDefaultAgentId(c);\n // Priority 1: Workspace\n const workspacePath = join(resolveWorkspaceExtensionsDir(c, aid), id);\n if (existsSync(workspacePath)) return workspacePath;\n\n // Priority 2: Global\n const globalPath = join(resolveExtensionsDir(), id);\n if (existsSync(globalPath)) return globalPath;\n\n // Priority 3: Bundled\n const bundledDir = resolveBundledExtensionsDir();\n if (bundledDir) {\n const bundledPath = join(bundledDir, id);\n if (existsSync(bundledPath)) return bundledPath;\n }\n\n // Check if it's an npm package\n try {\n const require = createRequire(import.meta.url);\n const resolved = require.resolve(id);\n return dirname(resolved);\n } catch {\n return null;\n }\n}\n\nexport function normalizeExtensionConfig(\n rawConfig: Record<string, unknown>,\n): ResolvedExtensionConfig[] {\n const extensions: ResolvedExtensionConfig[] = [];\n\n const enabled = (rawConfig.enabled as string[]) || [];\n const disabled = (rawConfig.disabled as string[]) || [];\n\n // Parse enabled extensions\n for (const id of enabled) {\n const config = (rawConfig[id] as Record<string, unknown>) || {};\n extensions.push({\n id,\n name: id,\n source: 'config',\n path: id,\n enabled: true,\n config,\n });\n }\n\n // Parse disabled extensions\n for (const id of disabled) {\n if (!extensions.find((p) => p.id === id)) {\n const config = (rawConfig[id] as Record<string, unknown>) || {};\n extensions.push({\n id,\n name: id,\n source: 'config',\n path: id,\n enabled: false,\n config,\n });\n }\n }\n\n return extensions;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"loader.js","names":["apiImpl"],"sources":["../../../src/extensions/loader.ts"],"sourcesContent":["/**\n * Extension Loader and Registry\n * \n * Supports three-tier extension storage:\n * 1. Workspace level (workspace/.extensions/) - highest priority\n * 2. Global level (~/.xopc/extensions/) - shared across workspaces\n * 3. Bundled level (xopc/extensions/) - shipped with xopc\n */\n\nimport { existsSync, readFileSync } from 'fs';\nimport { join, dirname, isAbsolute } from 'path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport { createJiti } from 'jiti';\nimport { resolveDefaultAgentId } from '../agent/agent-scope.js';\nimport { loadConfig } from '../config/loader.js';\nimport {\n resolveAgentWorkspaceDir,\n resolveExtensionsDir,\n resolveWorkspaceExtensionsDir,\n resolveBundledExtensionsDir,\n resolveExtensionSdkPath,\n} from '../config/paths.js';\nimport type { Config } from '../config/config-surface.js';\nimport type { MessageBus } from '../infra/bus/index.js';\nimport type { SessionIndex } from '../session/manager.js';\nimport type { AgentTool } from '@earendil-works/pi-agent-core';\nimport type {\n ExtensionApi,\n ExtensionModule,\n ExtensionManifest,\n ResolvedExtensionConfig,\n DiscoveredExtension,\n} from './types/index.js';\nimport type { ActivationContext } from './activation-planner.js';\nimport { ActivationPlanner, type ActivationLoadPhase } from './activation-planner.js';\nimport { mergeActivationContext } from './activation-context.js';\nimport {\n areExtensionsGloballyDisabled,\n discoverExtensionsFromDisk,\n type DiscoverConfig,\n type ExtensionLoaderOptions,\n} from './discover-extensions.js';\nimport type { ExtensionMetadataSnapshot } from './extension-metadata-snapshot.js';\nimport { ManifestRegistry } from './manifest-registry.js';\nimport { normalizeExtensionManifest } from './normalize-manifest.js';\nimport { checkEngineCompatibility } from './engine-check.js';\nimport { PACKAGE_VERSION } from '../package-version.js';\nimport { ExtensionApiImpl, createExtensionLogger, createPathResolver } from './api.js';\nimport { validateSpeechProviderContracts } from './speech-provider-contracts.js';\nimport { validateMediaUnderstandingProviderContracts } from './media-provider-contracts.js';\nimport { createLogger, createServiceLogger } from '../utils/logger.js';\n\n// Security imports\nimport {\n checkExtensionPathSafety,\n isExtensionAllowed,\n provenanceTracker,\n logSecurityIssue,\n DEFAULT_SECURITY_CONFIG,\n type SecurityConfig,\n // Note: ExtensionSourceOrigin is defined locally in this file\n} from './security.js';\n\n// Provider imports\nimport { getProviderRegistry, type ProviderPluginRegistry } from '../providers/plugin-registry.js';\n\n// Slot imports\nimport {\n getSlotRegistry,\n type SlotRegistry,\n type SlotKey,\n} from './slots.js';\n\n// Diagnostics imports\nimport {\n getExtensionCache,\n getExtensionDiagnostics,\n type ExtensionLoaderCache,\n type ExtensionDiagnostics,\n} from './diagnostics.js';\n\nconst EXTENSION_MANIFEST_FILE = 'xopc.extension.json';\n\nconst log = createLogger('ExtensionLoader');\n\nconst DEFAULT_EXTENSION_LOAD_CONCURRENCY = 4;\n\nasync function mapWithConcurrency<T>(\n items: readonly T[],\n concurrency: number,\n fn: (item: T) => Promise<void>,\n): Promise<void> {\n if (items.length === 0) {\n return;\n }\n const queue = [...items];\n const workerCount = Math.min(Math.max(1, concurrency), queue.length);\n await Promise.all(\n Array.from({ length: workerCount }, async () => {\n while (queue.length > 0) {\n const item = queue.shift();\n if (item === undefined) {\n break;\n }\n await fn(item);\n }\n }),\n );\n}\n\nexport type { ExtensionLoaderOptions, ExtensionSourceOrigin } from './discover-extensions.js';\nexport { areExtensionsGloballyDisabled } from './discover-extensions.js';\n\n// ============================================================================\n// Extension Registry\n// ============================================================================\n\n// `ExtensionRegistryImpl` moved to `./extension-registry-impl.ts` so `api.ts`\n// can use the class without going through loader.ts (which imports back from\n// api.ts and formed a circular cycle). Re-exported here for backward-compat.\nexport { ExtensionRegistryImpl } from './extension-registry-impl.js';\nimport { ExtensionRegistryImpl } from './extension-registry-impl.js';\n\n// ============================================================================\n// Extension Loader\n// ============================================================================\n\nexport interface ActivationPlanLoadOptions extends Partial<ActivationContext> {\n phase?: ActivationLoadPhase | 'all';\n}\n\nexport class ExtensionLoader {\n private registry: ExtensionRegistryImpl;\n private options: ExtensionLoaderOptions;\n private extensionInstances: Map<string, ExtensionApi> = new Map();\n private jiti: ReturnType<typeof createJiti>;\n private _appConfig?: Config;\n private _runtimeContext?: {\n bus?: MessageBus;\n sessionManager?: SessionIndex;\n scheduleWebchatContinuation?: (sessionKey: string, message: string) => void;\n setLabel?: (entryId: string, label: string | undefined) => void;\n sendUserMessage?: import('./types/index.js').ExtensionRuntime['sendUserMessage'];\n appendEntry?: import('./types/index.js').ExtensionRuntime['appendEntry'];\n sendMessage?: import('./types/index.js').ExtensionRuntime['sendMessage'];\n };\n \n // Security\n private securityConfig: SecurityConfig;\n \n // Provider Registry\n private providerRegistry: ProviderPluginRegistry;\n \n // Slot Registry & Config\n private slotRegistry: SlotRegistry;\n private slotsConfig: Partial<Record<SlotKey, string>> = {};\n \n // Cache and Diagnostics\n private cache: ExtensionLoaderCache;\n private diagnostics: ExtensionDiagnostics;\n\n /** Manifest-only registry cache (no runtime module load). */\n private manifestRegistry: ManifestRegistry | null = null;\n private manifestSnapshot: ExtensionMetadataSnapshot | null = null;\n\n constructor(options?: ExtensionLoaderOptions) {\n this.registry = new ExtensionRegistryImpl();\n this.options = options || (() => {\n const c = loadConfig();\n const aid = resolveDefaultAgentId(c);\n return {\n workspaceDir: resolveAgentWorkspaceDir(c, aid),\n extensionsDir: resolveWorkspaceExtensionsDir(c, aid),\n };\n })();\n\n // Initialize security config\n this.securityConfig = DEFAULT_SECURITY_CONFIG;\n \n // Initialize provider registry\n this.providerRegistry = getProviderRegistry();\n \n // Initialize slot registry\n this.slotRegistry = getSlotRegistry();\n \n // Initialize cache and diagnostics \n this.cache = getExtensionCache();\n this.diagnostics = getExtensionDiagnostics();\n\n // Build jiti aliases for the public, host-provided extension SDK contract.\n // Extensions must import from @xopcai/xopc/extension-sdk; private aliases\n // are intentionally not registered.\n const alias: Record<string, string> = {};\n const sdkPath = resolveExtensionSdkPath();\n if (sdkPath) {\n const sdkDir = dirname(sdkPath);\n const sdkSubpaths = [\n 'core',\n 'lazy',\n 'provider',\n 'channel',\n 'hooks',\n 'tools',\n 'testing',\n 'speech',\n 'media',\n ];\n const prefix = '@xopcai/xopc/extension-sdk';\n alias[prefix] = sdkPath;\n for (const subpath of sdkSubpaths) {\n alias[`${prefix}/${subpath}`] = join(sdkDir, `${subpath}.ts`);\n }\n }\n\n // Initialize jiti with TypeScript support and SDK alias\n this.jiti = createJiti(fileURLToPath(import.meta.url), {\n interopDefault: true,\n extensions: ['.ts', '.tsx', '.mts', '.cts', '.js', '.mjs', '.cjs', '.json'],\n alias,\n });\n }\n\n /**\n * Reuse a pre-built metadata snapshot (avoids duplicate filesystem discovery).\n */\n setManifestSnapshot(snapshot: ExtensionMetadataSnapshot | null): void {\n this.manifestSnapshot = snapshot;\n this.manifestRegistry = snapshot?.manifestRegistry ?? null;\n }\n\n getManifestSnapshot(): ExtensionMetadataSnapshot | null {\n return this.manifestSnapshot;\n }\n\n /**\n * Set security configuration \n */\n setSecurityConfig(config: Partial<SecurityConfig>): void {\n this.securityConfig = { ...this.securityConfig, ...config };\n }\n\n /**\n * Get security configuration \n */\n getSecurityConfig(): SecurityConfig {\n return this.securityConfig;\n }\n\n /**\n * Get provider registry \n */\n getProviderRegistry(): ProviderPluginRegistry {\n return this.providerRegistry;\n }\n\n /**\n * Get slot registry \n */\n getSlotRegistry(): SlotRegistry {\n return this.slotRegistry;\n }\n\n /**\n * Get diagnostics \n */\n getDiagnostics(): ExtensionDiagnostics {\n return this.diagnostics;\n }\n\n /**\n * Set configuration from main Config object \n */\n setConfig(config: Config): void {\n this._appConfig = config;\n // Wire slot config\n const slots = (config.extensions as any)?.slots || {};\n this.slotsConfig = {\n memory: slots.memory,\n tts: slots.tts,\n imageGeneration: slots.imageGeneration,\n webSearch: slots.webSearch,\n };\n\n // Wire security config\n const security = (config.extensions as any)?.security;\n if (security) {\n this.securityConfig = {\n checkPermissions: security.checkPermissions ?? true,\n allowUntrusted: security.allowUntrusted ?? false,\n allow: security.allow ?? [],\n trackProvenance: security.trackProvenance ?? true,\n allowPromptInjection: security.allowPromptInjection ?? false,\n };\n }\n }\n\n /**\n * Inject MessageBus and optional SessionManager for ExtensionApi.runtime (Gateway).\n */\n setRuntimeContext(ctx: {\n bus?: MessageBus;\n sessionManager?: SessionIndex;\n scheduleWebchatContinuation?: (sessionKey: string, message: string) => void;\n setLabel?: (entryId: string, label: string | undefined) => void;\n sendUserMessage?: import('./types/index.js').ExtensionRuntime['sendUserMessage'];\n appendEntry?: import('./types/index.js').ExtensionRuntime['appendEntry'];\n sendMessage?: import('./types/index.js').ExtensionRuntime['sendMessage'];\n }): void {\n this._runtimeContext = ctx;\n // ExtensionApi snapshots `runtime` at construction and is tied to this loader's registry.\n // CLI startup loads extensions with `{ bus }` first; a global cache hit would reuse that\n // api for the gateway loader (no sessionManager, wrong registry) — breaks extensions that need SessionManager.\n this.cache.invalidate();\n }\n\n getRegistry(): ExtensionRegistryImpl {\n return this.registry;\n }\n\n /**\n * Phase 1: build manifest registry (filesystem manifests only, no extension code load).\n */\n buildManifestRegistry(): ManifestRegistry {\n if (this.manifestRegistry) {\n return this.manifestRegistry;\n }\n const discovered = this.discoverExtensions();\n this.manifestRegistry = ManifestRegistry.fromDiscovered(discovered);\n return this.manifestRegistry;\n }\n\n /**\n * Phase 2: activation planner over the manifest registry (pure logic).\n */\n planActivation(_context?: Partial<ActivationContext>): ActivationPlanner {\n return new ActivationPlanner(this.buildManifestRegistry());\n }\n\n /**\n * Phase 3: load only extensions selected by the activation plan.\n */\n async loadByActivationPlan(context?: ActivationPlanLoadOptions): Promise<void> {\n if (areExtensionsGloballyDisabled(this._appConfig as DiscoverConfig | undefined)) {\n log.debug('Extension loading skipped (extensions globally disabled)');\n return;\n }\n\n const registry = this.buildManifestRegistry();\n const planner = new ActivationPlanner(registry);\n const fullContext = mergeActivationContext(this._appConfig, context);\n let activatedIds = planner.getActivatedIds(fullContext).sort((a, b) => a.localeCompare(b));\n\n const phase = context?.phase ?? 'all';\n if (phase === 'startup' || phase === 'deferred') {\n activatedIds = planner.filterActivatedIdsByLoadPhase(activatedIds, phase);\n }\n\n const concurrency = Number.parseInt(\n process.env.XOPC_EXTENSION_LOAD_CONCURRENCY ?? '',\n 10,\n );\n const loadConcurrency = Number.isFinite(concurrency) && concurrency > 0\n ? concurrency\n : DEFAULT_EXTENSION_LOAD_CONCURRENCY;\n\n await mapWithConcurrency(activatedIds, loadConcurrency, async (extensionId) => {\n if (this.extensionInstances.has(extensionId)) {\n return;\n }\n const entry = registry.getEntry(extensionId);\n if (!entry) {\n log.debug(\n { extensionId },\n 'Activation plan references extension id that was not discovered on disk',\n );\n return;\n }\n\n const config: ResolvedExtensionConfig = {\n id: extensionId,\n name: entry.manifest.name || extensionId,\n source: entry.source,\n path: entry.path,\n enabled: true,\n config: this.resolveExtensionConfig(extensionId),\n };\n\n await this.loadExtension(config);\n });\n }\n\n getManifestRegistry(): ManifestRegistry {\n return this.buildManifestRegistry();\n }\n\n invalidateManifestCache(): void {\n this.manifestRegistry = this.manifestSnapshot?.manifestRegistry ?? null;\n }\n\n private resolveExtensionConfig(extensionId: string): Record<string, unknown> {\n if (!this._appConfig) return {};\n const extensionsConfig = (this._appConfig as Record<string, unknown>).extensions as\n | Record<string, unknown>\n | undefined;\n if (!extensionsConfig || typeof extensionsConfig !== 'object') return {};\n const raw = extensionsConfig[extensionId];\n if (raw && typeof raw === 'object' && !Array.isArray(raw)) {\n return raw as Record<string, unknown>;\n }\n return {};\n }\n\n /**\n * Discover extensions from all three tiers:\n * 1. Workspace (.extensions/) - highest priority\n * 2. Global (~/.xopc/extensions/) - shared\n * 3. Bundled (xopc/extensions/) - lowest priority\n */\n discoverExtensions(): DiscoveredExtension[] {\n if (this.manifestSnapshot) {\n return this.manifestSnapshot.discovered;\n }\n return discoverExtensionsFromDisk(this.options, this._appConfig as DiscoverConfig | undefined);\n }\n\n /**\n * Load all discovered extensions\n */\n async loadAllExtensions(enabledIds?: string[]): Promise<void> {\n const extensions = this.discoverExtensions();\n\n for (const extension of extensions) {\n // If enabledIds specified, only load those\n if (enabledIds && !enabledIds.includes(extension.id)) {\n continue;\n }\n\n const config: ResolvedExtensionConfig = {\n id: extension.id,\n name: extension.manifest.name || extension.id,\n source: extension.source,\n path: extension.path,\n enabled: true,\n config: {},\n };\n\n await this.loadExtension(config);\n }\n }\n\n async loadExtensions(configs: ResolvedExtensionConfig[]): Promise<void> {\n for (const extensionConfig of configs) {\n if (extensionConfig.enabled) {\n await this.loadExtension(extensionConfig);\n }\n }\n }\n\n async loadExtension(config: ResolvedExtensionConfig): Promise<ExtensionApi | null> {\n try {\n // Check cache first\n const cacheKey = this.cache.buildKey(this.options, [config.id]);\n const cached = this.cache.get<ExtensionApi>(cacheKey);\n if (cached) {\n log.debug({ extensionId: config.id }, 'Extension loaded from cache');\n return cached;\n }\n\n // Check if already loaded\n if (this.extensionInstances.has(config.id)) {\n return this.extensionInstances.get(config.id)!;\n }\n\n // Resolve extension path using resolveExtensionPath\n let extensionPath: string | null;\n if (isAbsolute(config.path)) {\n extensionPath = config.path;\n } else {\n // Try to resolve extension ID to actual path\n extensionPath = resolveExtensionPath(config.path, this.options) ||\n resolveExtensionPath(config.id, this.options);\n }\n \n if (!extensionPath) {\n log.error({ extensionId: config.id, path: config.path }, `Could not resolve extension path`);\n this.diagnostics.error(config.id, `Could not resolve extension path: ${config.path}`);\n return null;\n }\n\n log.debug({ extensionId: config.id, extensionPath }, 'Resolved extension path');\n\n // Security check\n const source = config.source || 'bundled';\n const safetyResult = checkExtensionPathSafety(extensionPath, extensionPath, source);\n \n if (!safetyResult.safe) {\n logSecurityIssue(config.id, safetyResult);\n \n if (this.securityConfig.checkPermissions && source !== 'bundled') {\n // Check allowlist\n if (!isExtensionAllowed(config.id, this.securityConfig)) {\n this.diagnostics.error(config.id, `Extension not allowed: ${safetyResult.detail}`);\n log.error({ extensionId: config.id, reason: safetyResult.reason }, 'Extension blocked by security policy');\n return null;\n }\n }\n }\n\n // Track provenance \n provenanceTracker.track(config.id, source);\n\n const manifest = this.loadManifest(extensionPath);\n if (!manifest) {\n log.error({ extensionId: config.id, extensionPath }, `Failed to load manifest for extension`);\n this.diagnostics.error(config.id, `Failed to load manifest`);\n return null;\n }\n\n if (!manifest.main || !/\\.(js|mjs|cjs)$/i.test(manifest.main)) {\n const reason = `Extension manifest main must point at built JavaScript (.js/.mjs/.cjs): ${manifest.main ?? '(missing)'}`;\n log.warn({ extensionId: config.id, main: manifest.main }, reason);\n this.diagnostics.error(config.id, reason);\n return null;\n }\n\n if (!manifest.engines?.xopc) {\n const reason = 'Extension manifest must declare engines.xopc';\n log.warn({ extensionId: config.id }, reason);\n this.diagnostics.error(config.id, reason);\n return null;\n }\n const range = manifest.engines.xopc;\n const engineResult = checkEngineCompatibility(PACKAGE_VERSION, range);\n if (engineResult.parseWarning) {\n const reason = engineResult.reason ?? `Could not parse engines.xopc: ${range}`;\n log.warn({ extensionId: config.id, range, reason }, 'Extension engine range parse failure — skipping load');\n this.diagnostics.error(config.id, reason);\n return null;\n }\n if (!engineResult.compatible) {\n log.warn(\n { extensionId: config.id, range, currentVersion: PACKAGE_VERSION },\n 'Extension engine requirement not met (engines.xopc) — skipping load',\n );\n this.diagnostics.error(\n config.id,\n engineResult.reason ?? 'Incompatible xopc version (engines.xopc)',\n );\n return null;\n }\n\n // Validate extension config against schema (basic validation)\n if (manifest.configSchema) {\n try {\n const schema = manifest.configSchema as Record<string, unknown>;\n const extensionConfig = config.config as Record<string, unknown>;\n \n // Basic validation: check required fields and types\n if (schema.type === 'object' && schema.properties) {\n const props = schema.properties as Record<string, Record<string, unknown>>;\n const required = (schema.required as string[]) || [];\n \n for (const field of required) {\n if (extensionConfig[field] === undefined) {\n log.error({ \n extensionId: config.id, \n field \n }, 'Extension config validation failed: missing required field');\n return null;\n }\n }\n \n for (const [key, value] of Object.entries(extensionConfig)) {\n const propSchema = props[key];\n if (propSchema) {\n if (propSchema.type && !this.validateType(value, propSchema.type as string)) {\n log.error({ \n extensionId: config.id, \n field: key,\n expected: propSchema.type,\n actual: typeof value\n }, 'Extension config validation failed: type mismatch');\n return null;\n }\n }\n }\n }\n \n log.debug({ extensionId: config.id }, 'Extension config validated');\n } catch (err) {\n log.warn({ err, extensionId: config.id }, 'Config schema validation skipped');\n }\n }\n\n // Create extension API\n const extensionDir = dirname(extensionPath);\n const api = this.createExtensionApi(manifest, config, extensionDir);\n\n // Load extension module\n const module = await this.loadModule(extensionPath, manifest);\n if (!module) {\n log.error({ extensionId: config.id }, `Failed to load module for extension`);\n this.diagnostics.error(config.id, `Failed to load module`);\n return null;\n }\n\n // Check and claim slots\n const slotClaimed = this.claimExtensionSlots(config.id, manifest);\n if (!slotClaimed) {\n log.warn({ extensionId: config.id }, 'Failed to claim required slots');\n }\n\n // Initialize extension\n await this.initializeExtension(module, api, manifest);\n\n validateSpeechProviderContracts({\n extensionId: config.id,\n manifest,\n registeredProviderIds: (api as ExtensionApiImpl).getRegisteredSpeechProviderIds(),\n logger: api.logger,\n });\n\n validateMediaUnderstandingProviderContracts({\n extensionId: config.id,\n manifest,\n registeredProviderIds: (api as ExtensionApiImpl).getRegisteredMediaUnderstandingProviderIds(),\n logger: api.logger,\n });\n\n // Register to registry\n this.registry.addExtension({\n id: config.id,\n name: manifest.name,\n version: manifest.version,\n path: extensionPath,\n module,\n config: config.config,\n enabled: true,\n source: config.source,\n });\n\n // Register extension tools to registry (so AgentManager can access them)\n // Note: api is actually ExtensionApiImpl at runtime\n const apiImpl = api as unknown as { _getTools: () => Map<string, AgentTool> };\n const extensionTools = apiImpl._getTools();\n for (const tool of extensionTools.values()) {\n this.registry.addTool(tool);\n }\n\n this.extensionInstances.set(config.id, api);\n \n // Cache the loaded extension\n this.cache.set(cacheKey, api);\n\n this.diagnostics.info(config.id, `Loaded extension: ${manifest.name}`);\n log.info({ name: manifest.name, id: manifest.id, source: config.source }, `Loaded extension`);\n\n return api;\n } catch (error) {\n log.error({ err: error, extensionId: config.id }, `Error loading extension`);\n this.diagnostics.error(config.id, `Error loading extension: ${error}`);\n return null;\n }\n }\n\n /**\n * Claim extension slots based on manifest kind\n * Respects configured preferred plugin from config.extensions.slots\n */\n private claimExtensionSlots(extensionId: string, manifest: ExtensionManifest): boolean {\n const kind = manifest.kind as string;\n \n // Map extension kind to slot\n const slotMap: Record<string, SlotKey> = {\n 'memory': 'memory',\n 'tts': 'tts',\n 'speech-provider': 'tts',\n 'web-search': 'webSearch',\n };\n \n const slotKey = slotMap[kind];\n if (!slotKey) {\n return true; // No slot required\n }\n \n // Check if slot is reserved for a different plugin in config\n const preferredPlugin = this.slotsConfig[slotKey];\n if (preferredPlugin && preferredPlugin !== extensionId) {\n log.info(\n { extensionId, slotKey, preferredPlugin },\n `Skipping slot claim: slot \"${slotKey}\" is reserved for \"${preferredPlugin}\"`\n );\n this.diagnostics.info(\n extensionId,\n `Slot \"${slotKey}\" is reserved for \"${preferredPlugin}\", skipping claim`\n );\n return false;\n }\n \n const claimed = this.slotRegistry.claim(slotKey, extensionId, null);\n if (!claimed) {\n this.diagnostics.warn(extensionId, `Slot \"${slotKey}\" already claimed by another extension`);\n }\n return claimed;\n }\n\n loadManifest(extensionPath: string): ExtensionManifest | null {\n const manifestPath = join(extensionPath, EXTENSION_MANIFEST_FILE);\n\n // First try to load xopc.extension.json\n if (existsSync(manifestPath)) {\n try {\n const raw = JSON.parse(readFileSync(manifestPath, 'utf-8'));\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n log.error({ manifestPath }, 'Manifest root must be a JSON object');\n return null;\n }\n return normalizeExtensionManifest(raw as Record<string, unknown>);\n } catch (error) {\n log.error({ err: error, manifestPath }, `Failed to parse manifest`);\n return null;\n }\n }\n\n return null;\n }\n\n private moduleEntryCandidates(manifest: ExtensionManifest): string[] {\n if (!manifest.main) return [];\n return [manifest.main];\n }\n\n private async loadModule(\n extensionPath: string,\n manifest: ExtensionManifest,\n ): Promise<ExtensionModule | null> {\n const entryPoints = this.moduleEntryCandidates(manifest);\n\n for (const entry of entryPoints) {\n const fullPath = isAbsolute(entry) ? entry : join(extensionPath, entry);\n\n if (existsSync(fullPath)) {\n try {\n if (!/\\.(js|mjs|cjs)$/.test(fullPath)) {\n throw new Error(`Extension runtime entry must be built JavaScript: ${entry}`);\n }\n const mod = await import(pathToFileURL(fullPath).href);\n return mod.default || mod;\n } catch (error) {\n log.warn({ err: error, path: fullPath }, `Failed to load module`);\n }\n }\n }\n\n return null;\n }\n\n private createExtensionApi(\n manifest: ExtensionManifest,\n resolved: ResolvedExtensionConfig,\n extensionDir: string,\n ): ExtensionApi {\n const logger = createExtensionLogger(`[${manifest.id}]`);\n const resolvePath = createPathResolver(extensionDir, this.options.workspaceDir || '');\n\n const appConfig = this._appConfig ?? ({} as Config);\n const extensionOnly = (resolved.config ?? {}) as Record<string, unknown>;\n\n const runtime =\n this._appConfig && this._runtimeContext\n ? {\n config: this._appConfig,\n bus: this._runtimeContext.bus,\n log: logger,\n sessionManager: this._runtimeContext.sessionManager,\n scheduleWebchatContinuation: this._runtimeContext.scheduleWebchatContinuation,\n setLabel: this._runtimeContext.setLabel,\n sendUserMessage: this._runtimeContext.sendUserMessage,\n appendEntry: this._runtimeContext.appendEntry,\n sendMessage: this._runtimeContext.sendMessage,\n }\n : this._appConfig\n ? {\n config: this._appConfig,\n log: logger,\n }\n : undefined;\n\n const api = new ExtensionApiImpl(\n manifest.id,\n manifest.name,\n manifest.version,\n extensionDir,\n appConfig,\n extensionOnly,\n logger,\n resolvePath,\n this.registry,\n manifest.contracts ?? {},\n runtime,\n );\n if (manifest.reload?.configPrefixes?.length) {\n api._setReloadConfigPrefixes(manifest.reload.configPrefixes);\n }\n const manifestCommands = manifest.ui?.contributions?.commands;\n if (manifestCommands?.length) {\n (api as ExtensionApiImpl)._setManifestCommands(manifestCommands);\n }\n return api;\n }\n\n private async initializeExtension(\n module: ExtensionModule,\n api: ExtensionApi,\n _manifest: ExtensionManifest,\n ): Promise<void> {\n if (typeof module === 'function') {\n // Module is a function that receives the API\n await module(api);\n } else if (typeof module === 'object' && module.register) {\n // Module is a ExtensionDefinition with register method\n await module.register(api);\n }\n }\n\n async startServices(): Promise<void> {\n const services = Array.from(this.registry.services.values());\n\n for (const service of services) {\n const serviceLog = createServiceLogger(service.id);\n try {\n await service.start?.();\n serviceLog.info(`Started service`);\n } catch (error) {\n serviceLog.error({ err: error }, `Failed to start service`);\n }\n }\n }\n\n async stopServices(): Promise<void> {\n const services = Array.from(this.registry.services.values()).reverse();\n\n for (const service of services) {\n if (service.stop) {\n const serviceLog = createServiceLogger(service.id);\n try {\n await service.stop();\n serviceLog.info(`Stopped service`);\n } catch (error) {\n serviceLog.error({ err: error }, `Failed to stop service`);\n }\n }\n }\n }\n\n /**\n * Basic type validation for config values\n */\n private validateType(value: unknown, expectedType: string): boolean {\n if (expectedType === 'string') return typeof value === 'string';\n if (expectedType === 'number' || expectedType === 'integer') return typeof value === 'number';\n if (expectedType === 'boolean') return typeof value === 'boolean';\n if (expectedType === 'array') return Array.isArray(value);\n if (expectedType === 'object') return typeof value === 'object' && value !== null && !Array.isArray(value);\n return true;\n }\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\nexport function resolveExtensionPath(id: string, _options: ExtensionLoaderOptions): string | null {\n const c = loadConfig();\n const aid = resolveDefaultAgentId(c);\n // Priority 1: Workspace\n const workspacePath = join(resolveWorkspaceExtensionsDir(c, aid), id);\n if (existsSync(workspacePath)) return workspacePath;\n\n // Priority 2: Global\n const globalPath = join(resolveExtensionsDir(), id);\n if (existsSync(globalPath)) return globalPath;\n\n // Priority 3: Bundled\n const bundledDir = resolveBundledExtensionsDir();\n if (bundledDir) {\n const bundledPath = join(bundledDir, id);\n if (existsSync(bundledPath)) return bundledPath;\n }\n\n return null;\n}\n\nexport function normalizeExtensionConfig(\n rawConfig: Record<string, unknown>,\n): ResolvedExtensionConfig[] {\n const extensions: ResolvedExtensionConfig[] = [];\n\n const enabled = (rawConfig.enabled as string[]) || [];\n const disabled = (rawConfig.disabled as string[]) || [];\n\n // Parse enabled extensions\n for (const id of enabled) {\n const config = (rawConfig[id] as Record<string, unknown>) || {};\n extensions.push({\n id,\n name: id,\n source: 'config',\n path: id,\n enabled: true,\n config,\n });\n }\n\n // Parse disabled extensions\n for (const id of disabled) {\n if (!extensions.find((p) => p.id === id)) {\n const config = (rawConfig[id] as Record<string, unknown>) || {};\n extensions.push({\n id,\n name: id,\n source: 'config',\n path: id,\n enabled: false,\n config,\n });\n }\n }\n\n return extensions;\n}\n"],"mappings":"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"}
|
|
@@ -6,8 +6,16 @@ export interface ExtensionLockEntry {
|
|
|
6
6
|
version: string;
|
|
7
7
|
/** Resolved URL or path */
|
|
8
8
|
resolved: string;
|
|
9
|
-
/**
|
|
9
|
+
/** Download artifact integrity, formatted as sha256-<base64>. */
|
|
10
10
|
integrity?: string;
|
|
11
|
+
/** Deterministic hash of installed files, formatted as dir-sha256-<base64>. */
|
|
12
|
+
installedIntegrity?: string;
|
|
13
|
+
/** Immutable artifact URL used during install, when available. */
|
|
14
|
+
artifactUrl?: string;
|
|
15
|
+
/** Manifest snapshot captured at install time. */
|
|
16
|
+
manifest?: Record<string, unknown>;
|
|
17
|
+
/** package.json snapshot captured at install time. */
|
|
18
|
+
packageJson?: Record<string, unknown>;
|
|
11
19
|
/** Installation timestamp */
|
|
12
20
|
installedAt: string;
|
|
13
21
|
/** Source type */
|