@xopcai/xopc 0.0.116 → 0.0.118
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -28
- package/README.zh-CN.md +63 -45
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/demo-memory/src/index.d.ts +6 -0
- package/dist/extensions/demo-memory/src/index.js +132 -0
- package/dist/extensions/demo-memory/src/index.js.map +1 -0
- package/dist/extensions/demo-memory/xopc.extension.json +15 -0
- package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
- package/dist/extensions/feishu/src/schema/config-schema.d.ts +3 -3
- package/dist/extensions/feishu/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/src/adapters/streaming-adapter.js +1 -1
- package/dist/extensions/telegram/src/command-handler.js +1 -2
- package/dist/extensions/telegram/src/command-handler.js.map +1 -1
- package/dist/extensions/telegram/src/config-schema.d.ts +8 -8
- package/dist/extensions/telegram/src/inbound-processor.js +1 -1
- package/dist/extensions/telegram/src/plugin.js +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.js +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- 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/config-schema.d.ts +3 -3
- 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.js +1 -1
- package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
- package/dist/extensions/weixin/src/workflow-progress.js +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CWM1UU5P.js → agent-avatar-dicebear-dzUrQoeZ.js} +1 -1
- package/dist/gateway/static/root/assets/agents-BCxZbkOw.js +2 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-yXSXY_bu.js → app-management-settings-panel-bxYJVJpx.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-DjY1P_ug.js → appearance-settings-BCIykXlI.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page--wMEL00f.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-CytE5j-e.js → archive-plugin-Cki4SfU2.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-BvvrN6rF.js → attachment-load-D-KnS2Do.js} +1 -1
- package/dist/gateway/static/root/assets/{binary-plugins-IBWSitnj.js → binary-plugins-D2sgvJja.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-C-wDpsf-.js → block-editor-DIq-4Gvb.js} +27 -27
- package/dist/gateway/static/root/assets/browser-settings-page-DRhKdn81.js +8 -0
- package/dist/gateway/static/root/assets/capability-presets-api-CorhiHlg.js +1 -0
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-qFx9Jtce.js +1 -0
- package/dist/gateway/static/root/assets/channels-settings-BAwAkqIA.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-BQLcfitM.js +2 -0
- package/dist/gateway/static/root/assets/cron-api-qGwmL-24.js +1 -0
- package/dist/gateway/static/root/assets/cron-page-BBWMAj8-.js +3 -0
- package/dist/gateway/static/root/assets/dreaming-settings-Dw89Obml.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-BAIyjDlq.js → extension-debug-page-DYu1KaFQ.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-DEhv2GpC.js → extension-page-B3W6QwlZ.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-DOuAxTDW.js → extension-settings-page-D7VQ-cxE.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-CTsREQIe.js → fetch-B7xDPu-R.js} +1 -1
- package/dist/gateway/static/root/assets/{format-interval-label-D35Bfhtx.js → format-interval-label-BzxafKxR.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-config-api-BTBLSeUu.js +1 -0
- package/dist/gateway/static/root/assets/gateway-settings-Cmwy58rS.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-C1KAHrd2.js → gateway-startup-retry-CYj9FWCp.js} +1 -1
- package/dist/gateway/static/root/assets/goal-detail-page-l7mu5GWX.js +1 -0
- package/dist/gateway/static/root/assets/{goals-config-api-KnLGpu6h.js → goals-config-api-CQQgzPr3.js} +1 -1
- package/dist/gateway/static/root/assets/goals-page-BHitvJAv.js +2 -0
- package/dist/gateway/static/root/assets/{goals-settings-DtPtqZi8.js → goals-settings-CYVY4NGp.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-uKw1f0IG.js → heartbeat-config-api-DriO_CN9.js} +1 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-CUQTKxg7.js +1 -0
- package/dist/gateway/static/root/assets/index-C17Tsd_b.css +1 -0
- package/dist/gateway/static/root/assets/index-Cc41r16l.js +191 -0
- package/dist/gateway/static/root/assets/{interval-presets-Dq0FXJ65.js → interval-presets-DFPCKW_W.js} +1 -1
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-C9_t4m7t.js → keyboard-shortcuts-settings-CcVcqstx.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-SNkWzidV.js → logs-page-C2Uqvae9.js} +2 -2
- package/dist/gateway/static/root/assets/{markdown-split-Ca87W8-h.js → markdown-split-BwOFrJ2E.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-BAcUjPRJ.js → media-plugins-Cnz6Q5G6.js} +1 -1
- package/dist/gateway/static/root/assets/messages-B1iSKjiw.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-panel-BfLfcta8.js +2 -0
- package/dist/gateway/static/root/assets/note-detail-page-BjwOQBfT.js +2 -0
- package/dist/gateway/static/root/assets/{note-image-lightbox-hnSX5SSn.js → note-image-lightbox-B-Svpmza.js} +1 -1
- package/dist/gateway/static/root/assets/notes-page-DktdBiwB.js +1 -0
- package/dist/gateway/static/root/assets/{preview-open-alternatives-CNgM20H5.js → preview-open-alternatives-Bss4TiwP.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-rfVx96fq.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-CcdjGcfT.js → save-bar-controls-BRNjdgKq.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-CYr39z76.js → schedule-field-CUCKODde.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-BRAJgZQ2.js → schema-form-Dub9sy8r.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-DbtMFuuH.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-5re5gAnP.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-BhzjeGWi.js → settings-collapsible-section-BeFLavGi.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-Cz3Pcr9b.js → settings-form-section-dmyaPOTG.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-D-WMyLlj.js +1 -0
- package/dist/gateway/static/root/assets/setup-status-panel-Cl-DEJAU.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-DL4y9K5e.js → share-preview-page-C8glrdqe.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-CyPVvbLt.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-CleTH1oz.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-Ck8hdXqR.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-FD2jxRZ3.js → system-settings-panel-DI-LN_8G.js} +1 -1
- package/dist/gateway/static/root/assets/typed-models-lib-kX9duch4.js +1 -0
- package/dist/gateway/static/root/assets/{use-channel-catalog-BInPrfR5.js → use-channel-catalog-DqlWTsDb.js} +1 -1
- package/dist/gateway/static/root/assets/user-profile-settings-panel-B-UFPMXy.js +1 -0
- package/dist/gateway/static/root/assets/utils-Dm0hKalR.js +1 -0
- package/dist/gateway/static/root/assets/voice-api-key-field-C73IVZeC.js +1 -0
- package/dist/gateway/static/root/assets/{voice-player-store-1U3vFppm.js → voice-player-store-C_ArLJPM.js} +1 -1
- package/dist/gateway/static/root/assets/workflows-page-BtFGp2y_.js +18 -0
- package/dist/gateway/static/root/index.html +5 -5
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +1 -1
- package/dist/src/agent/agent-manager.js +14 -14
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/agent-scope.js +5 -9
- package/dist/src/agent/agent-scope.js.map +1 -1
- package/dist/src/agent/background-review/coordinator.js +0 -1
- package/dist/src/agent/background-review/coordinator.js.map +1 -1
- package/dist/src/agent/background-review/prompts.d.ts +2 -2
- package/dist/src/agent/background-review/prompts.js +2 -2
- package/dist/src/agent/background-review/prompts.js.map +1 -1
- package/dist/src/agent/background-review/run-background-review.d.ts +0 -2
- package/dist/src/agent/background-review/run-background-review.js +2 -4
- package/dist/src/agent/background-review/run-background-review.js.map +1 -1
- package/dist/src/agent/background-review/settings.d.ts +1 -1
- package/dist/src/agent/background-review/settings.js +8 -8
- package/dist/src/agent/background-review/settings.js.map +1 -1
- package/dist/src/agent/bootstrap/bootstrap-cache.d.ts +1 -0
- package/dist/src/agent/bootstrap/bootstrap-cache.js +4 -3
- package/dist/src/agent/bootstrap/bootstrap-cache.js.map +1 -1
- package/dist/src/agent/bootstrap/bootstrap-context.d.ts +2 -2
- package/dist/src/agent/bootstrap/bootstrap-context.js +4 -4
- package/dist/src/agent/bootstrap/bootstrap-context.js.map +1 -1
- package/dist/src/agent/bootstrap/bootstrap-files.d.ts +4 -0
- package/dist/src/agent/bootstrap/bootstrap-files.js +4 -3
- package/dist/src/agent/bootstrap/bootstrap-files.js.map +1 -1
- package/dist/src/agent/bootstrap/filter-bootstrap-files.js +4 -2
- package/dist/src/agent/bootstrap/filter-bootstrap-files.js.map +1 -1
- package/dist/src/agent/bootstrap/load-bootstrap-files.d.ts +2 -1
- package/dist/src/agent/bootstrap/load-bootstrap-files.js +18 -17
- package/dist/src/agent/bootstrap/load-bootstrap-files.js.map +1 -1
- package/dist/src/agent/bootstrap/project-agents-context.js +1 -1
- package/dist/src/agent/bootstrap/types.d.ts +1 -1
- package/dist/src/agent/context/workspace-seed.js +3 -3
- package/dist/src/agent/context/workspace-state.js +1 -1
- package/dist/src/agent/context/workspace-templates/AGENTS.md +1 -1
- package/dist/src/agent/context/workspace.d.ts +4 -2
- package/dist/src/agent/context/workspace.js +6 -5
- package/dist/src/agent/context/workspace.js.map +1 -1
- package/dist/src/agent/embedded/run-for-session.js +4 -1
- package/dist/src/agent/embedded/run-for-session.js.map +1 -1
- package/dist/src/agent/fallback/candidates.js +11 -9
- package/dist/src/agent/fallback/candidates.js.map +1 -1
- package/dist/src/agent/goals/goal-locale.js +2 -2
- package/dist/src/agent/goals/post-turn.js +3 -3
- package/dist/src/agent/image/generation/runtime-types.d.ts +2 -0
- package/dist/src/agent/image/generation/runtime.js +1 -1
- package/dist/src/agent/image/generation/runtime.js.map +1 -1
- package/dist/src/agent/image/image-helpers.d.ts +1 -1
- package/dist/src/agent/image/image-helpers.js +4 -17
- package/dist/src/agent/image/image-helpers.js.map +1 -1
- package/dist/src/agent/image/image-model-fallback.js +1 -1
- package/dist/src/agent/image/image-model-fallback.js.map +1 -1
- package/dist/src/agent/image/inbound-image-handling.js +1 -1
- package/dist/src/agent/image/inbound-image-handling.js.map +1 -1
- package/dist/src/agent/image/load-image-media.js +2 -2
- package/dist/src/agent/image/tool-model-config.d.ts +1 -1
- package/dist/src/agent/image/tool-model-config.js +2 -2
- package/dist/src/agent/image/tool-model-config.js.map +1 -1
- package/dist/src/agent/ipc/inbox.js +3 -3
- package/dist/src/agent/ipc/socket.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js +1 -1
- package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
- package/dist/src/agent/mcp/mcp-transport.js +1 -1
- package/dist/src/agent/mcp/resolve-embedded-mcp-tools.js +1 -1
- package/dist/src/agent/mcp/resolve-embedded-mcp-tools.js.map +1 -1
- package/dist/src/agent/media-generation/runtime-shared.d.ts +5 -2
- package/dist/src/agent/media-generation/runtime-shared.js +1 -1
- package/dist/src/agent/media-generation/runtime-shared.js.map +1 -1
- package/dist/src/agent/memory/builtin-memory-store.d.ts +6 -2
- package/dist/src/agent/memory/builtin-memory-store.js +15 -6
- package/dist/src/agent/memory/builtin-memory-store.js.map +1 -1
- package/dist/src/agent/memory/builtin-provider.d.ts +31 -9
- package/dist/src/agent/memory/builtin-provider.js +290 -11
- package/dist/src/agent/memory/builtin-provider.js.map +1 -1
- package/dist/src/agent/memory/candidate-extractor.d.ts +6 -0
- package/dist/src/agent/memory/candidate-extractor.js +60 -0
- package/dist/src/agent/memory/candidate-extractor.js.map +1 -0
- package/dist/src/agent/memory/context-assembler.d.ts +10 -0
- package/dist/src/agent/memory/context-assembler.js +26 -0
- package/dist/src/agent/memory/context-assembler.js.map +1 -0
- package/dist/src/agent/memory/create-memory-manager.js +25 -7
- package/dist/src/agent/memory/create-memory-manager.js.map +1 -1
- package/dist/src/agent/memory/dreaming/config.d.ts +1 -6
- package/dist/src/agent/memory/dreaming/config.js +8 -8
- package/dist/src/agent/memory/dreaming/config.js.map +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.d.ts +2 -0
- package/dist/src/agent/memory/dreaming/deep-promotion.js +25 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.js.map +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/index.d.ts +1 -0
- package/dist/src/agent/memory/index.js +4 -3
- package/dist/src/agent/memory/inject-prefetch.js +6 -2
- package/dist/src/agent/memory/inject-prefetch.js.map +1 -1
- package/dist/src/agent/memory/manager.d.ts +39 -2
- package/dist/src/agent/memory/manager.js +355 -39
- package/dist/src/agent/memory/manager.js.map +1 -1
- package/dist/src/agent/memory/memory-config.js +15 -15
- package/dist/src/agent/memory/memory-config.js.map +1 -1
- package/dist/src/agent/memory/memory-flush.js +1 -1
- package/dist/src/agent/memory/plugin-discovery.d.ts +19 -5
- package/dist/src/agent/memory/plugin-discovery.js +97 -31
- package/dist/src/agent/memory/plugin-discovery.js.map +1 -1
- package/dist/src/agent/memory/prefetch-coordinator.js.map +1 -1
- package/dist/src/agent/memory/provider.d.ts +20 -15
- package/dist/src/agent/memory/stub-memory-provider.d.ts +17 -2
- package/dist/src/agent/memory/stub-memory-provider.js +20 -3
- package/dist/src/agent/memory/stub-memory-provider.js.map +1 -1
- package/dist/src/agent/memory/types.d.ts +162 -3
- package/dist/src/agent/models/manager.d.ts +1 -1
- package/dist/src/agent/models/manager.js +2 -2
- package/dist/src/agent/models/manager.js.map +1 -1
- package/dist/src/agent/orchestration/agent-orchestrator.d.ts +1 -1
- package/dist/src/agent/orchestration/agent-orchestrator.js +2 -1
- package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
- package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.d.ts +2 -2
- package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.js +1 -1
- package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.js.map +1 -1
- package/dist/src/agent/orchestration/run-agent-turn-with-timeout.d.ts +2 -6
- package/dist/src/agent/orchestration/run-agent-turn-with-timeout.js +2 -8
- package/dist/src/agent/orchestration/run-agent-turn-with-timeout.js.map +1 -1
- package/dist/src/agent/prompt/memory/index.d.ts +4 -2
- package/dist/src/agent/prompt/memory/index.js +19 -13
- package/dist/src/agent/prompt/memory/index.js.map +1 -1
- package/dist/src/agent/prompt/sections/memory-skills.js +1 -1
- package/dist/src/agent/prompt/sections/memory-skills.js.map +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +5 -20
- package/dist/src/agent/prompt/service-prompt-builder.js.map +1 -1
- package/dist/src/agent/reply/post-compaction-context.js +10 -7
- package/dist/src/agent/reply/post-compaction-context.js.map +1 -1
- package/dist/src/agent/reply/startup-context.js +7 -12
- package/dist/src/agent/reply/startup-context.js.map +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/process-direct-streaming.js +1 -4
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service/session-context-report.js +1 -1
- package/dist/src/agent/service/session-context-report.js.map +1 -1
- package/dist/src/agent/service.d.ts +3 -3
- package/dist/src/agent/service.js +30 -35
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/service.types.d.ts +1 -2
- package/dist/src/agent/session/session-hydrator.js +1 -2
- package/dist/src/agent/session/session-hydrator.js.map +1 -1
- package/dist/src/agent/session/session-inspector.d.ts +1 -1
- package/dist/src/agent/session/session-inspector.js +10 -15
- package/dist/src/agent/session/session-inspector.js.map +1 -1
- package/dist/src/agent/skills/config.js +2 -2
- package/dist/src/agent/skills/filesystem-watcher.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 +3 -3
- package/dist/src/agent/skills/index.js +2 -2
- package/dist/src/agent/skills/installer.js +2 -2
- package/dist/src/agent/skills/managed-store.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/skills/skill-view-path.js +1 -1
- package/dist/src/agent/skills/test-framework.js +1 -1
- package/dist/src/agent/starter-agents.d.ts +1 -3
- package/dist/src/agent/starter-agents.js +14 -22
- package/dist/src/agent/starter-agents.js.map +1 -1
- package/dist/src/agent/tools/browser/tool/browser-use-tool.js +1 -2
- package/dist/src/agent/tools/browser/tool/browser-use-tool.js.map +1 -1
- package/dist/src/agent/tools/curated-memory-tool.d.ts +2 -5
- package/dist/src/agent/tools/curated-memory-tool.js +77 -18
- package/dist/src/agent/tools/curated-memory-tool.js.map +1 -1
- package/dist/src/agent/tools/dreaming-tool.js +1 -1
- package/dist/src/agent/tools/factory.d.ts +0 -4
- package/dist/src/agent/tools/factory.js +19 -58
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/find.js +1 -1
- package/dist/src/agent/tools/grep.js +1 -1
- package/dist/src/agent/tools/image-generate-tool.d.ts +1 -1
- package/dist/src/agent/tools/image-generate-tool.js +20 -15
- package/dist/src/agent/tools/image-generate-tool.js.map +1 -1
- package/dist/src/agent/tools/image-tool.js +1 -3
- package/dist/src/agent/tools/image-tool.js.map +1 -1
- package/dist/src/agent/tools/memory-tool.d.ts +2 -2
- package/dist/src/agent/tools/memory-tool.js +39 -14
- package/dist/src/agent/tools/memory-tool.js.map +1 -1
- package/dist/src/agent/tools/session-search-tool.js +1 -3
- package/dist/src/agent/tools/session-search-tool.js.map +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js +1 -1
- package/dist/src/agent/tools/web-extract.js +8 -9
- package/dist/src/agent/tools/web-extract.js.map +1 -1
- package/dist/src/agent/tools/workflow-tool.js +1 -1
- package/dist/src/agent/workflow/catalog.js +1 -1
- package/dist/src/agent/workflow/subagent-runner.js +1 -3
- package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
- package/dist/src/agent-manifest/index.d.ts +4 -0
- package/dist/src/agent-manifest/index.js +10 -0
- package/dist/src/agent-manifest/index.js.map +1 -0
- package/dist/src/agent-manifest/prompt.d.ts +2 -0
- package/dist/src/agent-manifest/prompt.js +57 -0
- package/dist/src/agent-manifest/prompt.js.map +1 -0
- package/dist/src/agent-manifest/resolver.d.ts +12 -0
- package/dist/src/agent-manifest/resolver.js +95 -0
- package/dist/src/agent-manifest/resolver.js.map +1 -0
- package/dist/src/agent-manifest/schema.d.ts +1010 -0
- package/dist/src/agent-manifest/schema.js +269 -0
- package/dist/src/agent-manifest/schema.js.map +1 -0
- package/dist/src/agent-manifest/validator.d.ts +25 -0
- package/dist/src/agent-manifest/validator.js +88 -0
- package/dist/src/agent-manifest/validator.js.map +1 -0
- package/dist/src/agent-runtime/boundary-guard.d.ts +12 -0
- package/dist/src/agent-runtime/boundary-guard.js +23 -0
- package/dist/src/agent-runtime/boundary-guard.js.map +1 -0
- package/dist/src/agent-runtime/index.d.ts +7 -0
- package/dist/src/agent-runtime/index.js +8 -0
- package/dist/src/agent-runtime/memory-runtime.d.ts +21 -0
- package/dist/src/agent-runtime/memory-runtime.js +50 -0
- package/dist/src/agent-runtime/memory-runtime.js.map +1 -0
- package/dist/src/agent-runtime/model-router.d.ts +11 -0
- package/dist/src/agent-runtime/model-router.js +16 -0
- package/dist/src/agent-runtime/model-router.js.map +1 -0
- package/dist/src/agent-runtime/run-trace.d.ts +27 -0
- package/dist/src/agent-runtime/run-trace.js +53 -0
- package/dist/src/agent-runtime/run-trace.js.map +1 -0
- package/dist/src/agent-runtime/runtime-profile.d.ts +24 -0
- package/dist/src/agent-runtime/runtime-profile.js +44 -0
- package/dist/src/agent-runtime/runtime-profile.js.map +1 -0
- package/dist/src/agent-runtime/tool-registry.d.ts +28 -0
- package/dist/src/agent-runtime/tool-registry.js +52 -0
- package/dist/src/agent-runtime/tool-registry.js.map +1 -0
- package/dist/src/agent-runtime/workflow-runtime.d.ts +31 -0
- package/dist/src/agent-runtime/workflow-runtime.js +34 -0
- package/dist/src/agent-runtime/workflow-runtime.js.map +1 -0
- package/dist/src/ai-assist/text-assist.js +1 -1
- package/dist/src/auth/credentials.js +2 -2
- package/dist/src/auth/profiles/store.js +2 -2
- package/dist/src/auth/sync-provider-auth.js +1 -1
- package/dist/src/browser/actions/extension-registry-bridge.js +1 -1
- package/dist/src/browser/actions/extension-registry-bridge.js.map +1 -1
- package/dist/src/browser/actions/registry.js +5 -8
- package/dist/src/browser/actions/registry.js.map +1 -1
- package/dist/src/browser/backend-from-config.d.ts +1 -1
- package/dist/src/browser/backend-from-config.js +50 -71
- package/dist/src/browser/backend-from-config.js.map +1 -1
- package/dist/src/browser/browser-command-timeout.d.ts +0 -1
- package/dist/src/browser/browser-command-timeout.js +3 -7
- package/dist/src/browser/browser-command-timeout.js.map +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/pipeline/source.js +1 -1
- package/dist/src/browser/providers/browser-ext-install.d.ts +2 -12
- package/dist/src/browser/providers/browser-ext-install.js +7 -12
- package/dist/src/browser/providers/browser-ext-install.js.map +1 -1
- package/dist/src/browser/providers/cloakbrowser.js +5 -5
- package/dist/src/browser/providers/playwright-doctor.js +1 -1
- package/dist/src/browser/readiness.js +16 -16
- package/dist/src/browser/readiness.js.map +1 -1
- package/dist/src/browser/schemas.js +1 -1
- package/dist/src/browser/schemas.js.map +1 -1
- package/dist/src/browser/stealth.js +1 -1
- package/dist/src/channels/catalog/channel-catalog-service.js +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/pipeline.d.ts +1 -1
- package/dist/src/channels/pipeline.js.map +1 -1
- package/dist/src/chat-commands/agent-edit.js +2 -3
- package/dist/src/chat-commands/agent-edit.js.map +1 -1
- package/dist/src/chat-commands/builtins/config.js +6 -6
- package/dist/src/chat-commands/builtins/config.js.map +1 -1
- package/dist/src/chat-commands/builtins/model.js +2 -2
- package/dist/src/chat-commands/builtins/model.js.map +1 -1
- package/dist/src/chat-commands/builtins/thinking.js +16 -42
- package/dist/src/chat-commands/builtins/thinking.js.map +1 -1
- package/dist/src/chat-commands/config-paths.js +1 -1
- package/dist/src/chat-commands/config-paths.js.map +1 -1
- package/dist/src/chat-commands/context.js +3 -4
- package/dist/src/chat-commands/context.js.map +1 -1
- package/dist/src/cli/command-manifest.d.ts +1 -1
- package/dist/src/cli/command-manifest.js +2 -2
- package/dist/src/cli/command-manifest.js.map +1 -1
- package/dist/src/cli/commands/agent.js +3 -1
- package/dist/src/cli/commands/agent.js.map +1 -1
- package/dist/src/cli/commands/agents.js +3 -6
- package/dist/src/cli/commands/agents.js.map +1 -1
- package/dist/src/cli/commands/browser-cli-helpers.js +9 -11
- package/dist/src/cli/commands/browser-cli-helpers.js.map +1 -1
- package/dist/src/cli/commands/config.js +6 -6
- package/dist/src/cli/commands/config.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +3 -18
- package/dist/src/cli/commands/doctor/checks/provider-auth.js.map +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 -2
- package/dist/src/cli/commands/doctor/checks/workspace-status.js.map +1 -1
- package/dist/src/cli/commands/extension-create.js +1 -1
- package/dist/src/cli/commands/extension-dev.js +2 -2
- package/dist/src/cli/commands/extension-marketplace.js +2 -2
- package/dist/src/cli/commands/extension-pack.js +2 -2
- package/dist/src/cli/commands/extension.js +3 -3
- package/dist/src/cli/commands/gateway/logs.js +1 -1
- package/dist/src/cli/commands/goal.js +1 -1
- package/dist/src/cli/commands/image.js +13 -372
- package/dist/src/cli/commands/image.js.map +1 -1
- package/dist/src/cli/commands/init.js +7 -6
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/models.js +14 -16
- package/dist/src/cli/commands/models.js.map +1 -1
- package/dist/src/cli/commands/onboard/channels/registry.js.map +1 -1
- package/dist/src/cli/commands/onboard/model.js +28 -23
- package/dist/src/cli/commands/onboard/model.js.map +1 -1
- package/dist/src/cli/commands/onboard.js +3 -3
- package/dist/src/cli/commands/onboard.js.map +1 -1
- package/dist/src/cli/commands/skills-test.js +1 -1
- package/dist/src/cli/commands/tui.js +2 -2
- package/dist/src/cli/commands/tui.js.map +1 -1
- package/dist/src/cli/index.d.ts +1 -0
- package/dist/src/cli/index.js +10 -5
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/registry.js +1 -1
- package/dist/src/cli/registry.js.map +1 -1
- package/dist/src/cli/templates.d.ts +1 -1
- package/dist/src/cli/templates.js +2 -12
- package/dist/src/cli/templates.js.map +1 -1
- package/dist/src/cli/utils/gateway-client.js +1 -1
- package/dist/src/cli/utils/init-workspace-core.d.ts +1 -4
- package/dist/src/cli/utils/init-workspace-core.js +9 -8
- package/dist/src/cli/utils/init-workspace-core.js.map +1 -1
- package/dist/src/commands/agents.config.d.ts +0 -1
- package/dist/src/commands/agents.config.js +59 -13
- package/dist/src/commands/agents.config.js.map +1 -1
- package/dist/src/config/agent-profile.d.ts +5 -17
- package/dist/src/config/agent-profile.js +32 -64
- package/dist/src/config/agent-profile.js.map +1 -1
- package/dist/src/config/agent-typed-models.d.ts +1 -1
- package/dist/src/config/agent-typed-models.js +3 -6
- package/dist/src/config/agent-typed-models.js.map +1 -1
- package/dist/src/config/gateway-bind.js +1 -1
- package/dist/src/config/index.js +9 -9
- package/dist/src/config/integration.d.ts +1 -1
- package/dist/src/config/loader.js +4 -4
- 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 +8 -1
- package/dist/src/config/paths.js +17 -4
- package/dist/src/config/paths.js.map +1 -1
- package/dist/src/config/profile.js +1 -1
- package/dist/src/config/reload.js +2 -2
- package/dist/src/config/reload.js.map +1 -1
- package/dist/src/config/rules.js +6 -56
- package/dist/src/config/rules.js.map +1 -1
- package/dist/src/config/schema.d.ts +916 -779
- package/dist/src/config/schema.js +174 -423
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/workspace-path.js +1 -1
- package/dist/src/connectors/composio-triggers.js +1 -1
- package/dist/src/cron/executor.js +1 -1
- package/dist/src/cron/index.js +1 -1
- package/dist/src/cron/service.js +2 -2
- package/dist/src/cron/validation.d.ts +3 -3
- 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/activation-context.js +13 -7
- package/dist/src/extensions/activation-context.js.map +1 -1
- package/dist/src/extensions/bundle-mcp.js +1 -1
- package/dist/src/extensions/discover-extensions.js +2 -2
- package/dist/src/extensions/health.js +1 -1
- package/dist/src/extensions/install.js +2 -2
- package/dist/src/extensions/loader.js +2 -2
- package/dist/src/extensions/lockfile.js +3 -3
- package/dist/src/extensions/security.js +1 -1
- package/dist/src/extensions/update.js +2 -2
- package/dist/src/gateway/agents-admin.d.ts +24 -18
- package/dist/src/gateway/agents-admin.js +158 -92
- package/dist/src/gateway/agents-admin.js.map +1 -1
- package/dist/src/gateway/capability-presets-admin.d.ts +56 -0
- package/dist/src/gateway/capability-presets-admin.js +214 -0
- package/dist/src/gateway/capability-presets-admin.js.map +1 -0
- package/dist/src/gateway/chat-stream/mapper.js +9 -2
- package/dist/src/gateway/chat-stream/mapper.js.map +1 -1
- package/dist/src/gateway/file-path-classifier.js +2 -2
- package/dist/src/gateway/global-defaults-admin.d.ts +36 -0
- package/dist/src/gateway/global-defaults-admin.js +146 -0
- package/dist/src/gateway/global-defaults-admin.js.map +1 -0
- package/dist/src/gateway/hono/lib/agent-model.d.ts +1 -1
- package/dist/src/gateway/hono/lib/agent-model.js +1 -1
- package/dist/src/gateway/hono/lib/agent-model.js.map +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +234 -127
- package/dist/src/gateway/hono/lib/config-payload.js +14 -38
- package/dist/src/gateway/hono/lib/config-payload.js.map +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/routes/agents.js +88 -33
- 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/browser.js +8 -15
- package/dist/src/gateway/hono/routes/browser.js.map +1 -1
- package/dist/src/gateway/hono/routes/capability-presets.d.ts +3 -0
- package/dist/src/gateway/hono/routes/capability-presets.js +145 -0
- package/dist/src/gateway/hono/routes/capability-presets.js.map +1 -0
- package/dist/src/gateway/hono/routes/commands-skills.js +4 -5
- package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/agents.d.ts +1 -17
- package/dist/src/gateway/hono/routes/config-patch/agents.js +2 -443
- package/dist/src/gateway/hono/routes/config-patch/agents.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +7 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js.map +1 -1
- package/dist/src/gateway/hono/routes/config.js +1 -1
- package/dist/src/gateway/hono/routes/config.js.map +1 -1
- package/dist/src/gateway/hono/routes/dreaming.js +8 -1
- package/dist/src/gateway/hono/routes/dreaming.js.map +1 -1
- package/dist/src/gateway/hono/routes/global-defaults.d.ts +3 -0
- package/dist/src/gateway/hono/routes/global-defaults.js +61 -0
- package/dist/src/gateway/hono/routes/global-defaults.js.map +1 -0
- package/dist/src/gateway/hono/routes/host-fs.js +2 -2
- package/dist/src/gateway/hono/routes/index.js +2 -0
- package/dist/src/gateway/hono/routes/index.js.map +1 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js +17 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/memory.d.ts +3 -0
- package/dist/src/gateway/hono/routes/memory.js +361 -0
- package/dist/src/gateway/hono/routes/memory.js.map +1 -0
- package/dist/src/gateway/hono/routes/models.js +2 -2
- package/dist/src/gateway/hono/routes/shares.js +1 -1
- package/dist/src/gateway/hono/routes/workflows.js +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/config-coordinator.js +1 -1
- package/dist/src/gateway/service/marketplace-service.d.ts +4 -4
- package/dist/src/gateway/service/marketplace-service.js +13 -9
- package/dist/src/gateway/service/marketplace-service.js.map +1 -1
- package/dist/src/gateway/service.d.ts +1 -1
- package/dist/src/gateway/service.js +15 -16
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/workspace-fs-file-list.js +1 -1
- package/dist/src/goals/goal-workflow-judge.js +2 -2
- package/dist/src/i18n/goals-bundle.js +1 -1
- package/dist/src/i18n/index.js +1 -1
- package/dist/src/i18n/share-tool-bundle.js +2 -2
- 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 +1 -1
- 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 +2 -2
- package/dist/src/infra/update-restart.js +1 -1
- package/dist/src/infra/update-runner.js +1 -1
- package/dist/src/infra/update-startup.js +1 -1
- package/dist/src/infra/write-file-atomic.js +2 -2
- package/dist/src/media/store.js +1 -1
- package/dist/src/notes/agent-context.js +3 -3
- package/dist/src/notes/service.js +4 -2
- package/dist/src/notes/service.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.d.ts +5 -6
- package/dist/src/providers/index.js +26 -30
- package/dist/src/providers/index.js.map +1 -1
- package/dist/src/providers/model-registry.js +4 -4
- package/dist/src/session/index.js +1 -1
- package/dist/src/session/init-session-turn.js +1 -1
- package/dist/src/session/resolve-session.js +1 -1
- package/dist/src/session/session-title.js +2 -2
- package/dist/src/session/store.js +1 -1
- package/dist/src/session/thinking-resolve.d.ts +1 -1
- package/dist/src/session/thinking-resolve.js +1 -1
- package/dist/src/session/thinking-resolve.js.map +1 -1
- 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/index.d.ts +1 -0
- package/dist/src/storage/sqlite/index.js +2 -1
- package/dist/src/storage/sqlite/memory-index-repository.d.ts +1 -0
- package/dist/src/storage/sqlite/memory-index-repository.js +17 -16
- package/dist/src/storage/sqlite/memory-index-repository.js.map +1 -1
- package/dist/src/storage/sqlite/memory-records-repository.d.ts +144 -0
- package/dist/src/storage/sqlite/memory-records-repository.js +453 -0
- package/dist/src/storage/sqlite/memory-records-repository.js.map +1 -0
- package/dist/src/storage/sqlite/migrations/012_memory_records.sql +63 -0
- package/dist/src/storage/sqlite/migrations/013_memory_trace_events.sql +21 -0
- package/dist/src/storage/sqlite/migrations/014_memory_record_governance.sql +10 -0
- package/dist/src/storage/sqlite/migrations/015_memory_trace_feedback.sql +4 -0
- package/dist/src/storage/sqlite/migrations/discover.js +1 -1
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +4 -4
- package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +2 -2
- package/dist/src/storage/sqlite/schema.sql +86 -0
- package/dist/src/tui/backends/embedded-backend.d.ts +3 -0
- package/dist/src/tui/backends/embedded-backend.js +43 -24
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.d.ts +1 -0
- package/dist/src/tui/backends/gateway-sse-backend.js +16 -3
- 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/components/tui-header.d.ts +0 -1
- package/dist/src/tui/components/tui-header.js +3 -8
- package/dist/src/tui/components/tui-header.js.map +1 -1
- package/dist/src/tui/extension-host/load-extensions.js +1 -1
- package/dist/src/tui/extension-host/load-extensions.js.map +1 -1
- package/dist/src/tui/theme-manager.js +1 -1
- package/dist/src/tui/tui-command-formatters.js +4 -4
- package/dist/src/tui/tui-commands.js +2 -2
- package/dist/src/tui/tui-keybindings-file.js +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 -1
- package/dist/src/tui/tui-startup-resources.js.map +1 -1
- package/dist/src/tui/tui-startup-text.js +12 -12
- package/dist/src/tui/tui-startup-text.js.map +1 -1
- package/dist/src/tui/tui.js +10 -7
- package/dist/src/tui/tui.js.map +1 -1
- package/dist/src/tunnel/frpc-binary.js +4 -4
- 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/utils/logger/streams.js +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/draft/workflow-draft-service.js +1 -1
- package/dist/src/workflows/service/workflow-run-service.js +4 -5
- package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
- package/dist/src/workflows/service/workflow-session-bridge.js +1 -1
- package/dist/src/workflows/store/event-store.js +1 -1
- package/dist/src/workflows/store/run-store.js +1 -1
- package/package.json +3 -2
- package/dist/gateway/static/root/assets/agent-browser-settings-page-D1SyFYeh.js +0 -6
- package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-C9YxgvuI.js +0 -1
- package/dist/gateway/static/root/assets/agents-CteVs3UO.js +0 -71
- package/dist/gateway/static/root/assets/apps-page-CVQ1M8Ax.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-Cd3JbeQ1.js +0 -1
- package/dist/gateway/static/root/assets/config-api-C4RAtTKW.js +0 -3
- package/dist/gateway/static/root/assets/connectors-page-MsMa5qBr.js +0 -2
- package/dist/gateway/static/root/assets/cron-api-sJNMqB6P.js +0 -1
- package/dist/gateway/static/root/assets/cron-page-D30CSwkn.js +0 -3
- package/dist/gateway/static/root/assets/dreaming-settings-6fCUWRQf.js +0 -1
- package/dist/gateway/static/root/assets/gateway-config-api-C6989a-W.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-BpF26t91.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-DOjhmRyf.js +0 -1
- package/dist/gateway/static/root/assets/goals-page-Xl9_wrFc.js +0 -2
- package/dist/gateway/static/root/assets/heartbeat-settings-DN9vEj9P.js +0 -1
- package/dist/gateway/static/root/assets/index-C8ytlAF2.js +0 -122
- package/dist/gateway/static/root/assets/index-CVpJW2NS.css +0 -1
- package/dist/gateway/static/root/assets/messages-BqzIDrlr.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-BO4o-GmO.js +0 -2
- package/dist/gateway/static/root/assets/note-detail-page-DLV_XDmT.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-ycsDlkFA.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-DQpnE8K9.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-BZui7iAY.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-DEfzZ1ax.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-CLuSsu1-.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-Cq4qpXLi.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-B9F3HyYQ.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-Bp9UPPwm.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-BIoBsfSV.js +0 -2
- package/dist/gateway/static/root/assets/use-agent-defaults-form-Cz2_pPzu.js +0 -1
- package/dist/gateway/static/root/assets/use-settings-tab-guard-nuHMmZQv.js +0 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-BUIrKb8s.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-qE3SexnO.js +0 -18
- package/dist/src/agent/context/workspace-templates/USER.md +0 -24
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-ext-install.js","names":[],"sources":["../../../../src/browser/providers/browser-ext-install.ts"],"sourcesContent":["/**\n * Install bundled Chrome extension artifacts into {resolveBinDir()}/browser-ext/.\n * Fixed path — gateway upgrades overwrite in place so Chrome sideload paths stay stable.\n */\n\nimport {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n renameSync,\n rmSync,\n statSync,\n writeFileSync,\n} from 'node:fs';\nimport { readFile, readdir, rm } from 'node:fs/promises';\nimport { spawn } from 'node:child_process';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { PACKAGE_VERSION } from '../../package-version.js';\nimport { resolveBinDir } from '../../config/paths.js';\nimport { resolvePackageRoot } from '../../infra/update-check.js';\nimport { writeTextAtomic } from '../../infra/write-file-atomic.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { assertCacheDir } from '../cache-dir-policy.js';\n\nconst log = createLogger('BrowserExtInstall');\n\nconst META_FILENAME = '.meta.json';\nconst STAGING_MAX_AGE_MS = 60 * 60 * 1000;\nconst INSTALLED_ARTIFACT_NAMES = ['manifest.json', 'popup.html', 'dist', 'icons'] as const;\n\nexport const BROWSER_EXT_REQUIRED_FILES = [\n 'manifest.json',\n 'popup.html',\n 'dist/background.js',\n 'dist/content.js',\n 'dist/popup.js',\n] as const;\n\nexport type BrowserExtBundledFrom = 'npm-dist' | 'git-dev' | 'electron-asar' | 'env-override';\n\nexport interface BrowserExtInstallMeta {\n xopcVersion: string;\n manifestVersion: string;\n source: 'bundled';\n bundledFrom: BrowserExtBundledFrom;\n installedAt: string;\n installPath: string;\n}\n\nexport interface BrowserExtDoctor {\n bundledAvailable: boolean;\n installed: boolean;\n xopcVersion: string;\n installedVersion?: string;\n manifestVersion?: string;\n extensionDir?: string;\n cacheDir: string;\n needsRefresh: boolean;\n needsChromeReload?: boolean;\n bundledFrom?: BrowserExtBundledFrom;\n runtimeExtensionVersion?: string;\n}\n\nexport interface EnsureBrowserExtResult {\n extensionDir: string;\n xopcVersion: string;\n copied: boolean;\n}\n\nfunction moduleDir(): string {\n return dirname(fileURLToPath(import.meta.url));\n}\n\n/** Validate a directory contains a loadable extension tree. */\nexport function validateBrowserExtLayout(dir: string): boolean {\n return BROWSER_EXT_REQUIRED_FILES.every((rel) => existsSync(join(dir, rel)));\n}\n\nfunction readManifestVersion(dir: string): string | undefined {\n try {\n const raw = readFileSync(join(dir, 'manifest.json'), 'utf8');\n const parsed = JSON.parse(raw) as { version?: unknown };\n return typeof parsed.version === 'string' ? parsed.version : undefined;\n } catch {\n return undefined;\n }\n}\n\nasync function readMeta(metaPath: string): Promise<BrowserExtInstallMeta | null> {\n try {\n const raw = await readFile(metaPath, 'utf8');\n const parsed = JSON.parse(raw) as BrowserExtInstallMeta;\n if (parsed && typeof parsed === 'object' && typeof parsed.xopcVersion === 'string') {\n return parsed;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nfunction browserExtRoot(cacheDir: string): string {\n return join(cacheDir, 'browser-ext');\n}\n\nfunction resolveMetaPath(cacheDir: string): string {\n return join(browserExtRoot(cacheDir), META_FILENAME);\n}\n\n/** Resolve the installed extension directory (fixed `browser-ext/` root). */\nexport function resolveInstalledExtensionPath(\n cacheDir: string,\n _meta: BrowserExtInstallMeta | null,\n): string | null {\n const root = browserExtRoot(cacheDir);\n if (validateBrowserExtLayout(root)) {\n return root;\n }\n\n return null;\n}\n\nfunction walkAncestorsForGitDevBundled(start: string): string | null {\n let dir = start;\n for (let i = 0; i < 12; i++) {\n const candidate = join(dir, 'packages/browser-ext');\n if (validateBrowserExtLayout(candidate)) {\n return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\n/**\n * Resolve the bundled extension source directory (read-only).\n */\nexport async function resolveBundledBrowserExtDir(): Promise<{\n dir: string;\n bundledFrom: BrowserExtBundledFrom;\n} | null> {\n const envOverride = process.env.XOPC_BROWSER_EXT_BUNDLED_ROOT?.trim();\n if (envOverride && validateBrowserExtLayout(envOverride)) {\n return { dir: envOverride, bundledFrom: 'env-override' };\n }\n\n const fromModule = join(moduleDir(), '../../../browser-ext');\n if (validateBrowserExtLayout(fromModule)) {\n const root = await resolvePackageRoot();\n const bundledFrom: BrowserExtBundledFrom =\n process.versions.electron && root && root.includes('app.asar') ? 'electron-asar' : 'npm-dist';\n return { dir: fromModule, bundledFrom };\n }\n\n const gitDev = walkAncestorsForGitDevBundled(moduleDir());\n if (gitDev) {\n return { dir: gitDev, bundledFrom: 'git-dev' };\n }\n\n const root = await resolvePackageRoot();\n if (root) {\n const distBundled = join(root, 'dist/browser-ext');\n if (validateBrowserExtLayout(distBundled)) {\n const bundledFrom: BrowserExtBundledFrom =\n process.versions.electron && root.includes('app.asar') ? 'electron-asar' : 'npm-dist';\n return { dir: distBundled, bundledFrom };\n }\n }\n\n return null;\n}\n\nexport function computeNeedsRefresh(params: {\n force?: boolean;\n bundledManifestVersion: string;\n installedPath: string | null;\n meta: BrowserExtInstallMeta | null;\n}): boolean {\n if (params.force) return true;\n if (!params.installedPath || !validateBrowserExtLayout(params.installedPath)) return true;\n\n const installedManifest = readManifestVersion(params.installedPath);\n if (!installedManifest || installedManifest !== params.bundledManifestVersion) return true;\n\n if (!params.meta || params.meta.xopcVersion !== PACKAGE_VERSION) return true;\n\n return false;\n}\n\nasync function cleanupStaleStaging(root: string): Promise<void> {\n if (!existsSync(root)) return;\n let entries: string[];\n try {\n entries = await readdir(root);\n } catch {\n return;\n }\n const now = Date.now();\n for (const name of entries) {\n if (!name.startsWith('.staging-')) continue;\n const full = join(root, name);\n try {\n const st = statSync(full);\n if (now - st.mtimeMs > STAGING_MAX_AGE_MS) {\n await rm(full, { recursive: true, force: true });\n }\n } catch {\n /* */\n }\n }\n}\n\nfunction removeInstalledArtifacts(root: string): void {\n for (const name of INSTALLED_ARTIFACT_NAMES) {\n const full = join(root, name);\n if (existsSync(full)) {\n rmSync(full, { recursive: true, force: true });\n }\n }\n}\n\nfunction promoteStagingToRoot(stagingDir: string, root: string): void {\n removeInstalledArtifacts(root);\n for (const name of readdirSync(stagingDir)) {\n renameSync(join(stagingDir, name), join(root, name));\n }\n rmSync(stagingDir, { recursive: true, force: true });\n if (!validateBrowserExtLayout(root)) {\n throw new Error('Bundled browser extension copy failed validation');\n }\n}\n\n/** Copy one bundled file (read/write works when src is inside Electron app.asar). */\nfunction copyBundledFile(src: string, dest: string): void {\n mkdirSync(dirname(dest), { recursive: true });\n writeFileSync(dest, readFileSync(src));\n}\n\nconst BROWSER_EXT_DIST_FILES = ['background.js', 'content.js', 'popup.js'] as const;\nconst BROWSER_EXT_ICON_FILES = ['icon-16.png', 'icon-32.png', 'icon-48.png', 'icon-128.png'] as const;\n\nfunction copyBundledTree(src: string, dest: string): void {\n mkdirSync(dest, { recursive: true });\n for (const name of ['manifest.json', 'popup.html']) {\n copyBundledFile(join(src, name), join(dest, name));\n }\n for (const file of BROWSER_EXT_DIST_FILES) {\n copyBundledFile(join(src, 'dist', file), join(dest, 'dist', file));\n }\n for (const icon of BROWSER_EXT_ICON_FILES) {\n const iconSrc = join(src, 'icons', icon);\n if (existsSync(iconSrc)) {\n copyBundledFile(iconSrc, join(dest, 'icons', icon));\n }\n }\n if (!validateBrowserExtLayout(dest)) {\n throw new Error('Bundled browser extension copy failed validation');\n }\n}\n\nexport async function browserExtDoctor(opts?: {\n cacheDir?: string;\n runtimeExtensionVersion?: string;\n}): Promise<BrowserExtDoctor> {\n const resolvedCache = opts?.cacheDir?.trim()\n ? assertCacheDir(opts.cacheDir)\n : resolveBinDir();\n const cacheDir = resolvedCache || resolveBinDir();\n\n const bundled = await resolveBundledBrowserExtDir();\n const bundledManifestVersion = bundled ? readManifestVersion(bundled.dir) : undefined;\n const meta = await readMeta(resolveMetaPath(cacheDir));\n const installedPath = resolveInstalledExtensionPath(cacheDir, meta);\n\n const needsRefresh = bundled\n ? computeNeedsRefresh({\n force: false,\n bundledManifestVersion: bundledManifestVersion ?? PACKAGE_VERSION,\n installedPath,\n meta,\n })\n : false;\n\n const installed = Boolean(installedPath) && !needsRefresh;\n const manifestVersion = installedPath ? readManifestVersion(installedPath) : undefined;\n\n let needsChromeReload: boolean | undefined;\n const runtimeVer = opts?.runtimeExtensionVersion?.trim();\n if (runtimeVer && manifestVersion && runtimeVer !== manifestVersion) {\n needsChromeReload = true;\n }\n\n return {\n bundledAvailable: Boolean(bundled),\n installed,\n xopcVersion: PACKAGE_VERSION,\n installedVersion: meta?.xopcVersion,\n manifestVersion,\n extensionDir: installedPath ?? undefined,\n cacheDir,\n needsRefresh,\n needsChromeReload,\n bundledFrom: bundled?.bundledFrom,\n runtimeExtensionVersion: runtimeVer,\n };\n}\n\nexport async function ensureBrowserExtensionArtifacts(opts?: {\n force?: boolean;\n cacheDir?: string;\n}): Promise<EnsureBrowserExtResult> {\n const resolvedCache = opts?.cacheDir?.trim()\n ? assertCacheDir(opts.cacheDir)\n : resolveBinDir();\n const cacheDir = resolvedCache || resolveBinDir();\n\n const bundled = await resolveBundledBrowserExtDir();\n if (!bundled) {\n throw new Error(\n 'Bundled browser extension not found. Reinstall xopc or run from a built checkout (pnpm run build).',\n );\n }\n\n const bundledManifestVersion = readManifestVersion(bundled.dir) ?? PACKAGE_VERSION;\n const root = browserExtRoot(cacheDir);\n mkdirSync(root, { recursive: true });\n await cleanupStaleStaging(root);\n\n const meta = await readMeta(resolveMetaPath(cacheDir));\n const installedPath = resolveInstalledExtensionPath(cacheDir, meta);\n const needsRefresh = computeNeedsRefresh({\n force: opts?.force,\n bundledManifestVersion,\n installedPath,\n meta,\n });\n\n const extensionDir = root;\n\n if (!needsRefresh && installedPath) {\n return {\n extensionDir: installedPath,\n xopcVersion: PACKAGE_VERSION,\n copied: false,\n };\n }\n\n const stagingDir = join(root, `.staging-${process.pid}`);\n\n if (existsSync(stagingDir)) {\n rmSync(stagingDir, { recursive: true, force: true });\n }\n copyBundledTree(bundled.dir, stagingDir);\n promoteStagingToRoot(stagingDir, root);\n\n const nextMeta: BrowserExtInstallMeta = {\n xopcVersion: PACKAGE_VERSION,\n manifestVersion: bundledManifestVersion,\n source: 'bundled',\n bundledFrom: bundled.bundledFrom,\n installedAt: new Date().toISOString(),\n installPath: extensionDir,\n };\n await writeTextAtomic(resolveMetaPath(cacheDir), JSON.stringify(nextMeta, null, 2));\n\n log.info(\n { extensionDir, xopcVersion: PACKAGE_VERSION, bundledFrom: bundled.bundledFrom },\n 'Browser extension artifacts installed',\n );\n\n return {\n extensionDir,\n xopcVersion: PACKAGE_VERSION,\n copied: true,\n };\n}\n\n/**\n * Gateway startup hook: ensure artifacts when extension backend is enabled or prior install exists.\n */\nexport async function ensureBrowserExtensionOnStartup(config: {\n agents?: { defaults?: { browser?: { backend?: string } } };\n}): Promise<void> {\n const backend = config.agents?.defaults?.browser?.backend;\n const cacheDir = resolveBinDir();\n const metaExists = existsSync(resolveMetaPath(cacheDir));\n if (backend !== 'extension' && !metaExists) {\n return;\n }\n await ensureBrowserExtensionArtifacts();\n}\n\nexport async function readInstalledExtensionDir(cacheDir?: string): Promise<string | null> {\n const dir = cacheDir?.trim() ? assertCacheDir(cacheDir) : resolveBinDir();\n const resolved = dir || resolveBinDir();\n const meta = await readMeta(resolveMetaPath(resolved));\n return resolveInstalledExtensionPath(resolved, meta);\n}\n\nexport type BrowserExtensionOpenAction = 'chrome' | 'folder' | 'both';\n\nfunction spawnDetached(command: string, args: readonly string[]): void {\n spawn(command, [...args], { stdio: 'ignore', detached: true }).unref();\n}\n\nfunction openChromeExtensionsPage(): void {\n const chromeUrl = 'chrome://extensions';\n if (process.platform === 'darwin') {\n spawnDetached('open', ['-a', 'Google Chrome', chromeUrl]);\n return;\n }\n if (process.platform === 'win32') {\n spawnDetached('cmd', ['/c', 'start', 'chrome', chromeUrl]);\n return;\n }\n spawnDetached('xdg-open', [chromeUrl]);\n}\n\nfunction revealFolderInFileManager(dir: string): void {\n if (process.platform === 'darwin') {\n spawnDetached('open', [dir]);\n return;\n }\n if (process.platform === 'win32') {\n spawnDetached('explorer', [dir]);\n return;\n }\n spawnDetached('xdg-open', [dir]);\n}\n\n/**\n * Open chrome://extensions and/or reveal the installed extension folder on the gateway host.\n */\nexport async function openBrowserExtensionInstallUi(opts: {\n action: BrowserExtensionOpenAction;\n cacheDir?: string;\n}): Promise<{ extensionDir: string }> {\n const doctor = await browserExtDoctor({ cacheDir: opts.cacheDir });\n const dir = doctor.extensionDir;\n if (!dir) {\n throw new Error('Extension not installed. Run xopc browser extension install first.');\n }\n\n if (opts.action === 'chrome' || opts.action === 'both') {\n openChromeExtensionsPage();\n }\n if (opts.action === 'folder' || opts.action === 'both') {\n revealFolderInFileManager(dir);\n }\n\n return { extensionDir: dir };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"browser-ext-install.js","names":[],"sources":["../../../../src/browser/providers/browser-ext-install.ts"],"sourcesContent":["/**\n * Install bundled Chrome extension artifacts into {resolveBinDir()}/browser-ext/.\n * Fixed path — gateway upgrades overwrite in place so Chrome sideload paths stay stable.\n */\n\nimport {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n renameSync,\n rmSync,\n statSync,\n writeFileSync,\n} from 'node:fs';\nimport { readFile, readdir, rm } from 'node:fs/promises';\nimport { spawn } from 'node:child_process';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { PACKAGE_VERSION } from '../../package-version.js';\nimport { resolveBinDir } from '../../config/paths.js';\nimport { resolvePackageRoot } from '../../infra/update-check.js';\nimport { writeTextAtomic } from '../../infra/write-file-atomic.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { assertCacheDir } from '../cache-dir-policy.js';\n\nconst log = createLogger('BrowserExtInstall');\n\nconst META_FILENAME = '.meta.json';\nconst STAGING_MAX_AGE_MS = 60 * 60 * 1000;\nconst INSTALLED_ARTIFACT_NAMES = ['manifest.json', 'popup.html', 'dist', 'icons'] as const;\n\nexport const BROWSER_EXT_REQUIRED_FILES = [\n 'manifest.json',\n 'popup.html',\n 'dist/background.js',\n 'dist/content.js',\n 'dist/popup.js',\n] as const;\n\nexport type BrowserExtBundledFrom = 'npm-dist' | 'git-dev' | 'electron-asar' | 'env-override';\n\nexport interface BrowserExtInstallMeta {\n xopcVersion: string;\n manifestVersion: string;\n source: 'bundled';\n bundledFrom: BrowserExtBundledFrom;\n installedAt: string;\n installPath: string;\n}\n\nexport interface BrowserExtDoctor {\n bundledAvailable: boolean;\n installed: boolean;\n xopcVersion: string;\n installedVersion?: string;\n manifestVersion?: string;\n extensionDir?: string;\n cacheDir: string;\n needsRefresh: boolean;\n needsChromeReload?: boolean;\n bundledFrom?: BrowserExtBundledFrom;\n runtimeExtensionVersion?: string;\n}\n\nexport interface EnsureBrowserExtResult {\n extensionDir: string;\n xopcVersion: string;\n copied: boolean;\n}\n\nfunction moduleDir(): string {\n return dirname(fileURLToPath(import.meta.url));\n}\n\n/** Validate a directory contains a loadable extension tree. */\nexport function validateBrowserExtLayout(dir: string): boolean {\n return BROWSER_EXT_REQUIRED_FILES.every((rel) => existsSync(join(dir, rel)));\n}\n\nfunction readManifestVersion(dir: string): string | undefined {\n try {\n const raw = readFileSync(join(dir, 'manifest.json'), 'utf8');\n const parsed = JSON.parse(raw) as { version?: unknown };\n return typeof parsed.version === 'string' ? parsed.version : undefined;\n } catch {\n return undefined;\n }\n}\n\nasync function readMeta(metaPath: string): Promise<BrowserExtInstallMeta | null> {\n try {\n const raw = await readFile(metaPath, 'utf8');\n const parsed = JSON.parse(raw) as BrowserExtInstallMeta;\n if (parsed && typeof parsed === 'object' && typeof parsed.xopcVersion === 'string') {\n return parsed;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nfunction browserExtRoot(cacheDir: string): string {\n return join(cacheDir, 'browser-ext');\n}\n\nfunction resolveMetaPath(cacheDir: string): string {\n return join(browserExtRoot(cacheDir), META_FILENAME);\n}\n\n/** Resolve the installed extension directory (fixed `browser-ext/` root). */\nexport function resolveInstalledExtensionPath(\n cacheDir: string,\n _meta: BrowserExtInstallMeta | null,\n): string | null {\n const root = browserExtRoot(cacheDir);\n if (validateBrowserExtLayout(root)) {\n return root;\n }\n\n return null;\n}\n\nfunction walkAncestorsForGitDevBundled(start: string): string | null {\n let dir = start;\n for (let i = 0; i < 12; i++) {\n const candidate = join(dir, 'packages/browser-ext');\n if (validateBrowserExtLayout(candidate)) {\n return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\n/**\n * Resolve the bundled extension source directory (read-only).\n */\nexport async function resolveBundledBrowserExtDir(): Promise<{\n dir: string;\n bundledFrom: BrowserExtBundledFrom;\n} | null> {\n const envOverride = process.env.XOPC_BROWSER_EXT_BUNDLED_ROOT?.trim();\n if (envOverride && validateBrowserExtLayout(envOverride)) {\n return { dir: envOverride, bundledFrom: 'env-override' };\n }\n\n const fromModule = join(moduleDir(), '../../../browser-ext');\n if (validateBrowserExtLayout(fromModule)) {\n const root = await resolvePackageRoot();\n const bundledFrom: BrowserExtBundledFrom =\n process.versions.electron && root && root.includes('app.asar') ? 'electron-asar' : 'npm-dist';\n return { dir: fromModule, bundledFrom };\n }\n\n const gitDev = walkAncestorsForGitDevBundled(moduleDir());\n if (gitDev) {\n return { dir: gitDev, bundledFrom: 'git-dev' };\n }\n\n const root = await resolvePackageRoot();\n if (root) {\n const distBundled = join(root, 'dist/browser-ext');\n if (validateBrowserExtLayout(distBundled)) {\n const bundledFrom: BrowserExtBundledFrom =\n process.versions.electron && root.includes('app.asar') ? 'electron-asar' : 'npm-dist';\n return { dir: distBundled, bundledFrom };\n }\n }\n\n return null;\n}\n\nexport function computeNeedsRefresh(params: {\n force?: boolean;\n bundledManifestVersion: string;\n installedPath: string | null;\n meta: BrowserExtInstallMeta | null;\n}): boolean {\n if (params.force) return true;\n if (!params.installedPath || !validateBrowserExtLayout(params.installedPath)) return true;\n\n const installedManifest = readManifestVersion(params.installedPath);\n if (!installedManifest || installedManifest !== params.bundledManifestVersion) return true;\n\n if (!params.meta || params.meta.xopcVersion !== PACKAGE_VERSION) return true;\n\n return false;\n}\n\nasync function cleanupStaleStaging(root: string): Promise<void> {\n if (!existsSync(root)) return;\n let entries: string[];\n try {\n entries = await readdir(root);\n } catch {\n return;\n }\n const now = Date.now();\n for (const name of entries) {\n if (!name.startsWith('.staging-')) continue;\n const full = join(root, name);\n try {\n const st = statSync(full);\n if (now - st.mtimeMs > STAGING_MAX_AGE_MS) {\n await rm(full, { recursive: true, force: true });\n }\n } catch {\n /* */\n }\n }\n}\n\nfunction removeInstalledArtifacts(root: string): void {\n for (const name of INSTALLED_ARTIFACT_NAMES) {\n const full = join(root, name);\n if (existsSync(full)) {\n rmSync(full, { recursive: true, force: true });\n }\n }\n}\n\nfunction promoteStagingToRoot(stagingDir: string, root: string): void {\n removeInstalledArtifacts(root);\n for (const name of readdirSync(stagingDir)) {\n renameSync(join(stagingDir, name), join(root, name));\n }\n rmSync(stagingDir, { recursive: true, force: true });\n if (!validateBrowserExtLayout(root)) {\n throw new Error('Bundled browser extension copy failed validation');\n }\n}\n\n/** Copy one bundled file (read/write works when src is inside Electron app.asar). */\nfunction copyBundledFile(src: string, dest: string): void {\n mkdirSync(dirname(dest), { recursive: true });\n writeFileSync(dest, readFileSync(src));\n}\n\nconst BROWSER_EXT_DIST_FILES = ['background.js', 'content.js', 'popup.js'] as const;\nconst BROWSER_EXT_ICON_FILES = ['icon-16.png', 'icon-32.png', 'icon-48.png', 'icon-128.png'] as const;\n\nfunction copyBundledTree(src: string, dest: string): void {\n mkdirSync(dest, { recursive: true });\n for (const name of ['manifest.json', 'popup.html']) {\n copyBundledFile(join(src, name), join(dest, name));\n }\n for (const file of BROWSER_EXT_DIST_FILES) {\n copyBundledFile(join(src, 'dist', file), join(dest, 'dist', file));\n }\n for (const icon of BROWSER_EXT_ICON_FILES) {\n const iconSrc = join(src, 'icons', icon);\n if (existsSync(iconSrc)) {\n copyBundledFile(iconSrc, join(dest, 'icons', icon));\n }\n }\n if (!validateBrowserExtLayout(dest)) {\n throw new Error('Bundled browser extension copy failed validation');\n }\n}\n\nexport async function browserExtDoctor(opts?: {\n cacheDir?: string;\n runtimeExtensionVersion?: string;\n}): Promise<BrowserExtDoctor> {\n const resolvedCache = opts?.cacheDir?.trim()\n ? assertCacheDir(opts.cacheDir)\n : resolveBinDir();\n const cacheDir = resolvedCache || resolveBinDir();\n\n const bundled = await resolveBundledBrowserExtDir();\n const bundledManifestVersion = bundled ? readManifestVersion(bundled.dir) : undefined;\n const meta = await readMeta(resolveMetaPath(cacheDir));\n const installedPath = resolveInstalledExtensionPath(cacheDir, meta);\n\n const needsRefresh = bundled\n ? computeNeedsRefresh({\n force: false,\n bundledManifestVersion: bundledManifestVersion ?? PACKAGE_VERSION,\n installedPath,\n meta,\n })\n : false;\n\n const installed = Boolean(installedPath) && !needsRefresh;\n const manifestVersion = installedPath ? readManifestVersion(installedPath) : undefined;\n\n let needsChromeReload: boolean | undefined;\n const runtimeVer = opts?.runtimeExtensionVersion?.trim();\n if (runtimeVer && manifestVersion && runtimeVer !== manifestVersion) {\n needsChromeReload = true;\n }\n\n return {\n bundledAvailable: Boolean(bundled),\n installed,\n xopcVersion: PACKAGE_VERSION,\n installedVersion: meta?.xopcVersion,\n manifestVersion,\n extensionDir: installedPath ?? undefined,\n cacheDir,\n needsRefresh,\n needsChromeReload,\n bundledFrom: bundled?.bundledFrom,\n runtimeExtensionVersion: runtimeVer,\n };\n}\n\nexport async function ensureBrowserExtensionArtifacts(opts?: {\n force?: boolean;\n cacheDir?: string;\n}): Promise<EnsureBrowserExtResult> {\n const resolvedCache = opts?.cacheDir?.trim()\n ? assertCacheDir(opts.cacheDir)\n : resolveBinDir();\n const cacheDir = resolvedCache || resolveBinDir();\n\n const bundled = await resolveBundledBrowserExtDir();\n if (!bundled) {\n throw new Error(\n 'Bundled browser extension not found. Reinstall xopc or run from a built checkout (pnpm run build).',\n );\n }\n\n const bundledManifestVersion = readManifestVersion(bundled.dir) ?? PACKAGE_VERSION;\n const root = browserExtRoot(cacheDir);\n mkdirSync(root, { recursive: true });\n await cleanupStaleStaging(root);\n\n const meta = await readMeta(resolveMetaPath(cacheDir));\n const installedPath = resolveInstalledExtensionPath(cacheDir, meta);\n const needsRefresh = computeNeedsRefresh({\n force: opts?.force,\n bundledManifestVersion,\n installedPath,\n meta,\n });\n\n const extensionDir = root;\n\n if (!needsRefresh && installedPath) {\n return {\n extensionDir: installedPath,\n xopcVersion: PACKAGE_VERSION,\n copied: false,\n };\n }\n\n const stagingDir = join(root, `.staging-${process.pid}`);\n\n if (existsSync(stagingDir)) {\n rmSync(stagingDir, { recursive: true, force: true });\n }\n copyBundledTree(bundled.dir, stagingDir);\n promoteStagingToRoot(stagingDir, root);\n\n const nextMeta: BrowserExtInstallMeta = {\n xopcVersion: PACKAGE_VERSION,\n manifestVersion: bundledManifestVersion,\n source: 'bundled',\n bundledFrom: bundled.bundledFrom,\n installedAt: new Date().toISOString(),\n installPath: extensionDir,\n };\n await writeTextAtomic(resolveMetaPath(cacheDir), JSON.stringify(nextMeta, null, 2));\n\n log.info(\n { extensionDir, xopcVersion: PACKAGE_VERSION, bundledFrom: bundled.bundledFrom },\n 'Browser extension artifacts installed',\n );\n\n return {\n extensionDir,\n xopcVersion: PACKAGE_VERSION,\n copied: true,\n };\n}\n\n/** Gateway startup hook: ensure extension artifacts for the fixed extension backend. */\nexport async function ensureBrowserExtensionOnStartup(_config: unknown): Promise<void> {\n await ensureBrowserExtensionArtifacts();\n}\n\nexport async function readInstalledExtensionDir(cacheDir?: string): Promise<string | null> {\n const dir = cacheDir?.trim() ? assertCacheDir(cacheDir) : resolveBinDir();\n const resolved = dir || resolveBinDir();\n const meta = await readMeta(resolveMetaPath(resolved));\n return resolveInstalledExtensionPath(resolved, meta);\n}\n\nexport type BrowserExtensionOpenAction = 'chrome' | 'folder' | 'both';\n\nfunction spawnDetached(command: string, args: readonly string[]): void {\n spawn(command, [...args], { stdio: 'ignore', detached: true }).unref();\n}\n\nfunction openChromeExtensionsPage(): void {\n const chromeUrl = 'chrome://extensions';\n if (process.platform === 'darwin') {\n spawnDetached('open', ['-a', 'Google Chrome', chromeUrl]);\n return;\n }\n if (process.platform === 'win32') {\n spawnDetached('cmd', ['/c', 'start', 'chrome', chromeUrl]);\n return;\n }\n spawnDetached('xdg-open', [chromeUrl]);\n}\n\nfunction revealFolderInFileManager(dir: string): void {\n if (process.platform === 'darwin') {\n spawnDetached('open', [dir]);\n return;\n }\n if (process.platform === 'win32') {\n spawnDetached('explorer', [dir]);\n return;\n }\n spawnDetached('xdg-open', [dir]);\n}\n\n/**\n * Open chrome://extensions and/or reveal the installed extension folder on the gateway host.\n */\nexport async function openBrowserExtensionInstallUi(opts: {\n action: BrowserExtensionOpenAction;\n cacheDir?: string;\n}): Promise<{ extensionDir: string }> {\n const doctor = await browserExtDoctor({ cacheDir: opts.cacheDir });\n const dir = doctor.extensionDir;\n if (!dir) {\n throw new Error('Extension not installed. Run xopc browser extension install first.');\n }\n\n if (opts.action === 'chrome' || opts.action === 'both') {\n openChromeExtensionsPage();\n }\n if (opts.action === 'folder' || opts.action === 'both') {\n revealFolderInFileManager(dir);\n }\n\n return { extensionDir: dir };\n}\n"],"mappings":"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"}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { assertCacheDir, expandHome, init_cache_dir_policy } from "../cache-dir-policy.js";
|
|
2
2
|
import { createLogger } from "../../utils/logger/index.js";
|
|
3
3
|
import { init_logger } from "../../utils/logger.js";
|
|
4
|
-
import {
|
|
4
|
+
import { init_paths, resolveBinDir } from "../../config/paths.js";
|
|
5
5
|
import { loadPlaywrightCoreModule } from "./playwright-doctor.js";
|
|
6
6
|
import { WEBDRIVER_OVERRIDE_SCRIPT, buildStealthArgs, filterCloakBrowserExtraArgs, generateFingerprintSeed, makeExecutable, removeQuarantineAttr } from "../stealth.js";
|
|
7
7
|
import { pickFreePort } from "../free-port.js";
|
|
8
|
-
import {
|
|
8
|
+
import { arch, platform, tmpdir } from "node:os";
|
|
9
|
+
import { join, resolve } from "node:path";
|
|
9
10
|
import { createReadStream, createWriteStream } from "node:fs";
|
|
11
|
+
import { createHash } from "node:crypto";
|
|
10
12
|
import { mkdir, mkdtemp, rm, stat } from "node:fs/promises";
|
|
11
|
-
import { join, resolve } from "node:path";
|
|
12
|
-
import { arch, platform, tmpdir } from "node:os";
|
|
13
13
|
import { spawn } from "node:child_process";
|
|
14
14
|
import { Readable, Transform } from "node:stream";
|
|
15
15
|
import AdmZip from "adm-zip";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
2
3
|
import { existsSync } from "node:fs";
|
|
3
4
|
import { stat } from "node:fs/promises";
|
|
4
|
-
import { dirname, join } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
//#region src/browser/providers/playwright-doctor.ts
|
|
7
7
|
/** Root directory of the `playwright-core` package (Electron extraResources or node_modules). */
|
|
@@ -23,16 +23,15 @@ function hint(backend, reason, detail) {
|
|
|
23
23
|
deepLink: buildBrowserSetupDeepLink(backend)
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
|
-
async function checkExtension(
|
|
26
|
+
async function checkExtension(config) {
|
|
27
27
|
try {
|
|
28
28
|
const { browserExtDoctor } = await import("./providers/browser-ext-install.js");
|
|
29
29
|
if (!(await browserExtDoctor()).installed) return hint("extension", "extension_not_installed", "extension artifacts not on disk");
|
|
30
30
|
} catch (e) {
|
|
31
31
|
return hint("extension", "extension_not_installed", e instanceof Error ? e.message : String(e));
|
|
32
32
|
}
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
const port = typeof ext?.port === "number" && ext.port >= 1024 && ext.port <= 65535 ? Math.floor(ext.port) : 19820;
|
|
33
|
+
const host = config?.host?.trim() || "127.0.0.1";
|
|
34
|
+
const port = typeof config?.port === "number" && config.port >= 1024 && config.port <= 65535 ? Math.floor(config.port) : 19820;
|
|
36
35
|
try {
|
|
37
36
|
const { getExtensionBrowserServerSnapshot } = await import("./providers/extension-ws-acquire.js");
|
|
38
37
|
if (getExtensionBrowserServerSnapshot().active) try {
|
|
@@ -56,13 +55,12 @@ async function checkLocal() {
|
|
|
56
55
|
return hint("local", "local_chromium_missing", e instanceof Error ? e.message : String(e));
|
|
57
56
|
}
|
|
58
57
|
}
|
|
59
|
-
async function checkCloak(
|
|
60
|
-
const cb = cfg?.agents?.defaults?.browser?.cloakbrowser;
|
|
58
|
+
async function checkCloak(config) {
|
|
61
59
|
try {
|
|
62
60
|
const { cloakBrowserDoctor } = await import("./providers/cloakbrowser.js");
|
|
63
61
|
const doctor = await cloakBrowserDoctor({
|
|
64
|
-
cacheDir:
|
|
65
|
-
binaryPath:
|
|
62
|
+
...config?.cacheDir ? { cacheDir: config.cacheDir } : {},
|
|
63
|
+
...config?.binaryPath ? { binaryPath: config.binaryPath } : {}
|
|
66
64
|
});
|
|
67
65
|
if (!doctor.installed) return hint("cloakbrowser", "cloakbrowser_not_installed", `CloakBrowser binary not found (cacheDir=${doctor.cacheDir})`);
|
|
68
66
|
return null;
|
|
@@ -89,11 +87,10 @@ async function checkCdp(cdpUrl) {
|
|
|
89
87
|
return hint("cdp", "cdp_unreachable", e instanceof Error ? e.message : String(e));
|
|
90
88
|
}
|
|
91
89
|
}
|
|
92
|
-
function checkCloud(
|
|
93
|
-
|
|
94
|
-
if (
|
|
95
|
-
|
|
96
|
-
return hint("cloud", "cloud_api_key_missing", `no API key configured for ${providerType}`);
|
|
90
|
+
function checkCloud(params) {
|
|
91
|
+
if (params.apiKey?.trim()) return null;
|
|
92
|
+
if (params.providerType === "browserbase" ? process.env.BROWSERBASE_API_KEY?.trim() : process.env.BROWSER_USE_API_KEY?.trim()) return null;
|
|
93
|
+
return hint("cloud", "cloud_api_key_missing", `no API key configured for ${params.providerType}`);
|
|
97
94
|
}
|
|
98
95
|
/**
|
|
99
96
|
* Probe the currently-configured browser backend. Returns `null` when ready.
|
|
@@ -108,19 +105,22 @@ async function checkBrowserReadiness(cfg) {
|
|
|
108
105
|
try {
|
|
109
106
|
switch (backend.mode) {
|
|
110
107
|
case "extension":
|
|
111
|
-
probe = await checkExtension(
|
|
108
|
+
probe = await checkExtension(backend.config);
|
|
112
109
|
break;
|
|
113
110
|
case "local":
|
|
114
111
|
probe = await checkLocal();
|
|
115
112
|
break;
|
|
116
113
|
case "cloakbrowser":
|
|
117
|
-
probe = await checkCloak(
|
|
114
|
+
probe = await checkCloak(backend.config);
|
|
118
115
|
break;
|
|
119
116
|
case "cdp":
|
|
120
117
|
probe = await checkCdp(backend.config.wsEndpoint);
|
|
121
118
|
break;
|
|
122
119
|
case "cloud":
|
|
123
|
-
probe = checkCloud(
|
|
120
|
+
probe = checkCloud({
|
|
121
|
+
providerType: backend.config.type,
|
|
122
|
+
apiKey: backend.config.apiKey
|
|
123
|
+
});
|
|
124
124
|
break;
|
|
125
125
|
}
|
|
126
126
|
} catch (e) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readiness.js","names":[],"sources":["../../../src/browser/readiness.ts"],"sourcesContent":["/**\n * Backend readiness preflight for the `browser_use` tool.\n *\n * Reuses the same doctor functions that power the Settings → Browser page so\n * the agent never tries to launch a backend that the UI already knows is\n * broken. Produces a structured signal the chat surface can render as a\n * \"Setup browser\" card instead of a bare error string.\n */\n\nimport type { Config } from '../config/schema.js';\n\nimport { resolveBrowserBackendFromConfig } from './backend-from-config.js';\nimport { createLogger } from '../utils/logger.js';\n\nconst log = createLogger('browser-readiness');\n\nexport type BrowserBackendKind =\n | 'extension'\n | 'local'\n | 'cloakbrowser'\n | 'cdp'\n | 'cloud';\n\nexport type BrowserNotReadyReason =\n | 'extension_not_installed'\n | 'extension_bridge_offline'\n | 'extension_not_connected'\n | 'local_chromium_missing'\n | 'cloakbrowser_not_installed'\n | 'cdp_unreachable'\n | 'cloud_api_key_missing';\n\nexport interface BrowserSetupHint {\n backend: BrowserBackendKind;\n reason: BrowserNotReadyReason;\n /** Raw probe diagnostic; surfaced behind a disclosure for debugging. */\n detail?: string;\n /** Deep link into Settings → Browser focused on the right backend tab. */\n deepLink: string;\n}\n\nexport class BrowserNotReadyError extends Error {\n constructor(public readonly hint: BrowserSetupHint) {\n super(`Browser backend \"${hint.backend}\" not ready: ${hint.reason}`);\n this.name = 'BrowserNotReadyError';\n }\n}\n\n/** Map backend → settings tab id (matches `BROWSER_BACKEND_TABS` on the web side). */\nexport function buildBrowserSetupDeepLink(backend: BrowserBackendKind): string {\n return `/settings/agent-browser?tab=${backend}`;\n}\n\nfunction hint(\n backend: BrowserBackendKind,\n reason: BrowserNotReadyReason,\n detail?: string,\n): BrowserSetupHint {\n return { backend, reason, detail, deepLink: buildBrowserSetupDeepLink(backend) };\n}\n\nasync function checkExtension(cfg: Config | undefined): Promise<BrowserSetupHint | null> {\n try {\n const { browserExtDoctor } = await import('./providers/browser-ext-install.js');\n const doctor = await browserExtDoctor();\n if (!doctor.installed) {\n return hint('extension', 'extension_not_installed', 'extension artifacts not on disk');\n }\n } catch (e) {\n return hint('extension', 'extension_not_installed', e instanceof Error ? e.message : String(e));\n }\n\n const ext = cfg?.agents?.defaults?.browser?.extension;\n const host = (typeof ext?.host === 'string' && ext.host.trim()) ? ext.host.trim() : '127.0.0.1';\n const port = (typeof ext?.port === 'number' && ext.port >= 1024 && ext.port <= 65535)\n ? Math.floor(ext.port)\n : 19820;\n\n try {\n const { getExtensionBrowserServerSnapshot } = await import(\n './providers/extension-ws-acquire.js'\n );\n const snapshot = getExtensionBrowserServerSnapshot();\n if (snapshot.active) {\n // Probe the HTTP `/` health endpoint to read `.connected`.\n try {\n const res = await fetch(`http://${host}:${port}/`, {\n signal: AbortSignal.timeout(2000),\n });\n const data = (await res.json().catch(() => null)) as { connected?: boolean } | null;\n if (data?.connected) return null;\n return hint(\n 'extension',\n 'extension_not_connected',\n 'WS bridge is listening but no Chrome Extension client connected yet',\n );\n } catch {\n // Bridge claims active but health probe failed — treat as offline.\n return hint('extension', 'extension_bridge_offline', `health probe failed on ${host}:${port}`);\n }\n }\n return hint('extension', 'extension_bridge_offline', `bridge not started on ${host}:${port}`);\n } catch (e) {\n return hint(\n 'extension',\n 'extension_bridge_offline',\n e instanceof Error ? e.message : String(e),\n );\n }\n}\n\nasync function checkLocal(): Promise<BrowserSetupHint | null> {\n try {\n const { playwrightChromiumDoctor } = await import('./providers/playwright-doctor.js');\n const doctor = await playwrightChromiumDoctor();\n if (!doctor.installed) {\n return hint(\n 'local',\n 'local_chromium_missing',\n doctor.reason ?? 'Chromium binary not found on disk',\n );\n }\n return null;\n } catch (e) {\n return hint('local', 'local_chromium_missing', e instanceof Error ? e.message : String(e));\n }\n}\n\nasync function checkCloak(cfg: Config | undefined): Promise<BrowserSetupHint | null> {\n const cb = cfg?.agents?.defaults?.browser?.cloakbrowser;\n try {\n const { cloakBrowserDoctor } = await import('./providers/cloakbrowser.js');\n const doctor = await cloakBrowserDoctor({\n cacheDir: cb?.cacheDir,\n binaryPath: cb?.binaryPath,\n });\n if (!doctor.installed) {\n return hint(\n 'cloakbrowser',\n 'cloakbrowser_not_installed',\n `CloakBrowser binary not found (cacheDir=${doctor.cacheDir})`,\n );\n }\n return null;\n } catch (e) {\n return hint(\n 'cloakbrowser',\n 'cloakbrowser_not_installed',\n e instanceof Error ? e.message : String(e),\n );\n }\n}\n\nasync function checkCdp(cdpUrl: string): Promise<BrowserSetupHint | null> {\n let httpBase: URL;\n try {\n httpBase = new URL(cdpUrl);\n httpBase.protocol = httpBase.protocol === 'wss:' ? 'https:' : 'http:';\n httpBase.pathname = '/json/version';\n httpBase.search = '';\n httpBase.hash = '';\n } catch (e) {\n return hint('cdp', 'cdp_unreachable', `invalid cdpUrl: ${e instanceof Error ? e.message : String(e)}`);\n }\n try {\n const res = await fetch(httpBase.toString(), { signal: AbortSignal.timeout(2000) });\n if (!res.ok) {\n return hint('cdp', 'cdp_unreachable', `HTTP ${res.status} from ${httpBase.toString()}`);\n }\n return null;\n } catch (e) {\n return hint('cdp', 'cdp_unreachable', e instanceof Error ? e.message : String(e));\n }\n}\n\nfunction checkCloud(cfg: Config | undefined, providerType: 'browserbase' | 'browser-use'): BrowserSetupHint | null {\n const cloud = cfg?.agents?.defaults?.browser?.cloud;\n const cfgKey = typeof cloud?.apiKey === 'string' ? cloud.apiKey.trim() : '';\n if (cfgKey) return null;\n const envKey =\n providerType === 'browserbase'\n ? process.env.BROWSERBASE_API_KEY?.trim()\n : process.env.BROWSER_USE_API_KEY?.trim();\n if (envKey) return null;\n return hint(\n 'cloud',\n 'cloud_api_key_missing',\n `no API key configured for ${providerType}`,\n );\n}\n\n/**\n * Probe the currently-configured browser backend. Returns `null` when ready.\n *\n * Probe budget is small (filesystem stats + loopback fetches with a 2s timeout)\n * so it's safe to call before every `browser_use` invocation — but callers\n * typically cache the result for a few seconds to handle bursts.\n */\nexport async function checkBrowserReadiness(\n cfg: Config | undefined,\n): Promise<BrowserNotReadyError | null> {\n const backend = resolveBrowserBackendFromConfig(cfg);\n let probe: BrowserSetupHint | null = null;\n try {\n switch (backend.mode) {\n case 'extension':\n probe = await checkExtension(cfg);\n break;\n case 'local':\n probe = await checkLocal();\n break;\n case 'cloakbrowser':\n probe = await checkCloak(cfg);\n break;\n case 'cdp':\n probe = await checkCdp(backend.config.wsEndpoint);\n break;\n case 'cloud':\n probe = checkCloud(cfg, backend.config.type);\n break;\n }\n } catch (e) {\n log.warn({ err: e, backend: backend.mode }, 'Readiness probe threw unexpectedly');\n return null;\n }\n return probe ? new BrowserNotReadyError(probe) : null;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"readiness.js","names":[],"sources":["../../../src/browser/readiness.ts"],"sourcesContent":["/**\n * Backend readiness preflight for the `browser_use` tool.\n *\n * Reuses the same doctor functions that power the Settings → Browser page so\n * the agent never tries to launch a backend that the UI already knows is\n * broken. Produces a structured signal the chat surface can render as a\n * \"Setup browser\" card instead of a bare error string.\n */\n\nimport type { Config } from '../config/schema.js';\n\nimport { resolveBrowserBackendFromConfig } from './backend-from-config.js';\nimport type { CloakBrowserConfig, ExtensionConnectionConfig } from './providers/types.js';\nimport { createLogger } from '../utils/logger.js';\n\nconst log = createLogger('browser-readiness');\n\nexport type BrowserBackendKind =\n | 'extension'\n | 'local'\n | 'cloakbrowser'\n | 'cdp'\n | 'cloud';\n\nexport type BrowserNotReadyReason =\n | 'extension_not_installed'\n | 'extension_bridge_offline'\n | 'extension_not_connected'\n | 'local_chromium_missing'\n | 'cloakbrowser_not_installed'\n | 'cdp_unreachable'\n | 'cloud_api_key_missing';\n\nexport interface BrowserSetupHint {\n backend: BrowserBackendKind;\n reason: BrowserNotReadyReason;\n /** Raw probe diagnostic; surfaced behind a disclosure for debugging. */\n detail?: string;\n /** Deep link into Settings → Browser focused on the right backend tab. */\n deepLink: string;\n}\n\nexport class BrowserNotReadyError extends Error {\n constructor(public readonly hint: BrowserSetupHint) {\n super(`Browser backend \"${hint.backend}\" not ready: ${hint.reason}`);\n this.name = 'BrowserNotReadyError';\n }\n}\n\n/** Map backend → settings tab id (matches `BROWSER_BACKEND_TABS` on the web side). */\nexport function buildBrowserSetupDeepLink(backend: BrowserBackendKind): string {\n return `/settings/agent-browser?tab=${backend}`;\n}\n\nfunction hint(\n backend: BrowserBackendKind,\n reason: BrowserNotReadyReason,\n detail?: string,\n): BrowserSetupHint {\n return { backend, reason, detail, deepLink: buildBrowserSetupDeepLink(backend) };\n}\n\nasync function checkExtension(config: ExtensionConnectionConfig | undefined): Promise<BrowserSetupHint | null> {\n try {\n const { browserExtDoctor } = await import('./providers/browser-ext-install.js');\n const doctor = await browserExtDoctor();\n if (!doctor.installed) {\n return hint('extension', 'extension_not_installed', 'extension artifacts not on disk');\n }\n } catch (e) {\n return hint('extension', 'extension_not_installed', e instanceof Error ? e.message : String(e));\n }\n\n const host = config?.host?.trim() || '127.0.0.1';\n const port =\n typeof config?.port === 'number' && config.port >= 1024 && config.port <= 65535\n ? Math.floor(config.port)\n : 19820;\n\n try {\n const { getExtensionBrowserServerSnapshot } = await import(\n './providers/extension-ws-acquire.js'\n );\n const snapshot = getExtensionBrowserServerSnapshot();\n if (snapshot.active) {\n // Probe the HTTP `/` health endpoint to read `.connected`.\n try {\n const res = await fetch(`http://${host}:${port}/`, {\n signal: AbortSignal.timeout(2000),\n });\n const data = (await res.json().catch(() => null)) as { connected?: boolean } | null;\n if (data?.connected) return null;\n return hint(\n 'extension',\n 'extension_not_connected',\n 'WS bridge is listening but no Chrome Extension client connected yet',\n );\n } catch {\n // Bridge claims active but health probe failed — treat as offline.\n return hint('extension', 'extension_bridge_offline', `health probe failed on ${host}:${port}`);\n }\n }\n return hint('extension', 'extension_bridge_offline', `bridge not started on ${host}:${port}`);\n } catch (e) {\n return hint(\n 'extension',\n 'extension_bridge_offline',\n e instanceof Error ? e.message : String(e),\n );\n }\n}\n\nasync function checkLocal(): Promise<BrowserSetupHint | null> {\n try {\n const { playwrightChromiumDoctor } = await import('./providers/playwright-doctor.js');\n const doctor = await playwrightChromiumDoctor();\n if (!doctor.installed) {\n return hint(\n 'local',\n 'local_chromium_missing',\n doctor.reason ?? 'Chromium binary not found on disk',\n );\n }\n return null;\n } catch (e) {\n return hint('local', 'local_chromium_missing', e instanceof Error ? e.message : String(e));\n }\n}\n\nasync function checkCloak(config: CloakBrowserConfig | undefined): Promise<BrowserSetupHint | null> {\n try {\n const { cloakBrowserDoctor } = await import('./providers/cloakbrowser.js');\n const doctor = await cloakBrowserDoctor({\n ...(config?.cacheDir ? { cacheDir: config.cacheDir } : {}),\n ...(config?.binaryPath ? { binaryPath: config.binaryPath } : {}),\n });\n if (!doctor.installed) {\n return hint(\n 'cloakbrowser',\n 'cloakbrowser_not_installed',\n `CloakBrowser binary not found (cacheDir=${doctor.cacheDir})`,\n );\n }\n return null;\n } catch (e) {\n return hint(\n 'cloakbrowser',\n 'cloakbrowser_not_installed',\n e instanceof Error ? e.message : String(e),\n );\n }\n}\n\nasync function checkCdp(cdpUrl: string): Promise<BrowserSetupHint | null> {\n let httpBase: URL;\n try {\n httpBase = new URL(cdpUrl);\n httpBase.protocol = httpBase.protocol === 'wss:' ? 'https:' : 'http:';\n httpBase.pathname = '/json/version';\n httpBase.search = '';\n httpBase.hash = '';\n } catch (e) {\n return hint('cdp', 'cdp_unreachable', `invalid cdpUrl: ${e instanceof Error ? e.message : String(e)}`);\n }\n try {\n const res = await fetch(httpBase.toString(), { signal: AbortSignal.timeout(2000) });\n if (!res.ok) {\n return hint('cdp', 'cdp_unreachable', `HTTP ${res.status} from ${httpBase.toString()}`);\n }\n return null;\n } catch (e) {\n return hint('cdp', 'cdp_unreachable', e instanceof Error ? e.message : String(e));\n }\n}\n\nfunction checkCloud(params: {\n apiKey?: string;\n providerType: 'browserbase' | 'browser-use';\n}): BrowserSetupHint | null {\n if (params.apiKey?.trim()) return null;\n const envKey =\n params.providerType === 'browserbase'\n ? process.env.BROWSERBASE_API_KEY?.trim()\n : process.env.BROWSER_USE_API_KEY?.trim();\n if (envKey) return null;\n return hint(\n 'cloud',\n 'cloud_api_key_missing',\n `no API key configured for ${params.providerType}`,\n );\n}\n\n/**\n * Probe the currently-configured browser backend. Returns `null` when ready.\n *\n * Probe budget is small (filesystem stats + loopback fetches with a 2s timeout)\n * so it's safe to call before every `browser_use` invocation — but callers\n * typically cache the result for a few seconds to handle bursts.\n */\nexport async function checkBrowserReadiness(\n cfg: Config | undefined,\n): Promise<BrowserNotReadyError | null> {\n const backend = resolveBrowserBackendFromConfig(cfg);\n let probe: BrowserSetupHint | null = null;\n try {\n switch (backend.mode) {\n case 'extension':\n probe = await checkExtension(backend.config);\n break;\n case 'local':\n probe = await checkLocal();\n break;\n case 'cloakbrowser':\n probe = await checkCloak(backend.config);\n break;\n case 'cdp':\n probe = await checkCdp(backend.config.wsEndpoint);\n break;\n case 'cloud':\n probe = checkCloud({ providerType: backend.config.type, apiKey: backend.config.apiKey });\n break;\n }\n } catch (e) {\n log.warn({ err: e, backend: backend.mode }, 'Readiness probe threw unexpectedly');\n return null;\n }\n return probe ? new BrowserNotReadyError(probe) : null;\n}\n"],"mappings":"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"}
|
|
@@ -53,7 +53,7 @@ const BrowserGetImagesSchema = Type.Object({
|
|
|
53
53
|
});
|
|
54
54
|
const BrowserCloseSchema = Type.Object({});
|
|
55
55
|
const BrowserVisionSchema = Type.Object({
|
|
56
|
-
prompt: Type.Optional(Type.String({ description: "What to analyze in the screenshot (default: describe the visible UI state). Requires
|
|
56
|
+
prompt: Type.Optional(Type.String({ description: "What to analyze in the screenshot (default: describe the visible UI state). Requires an available image model." })),
|
|
57
57
|
selector: Type.Optional(Type.String({ description: "CSS selector to screenshot a specific element. Omit for full page." }))
|
|
58
58
|
});
|
|
59
59
|
const BrowserDialogSchema = Type.Object({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.js","names":[],"sources":["../../../src/browser/schemas.ts"],"sourcesContent":["import { Type } from '@sinclair/typebox';\n\nexport const BrowserNavigateSchema = Type.Object({\n url: Type.String({ description: 'URL to navigate to' }),\n waitFor: Type.Optional(\n Type.Union(\n [Type.Literal('load'), Type.Literal('domcontentloaded'), Type.Literal('networkidle')],\n {\n description: 'Wait condition (default: domcontentloaded)',\n },\n ),\n ),\n});\n\nexport const BrowserSnapshotSchema = Type.Object({\n selector: Type.Optional(\n Type.String({ description: 'CSS selector to snapshot a specific element. Omit for full page.' }),\n ),\n maxLength: Type.Optional(\n Type.Number({ description: 'Max characters in snapshot (default: 30000)', default: 30000 }),\n ),\n});\n\nexport const BrowserClickSchema = Type.Object({\n selector: Type.Optional(Type.String({ description: 'CSS selector of the element to click' })),\n text: Type.Optional(\n Type.String({ description: 'Visible text of the element to click (uses getByText)' }),\n ),\n role: Type.Optional(\n Type.String({\n description: 'ARIA role and accessible name, e.g. \"button:Submit\" (uses getByRole)',\n }),\n ),\n});\n\nexport const BrowserTypeSchema = Type.Object({\n selector: Type.Optional(Type.String({ description: 'CSS selector of the input field' })),\n label: Type.Optional(Type.String({ description: 'Label text of the input field (uses getByLabel)' })),\n text: Type.String({ description: 'Text to type into the field' }),\n pressEnter: Type.Optional(\n Type.Boolean({ description: 'Press Enter after typing (default: false)' }),\n ),\n});\n\nexport const BrowserScrollSchema = Type.Object({\n direction: Type.Union([Type.Literal('down'), Type.Literal('up')], {\n description: 'Scroll direction',\n }),\n amount: Type.Optional(\n Type.Number({ description: 'Pixels to scroll (default: 500)', default: 500 }),\n ),\n});\n\nexport const BrowserScreenshotSchema = Type.Object({\n selector: Type.Optional(\n Type.String({ description: 'CSS selector to screenshot a specific element. Omit for full page.' }),\n ),\n description: Type.Optional(\n Type.String({ description: 'What to look for in the screenshot (passed to the vision model)' }),\n ),\n});\n\nexport const BrowserBackSchema = Type.Object({\n waitFor: Type.Optional(\n Type.Union(\n [Type.Literal('load'), Type.Literal('domcontentloaded'), Type.Literal('networkidle')],\n { description: 'Wait condition after going back (default: domcontentloaded)' },\n ),\n ),\n});\n\nexport const BrowserPressSchema = Type.Object({\n key: Type.String({\n description:\n 'Key or key combination to press, e.g. \"Enter\", \"Tab\", \"Escape\", \"ArrowDown\", \"Control+A\", \"Shift+Enter\"',\n }),\n});\n\nexport const BrowserConsoleSchema = Type.Object({\n javascript: Type.Optional(\n Type.String({\n description:\n 'JavaScript expression to evaluate in the page context. The return value is serialized to JSON.',\n }),\n ),\n});\n\nexport const BrowserGetImagesSchema = Type.Object({\n selector: Type.Optional(\n Type.String({ description: 'CSS selector to limit image extraction scope. Omit for full page.' }),\n ),\n maxImages: Type.Optional(\n Type.Number({ description: 'Max images to return (default: 20)', default: 20 }),\n ),\n});\n\nexport const BrowserCloseSchema = Type.Object({});\n\nexport const BrowserVisionSchema = Type.Object({\n prompt: Type.Optional(\n Type.String({\n description:\n 'What to analyze in the screenshot (default: describe the visible UI state). Requires
|
|
1
|
+
{"version":3,"file":"schemas.js","names":[],"sources":["../../../src/browser/schemas.ts"],"sourcesContent":["import { Type } from '@sinclair/typebox';\n\nexport const BrowserNavigateSchema = Type.Object({\n url: Type.String({ description: 'URL to navigate to' }),\n waitFor: Type.Optional(\n Type.Union(\n [Type.Literal('load'), Type.Literal('domcontentloaded'), Type.Literal('networkidle')],\n {\n description: 'Wait condition (default: domcontentloaded)',\n },\n ),\n ),\n});\n\nexport const BrowserSnapshotSchema = Type.Object({\n selector: Type.Optional(\n Type.String({ description: 'CSS selector to snapshot a specific element. Omit for full page.' }),\n ),\n maxLength: Type.Optional(\n Type.Number({ description: 'Max characters in snapshot (default: 30000)', default: 30000 }),\n ),\n});\n\nexport const BrowserClickSchema = Type.Object({\n selector: Type.Optional(Type.String({ description: 'CSS selector of the element to click' })),\n text: Type.Optional(\n Type.String({ description: 'Visible text of the element to click (uses getByText)' }),\n ),\n role: Type.Optional(\n Type.String({\n description: 'ARIA role and accessible name, e.g. \"button:Submit\" (uses getByRole)',\n }),\n ),\n});\n\nexport const BrowserTypeSchema = Type.Object({\n selector: Type.Optional(Type.String({ description: 'CSS selector of the input field' })),\n label: Type.Optional(Type.String({ description: 'Label text of the input field (uses getByLabel)' })),\n text: Type.String({ description: 'Text to type into the field' }),\n pressEnter: Type.Optional(\n Type.Boolean({ description: 'Press Enter after typing (default: false)' }),\n ),\n});\n\nexport const BrowserScrollSchema = Type.Object({\n direction: Type.Union([Type.Literal('down'), Type.Literal('up')], {\n description: 'Scroll direction',\n }),\n amount: Type.Optional(\n Type.Number({ description: 'Pixels to scroll (default: 500)', default: 500 }),\n ),\n});\n\nexport const BrowserScreenshotSchema = Type.Object({\n selector: Type.Optional(\n Type.String({ description: 'CSS selector to screenshot a specific element. Omit for full page.' }),\n ),\n description: Type.Optional(\n Type.String({ description: 'What to look for in the screenshot (passed to the vision model)' }),\n ),\n});\n\nexport const BrowserBackSchema = Type.Object({\n waitFor: Type.Optional(\n Type.Union(\n [Type.Literal('load'), Type.Literal('domcontentloaded'), Type.Literal('networkidle')],\n { description: 'Wait condition after going back (default: domcontentloaded)' },\n ),\n ),\n});\n\nexport const BrowserPressSchema = Type.Object({\n key: Type.String({\n description:\n 'Key or key combination to press, e.g. \"Enter\", \"Tab\", \"Escape\", \"ArrowDown\", \"Control+A\", \"Shift+Enter\"',\n }),\n});\n\nexport const BrowserConsoleSchema = Type.Object({\n javascript: Type.Optional(\n Type.String({\n description:\n 'JavaScript expression to evaluate in the page context. The return value is serialized to JSON.',\n }),\n ),\n});\n\nexport const BrowserGetImagesSchema = Type.Object({\n selector: Type.Optional(\n Type.String({ description: 'CSS selector to limit image extraction scope. Omit for full page.' }),\n ),\n maxImages: Type.Optional(\n Type.Number({ description: 'Max images to return (default: 20)', default: 20 }),\n ),\n});\n\nexport const BrowserCloseSchema = Type.Object({});\n\nexport const BrowserVisionSchema = Type.Object({\n prompt: Type.Optional(\n Type.String({\n description:\n 'What to analyze in the screenshot (default: describe the visible UI state). Requires an available image model.',\n }),\n ),\n selector: Type.Optional(\n Type.String({ description: 'CSS selector to screenshot a specific element. Omit for full page.' }),\n ),\n});\n\nexport const BrowserDialogSchema = Type.Object({\n action: Type.Union([Type.Literal('accept'), Type.Literal('dismiss')], {\n description: 'Whether to accept or dismiss the dialog',\n }),\n promptText: Type.Optional(\n Type.String({ description: 'Text to enter into a prompt() dialog before accepting' }),\n ),\n});\n\nexport const BrowserCdpSchema = Type.Object({\n method: Type.String({\n description: 'CDP method name, e.g. \"Runtime.evaluate\", \"Page.captureScreenshot\"',\n }),\n params: Type.Optional(\n Type.Record(Type.String(), Type.Unknown(), {\n description: 'CDP method parameters as a JSON object',\n }),\n ),\n});\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createLogger } from "../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../utils/logger.js";
|
|
3
|
-
import { chmod, stat } from "node:fs/promises";
|
|
4
3
|
import { platform } from "node:os";
|
|
4
|
+
import { chmod, stat } from "node:fs/promises";
|
|
5
5
|
import { exec } from "node:child_process";
|
|
6
6
|
import { promisify } from "node:util";
|
|
7
7
|
//#region src/browser/stealth.ts
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { __esmMin } from "../../../_virtual/_rolldown/runtime.js";
|
|
2
2
|
import { init_paths_state, resolveStateDir } from "../../config/paths-state.js";
|
|
3
3
|
import { buildExtensionMetadataSnapshot, init_extension_metadata_snapshot, resolveExtensionLoaderOptionsFromConfig } from "../../extensions/extension-metadata-snapshot.js";
|
|
4
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
5
4
|
import { join } from "node:path";
|
|
5
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
6
6
|
//#region src/channels/catalog/channel-catalog-service.ts
|
|
7
7
|
function normalizeChannelId(raw) {
|
|
8
8
|
return raw.trim().toLowerCase();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { init_write_file_atomic, writeTextAtomicSync } from "../../infra/write-file-atomic.js";
|
|
2
|
+
import { join } from "path";
|
|
2
3
|
import { existsSync, mkdirSync, readFileSync } from "fs";
|
|
3
4
|
import { randomUUID } from "node:crypto";
|
|
4
|
-
import { join } from "path";
|
|
5
5
|
//#region src/channels/outbound/persist-store.ts
|
|
6
6
|
/**
|
|
7
7
|
* Durable outbound queue (crash recovery): JSON file under agent internal dir.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { appendAllowFromIdSync } from "./allow-from-file.js";
|
|
2
2
|
import "./pairing-constants.js";
|
|
3
|
-
import crypto from "node:crypto";
|
|
4
|
-
import fs from "node:fs";
|
|
5
3
|
import path from "node:path";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import crypto from "node:crypto";
|
|
6
6
|
//#region src/channels/pairing/pairing-store.ts
|
|
7
7
|
const PAIRING_CODE_LENGTH = 8;
|
|
8
8
|
const PAIRING_CODE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
|
@@ -115,7 +115,7 @@ export interface CreatePipelineParams {
|
|
|
115
115
|
botId: string;
|
|
116
116
|
agentInvoke: PipelineOptions['agentInvoke'];
|
|
117
117
|
onError?: PipelineOptions['onError'];
|
|
118
|
-
/** IANA timezone — matches userTimezone from
|
|
118
|
+
/** IANA timezone — matches userTimezone from config or global user profile */
|
|
119
119
|
timezone?: string;
|
|
120
120
|
}
|
|
121
121
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.js","names":[],"sources":["../../../src/channels/pipeline.ts"],"sourcesContent":["/**\n * Message Processing Pipeline\n * \n * Three-stage pipeline:\n * - Preflight: Filter empty messages, self-messages, detect commands\n * - Process: Transform format, extract metadata\n * - Delivery: Send to Agent\n */\n\nimport { randomUUID } from 'node:crypto';\n\nimport { createLogger, runWithLogContext, updateAsyncLogContext } from '../utils/logger.js';\nimport type { AgentResponse } from './plugin-types.js';\nimport { formatEnvelopeTimestamp } from './envelope-timestamp.js';\n\n// Re-export for convenience\nexport type { AgentResponse } from './plugin-types.js';\n\nconst log = createLogger('Pipeline');\n\nfunction pipelineLogRequestId(ctx: PipelineMessageContext): string {\n const raw = ctx.metadata?.requestId;\n if (typeof raw === 'string' && raw.trim().length > 0) {\n return raw.trim();\n }\n return randomUUID();\n}\n\nfunction pipelineLogSessionId(ctx: PipelineMessageContext): string {\n const sk = ctx.metadata?.sessionKey;\n if (typeof sk === 'string' && sk.trim().length > 0) {\n return sk.trim();\n }\n return `${ctx.channel}:${ctx.chatId}`;\n}\n\n// ============================================\n// Types\n// ============================================\n\nexport interface PipelineMessageContext {\n /** Channel identifier */\n channel: string;\n /** Account ID */\n accountId: string;\n /** Chat ID */\n chatId: string;\n /** Sender ID */\n senderId: string;\n /** Message content */\n content: string;\n /** Original message metadata */\n metadata: Record<string, unknown>;\n /** Is group chat */\n isGroup: boolean;\n /** Is direct message */\n isDm: boolean;\n /** Thread ID (optional) */\n threadId?: string;\n /** Message ID (optional) */\n messageId?: string;\n}\n\nexport interface PipelineMediaRef {\n type: 'photo' | 'video' | 'audio' | 'document' | 'voice';\n fileId: string;\n mimeType?: string;\n fileName?: string;\n url?: string;\n}\n\n// ============================================\n// Handler Interfaces\n// ============================================\n\nexport interface PreflightHandler {\n /** Handler name */\n name: string;\n /** Preflight - return null to skip message */\n preflight?(ctx: PipelineMessageContext): Promise<PipelineMessageContext | null>;\n}\n\nexport interface ProcessHandler {\n /** Handler name */\n name: string;\n /** Process message - transform and extract */\n process(ctx: PipelineMessageContext): Promise<PipelineMessageContext>;\n}\n\nexport interface DeliveryHandler {\n /** Handler name */\n name: string;\n /** Deliver message to Agent */\n deliver(ctx: PipelineMessageContext, response: AgentResponse): Promise<void>;\n}\n\n// ============================================\n// Pipeline Options\n// ============================================\n\nexport interface PipelineOptions {\n /** Channel name */\n channel: string;\n /** Preflight handlers */\n preflightHandlers?: PreflightHandler[];\n /** Process handlers */\n processHandlers?: ProcessHandler[];\n /** Delivery handlers */\n deliveryHandlers?: DeliveryHandler[];\n /** Agent callback */\n agentInvoke?: (ctx: PipelineMessageContext) => Promise<AgentResponse>;\n /** Error handler */\n onError?: (err: unknown, ctx: PipelineMessageContext) => void;\n}\n\n// ============================================\n// Pipeline Implementation\n// ============================================\n\nexport class MessagePipeline {\n private channel: string;\n private preflightHandlers: PreflightHandler[];\n private processHandlers: ProcessHandler[];\n private deliveryHandlers: DeliveryHandler[];\n private agentInvoke?: PipelineOptions['agentInvoke'];\n private onError?: PipelineOptions['onError'];\n\n constructor(options: PipelineOptions) {\n this.channel = options.channel;\n this.preflightHandlers = options.preflightHandlers ?? [];\n this.processHandlers = options.processHandlers ?? [];\n this.deliveryHandlers = options.deliveryHandlers ?? [];\n this.agentInvoke = options.agentInvoke;\n this.onError = options.onError;\n }\n\n /**\n * Handle inbound message\n */\n async handleMessage(ctx: PipelineMessageContext): Promise<void> {\n const channel = this.channel;\n const requestId = pipelineLogRequestId(ctx);\n\n await runWithLogContext(\n {\n requestId,\n sessionId: pipelineLogSessionId(ctx),\n },\n async () => {\n // 1. Preflight stage\n let processedCtx = await this.runPreflight(ctx);\n if (!processedCtx) {\n log.debug({ channel, chatId: ctx.chatId }, 'Message filtered in preflight');\n return;\n }\n\n // 2. Process stage\n try {\n processedCtx = await this.runProcess(processedCtx);\n } catch (err) {\n log.error({ channel, err, phase: 'channel.inbound' }, `Process handler error: ${err instanceof Error ? err.message : String(err)}`);\n this.onError?.(err, processedCtx);\n return;\n }\n\n const resolvedSk = processedCtx.metadata?.sessionKey;\n if (typeof resolvedSk === 'string' && resolvedSk.trim().length > 0) {\n updateAsyncLogContext({ sessionId: resolvedSk.trim() });\n }\n\n // 3. Deliver to Agent\n if (!this.agentInvoke) {\n log.warn({ channel }, 'No agentInvoke configured');\n return;\n }\n\n let response: AgentResponse;\n try {\n response = await this.agentInvoke(processedCtx);\n } catch (err) {\n log.error({ channel, err }, 'Agent invocation error');\n this.onError?.(err, processedCtx);\n return;\n }\n\n // 4. Delivery stage\n try {\n await this.runDelivery(processedCtx, response);\n } catch (err) {\n log.error({ channel, err }, 'Delivery handler error');\n this.onError?.(err, processedCtx);\n }\n },\n );\n }\n\n private async runPreflight(ctx: PipelineMessageContext): Promise<PipelineMessageContext | null> {\n for (const handler of this.preflightHandlers) {\n try {\n const result = await handler.preflight?.(ctx);\n if (!result) {\n log.debug({ channel: this.channel, handler: handler.name }, 'Preflight filtered message');\n return null;\n }\n ctx = result;\n } catch (err) {\n log.error({ channel: this.channel, handler: handler.name, err }, 'Preflight handler error');\n return null;\n }\n }\n return ctx;\n }\n\n private async runProcess(ctx: PipelineMessageContext): Promise<PipelineMessageContext> {\n for (const handler of this.processHandlers) {\n try {\n ctx = await handler.process(ctx);\n } catch (err) {\n log.error({ channel: this.channel, handler: handler.name, err }, 'Process handler error');\n throw err;\n }\n }\n return ctx;\n }\n\n private async runDelivery(ctx: PipelineMessageContext, response: AgentResponse): Promise<void> {\n for (const handler of this.deliveryHandlers) {\n try {\n await handler.deliver(ctx, response);\n } catch (err) {\n log.error({ channel: this.channel, handler: handler.name, err }, 'Delivery handler error');\n throw err;\n }\n }\n }\n}\n\n// ============================================\n// Standard Handlers\n// ============================================\n\n/**\n * Create filter-self handler\n */\nexport function createFilterSelfHandler(currentBotId: string): PreflightHandler {\n return {\n name: 'filterSelf',\n preflight: async (ctx) => {\n if (ctx.senderId === currentBotId) {\n return null;\n }\n return ctx;\n },\n };\n}\n\n/**\n * Create filter-empty handler\n */\nexport function createFilterEmptyHandler(): PreflightHandler {\n return {\n name: 'filterEmpty',\n preflight: async (ctx) => {\n const content = ctx.content?.trim() ?? '';\n if (!content && (!ctx.metadata.media || (ctx.metadata.media as PipelineMediaRef[]).length === 0)) {\n return null;\n }\n return ctx;\n },\n };\n}\n\n/**\n * Create filter-commands handler\n */\nexport function createFilterCommandsHandler(commands: string[]): PreflightHandler {\n const commandSet = new Set(commands.map(c => c.toLowerCase()));\n return {\n name: 'filterCommands',\n preflight: async (ctx) => {\n const firstWord = ctx.content?.split(/\\s/)[0]?.toLowerCase() ?? '';\n if (firstWord.startsWith('/') && commandSet.has(firstWord.slice(1))) {\n ctx.metadata.isCommand = true;\n ctx.metadata.command = firstWord.slice(1);\n }\n return ctx;\n },\n };\n}\n\n/**\n * Create standard preflight handlers\n */\nexport function standardPreflightHandlers(botId: string): PreflightHandler[] {\n return [\n createFilterSelfHandler(botId),\n createFilterEmptyHandler(),\n createFilterCommandsHandler(['start', 'help', 'status', 'stop']),\n ];\n}\n\n/**\n * Prepends a per-turn `[YYYY-MM-DD HH:MM TZ]` prefix to inbound text so the model has\n * a stable \"now\" without changing the system prompt (prompt-cache friendly).\n */\nexport function createEnvelopeTimestampHandler(timezone?: string): ProcessHandler {\n return {\n name: 'envelopeTimestamp',\n process: async (ctx) => {\n const text = ctx.content?.trim();\n if (!text) {\n return ctx;\n }\n const timestamp = formatEnvelopeTimestamp(timezone);\n return { ...ctx, content: `[${timestamp}] ${ctx.content}` };\n },\n };\n}\n\n/**\n * Create standard process handlers\n */\nexport function standardProcessHandlers(timezone?: string): ProcessHandler[] {\n return [createEnvelopeTimestampHandler(timezone)];\n}\n\n// ============================================\n// Factory\n// ============================================\n\nexport interface CreatePipelineParams {\n channel: string;\n botId: string;\n agentInvoke: PipelineOptions['agentInvoke'];\n onError?: PipelineOptions['onError'];\n /** IANA timezone — matches userTimezone from agent config / USER.md */\n timezone?: string;\n}\n\n/**\n * Create message processing pipeline\n */\nexport function createPipeline(params: CreatePipelineParams): MessagePipeline {\n return new MessagePipeline({\n channel: params.channel,\n preflightHandlers: standardPreflightHandlers(params.botId),\n processHandlers: standardProcessHandlers(params.timezone),\n agentInvoke: params.agentInvoke,\n onError: params.onError,\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pipeline.js","names":[],"sources":["../../../src/channels/pipeline.ts"],"sourcesContent":["/**\n * Message Processing Pipeline\n * \n * Three-stage pipeline:\n * - Preflight: Filter empty messages, self-messages, detect commands\n * - Process: Transform format, extract metadata\n * - Delivery: Send to Agent\n */\n\nimport { randomUUID } from 'node:crypto';\n\nimport { createLogger, runWithLogContext, updateAsyncLogContext } from '../utils/logger.js';\nimport type { AgentResponse } from './plugin-types.js';\nimport { formatEnvelopeTimestamp } from './envelope-timestamp.js';\n\n// Re-export for convenience\nexport type { AgentResponse } from './plugin-types.js';\n\nconst log = createLogger('Pipeline');\n\nfunction pipelineLogRequestId(ctx: PipelineMessageContext): string {\n const raw = ctx.metadata?.requestId;\n if (typeof raw === 'string' && raw.trim().length > 0) {\n return raw.trim();\n }\n return randomUUID();\n}\n\nfunction pipelineLogSessionId(ctx: PipelineMessageContext): string {\n const sk = ctx.metadata?.sessionKey;\n if (typeof sk === 'string' && sk.trim().length > 0) {\n return sk.trim();\n }\n return `${ctx.channel}:${ctx.chatId}`;\n}\n\n// ============================================\n// Types\n// ============================================\n\nexport interface PipelineMessageContext {\n /** Channel identifier */\n channel: string;\n /** Account ID */\n accountId: string;\n /** Chat ID */\n chatId: string;\n /** Sender ID */\n senderId: string;\n /** Message content */\n content: string;\n /** Original message metadata */\n metadata: Record<string, unknown>;\n /** Is group chat */\n isGroup: boolean;\n /** Is direct message */\n isDm: boolean;\n /** Thread ID (optional) */\n threadId?: string;\n /** Message ID (optional) */\n messageId?: string;\n}\n\nexport interface PipelineMediaRef {\n type: 'photo' | 'video' | 'audio' | 'document' | 'voice';\n fileId: string;\n mimeType?: string;\n fileName?: string;\n url?: string;\n}\n\n// ============================================\n// Handler Interfaces\n// ============================================\n\nexport interface PreflightHandler {\n /** Handler name */\n name: string;\n /** Preflight - return null to skip message */\n preflight?(ctx: PipelineMessageContext): Promise<PipelineMessageContext | null>;\n}\n\nexport interface ProcessHandler {\n /** Handler name */\n name: string;\n /** Process message - transform and extract */\n process(ctx: PipelineMessageContext): Promise<PipelineMessageContext>;\n}\n\nexport interface DeliveryHandler {\n /** Handler name */\n name: string;\n /** Deliver message to Agent */\n deliver(ctx: PipelineMessageContext, response: AgentResponse): Promise<void>;\n}\n\n// ============================================\n// Pipeline Options\n// ============================================\n\nexport interface PipelineOptions {\n /** Channel name */\n channel: string;\n /** Preflight handlers */\n preflightHandlers?: PreflightHandler[];\n /** Process handlers */\n processHandlers?: ProcessHandler[];\n /** Delivery handlers */\n deliveryHandlers?: DeliveryHandler[];\n /** Agent callback */\n agentInvoke?: (ctx: PipelineMessageContext) => Promise<AgentResponse>;\n /** Error handler */\n onError?: (err: unknown, ctx: PipelineMessageContext) => void;\n}\n\n// ============================================\n// Pipeline Implementation\n// ============================================\n\nexport class MessagePipeline {\n private channel: string;\n private preflightHandlers: PreflightHandler[];\n private processHandlers: ProcessHandler[];\n private deliveryHandlers: DeliveryHandler[];\n private agentInvoke?: PipelineOptions['agentInvoke'];\n private onError?: PipelineOptions['onError'];\n\n constructor(options: PipelineOptions) {\n this.channel = options.channel;\n this.preflightHandlers = options.preflightHandlers ?? [];\n this.processHandlers = options.processHandlers ?? [];\n this.deliveryHandlers = options.deliveryHandlers ?? [];\n this.agentInvoke = options.agentInvoke;\n this.onError = options.onError;\n }\n\n /**\n * Handle inbound message\n */\n async handleMessage(ctx: PipelineMessageContext): Promise<void> {\n const channel = this.channel;\n const requestId = pipelineLogRequestId(ctx);\n\n await runWithLogContext(\n {\n requestId,\n sessionId: pipelineLogSessionId(ctx),\n },\n async () => {\n // 1. Preflight stage\n let processedCtx = await this.runPreflight(ctx);\n if (!processedCtx) {\n log.debug({ channel, chatId: ctx.chatId }, 'Message filtered in preflight');\n return;\n }\n\n // 2. Process stage\n try {\n processedCtx = await this.runProcess(processedCtx);\n } catch (err) {\n log.error({ channel, err, phase: 'channel.inbound' }, `Process handler error: ${err instanceof Error ? err.message : String(err)}`);\n this.onError?.(err, processedCtx);\n return;\n }\n\n const resolvedSk = processedCtx.metadata?.sessionKey;\n if (typeof resolvedSk === 'string' && resolvedSk.trim().length > 0) {\n updateAsyncLogContext({ sessionId: resolvedSk.trim() });\n }\n\n // 3. Deliver to Agent\n if (!this.agentInvoke) {\n log.warn({ channel }, 'No agentInvoke configured');\n return;\n }\n\n let response: AgentResponse;\n try {\n response = await this.agentInvoke(processedCtx);\n } catch (err) {\n log.error({ channel, err }, 'Agent invocation error');\n this.onError?.(err, processedCtx);\n return;\n }\n\n // 4. Delivery stage\n try {\n await this.runDelivery(processedCtx, response);\n } catch (err) {\n log.error({ channel, err }, 'Delivery handler error');\n this.onError?.(err, processedCtx);\n }\n },\n );\n }\n\n private async runPreflight(ctx: PipelineMessageContext): Promise<PipelineMessageContext | null> {\n for (const handler of this.preflightHandlers) {\n try {\n const result = await handler.preflight?.(ctx);\n if (!result) {\n log.debug({ channel: this.channel, handler: handler.name }, 'Preflight filtered message');\n return null;\n }\n ctx = result;\n } catch (err) {\n log.error({ channel: this.channel, handler: handler.name, err }, 'Preflight handler error');\n return null;\n }\n }\n return ctx;\n }\n\n private async runProcess(ctx: PipelineMessageContext): Promise<PipelineMessageContext> {\n for (const handler of this.processHandlers) {\n try {\n ctx = await handler.process(ctx);\n } catch (err) {\n log.error({ channel: this.channel, handler: handler.name, err }, 'Process handler error');\n throw err;\n }\n }\n return ctx;\n }\n\n private async runDelivery(ctx: PipelineMessageContext, response: AgentResponse): Promise<void> {\n for (const handler of this.deliveryHandlers) {\n try {\n await handler.deliver(ctx, response);\n } catch (err) {\n log.error({ channel: this.channel, handler: handler.name, err }, 'Delivery handler error');\n throw err;\n }\n }\n }\n}\n\n// ============================================\n// Standard Handlers\n// ============================================\n\n/**\n * Create filter-self handler\n */\nexport function createFilterSelfHandler(currentBotId: string): PreflightHandler {\n return {\n name: 'filterSelf',\n preflight: async (ctx) => {\n if (ctx.senderId === currentBotId) {\n return null;\n }\n return ctx;\n },\n };\n}\n\n/**\n * Create filter-empty handler\n */\nexport function createFilterEmptyHandler(): PreflightHandler {\n return {\n name: 'filterEmpty',\n preflight: async (ctx) => {\n const content = ctx.content?.trim() ?? '';\n if (!content && (!ctx.metadata.media || (ctx.metadata.media as PipelineMediaRef[]).length === 0)) {\n return null;\n }\n return ctx;\n },\n };\n}\n\n/**\n * Create filter-commands handler\n */\nexport function createFilterCommandsHandler(commands: string[]): PreflightHandler {\n const commandSet = new Set(commands.map(c => c.toLowerCase()));\n return {\n name: 'filterCommands',\n preflight: async (ctx) => {\n const firstWord = ctx.content?.split(/\\s/)[0]?.toLowerCase() ?? '';\n if (firstWord.startsWith('/') && commandSet.has(firstWord.slice(1))) {\n ctx.metadata.isCommand = true;\n ctx.metadata.command = firstWord.slice(1);\n }\n return ctx;\n },\n };\n}\n\n/**\n * Create standard preflight handlers\n */\nexport function standardPreflightHandlers(botId: string): PreflightHandler[] {\n return [\n createFilterSelfHandler(botId),\n createFilterEmptyHandler(),\n createFilterCommandsHandler(['start', 'help', 'status', 'stop']),\n ];\n}\n\n/**\n * Prepends a per-turn `[YYYY-MM-DD HH:MM TZ]` prefix to inbound text so the model has\n * a stable \"now\" without changing the system prompt (prompt-cache friendly).\n */\nexport function createEnvelopeTimestampHandler(timezone?: string): ProcessHandler {\n return {\n name: 'envelopeTimestamp',\n process: async (ctx) => {\n const text = ctx.content?.trim();\n if (!text) {\n return ctx;\n }\n const timestamp = formatEnvelopeTimestamp(timezone);\n return { ...ctx, content: `[${timestamp}] ${ctx.content}` };\n },\n };\n}\n\n/**\n * Create standard process handlers\n */\nexport function standardProcessHandlers(timezone?: string): ProcessHandler[] {\n return [createEnvelopeTimestampHandler(timezone)];\n}\n\n// ============================================\n// Factory\n// ============================================\n\nexport interface CreatePipelineParams {\n channel: string;\n botId: string;\n agentInvoke: PipelineOptions['agentInvoke'];\n onError?: PipelineOptions['onError'];\n /** IANA timezone — matches userTimezone from config or global user profile */\n timezone?: string;\n}\n\n/**\n * Create message processing pipeline\n */\nexport function createPipeline(params: CreatePipelineParams): MessagePipeline {\n return new MessagePipeline({\n channel: params.channel,\n preflightHandlers: standardPreflightHandlers(params.botId),\n processHandlers: standardProcessHandlers(params.timezone),\n agentInvoke: params.agentInvoke,\n onError: params.onError,\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { init_agent_scope, normalizeAgentId, resolveAgentProfileDir } from "../agent/agent-scope.js";
|
|
2
|
-
import { WORKSPACE_FILES, init_paths } from "../config/paths.js";
|
|
3
2
|
import { init_agent_session_key, resolveAgentIdFromSessionKey } from "../routing/agent-session-key.js";
|
|
3
|
+
import { WORKSPACE_FILES, init_paths } from "../config/paths.js";
|
|
4
4
|
import { commandRegistry } from "./registry.js";
|
|
5
|
-
import { readFile } from "node:fs/promises";
|
|
6
5
|
import { join } from "node:path";
|
|
6
|
+
import { readFile } from "node:fs/promises";
|
|
7
7
|
//#region src/chat-commands/agent-edit.ts
|
|
8
8
|
/**
|
|
9
9
|
* /agent-edit — open the current chat as an agent profile editing session.
|
|
@@ -14,7 +14,6 @@ init_paths();
|
|
|
14
14
|
const PROFILE_FILE_NAMES = [
|
|
15
15
|
WORKSPACE_FILES.SOUL,
|
|
16
16
|
WORKSPACE_FILES.IDENTITY,
|
|
17
|
-
WORKSPACE_FILES.USER,
|
|
18
17
|
WORKSPACE_FILES.TOOLS,
|
|
19
18
|
WORKSPACE_FILES.AGENTS,
|
|
20
19
|
WORKSPACE_FILES.HEARTBEAT,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-edit.js","names":[],"sources":["../../../src/chat-commands/agent-edit.ts"],"sourcesContent":["/**\n * /agent-edit — open the current chat as an agent profile editing session.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport type { CommandContext, CommandDefinition } from './types.js';\nimport { commandRegistry } from './registry.js';\nimport { resolveAgentIdFromSessionKey } from '../routing/agent-session-key.js';\nimport { normalizeAgentId, resolveAgentProfileDir } from '../agent/agent-scope.js';\nimport { WORKSPACE_FILES } from '../config/paths.js';\n\nconst PROFILE_FILE_NAMES = [\n WORKSPACE_FILES.SOUL,\n WORKSPACE_FILES.IDENTITY,\n WORKSPACE_FILES.
|
|
1
|
+
{"version":3,"file":"agent-edit.js","names":[],"sources":["../../../src/chat-commands/agent-edit.ts"],"sourcesContent":["/**\n * /agent-edit — open the current chat as an agent profile editing session.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport type { CommandContext, CommandDefinition } from './types.js';\nimport { commandRegistry } from './registry.js';\nimport { resolveAgentIdFromSessionKey } from '../routing/agent-session-key.js';\nimport { normalizeAgentId, resolveAgentProfileDir } from '../agent/agent-scope.js';\nimport { WORKSPACE_FILES } from '../config/paths.js';\n\nconst PROFILE_FILE_NAMES = [\n WORKSPACE_FILES.SOUL,\n WORKSPACE_FILES.IDENTITY,\n WORKSPACE_FILES.TOOLS,\n WORKSPACE_FILES.AGENTS,\n WORKSPACE_FILES.HEARTBEAT,\n WORKSPACE_FILES.MEMORY,\n] as const;\n\nconst DEFAULT_PREVIEW_CHARS = 900;\nconst MAX_PREVIEW_CHARS = 4_000;\n\nfunction parseArgs(args: string): { fileName?: string; previewChars: number } {\n const trimmed = args.trim();\n if (!trimmed) {\n return { previewChars: DEFAULT_PREVIEW_CHARS };\n }\n\n const parts = trimmed.split(/\\s+/);\n let fileName: string | undefined;\n let previewChars = DEFAULT_PREVIEW_CHARS;\n\n for (const part of parts) {\n const limitMatch = /^--limit=(\\d+)$/.exec(part);\n if (limitMatch) {\n previewChars = Math.min(Number(limitMatch[1]), MAX_PREVIEW_CHARS);\n continue;\n }\n if (!fileName) {\n fileName = part;\n }\n }\n\n return { fileName, previewChars };\n}\n\nfunction normalizeProfileFileName(input: string | undefined): string | undefined {\n if (!input) {\n return undefined;\n }\n const basename = input.trim().replace(/\\\\/g, '/').split('/').pop();\n const matched = PROFILE_FILE_NAMES.find((name) => name.toLowerCase() === basename?.toLowerCase());\n return matched;\n}\n\nasync function readPreview(path: string, limit: number): Promise<{ content: string; missing: boolean }> {\n try {\n const content = await readFile(path, 'utf-8');\n const trimmed = content.trimEnd();\n if (trimmed.length <= limit) {\n return { content: trimmed, missing: false };\n }\n return {\n content: `${trimmed.slice(0, limit)}\\n\\n… truncated, ask me to read the full file before editing …`,\n missing: false,\n };\n } catch {\n return { content: '', missing: true };\n }\n}\n\nfunction buildEditInstructions(agentId: string, fileNames: readonly string[]): string {\n const files = fileNames.map((name) => `\\`${name}\\``).join(', ');\n return [\n `You are editing agent \\`${agentId}\\`.`,\n '',\n 'Tell me what to change, or say things like:',\n '- “Refine `SOUL.md` to sound warmer and more concise.”',\n '- “Update `IDENTITY.md` so this agent is focused on data analysis.”',\n '- “Read `SOUL.md` first, propose changes, then write them back.”',\n '',\n `Editable profile files: ${files}.`,\n 'I can read and update these by bare filename with `read_file`, `edit_file`, and `write_file`.',\n ].join('\\n');\n}\n\nconst agentEditCommand: CommandDefinition = {\n id: 'agent.edit',\n name: 'agent-edit',\n aliases: ['agentedit'],\n description: 'Show editable profile files for the current agent and prepare this chat for profile edits.',\n category: 'system',\n scope: ['global', 'private', 'group'],\n acceptsArgs: true,\n examples: ['/agent-edit', '/agent-edit SOUL.md', '/agent-edit IDENTITY.md --limit=2000'],\n handler: async (ctx: CommandContext, args: string) => {\n await ctx.setTyping(true);\n\n const { fileName: rawFileName, previewChars } = parseArgs(args);\n const fileName = normalizeProfileFileName(rawFileName);\n if (rawFileName && !fileName) {\n return {\n content: `⚠️ Unsupported profile file: \\`${rawFileName}\\`. Use one of: ${PROFILE_FILE_NAMES.map((name) => `\\`${name}\\``).join(', ')}.`,\n success: false,\n };\n }\n\n const agentId = normalizeAgentId(resolveAgentIdFromSessionKey(ctx.sessionKey));\n const profileDir = resolveAgentProfileDir(ctx.config, agentId);\n const namesToShow = fileName ? [fileName] : [WORKSPACE_FILES.SOUL, WORKSPACE_FILES.IDENTITY];\n\n const sections: string[] = [];\n for (const name of namesToShow) {\n const preview = await readPreview(join(profileDir, name), previewChars);\n if (preview.missing) {\n sections.push(`## ${name}\\n_missing_`);\n } else {\n sections.push(`## ${name}\\n\\`\\`\\`markdown\\n${preview.content}\\n\\`\\`\\``);\n }\n }\n\n return {\n content: [\n '🛠️ Agent editor mode',\n '',\n buildEditInstructions(agentId, PROFILE_FILE_NAMES),\n '',\n `Profile directory: \\`${profileDir}\\``,\n '',\n ...sections,\n ].join('\\n'),\n success: true,\n };\n },\n};\n\nexport function registerAgentEditCommand(): void {\n commandRegistry.register(agentEditCommand);\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ConfigSchema, init_schema } from "../../config/schema.js";
|
|
2
2
|
import { createLogger } from "../../utils/logger/index.js";
|
|
3
3
|
import { init_logger } from "../../utils/logger.js";
|
|
4
|
-
import {
|
|
4
|
+
import { init_paths, resolveConfigPath } from "../../config/paths.js";
|
|
5
5
|
import { init_loader, loadConfig, saveConfig } from "../../config/loader.js";
|
|
6
6
|
import { commandRegistry } from "../registry.js";
|
|
7
7
|
import { parseConfigValue } from "../config-value.js";
|
|
@@ -74,9 +74,9 @@ const configCommand = {
|
|
|
74
74
|
acceptsArgs: true,
|
|
75
75
|
examples: [
|
|
76
76
|
"/config show",
|
|
77
|
-
"/config show agents.
|
|
78
|
-
"/config set agents.
|
|
79
|
-
"/config
|
|
77
|
+
"/config show agents.list",
|
|
78
|
+
"/config set agents.default=main",
|
|
79
|
+
"/config show agents.capabilityPresets",
|
|
80
80
|
"/config unset tts"
|
|
81
81
|
],
|
|
82
82
|
handler: async (ctx, args) => {
|
|
@@ -176,7 +176,7 @@ const configCommand = {
|
|
|
176
176
|
log.info({ path: rest }, "Config key removed via /config unset");
|
|
177
177
|
return { content: `⚙️ Config updated: \`${rest}\` removed.` };
|
|
178
178
|
}
|
|
179
|
-
return { content: "⚙️ *Config Command*\n\n`/config show [path]` — view config (or a specific path)\n`/config set path=value` — update a config value\n`/config unset path` — remove a config key\n\nExamples:\n`/config show agents.
|
|
179
|
+
return { content: "⚙️ *Config Command*\n\n`/config show [path]` — view config (or a specific path)\n`/config set path=value` — update a config value\n`/config unset path` — remove a config key\n\nExamples:\n`/config show agents.list`\n`/config set agents.default=main`\n`/config show agents.capabilityPresets`\n`/config unset tts`" };
|
|
180
180
|
}
|
|
181
181
|
};
|
|
182
182
|
function registerConfigCommand() {
|