@xopcai/xopc 0.0.113 → 0.0.114
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CBlklyNr.js → agent-avatar-dicebear-Fp-p7bP1.js} +1 -1
- package/dist/gateway/static/root/assets/agent-browser-settings-page-CWh7trjd.js +6 -0
- package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-kC8OuLoj.js +1 -0
- package/dist/gateway/static/root/assets/agents-DJWG26Si.js +71 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-28E_WfMe.js → app-management-settings-panel-v24i25Oj.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-Do1z0XgJ.js → appearance-settings-ycbdJRuZ.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-0V3DXZ7J.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-BAFlsov_.js → archive-plugin-CJzSADJo.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-V3qGPC3x.js → attachment-load-BTAB4zGS.js} +1 -1
- package/dist/gateway/static/root/assets/{binary-plugins-DT8NvA6W.js → binary-plugins-DXR1-mct.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-CdLMEcHd.js → block-editor-CzQri9h2.js} +44 -44
- package/dist/gateway/static/root/assets/channels-settings-CIKOkYdO.js +1 -0
- package/dist/gateway/static/root/assets/{config-api-Bf5mjpu7.js → config-api-DRqjEvAx.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-settings-ClrDS5jH.js +2 -0
- package/dist/gateway/static/root/assets/{cron-api--pAB_rps.js → cron-api-BXaZXv1o.js} +1 -1
- package/dist/gateway/static/root/assets/cron-page-Chi_4u4P.js +3 -0
- package/dist/gateway/static/root/assets/dreaming-settings-B0_rs2tj.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-BGhE7msg.js → extension-debug-page-DSkqMYo7.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-CvpI45WG.js → extension-page-h2dGDbMN.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-DAmR5FUe.js → extension-settings-page-hN99RhOi.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-NZmjSXLl.js → fetch-D9QqUtzZ.js} +1 -1
- package/dist/gateway/static/root/assets/{format-interval-label-qhth3BMV.js → format-interval-label-D6E687rG.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-CaXBt-9R.js → gateway-config-api-CLt_SKTC.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-DphpbLBc.js → gateway-settings-1PDi4lI0.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-Be1omjh3.js → gateway-startup-retry-N7Z_sz7p.js} +1 -1
- package/dist/gateway/static/root/assets/goal-detail-page-D_wwXL-t.js +1 -0
- package/dist/gateway/static/root/assets/goals-page-DZ2toZ8y.js +2 -0
- package/dist/gateway/static/root/assets/{goals-settings-ceEBjnfc.js → goals-settings-LFlwtIKE.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-BzO6G4fD.js → heartbeat-config-api-DGPadTw-.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-DCST9-du.js → heartbeat-settings-BHHAs8ZX.js} +1 -1
- package/dist/gateway/static/root/assets/index-DefIdW9q.js +122 -0
- package/dist/gateway/static/root/assets/index-DzmWBkq-.css +1 -0
- package/dist/gateway/static/root/assets/{interval-presets-DJmshV8n.js → interval-presets-CEklPQ_r.js} +1 -1
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-9AUUlQ5Q.js → keyboard-shortcuts-settings-Ce_aQ8Iv.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-j_D2QTuQ.js +2 -0
- package/dist/gateway/static/root/assets/{markdown-split-CYYELqAr.js → markdown-split-BMz3xPXO.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-BEcMR2M8.js → media-plugins-BalOSoz9.js} +1 -1
- package/dist/gateway/static/root/assets/messages-BN_WiUg0.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-panel-CMH_TmZz.js +2 -0
- package/dist/gateway/static/root/assets/note-detail-page-O18BrQPq.js +2 -0
- package/dist/gateway/static/root/assets/{note-image-lightbox-DNAoPcmm.js → note-image-lightbox-C5D1Q5mY.js} +1 -1
- package/dist/gateway/static/root/assets/notes-page-B_ZYCmY9.js +1 -0
- package/dist/gateway/static/root/assets/{preview-open-alternatives-BPLz0AIv.js → preview-open-alternatives-CYFR5U9l.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-CwKgWixY.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-CrWwWRVK.js → save-bar-controls-BQ79Z5IP.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-CF2sadvN.js → schedule-field-Bgk6Emue.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-Di5cKjYE.js → schema-form-DzS36TMa.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-C4fcD-7B.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-Ad2OJ86w.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-Chh282jW.js → settings-collapsible-section-CdjFnSAy.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-Dq-83cQd.js → settings-form-section-DZLy_exu.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-D2BMY5wo.js +1 -0
- package/dist/gateway/static/root/assets/setup-status-panel-aWwxl_E1.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-0FXYnSUA.js → share-preview-page-_qRDr4g_.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-DUE83uIf.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-mWKJcrog.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-0Sx1Q58n.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-W1pTcojB.js → system-settings-panel-hqaBF5aG.js} +1 -1
- package/dist/gateway/static/root/assets/{use-agent-defaults-form-BVRvkK7m.js → use-agent-defaults-form-zbVIQLOA.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-CgJibfMM.js → use-channel-catalog-CbXq97rT.js} +1 -1
- package/dist/gateway/static/root/assets/{use-settings-tab-guard-Bw_qkRQE.js → use-settings-tab-guard-DwS3drWK.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-D6HR0hR2.js +1 -0
- package/dist/gateway/static/root/assets/{voice-player-store-C7lziaAx.js → voice-player-store-DSuOd9zy.js} +1 -1
- package/dist/gateway/static/root/assets/workflow-page.utils-C0Uq3xyq.js +1 -0
- package/dist/gateway/static/root/assets/workflows-page-DW0fmWhQ.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 +8 -0
- package/dist/src/agent/agent-manager.js +57 -22
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/bootstrap/project-agents-context.d.ts +2 -0
- package/dist/src/agent/bootstrap/project-agents-context.js +32 -0
- package/dist/src/agent/bootstrap/project-agents-context.js.map +1 -0
- package/dist/src/agent/goals/persistent-goal-service.js +2 -4
- package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
- package/dist/src/agent/inbound/inbound-loop.js +5 -1
- package/dist/src/agent/inbound/inbound-loop.js.map +1 -1
- package/dist/src/agent/inbound/turn-dispatcher.d.ts +2 -2
- package/dist/src/agent/inbound/turn-dispatcher.js +2 -2
- package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.d.ts +27 -0
- package/dist/src/agent/mcp/bundle-mcp-materialize.js +49 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js +78 -3
- package/dist/src/agent/mcp/bundle-mcp-runtime.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-types.d.ts +19 -0
- package/dist/src/agent/service/btw-query.js +11 -3
- package/dist/src/agent/service/btw-query.js.map +1 -1
- package/dist/src/agent/service/parse-outbound-session-key.js +13 -8
- package/dist/src/agent/service/parse-outbound-session-key.js.map +1 -1
- package/dist/src/agent/service/process-direct-one-shot.d.ts +2 -2
- package/dist/src/agent/service/process-direct-one-shot.js +1 -1
- package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
- package/dist/src/agent/service/process-direct-streaming.d.ts +2 -2
- package/dist/src/agent/service/process-direct-streaming.js +1 -1
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service.d.ts +1 -1
- package/dist/src/agent/service.js +9 -5
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/service.types.d.ts +5 -0
- package/dist/src/agent/skills/filesystem-watcher.js +4 -3
- package/dist/src/agent/skills/filesystem-watcher.js.map +1 -1
- package/dist/src/agent/skills/index.js +2 -1
- package/dist/src/agent/skills/index.js.map +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +2 -1
- package/dist/src/agent/skills/skill-manage-ops.js.map +1 -1
- package/dist/src/agent/skills/types.d.ts +1 -1
- package/dist/src/agent/skills/watcher.js +2 -5
- package/dist/src/agent/skills/watcher.js.map +1 -1
- package/dist/src/agent/skills/workspace-skills-dir.d.ts +1 -0
- package/dist/src/agent/skills/workspace-skills-dir.js +11 -0
- package/dist/src/agent/skills/workspace-skills-dir.js.map +1 -0
- package/dist/src/agent/tool-manuals/browser.d.ts +1 -1
- package/dist/src/agent/tool-manuals/browser.js +62 -3
- package/dist/src/agent/tool-manuals/browser.js.map +1 -1
- package/dist/src/agent/tools/browser/tool/browser-use-tool.d.ts +4 -1
- package/dist/src/agent/tools/browser/tool/browser-use-tool.js +13 -4
- package/dist/src/agent/tools/browser/tool/browser-use-tool.js.map +1 -1
- package/dist/src/agent/tools/browser/tool/schemas.d.ts +0 -2
- package/dist/src/agent/tools/browser/tool/schemas.js +1 -2
- package/dist/src/agent/tools/browser/tool/schemas.js.map +1 -1
- package/dist/src/agent/tools/factory.js +1 -10
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js.map +1 -1
- package/dist/src/agent/workflow/subagent-runner.js +18 -1
- package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
- package/dist/src/browser/actions/extension-registry-bridge.js +91 -7
- package/dist/src/browser/actions/extension-registry-bridge.js.map +1 -1
- package/dist/src/browser/actions/registry.js +383 -7
- package/dist/src/browser/actions/registry.js.map +1 -1
- package/dist/src/browser/actions/types.d.ts +11 -3
- package/dist/src/browser/index.js +2 -2
- package/dist/src/browser/pipeline/output.d.ts +18 -16
- package/dist/src/browser/pipeline/output.js +28 -20
- package/dist/src/browser/pipeline/output.js.map +1 -1
- package/dist/src/browser/pipeline/runner.d.ts +7 -14
- package/dist/src/browser/pipeline/runner.js +349 -102
- package/dist/src/browser/pipeline/runner.js.map +1 -1
- package/dist/src/browser/pipeline/schema.d.ts +1 -0
- package/dist/src/browser/pipeline/schema.js +35 -58
- package/dist/src/browser/pipeline/schema.js.map +1 -1
- package/dist/src/browser/pipeline/source.d.ts +2 -0
- package/dist/src/browser/pipeline/source.js +10 -1
- package/dist/src/browser/pipeline/source.js.map +1 -1
- package/dist/src/browser/pipeline/template.d.ts +10 -2
- package/dist/src/browser/pipeline/template.js +50 -8
- package/dist/src/browser/pipeline/template.js.map +1 -1
- package/dist/src/chat-commands/builtins/config.js +3 -5
- package/dist/src/chat-commands/builtins/config.js.map +1 -1
- package/dist/src/chat-commands/context.d.ts +5 -0
- package/dist/src/chat-commands/context.js +18 -9
- package/dist/src/chat-commands/context.js.map +1 -1
- package/dist/src/chat-commands/index.d.ts +1 -1
- package/dist/src/chat-commands/index.js +2 -2
- package/dist/src/chat-commands/index.js.map +1 -1
- package/dist/src/chat-commands/processor.js +22 -21
- package/dist/src/chat-commands/processor.js.map +1 -1
- package/dist/src/chat-commands/session-key.d.ts +3 -15
- package/dist/src/chat-commands/session-key.js +3 -49
- package/dist/src/chat-commands/session-key.js.map +1 -1
- package/dist/src/chat-commands/types.d.ts +4 -0
- package/dist/src/cli/commands/browser-cli-helpers.js +11 -5
- package/dist/src/cli/commands/browser-cli-helpers.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/doctor/checks/session-integrity.js +8 -8
- package/dist/src/cli/commands/doctor/checks/session-integrity.js.map +1 -1
- package/dist/src/config/rules.js +5 -0
- package/dist/src/config/rules.js.map +1 -1
- package/dist/src/connectors/builtin-catalog.js +180 -1
- package/dist/src/connectors/builtin-catalog.js.map +1 -1
- package/dist/src/connectors/health.js +18 -9
- package/dist/src/connectors/health.js.map +1 -1
- package/dist/src/connectors/types.d.ts +19 -0
- package/dist/src/connectors/usage.js +12 -4
- package/dist/src/connectors/usage.js.map +1 -1
- package/dist/src/extensions/types/tui.d.ts +2 -0
- package/dist/src/gateway/heartbeat/service.js +13 -1
- package/dist/src/gateway/heartbeat/service.js.map +1 -1
- package/dist/src/gateway/hono/app.js +13 -4
- package/dist/src/gateway/hono/app.js.map +1 -1
- package/dist/src/gateway/hono/oauth-async.js +1 -1
- package/dist/src/gateway/hono/routes/agent-stream.js +6 -6
- package/dist/src/gateway/hono/routes/agent-stream.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/gateway.d.ts +1 -1
- package/dist/src/gateway/hono/routes/config-patch/gateway.js +6 -0
- package/dist/src/gateway/hono/routes/config-patch/gateway.js.map +1 -1
- package/dist/src/gateway/hono/routes/goals.js +16 -3
- package/dist/src/gateway/hono/routes/goals.js.map +1 -1
- package/dist/src/gateway/hono/routes/logs.js +1 -0
- package/dist/src/gateway/hono/routes/logs.js.map +1 -1
- package/dist/src/gateway/hono/routes/mcp.js +27 -8
- package/dist/src/gateway/hono/routes/mcp.js.map +1 -1
- package/dist/src/gateway/hono/routes/notes.js +14 -2
- package/dist/src/gateway/hono/routes/notes.js.map +1 -1
- package/dist/src/gateway/hono/routes/sessions.js +62 -4
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +3 -66
- package/dist/src/gateway/hono/routes/workspace.js.map +1 -1
- package/dist/src/gateway/hono/sse.d.ts +2 -2
- package/dist/src/gateway/hono/sse.js +7 -15
- package/dist/src/gateway/hono/sse.js.map +1 -1
- package/dist/src/gateway/resolve-webchat-session-key.d.ts +2 -6
- package/dist/src/gateway/resolve-webchat-session-key.js +5 -31
- package/dist/src/gateway/resolve-webchat-session-key.js.map +1 -1
- package/dist/src/gateway/service/agent-runner.d.ts +2 -3
- package/dist/src/gateway/service/agent-runner.js +9 -22
- package/dist/src/gateway/service/agent-runner.js.map +1 -1
- package/dist/src/gateway/service/run-gateway-agent.js +9 -7
- package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
- package/dist/src/gateway/service/sessions-api.d.ts +9 -0
- package/dist/src/gateway/service/sessions-api.js +11 -0
- package/dist/src/gateway/service/sessions-api.js.map +1 -1
- package/dist/src/gateway/service.d.ts +1 -1
- package/dist/src/gateway/service.js +19 -5
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/workspace-file-search.d.ts +9 -0
- package/dist/src/gateway/workspace-file-search.js +76 -0
- package/dist/src/gateway/workspace-file-search.js.map +1 -0
- package/dist/src/goals/goal-notifications.d.ts +2 -0
- package/dist/src/goals/goal-notifications.js +16 -11
- package/dist/src/goals/goal-notifications.js.map +1 -1
- package/dist/src/goals/goal-service.js +1 -6
- package/dist/src/goals/goal-service.js.map +1 -1
- package/dist/src/project-trust/trust-store.js +2 -0
- package/dist/src/project-trust/trust-store.js.map +1 -1
- package/dist/src/session/index.d.ts +1 -1
- package/dist/src/session/index.js +2 -2
- package/dist/src/session/init-session-turn.js +6 -9
- package/dist/src/session/init-session-turn.js.map +1 -1
- package/dist/src/session/manager.d.ts +5 -1
- package/dist/src/session/manager.js +5 -2
- package/dist/src/session/manager.js.map +1 -1
- package/dist/src/session/reset-type.d.ts +0 -2
- package/dist/src/session/reset-type.js +3 -9
- package/dist/src/session/reset-type.js.map +1 -1
- package/dist/src/session/resolve-session.js +9 -20
- package/dist/src/session/resolve-session.js.map +1 -1
- package/dist/src/session/store.d.ts +11 -3
- package/dist/src/session/store.js +29 -13
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/session/types.d.ts +2 -4
- package/dist/src/session/types.js.map +1 -1
- package/dist/src/storage/sqlite/index.d.ts +2 -2
- package/dist/src/storage/sqlite/index.js +3 -3
- package/dist/src/storage/sqlite/migrations/010_session_id_identity.sql +30 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +2 -2
- 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 +2 -2
- package/dist/src/storage/sqlite/row-mappers.d.ts +4 -4
- package/dist/src/storage/sqlite/row-mappers.js +11 -14
- package/dist/src/storage/sqlite/row-mappers.js.map +1 -1
- package/dist/src/storage/sqlite/schema.js +3 -3
- package/dist/src/storage/sqlite/schema.js.map +1 -1
- package/dist/src/storage/sqlite/schema.sql +37 -10
- package/dist/src/storage/sqlite/session-metadata.d.ts +2 -7
- package/dist/src/storage/sqlite/session-metadata.js +18 -72
- package/dist/src/storage/sqlite/session-metadata.js.map +1 -1
- package/dist/src/storage/sqlite/session-repository.d.ts +6 -5
- package/dist/src/storage/sqlite/session-repository.js +34 -40
- package/dist/src/storage/sqlite/session-repository.js.map +1 -1
- package/dist/src/storage/sqlite/transcript-repository.d.ts +2 -2
- package/dist/src/storage/sqlite/transcript-repository.js +52 -52
- package/dist/src/storage/sqlite/transcript-repository.js.map +1 -1
- package/dist/src/tui/backends/embedded-backend.d.ts +11 -4
- package/dist/src/tui/backends/embedded-backend.js +27 -1
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.d.ts +4 -1
- package/dist/src/tui/backends/gateway-sse-backend.js +21 -2
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/extension-host/autocomplete.js +13 -10
- package/dist/src/tui/extension-host/autocomplete.js.map +1 -1
- package/dist/src/tui/extension-host/runtime.d.ts +7 -0
- package/dist/src/tui/extension-host/runtime.js +6 -4
- package/dist/src/tui/extension-host/runtime.js.map +1 -1
- package/dist/src/tui/tui-backend.d.ts +9 -0
- package/dist/src/tui/tui-commands.js +85 -6
- package/dist/src/tui/tui-commands.js.map +1 -1
- package/dist/src/tui/tui-file-autocomplete.d.ts +5 -0
- package/dist/src/tui/tui-file-autocomplete.js +26 -0
- package/dist/src/tui/tui-file-autocomplete.js.map +1 -0
- package/dist/src/tui/tui-picker-overlay.js +1 -1
- package/dist/src/tui/tui.js +29 -11
- package/dist/src/tui/tui.js.map +1 -1
- package/dist/src/utils/logger/context.d.ts +2 -2
- package/dist/src/utils/logger/context.js +2 -1
- package/dist/src/utils/logger/context.js.map +1 -1
- package/dist/src/utils/logger/log-store.js +1 -0
- package/dist/src/utils/logger/log-store.js.map +1 -1
- package/dist/src/utils/logger/pino-record.js +3 -0
- package/dist/src/utils/logger/pino-record.js.map +1 -1
- package/dist/src/utils/logger/types.d.ts +5 -0
- package/dist/src/utils/logger/types.js.map +1 -1
- package/dist/src/workflows/service/workflow-session-bridge.js +13 -1
- package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/agent-browser-settings-page-rGbKc2Hh.js +0 -6
- package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-CtwVbjOA.js +0 -1
- package/dist/gateway/static/root/assets/agents-CCBmGcwc.js +0 -71
- package/dist/gateway/static/root/assets/apps-page-xwCsJS15.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-C044DcYk.js +0 -1
- package/dist/gateway/static/root/assets/connectors-settings-8VEWUOTj.js +0 -2
- package/dist/gateway/static/root/assets/cron-page-DqmNGNOy.js +0 -3
- package/dist/gateway/static/root/assets/dreaming-settings-6UZE1FSK.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-bv0VRDaf.js +0 -1
- package/dist/gateway/static/root/assets/goals-page-1Ywnt4Cb.js +0 -2
- package/dist/gateway/static/root/assets/index-Cxm6xsps.js +0 -122
- package/dist/gateway/static/root/assets/index-b_R4tKqt.css +0 -1
- package/dist/gateway/static/root/assets/logs-page-B_wrxhee.js +0 -2
- package/dist/gateway/static/root/assets/messages-CkT-lcgP.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-D0JDSbNu.js +0 -2
- package/dist/gateway/static/root/assets/note-detail-page-DpFV-EO6.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-CdkjTch8.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-DSYVAi96.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-CenkcVjF.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-D9sva86V.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-DL35U0x0.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-Ctwbp9Er.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-DIM3JNsr.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-DAlNaNzL.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-CLrHVzAt.js +0 -2
- package/dist/gateway/static/root/assets/voice-api-key-field-vYAO71Gn.js +0 -1
- package/dist/gateway/static/root/assets/workflow-page.utils-sgHjOXOm.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-DYyOTmFx.js +0 -18
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","names":[],"sources":["../../../src/chat-commands/context.ts"],"sourcesContent":["/**\n * Command Context Implementation\n * \n * Provides the concrete implementation of CommandContext interface,\n * bridging commands to core services (AgentService, SessionStore, etc.)\n */\n\nimport type {\n CommandContext,\n ReplyOptions,\n UIComponent,\n SessionInfo,\n ModelInfo,\n UsageStats,\n PlatformFeature,\n MessageSource,\n CompactSessionResult,\n} from './types.js';\nimport { getSessionDisplayName } from './session-key.js';\nimport type { Config } from '../config/schema.js';\nimport type { AgentMessage } from '@earendil-works/pi-agent-core';\nimport type { MessageBus } from '../infra/bus/index.js';\nimport type { SessionStore, SessionConfigStore } from '../session/index.js';\nimport { createLogger } from '../utils/logger.js';\nimport { getRoutingInfo } from './session-key.js';\nimport { saveConfig } from '../config/loader.js';\nimport type { ThinkLevel, ReasoningLevel, VerboseLevel } from '../agent/transcript/thinking-types.js';\nimport { mkdir, writeFile } from 'fs/promises';\nimport { join } from 'path';\nimport { effectiveWorkspacePathForSession } from '../session/session-workspace.js';\nimport { wrapMarkdownExportAsHtml } from '../session/chat-export.js';\nimport type { CompactionResult } from '../agent/memory/compaction.js';\nimport type { PersistentGoalApis } from '../agent/goals/persistent-goal-apis.js';\nimport type { WorkflowRunServiceLike } from '../workflows/service/workflow-run-service.types.js';\n\nconst log = createLogger('CommandContext');\n\nexport interface CommandContextDeps {\n sessionKey: string;\n source: MessageSource;\n channelId: string;\n chatId: string;\n senderId: string;\n isGroup: boolean;\n config: Config;\n bus: MessageBus;\n sessionStore: SessionStore;\n sessionConfigStore?: SessionConfigStore;\n /** After persisting session thinking, sync pi-agent in-memory state */\n applySessionThinkingLevel?: (sessionKey: string, level: ThinkLevel) => void;\n // Callbacks for platform-specific operations\n replyHandler: (text: string, options?: ReplyOptions) => Promise<void>;\n componentHandler?: (component: UIComponent) => Promise<void>;\n typingHandler?: (typing: boolean) => Promise<void>;\n supportedFeatures: PlatformFeature[];\n /** Called after session files are removed so in-memory agents match disk */\n invalidateAgentSession?: (sessionKey: string) => void;\n /** Reset session in place (archive + new session id); optional — falls back to clearSession */\n resetSession?: (sessionKey: string) => Promise<void>;\n // Model management (optional, will be injected)\n getCurrentModel?: () => string;\n switchModel?: (modelId: string) => Promise<boolean>;\n listModels?: () => Promise<ModelInfo[]>;\n getUsage?: () => Promise<UsageStats>;\n /** Stop current LLM turn and clear channel preview stream (Telegram draft, etc.) */\n abortCurrentTurn?: () => Promise<void>;\n /** Reload skills from disk and refresh active agent prompts. */\n reloadSkills?: () => Promise<void>;\n\n compactSession?: (\n sessionKey: string,\n options?: { instructions?: string; force?: boolean },\n ) => Promise<CompactionResult>;\n\n btwQuery?: (sessionKey: string, question: string) => Promise<{ text: string; error?: string }>;\n\n getSessionContextReport?: (\n sessionKey: string,\n mode: 'list' | 'detail' | 'json',\n ) => Promise<string>;\n\n persistentGoalApis?: PersistentGoalApis;\n workflowRunService?: WorkflowRunServiceLike;\n}\n\nexport class CommandContextImpl implements CommandContext {\n readonly sessionKey: string;\n readonly source: MessageSource;\n readonly channelId: string;\n readonly chatId: string;\n readonly senderId: string;\n readonly isGroup: boolean;\n readonly config: Config;\n readonly abortCurrentTurn?: () => Promise<void>;\n readonly reloadSkills?: () => Promise<void>;\n readonly persistentGoalApis?: PersistentGoalApis;\n readonly workflowRunApis?: CommandContext['workflowRunApis'];\n\n private deps: CommandContextDeps;\n\n constructor(deps: CommandContextDeps) {\n this.sessionKey = deps.sessionKey;\n this.source = deps.source;\n this.channelId = deps.channelId;\n this.chatId = deps.chatId;\n this.senderId = deps.senderId;\n this.isGroup = deps.isGroup;\n this.config = deps.config;\n this.deps = deps;\n\n if (deps.abortCurrentTurn) {\n const run = deps.abortCurrentTurn;\n this.abortCurrentTurn = async () => {\n await run();\n };\n }\n\n if (deps.reloadSkills) {\n const run = deps.reloadSkills;\n this.reloadSkills = async () => {\n await run();\n };\n }\n\n this.persistentGoalApis = deps.persistentGoalApis;\n if (deps.workflowRunService) {\n this.workflowRunApis = {\n service: deps.workflowRunService,\n startWorkflowRun: (params) => deps.workflowRunService!.startWorkflowRun(params),\n };\n }\n }\n\n // === Reply API ===\n\n async reply(text: string, options?: ReplyOptions): Promise<void> {\n await this.deps.replyHandler(text, options);\n }\n\n async replyComponent(component: UIComponent): Promise<void> {\n if (this.deps.componentHandler) {\n await this.deps.componentHandler(component);\n } else {\n // Fallback to text representation\n await this.reply(this.renderComponentAsText(component));\n }\n }\n\n async setTyping(typing: boolean): Promise<void> {\n if (this.deps.typingHandler) {\n await this.deps.typingHandler(typing);\n }\n }\n\n // === Session Management ===\n\n async getSession(): Promise<AgentMessage[]> {\n return this.deps.sessionStore.load(this.sessionKey);\n }\n\n async resetSession(): Promise<void> {\n if (this.deps.resetSession) {\n await this.deps.resetSession(this.sessionKey);\n } else if (typeof this.deps.sessionStore.reset === 'function') {\n const outcome = await this.deps.sessionStore.reset(this.sessionKey);\n if (!outcome) {\n throw new Error('Session not found');\n }\n this.deps.invalidateAgentSession?.(this.sessionKey);\n } else {\n await this.clearSession();\n return;\n }\n\n const routing = getRoutingInfo(this.sessionKey);\n await this.deps.bus.publishOutbound({\n channel: routing.channel,\n chat_id: routing.chatId,\n content: '✅ New session started. Previous transcript archived; model and session overrides kept.',\n type: 'message',\n metadata: {\n threadId: routing.threadId,\n },\n });\n\n log.info({ sessionKey: this.sessionKey }, 'Session reset');\n }\n\n async clearSession(): Promise<void> {\n // Archive first if has messages\n const messages = await this.getSession();\n if (messages.length > 0) {\n await this.deps.sessionStore.archive(this.sessionKey);\n log.info({ sessionKey: this.sessionKey, messageCount: messages.length }, 'Session archived');\n }\n\n // Delete session\n await this.deps.sessionStore.deleteSession(this.sessionKey);\n this.deps.invalidateAgentSession?.(this.sessionKey);\n\n // Publish outbound message to confirm\n const routing = getRoutingInfo(this.sessionKey);\n await this.deps.bus.publishOutbound({\n channel: routing.channel,\n chat_id: routing.chatId,\n content: '✅ Session cleared.',\n type: 'message',\n metadata: {\n threadId: routing.threadId,\n },\n });\n\n log.info({ sessionKey: this.sessionKey }, 'Session cleared');\n }\n\n async archiveSession(): Promise<void> {\n await this.deps.sessionStore.archive(this.sessionKey);\n log.info({ sessionKey: this.sessionKey }, 'Session archived');\n }\n\n async listSessions(): Promise<SessionInfo[]> {\n // TODO: Implement listSessions in SessionStore\n // For now, return current session only\n const messages = await this.getSession();\n return [{\n key: this.sessionKey,\n name: getSessionDisplayName(this.sessionKey),\n messageCount: messages.length,\n createdAt: new Date(),\n updatedAt: new Date(),\n isActive: true,\n }];\n }\n\n async switchSession(sessionKey: string): Promise<void> {\n // This is mainly for CLI/Web UI where you can switch between sessions\n // For Telegram, each chat has its own session\n log.info({ from: this.sessionKey, to: sessionKey }, 'Session switch requested');\n \n // Note: In the current architecture, switching session means\n // the next message will use a different sessionKey\n // The actual switch happens at the adapter level\n }\n\n // === Model Management ===\n\n getCurrentModel(): string {\n if (this.deps.getCurrentModel) {\n return this.deps.getCurrentModel();\n }\n \n // Fallback to config default\n return this.config.agents?.defaults?.models?.chat?.primary || 'minimax/minimax-m2.1';\n }\n\n async listModels(): Promise<ModelInfo[]> {\n if (this.deps.listModels) {\n return this.deps.listModels();\n }\n \n // Fallback to empty list\n return [];\n }\n\n async switchModel(modelId: string): Promise<boolean> {\n if (this.deps.switchModel) {\n return this.deps.switchModel(modelId);\n }\n \n // No model manager available\n await this.reply('❌ Model switching not available in this context.');\n return false;\n }\n\n async getUsage(): Promise<UsageStats> {\n if (this.deps.getUsage) {\n return this.deps.getUsage();\n }\n \n // Fallback: calculate from session\n const messages = await this.getSession();\n let promptTokens = 0;\n let completionTokens = 0;\n \n for (const msg of messages) {\n if ('usage' in msg && msg.usage) {\n promptTokens += msg.usage.input || 0;\n completionTokens += msg.usage.output || 0;\n }\n }\n \n return {\n promptTokens,\n completionTokens,\n totalTokens: promptTokens + completionTokens,\n messageCount: messages.length,\n };\n }\n\n // === Platform Features ===\n\n supports(feature: PlatformFeature): boolean {\n return this.deps.supportedFeatures.includes(feature);\n }\n\n // === Configuration ===\n\n getConfig(): Config {\n return this.config;\n }\n\n async updateConfig(path: string, value: unknown): Promise<boolean> {\n try {\n // Update config object using path\n const keys = path.split('.');\n let target: Record<string, unknown> = this.config as Record<string, unknown>;\n \n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i];\n if (!(key in target) || typeof target[key] !== 'object' || target[key] === null) {\n target[key] = {};\n }\n target = target[key] as Record<string, unknown>;\n }\n \n target[keys[keys.length - 1]] = value;\n \n // Save to disk\n await saveConfig(this.config);\n \n log.info({ path, value }, 'Config updated via command');\n return true;\n } catch (error) {\n log.error({ err: error, path, value }, 'Failed to update config');\n return false;\n }\n }\n\n // === Private Helpers ===\n\n // === Thinking Configuration ===\n\n /**\n * Get the session config store (if available)\n */\n getSessionConfigStore(): SessionConfigStore | undefined {\n return this.deps.sessionConfigStore;\n }\n\n /**\n * Get current thinking level (session override or default)\n */\n async getThinkingLevel(): Promise<ThinkLevel | undefined> {\n const configStore = this.deps.sessionConfigStore;\n if (configStore) {\n const sessionConfig = await configStore.get(this.sessionKey);\n if (sessionConfig?.thinkingLevel) {\n return sessionConfig.thinkingLevel;\n }\n }\n // Fallback to agent default\n return this.config.agents?.defaults?.thinkingDefault;\n }\n\n /**\n * Set thinking level for this session\n */\n async setThinkingLevel(level: ThinkLevel): Promise<void> {\n const configStore = this.deps.sessionConfigStore;\n if (configStore) {\n await configStore.update(this.sessionKey, { thinkingLevel: level });\n }\n this.deps.applySessionThinkingLevel?.(this.sessionKey, level);\n }\n\n syncAgentThinkingLevel(level: ThinkLevel): void {\n this.deps.applySessionThinkingLevel?.(this.sessionKey, level);\n }\n\n async compactSession(options?: { instructions?: string; force?: boolean }): Promise<CompactSessionResult | null> {\n if (!this.deps.compactSession) {\n return null;\n }\n const r = await this.deps.compactSession(this.sessionKey, options);\n return {\n compacted: r.compacted,\n tokensBefore: r.tokensBefore,\n tokensAfter: r.tokensAfter,\n summary: r.summary,\n };\n }\n\n async btwQuery(question: string): Promise<{ text: string; error?: string }> {\n if (!this.deps.btwQuery) {\n return { text: '', error: 'Side questions are not available in this environment.' };\n }\n return this.deps.btwQuery(this.sessionKey, question);\n }\n\n async exportSessionToWorkspace(format: 'markdown' | 'html' | 'json'): Promise<{ path: string }> {\n const exportFmt = format === 'json' ? 'json' : 'markdown';\n let body = await this.deps.sessionStore.exportSession(this.sessionKey, exportFmt);\n if (format === 'html') {\n body = wrapMarkdownExportAsHtml(`Session ${this.sessionKey}`, body);\n }\n const sc = this.deps.sessionConfigStore\n ? await this.deps.sessionConfigStore.get(this.sessionKey)\n : null;\n const root = effectiveWorkspacePathForSession(this.config, this.sessionKey, sc);\n const dir = join(root, 'exports');\n await mkdir(dir, { recursive: true });\n const safe = this.sessionKey.replace(/[^a-zA-Z0-9._-]+/g, '_').slice(0, 96);\n const ext = format === 'json' ? 'json' : format === 'html' ? 'html' : 'md';\n const name = `session-${safe}-${Date.now()}.${ext}`;\n const outPath = join(dir, name);\n await writeFile(outPath, body, 'utf-8');\n return { path: outPath };\n }\n\n async agentContextReport(mode: 'list' | 'detail' | 'json' = 'list'): Promise<string> {\n if (!this.deps.getSessionContextReport) {\n return 'Context report is not available in this environment.';\n }\n return this.deps.getSessionContextReport(this.sessionKey, mode);\n }\n\n /**\n * Get current reasoning level (session override or default)\n */\n async getReasoningLevel(): Promise<ReasoningLevel | undefined> {\n const configStore = this.deps.sessionConfigStore;\n if (configStore) {\n const sessionConfig = await configStore.get(this.sessionKey);\n if (sessionConfig?.reasoningLevel) {\n return sessionConfig.reasoningLevel;\n }\n }\n // Fallback to agent default\n return this.config.agents?.defaults?.reasoningDefault;\n }\n\n /**\n * Set reasoning level for this session\n */\n async setReasoningLevel(level: ReasoningLevel): Promise<void> {\n const configStore = this.deps.sessionConfigStore;\n if (configStore) {\n await configStore.update(this.sessionKey, { reasoningLevel: level });\n }\n }\n\n /**\n * Get current verbose level (session override or default)\n */\n async getVerboseLevel(): Promise<VerboseLevel | undefined> {\n const configStore = this.deps.sessionConfigStore;\n if (configStore) {\n const sessionConfig = await configStore.get(this.sessionKey);\n if (sessionConfig?.verboseLevel) {\n return sessionConfig.verboseLevel;\n }\n }\n // Fallback to agent default\n return this.config.agents?.defaults?.verboseDefault;\n }\n\n /**\n * Set verbose level for this session\n */\n async setVerboseLevel(level: VerboseLevel): Promise<void> {\n const configStore = this.deps.sessionConfigStore;\n if (configStore) {\n await configStore.update(this.sessionKey, { verboseLevel: level });\n }\n }\n\n private renderComponentAsText(component: UIComponent): string {\n switch (component.type) {\n case 'buttons':\n return component.buttons.map(b => `[${b.text}]`).join(' ');\n \n case 'select':\n return component.options.map(o => `- ${o.label}`).join('\\n');\n \n case 'model-picker':\n return component.providers.map(p => \n `**${p.name}**\\n${p.models.map(m => ` - ${m.name}`).join('\\n')}`\n ).join('\\n\\n');\n \n case 'usage-display':\n return `📊 Usage Stats:\\n` +\n `📥 Prompt: ${component.stats.promptTokens.toLocaleString()} tokens\\n` +\n `📤 Completion: ${component.stats.completionTokens.toLocaleString()} tokens\\n` +\n `📊 Total: ${component.stats.totalTokens.toLocaleString()} tokens`;\n \n case 'session-list':\n return component.sessions.map(s => \n `${s.isActive ? '▶️' : ' '} ${s.key} (${s.messageCount} messages)`\n ).join('\\n');\n \n case 'text-input':\n return component.placeholder || 'Enter text...';\n \n default:\n return '[UI Component]';\n }\n }\n}\n\n/**\n * Create a command context from dependencies\n */\nexport function createCommandContext(deps: CommandContextDeps): CommandContext {\n return new CommandContextImpl(deps);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"context.js","names":[],"sources":["../../../src/chat-commands/context.ts"],"sourcesContent":["/**\n * Command Context Implementation\n * \n * Provides the concrete implementation of CommandContext interface,\n * bridging commands to core services (AgentService, SessionStore, etc.)\n */\n\nimport type {\n CommandContext,\n ReplyOptions,\n UIComponent,\n SessionInfo,\n ModelInfo,\n UsageStats,\n PlatformFeature,\n MessageSource,\n CompactSessionResult,\n} from './types.js';\nimport { getSessionDisplayName } from './session-key.js';\nimport type { Config } from '../config/schema.js';\nimport type { AgentMessage } from '@earendil-works/pi-agent-core';\nimport type { MessageBus } from '../infra/bus/index.js';\nimport type { SessionStore, SessionConfigStore } from '../session/index.js';\nimport { createLogger } from '../utils/logger.js';\nimport { saveConfig } from '../config/loader.js';\nimport type { ThinkLevel, ReasoningLevel, VerboseLevel } from '../agent/transcript/thinking-types.js';\nimport { mkdir, writeFile } from 'fs/promises';\nimport { join } from 'path';\nimport { effectiveWorkspacePathForSession } from '../session/session-workspace.js';\nimport { wrapMarkdownExportAsHtml } from '../session/chat-export.js';\nimport type { CompactionResult } from '../agent/memory/compaction.js';\nimport type { PersistentGoalApis } from '../agent/goals/persistent-goal-apis.js';\nimport type { WorkflowRunServiceLike } from '../workflows/service/workflow-run-service.types.js';\n\nconst log = createLogger('CommandContext');\n\nexport interface CommandContextDeps {\n sessionKey: string;\n source: MessageSource;\n channelId: string;\n chatId: string;\n senderId: string;\n isGroup: boolean;\n accountId?: string;\n threadId?: string;\n config: Config;\n bus: MessageBus;\n sessionStore: SessionStore;\n sessionConfigStore?: SessionConfigStore;\n /** After persisting session thinking, sync pi-agent in-memory state */\n applySessionThinkingLevel?: (sessionKey: string, level: ThinkLevel) => void;\n // Callbacks for platform-specific operations\n replyHandler: (text: string, options?: ReplyOptions) => Promise<void>;\n componentHandler?: (component: UIComponent) => Promise<void>;\n typingHandler?: (typing: boolean) => Promise<void>;\n supportedFeatures: PlatformFeature[];\n /** Called after session files are removed so in-memory agents match disk */\n invalidateAgentSession?: (sessionKey: string) => void;\n /** Reset session in place (archive + new session id); optional — falls back to clearSession */\n resetSession?: (sessionKey: string) => Promise<void>;\n // Model management (optional, will be injected)\n getCurrentModel?: () => string;\n switchModel?: (modelId: string) => Promise<boolean>;\n listModels?: () => Promise<ModelInfo[]>;\n getUsage?: () => Promise<UsageStats>;\n /** Stop current LLM turn and clear channel preview stream (Telegram draft, etc.) */\n abortCurrentTurn?: () => Promise<void>;\n /** Reload skills from disk and refresh active agent prompts. */\n reloadSkills?: () => Promise<void>;\n\n compactSession?: (\n sessionKey: string,\n options?: { instructions?: string; force?: boolean },\n ) => Promise<CompactionResult>;\n\n btwQuery?: (sessionKey: string, question: string) => Promise<{ text: string; error?: string }>;\n\n getSessionContextReport?: (\n sessionKey: string,\n mode: 'list' | 'detail' | 'json',\n ) => Promise<string>;\n\n persistentGoalApis?: PersistentGoalApis;\n workflowRunService?: WorkflowRunServiceLike;\n}\n\nexport class CommandContextImpl implements CommandContext {\n readonly sessionKey: string;\n readonly source: MessageSource;\n readonly channelId: string;\n readonly chatId: string;\n readonly senderId: string;\n readonly isGroup: boolean;\n readonly accountId?: string;\n readonly threadId?: string;\n readonly config: Config;\n readonly abortCurrentTurn?: () => Promise<void>;\n readonly reloadSkills?: () => Promise<void>;\n readonly persistentGoalApis?: PersistentGoalApis;\n readonly workflowRunApis?: CommandContext['workflowRunApis'];\n\n private deps: CommandContextDeps;\n\n constructor(deps: CommandContextDeps) {\n this.sessionKey = deps.sessionKey;\n this.source = deps.source;\n this.channelId = deps.channelId;\n this.chatId = deps.chatId;\n this.senderId = deps.senderId;\n this.isGroup = deps.isGroup;\n this.accountId = deps.accountId;\n this.threadId = deps.threadId;\n this.config = deps.config;\n this.deps = deps;\n\n if (deps.abortCurrentTurn) {\n const run = deps.abortCurrentTurn;\n this.abortCurrentTurn = async () => {\n await run();\n };\n }\n\n if (deps.reloadSkills) {\n const run = deps.reloadSkills;\n this.reloadSkills = async () => {\n await run();\n };\n }\n\n this.persistentGoalApis = deps.persistentGoalApis;\n if (deps.workflowRunService) {\n this.workflowRunApis = {\n service: deps.workflowRunService,\n startWorkflowRun: (params) => deps.workflowRunService!.startWorkflowRun(params),\n };\n }\n }\n\n private outboundMetadata(extra?: Record<string, unknown>): Record<string, unknown> {\n return {\n accountId: this.deps.accountId,\n threadId: this.deps.threadId,\n ...extra,\n };\n }\n\n // === Reply API ===\n\n async reply(text: string, options?: ReplyOptions): Promise<void> {\n await this.deps.replyHandler(text, options);\n }\n\n async replyComponent(component: UIComponent): Promise<void> {\n if (this.deps.componentHandler) {\n await this.deps.componentHandler(component);\n } else {\n // Fallback to text representation\n await this.reply(this.renderComponentAsText(component));\n }\n }\n\n async setTyping(typing: boolean): Promise<void> {\n if (this.deps.typingHandler) {\n await this.deps.typingHandler(typing);\n }\n }\n\n // === Session Management ===\n\n async getSession(): Promise<AgentMessage[]> {\n return this.deps.sessionStore.load(this.sessionKey);\n }\n\n async resetSession(): Promise<void> {\n if (this.deps.resetSession) {\n await this.deps.resetSession(this.sessionKey);\n } else if (typeof this.deps.sessionStore.reset === 'function') {\n const outcome = await this.deps.sessionStore.reset(this.sessionKey);\n if (!outcome) {\n throw new Error('Session not found');\n }\n this.deps.invalidateAgentSession?.(this.sessionKey);\n } else {\n await this.clearSession();\n return;\n }\n\n await this.deps.bus.publishOutbound({\n channel: this.source,\n chat_id: this.chatId,\n content: '✅ New session started. Previous transcript archived; model and session overrides kept.',\n type: 'message',\n metadata: this.outboundMetadata(),\n });\n\n log.info({ sessionKey: this.sessionKey }, 'Session reset');\n }\n\n async clearSession(): Promise<void> {\n // Archive first if has messages\n const messages = await this.getSession();\n if (messages.length > 0) {\n await this.deps.sessionStore.archive(this.sessionKey);\n log.info({ sessionKey: this.sessionKey, messageCount: messages.length }, 'Session archived');\n }\n\n // Delete session\n await this.deps.sessionStore.deleteSession(this.sessionKey);\n this.deps.invalidateAgentSession?.(this.sessionKey);\n\n // Publish outbound message to confirm\n await this.deps.bus.publishOutbound({\n channel: this.source,\n chat_id: this.chatId,\n content: '✅ Session cleared.',\n type: 'message',\n metadata: this.outboundMetadata(),\n });\n\n log.info({ sessionKey: this.sessionKey }, 'Session cleared');\n }\n\n async archiveSession(): Promise<void> {\n await this.deps.sessionStore.archive(this.sessionKey);\n log.info({ sessionKey: this.sessionKey }, 'Session archived');\n }\n\n async listSessions(): Promise<SessionInfo[]> {\n // TODO: Implement listSessions in SessionStore\n // For now, return current session only\n const messages = await this.getSession();\n return [{\n key: this.sessionKey,\n name: getSessionDisplayName(this.sessionKey),\n messageCount: messages.length,\n createdAt: new Date(),\n updatedAt: new Date(),\n isActive: true,\n }];\n }\n\n async switchSession(sessionKey: string): Promise<void> {\n // This is mainly for CLI/Web UI where you can switch between sessions\n // For Telegram, each chat has its own session\n log.info({ from: this.sessionKey, to: sessionKey }, 'Session switch requested');\n \n // Note: In the current architecture, switching session means\n // the next message will use a different sessionKey\n // The actual switch happens at the adapter level\n }\n\n // === Model Management ===\n\n getCurrentModel(): string {\n if (this.deps.getCurrentModel) {\n return this.deps.getCurrentModel();\n }\n \n // Fallback to config default\n return this.config.agents?.defaults?.models?.chat?.primary || 'minimax/minimax-m2.1';\n }\n\n async listModels(): Promise<ModelInfo[]> {\n if (this.deps.listModels) {\n return this.deps.listModels();\n }\n \n // Fallback to empty list\n return [];\n }\n\n async switchModel(modelId: string): Promise<boolean> {\n if (this.deps.switchModel) {\n return this.deps.switchModel(modelId);\n }\n \n // No model manager available\n await this.reply('❌ Model switching not available in this context.');\n return false;\n }\n\n async getUsage(): Promise<UsageStats> {\n if (this.deps.getUsage) {\n return this.deps.getUsage();\n }\n \n // Fallback: calculate from session\n const messages = await this.getSession();\n let promptTokens = 0;\n let completionTokens = 0;\n \n for (const msg of messages) {\n if ('usage' in msg && msg.usage) {\n promptTokens += msg.usage.input || 0;\n completionTokens += msg.usage.output || 0;\n }\n }\n \n return {\n promptTokens,\n completionTokens,\n totalTokens: promptTokens + completionTokens,\n messageCount: messages.length,\n };\n }\n\n // === Platform Features ===\n\n supports(feature: PlatformFeature): boolean {\n return this.deps.supportedFeatures.includes(feature);\n }\n\n // === Configuration ===\n\n getConfig(): Config {\n return this.config;\n }\n\n async updateConfig(path: string, value: unknown): Promise<boolean> {\n try {\n // Update config object using path\n const keys = path.split('.');\n let target: Record<string, unknown> = this.config as Record<string, unknown>;\n \n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i];\n if (!(key in target) || typeof target[key] !== 'object' || target[key] === null) {\n target[key] = {};\n }\n target = target[key] as Record<string, unknown>;\n }\n \n target[keys[keys.length - 1]] = value;\n \n // Save to disk\n await saveConfig(this.config);\n \n log.info({ path, value }, 'Config updated via command');\n return true;\n } catch (error) {\n log.error({ err: error, path, value }, 'Failed to update config');\n return false;\n }\n }\n\n // === Private Helpers ===\n\n // === Thinking Configuration ===\n\n /**\n * Get the session config store (if available)\n */\n getSessionConfigStore(): SessionConfigStore | undefined {\n return this.deps.sessionConfigStore;\n }\n\n /**\n * Get current thinking level (session override or default)\n */\n async getThinkingLevel(): Promise<ThinkLevel | undefined> {\n const configStore = this.deps.sessionConfigStore;\n if (configStore) {\n const sessionConfig = await configStore.get(this.sessionKey);\n if (sessionConfig?.thinkingLevel) {\n return sessionConfig.thinkingLevel;\n }\n }\n // Fallback to agent default\n return this.config.agents?.defaults?.thinkingDefault;\n }\n\n /**\n * Set thinking level for this session\n */\n async setThinkingLevel(level: ThinkLevel): Promise<void> {\n const configStore = this.deps.sessionConfigStore;\n if (configStore) {\n await configStore.update(this.sessionKey, { thinkingLevel: level });\n }\n this.deps.applySessionThinkingLevel?.(this.sessionKey, level);\n }\n\n syncAgentThinkingLevel(level: ThinkLevel): void {\n this.deps.applySessionThinkingLevel?.(this.sessionKey, level);\n }\n\n async compactSession(options?: { instructions?: string; force?: boolean }): Promise<CompactSessionResult | null> {\n if (!this.deps.compactSession) {\n return null;\n }\n const r = await this.deps.compactSession(this.sessionKey, options);\n return {\n compacted: r.compacted,\n tokensBefore: r.tokensBefore,\n tokensAfter: r.tokensAfter,\n summary: r.summary,\n };\n }\n\n async btwQuery(question: string): Promise<{ text: string; error?: string }> {\n if (!this.deps.btwQuery) {\n return { text: '', error: 'Side questions are not available in this environment.' };\n }\n return this.deps.btwQuery(this.sessionKey, question);\n }\n\n async exportSessionToWorkspace(format: 'markdown' | 'html' | 'json'): Promise<{ path: string }> {\n const exportFmt = format === 'json' ? 'json' : 'markdown';\n let body = await this.deps.sessionStore.exportSession(this.sessionKey, exportFmt);\n if (format === 'html') {\n body = wrapMarkdownExportAsHtml(`Session ${this.sessionKey}`, body);\n }\n const sc = this.deps.sessionConfigStore\n ? await this.deps.sessionConfigStore.get(this.sessionKey)\n : null;\n const root = effectiveWorkspacePathForSession(this.config, this.sessionKey, sc);\n const dir = join(root, 'exports');\n await mkdir(dir, { recursive: true });\n const safe = this.sessionKey.replace(/[^a-zA-Z0-9._-]+/g, '_').slice(0, 96);\n const ext = format === 'json' ? 'json' : format === 'html' ? 'html' : 'md';\n const name = `session-${safe}-${Date.now()}.${ext}`;\n const outPath = join(dir, name);\n await writeFile(outPath, body, 'utf-8');\n return { path: outPath };\n }\n\n async agentContextReport(mode: 'list' | 'detail' | 'json' = 'list'): Promise<string> {\n if (!this.deps.getSessionContextReport) {\n return 'Context report is not available in this environment.';\n }\n return this.deps.getSessionContextReport(this.sessionKey, mode);\n }\n\n /**\n * Get current reasoning level (session override or default)\n */\n async getReasoningLevel(): Promise<ReasoningLevel | undefined> {\n const configStore = this.deps.sessionConfigStore;\n if (configStore) {\n const sessionConfig = await configStore.get(this.sessionKey);\n if (sessionConfig?.reasoningLevel) {\n return sessionConfig.reasoningLevel;\n }\n }\n // Fallback to agent default\n return this.config.agents?.defaults?.reasoningDefault;\n }\n\n /**\n * Set reasoning level for this session\n */\n async setReasoningLevel(level: ReasoningLevel): Promise<void> {\n const configStore = this.deps.sessionConfigStore;\n if (configStore) {\n await configStore.update(this.sessionKey, { reasoningLevel: level });\n }\n }\n\n /**\n * Get current verbose level (session override or default)\n */\n async getVerboseLevel(): Promise<VerboseLevel | undefined> {\n const configStore = this.deps.sessionConfigStore;\n if (configStore) {\n const sessionConfig = await configStore.get(this.sessionKey);\n if (sessionConfig?.verboseLevel) {\n return sessionConfig.verboseLevel;\n }\n }\n // Fallback to agent default\n return this.config.agents?.defaults?.verboseDefault;\n }\n\n /**\n * Set verbose level for this session\n */\n async setVerboseLevel(level: VerboseLevel): Promise<void> {\n const configStore = this.deps.sessionConfigStore;\n if (configStore) {\n await configStore.update(this.sessionKey, { verboseLevel: level });\n }\n }\n\n private renderComponentAsText(component: UIComponent): string {\n switch (component.type) {\n case 'buttons':\n return component.buttons.map(b => `[${b.text}]`).join(' ');\n \n case 'select':\n return component.options.map(o => `- ${o.label}`).join('\\n');\n \n case 'model-picker':\n return component.providers.map(p => \n `**${p.name}**\\n${p.models.map(m => ` - ${m.name}`).join('\\n')}`\n ).join('\\n\\n');\n \n case 'usage-display':\n return `📊 Usage Stats:\\n` +\n `📥 Prompt: ${component.stats.promptTokens.toLocaleString()} tokens\\n` +\n `📤 Completion: ${component.stats.completionTokens.toLocaleString()} tokens\\n` +\n `📊 Total: ${component.stats.totalTokens.toLocaleString()} tokens`;\n \n case 'session-list':\n return component.sessions.map(s => \n `${s.isActive ? '▶️' : ' '} ${s.key} (${s.messageCount} messages)`\n ).join('\\n');\n \n case 'text-input':\n return component.placeholder || 'Enter text...';\n \n default:\n return '[UI Component]';\n }\n }\n}\n\n/**\n * Create a command context from dependencies\n */\nexport function createCommandContext(deps: CommandContextDeps): CommandContext {\n return new CommandContextImpl(deps);\n}\n"],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Telegram, Feishu, Web UI, CLI, and other channel surfaces.
|
|
6
6
|
*/
|
|
7
7
|
export type { MessageSource, UnifiedMessage, PlatformMetadata, MessageAttachment, CommandDefinition, CommandCategory, CommandScope, CommandHandler, CommandResult, CommandContext, ReplyOptions, UIComponent, ButtonGroup, SelectMenu, ModelPicker, UsageDisplay, SessionList, TextInput, ProviderInfo, ModelInfo, UsageStats, SessionInfo, PlatformFeature, ChannelAdapter, ReplyPayload, } from './types.js';
|
|
8
|
-
export { generateSessionKey,
|
|
8
|
+
export { generateSessionKey, getSessionDisplayName, type SessionKeyContext } from './session-key.js';
|
|
9
9
|
export { normalizeTelegramCommandName, parseSlashCommand } from './command-parse.js';
|
|
10
10
|
export { CommandRegistry, commandRegistry } from './registry.js';
|
|
11
11
|
export type { CommandRegistry as CommandRegistryType } from './types.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { normalizeTelegramCommandName, parseSlashCommand } from "./command-parse.js";
|
|
2
2
|
import { CommandRegistry, commandRegistry } from "./registry.js";
|
|
3
|
-
import { generateSessionKey,
|
|
3
|
+
import { generateSessionKey, getSessionDisplayName } from "./session-key.js";
|
|
4
4
|
import { registerSessionCommands } from "./builtins/session.js";
|
|
5
5
|
import { registerModelCommands } from "./builtins/model.js";
|
|
6
6
|
import { registerSystemCommands } from "./builtins/system.js";
|
|
@@ -37,6 +37,6 @@ function initializeCommands() {
|
|
|
37
37
|
registerAgentEditCommand();
|
|
38
38
|
}
|
|
39
39
|
//#endregion
|
|
40
|
-
export { CommandContextImpl, CommandRegistry, commandRegistry, createCommandContext, generateSessionKey,
|
|
40
|
+
export { CommandContextImpl, CommandRegistry, commandRegistry, createCommandContext, generateSessionKey, getSessionDisplayName, initializeCommands, normalizeTelegramCommandName, parseSlashCommand, registerAgentEditCommand, registerConfigCommand, registerContextCommands, registerGoalCommand, registerModelCommands, registerSessionCommands, registerSubgoalCommand, registerSystemCommands, registerTTSCommands, registerThinkingCommands, registerWorkflowCommands };
|
|
41
41
|
|
|
42
42
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/chat-commands/index.ts"],"sourcesContent":["/**\n * Unified Command System\n *\n * Provides a platform-agnostic command system that works across\n * Telegram, Feishu, Web UI, CLI, and other channel surfaces.\n */\n\n// Built-in Commands (import first to avoid circular deps)\nimport { registerSessionCommands } from './builtins/session.js';\nimport { registerModelCommands } from './builtins/model.js';\nimport { registerSystemCommands } from './builtins/system.js';\nimport { registerTTSCommands } from './builtins/tts.js';\nimport { registerThinkingCommands } from './builtins/thinking.js';\nimport { registerConfigCommand } from './builtins/config.js';\nimport { registerContextCommands } from './builtins/context.js';\nimport { registerGoalCommand } from './builtins/goal.js';\nimport { registerSubgoalCommand } from './builtins/subgoal.js';\nimport { registerWorkflowCommands } from './builtins/workflow.js';\nimport { registerAgentEditCommand } from './agent-edit.js';\n\n// Types\nexport type {\n MessageSource,\n UnifiedMessage,\n PlatformMetadata,\n MessageAttachment,\n CommandDefinition,\n CommandCategory,\n CommandScope,\n CommandHandler,\n CommandResult,\n CommandContext,\n ReplyOptions,\n UIComponent,\n ButtonGroup,\n SelectMenu,\n ModelPicker,\n UsageDisplay,\n SessionList,\n TextInput,\n ProviderInfo,\n ModelInfo,\n UsageStats,\n SessionInfo,\n PlatformFeature,\n ChannelAdapter,\n ReplyPayload,\n} from './types.js';\n\n// Session
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/chat-commands/index.ts"],"sourcesContent":["/**\n * Unified Command System\n *\n * Provides a platform-agnostic command system that works across\n * Telegram, Feishu, Web UI, CLI, and other channel surfaces.\n */\n\n// Built-in Commands (import first to avoid circular deps)\nimport { registerSessionCommands } from './builtins/session.js';\nimport { registerModelCommands } from './builtins/model.js';\nimport { registerSystemCommands } from './builtins/system.js';\nimport { registerTTSCommands } from './builtins/tts.js';\nimport { registerThinkingCommands } from './builtins/thinking.js';\nimport { registerConfigCommand } from './builtins/config.js';\nimport { registerContextCommands } from './builtins/context.js';\nimport { registerGoalCommand } from './builtins/goal.js';\nimport { registerSubgoalCommand } from './builtins/subgoal.js';\nimport { registerWorkflowCommands } from './builtins/workflow.js';\nimport { registerAgentEditCommand } from './agent-edit.js';\n\n// Types\nexport type {\n MessageSource,\n UnifiedMessage,\n PlatformMetadata,\n MessageAttachment,\n CommandDefinition,\n CommandCategory,\n CommandScope,\n CommandHandler,\n CommandResult,\n CommandContext,\n ReplyOptions,\n UIComponent,\n ButtonGroup,\n SelectMenu,\n ModelPicker,\n UsageDisplay,\n SessionList,\n TextInput,\n ProviderInfo,\n ModelInfo,\n UsageStats,\n SessionInfo,\n PlatformFeature,\n ChannelAdapter,\n ReplyPayload,\n} from './types.js';\n\n// Session display helpers\nexport { generateSessionKey, getSessionDisplayName, type SessionKeyContext } from './session-key.js';\n\n// Command parsing helpers\nexport { normalizeTelegramCommandName, parseSlashCommand } from './command-parse.js';\n\n// Registry\nexport { CommandRegistry, commandRegistry } from './registry.js';\nexport type { CommandRegistry as CommandRegistryType } from './types.js';\n\n// Context\nexport { CommandContextImpl, createCommandContext } from './context.js';\n\n// Built-in Commands\nexport { registerSessionCommands } from './builtins/session.js';\nexport { registerModelCommands } from './builtins/model.js';\nexport { registerSystemCommands } from './builtins/system.js';\nexport { registerTTSCommands } from './builtins/tts.js';\nexport { registerThinkingCommands } from './builtins/thinking.js';\nexport { registerConfigCommand } from './builtins/config.js';\nexport { registerContextCommands } from './builtins/context.js';\nexport { registerGoalCommand } from './builtins/goal.js';\nexport { registerSubgoalCommand } from './builtins/subgoal.js';\nexport { registerWorkflowCommands } from './builtins/workflow.js';\nexport { registerAgentEditCommand } from './agent-edit.js';\n\n/**\n * Initialize the command system with all built-in commands\n */\nexport function initializeCommands(): void {\n registerSessionCommands();\n registerModelCommands();\n registerSystemCommands();\n registerConfigCommand();\n registerContextCommands();\n registerTTSCommands();\n registerThinkingCommands();\n registerGoalCommand();\n registerSubgoalCommand();\n registerWorkflowCommands();\n registerAgentEditCommand();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA8EA,SAAgB,qBAA2B;AACzC,0BAAyB;AACzB,wBAAuB;AACvB,yBAAwB;AACxB,wBAAuB;AACvB,0BAAyB;AACzB,sBAAqB;AACrB,2BAA0B;AAC1B,sBAAqB;AACrB,yBAAwB;AACxB,2BAA0B;AAC1B,2BAA0B"}
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { createLogger } from "../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../utils/logger.js";
|
|
3
3
|
import { commandRegistry } from "./registry.js";
|
|
4
|
-
import { getRoutingInfo } from "./session-key.js";
|
|
5
4
|
import { createCommandContext } from "./context.js";
|
|
6
5
|
//#region src/chat-commands/processor.ts
|
|
7
6
|
init_logger();
|
|
8
7
|
const log = createLogger("CommandProcessor");
|
|
8
|
+
function commandOutboundMetadata(message, extra) {
|
|
9
|
+
return {
|
|
10
|
+
accountId: message.platformData.accountId,
|
|
11
|
+
threadId: message.platformData.threadId,
|
|
12
|
+
...extra
|
|
13
|
+
};
|
|
14
|
+
}
|
|
9
15
|
/**
|
|
10
16
|
* Process a unified message
|
|
11
17
|
* Returns true if the message was handled (command or otherwise), false if should continue to AI
|
|
@@ -26,23 +32,19 @@ async function executeCommand(message, deps) {
|
|
|
26
32
|
}, "Executing command");
|
|
27
33
|
const ctx = await createCommandContextFromMessage(message, deps);
|
|
28
34
|
const result = await commandRegistry.execute(commandName, ctx, commandArgs || "");
|
|
29
|
-
if (result.content) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
metadata: { threadId: routing.threadId }
|
|
37
|
-
});
|
|
38
|
-
}
|
|
35
|
+
if (result.content) await deps.bus.publishOutbound({
|
|
36
|
+
channel: message.source,
|
|
37
|
+
chat_id: message.chatId,
|
|
38
|
+
content: result.content,
|
|
39
|
+
type: "message",
|
|
40
|
+
metadata: commandOutboundMetadata(message)
|
|
41
|
+
});
|
|
39
42
|
return true;
|
|
40
43
|
}
|
|
41
44
|
/**
|
|
42
45
|
* Create a command context from a unified message
|
|
43
46
|
*/
|
|
44
47
|
async function createCommandContextFromMessage(message, deps) {
|
|
45
|
-
const routing = getRoutingInfo(message.sessionKey);
|
|
46
48
|
return createCommandContext({
|
|
47
49
|
sessionKey: message.sessionKey,
|
|
48
50
|
source: message.source,
|
|
@@ -50,27 +52,26 @@ async function createCommandContextFromMessage(message, deps) {
|
|
|
50
52
|
chatId: message.chatId,
|
|
51
53
|
senderId: message.senderId,
|
|
52
54
|
isGroup: message.platformData.isGroup,
|
|
55
|
+
accountId: message.platformData.accountId,
|
|
56
|
+
threadId: message.platformData.threadId,
|
|
53
57
|
config: deps.config,
|
|
54
58
|
bus: deps.bus,
|
|
55
59
|
sessionStore: deps.sessionStore,
|
|
56
60
|
replyHandler: async (text, options) => {
|
|
57
61
|
await deps.bus.publishOutbound({
|
|
58
|
-
channel:
|
|
59
|
-
chat_id:
|
|
62
|
+
channel: message.source,
|
|
63
|
+
chat_id: message.chatId,
|
|
60
64
|
content: text,
|
|
61
65
|
type: "message",
|
|
62
|
-
metadata: {
|
|
63
|
-
threadId: routing.threadId,
|
|
64
|
-
parseMode: options?.parseMode
|
|
65
|
-
}
|
|
66
|
+
metadata: commandOutboundMetadata(message, { parseMode: options?.parseMode })
|
|
66
67
|
});
|
|
67
68
|
},
|
|
68
69
|
typingHandler: async (typing) => {
|
|
69
70
|
await deps.bus.publishOutbound({
|
|
70
|
-
channel:
|
|
71
|
-
chat_id:
|
|
71
|
+
channel: message.source,
|
|
72
|
+
chat_id: message.chatId,
|
|
72
73
|
type: typing ? "typing_on" : "typing_off",
|
|
73
|
-
metadata:
|
|
74
|
+
metadata: commandOutboundMetadata(message)
|
|
74
75
|
});
|
|
75
76
|
},
|
|
76
77
|
supportedFeatures: ["markdown", "typing"],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"processor.js","names":[],"sources":["../../../src/chat-commands/processor.ts"],"sourcesContent":["/**\n * Command Processor\n *\n * Integrates the command system with AgentService.\n * Processes incoming messages and routes commands appropriately.\n */\n\nimport type { UnifiedMessage, CommandContext } from './types.js';\nimport { commandRegistry } from './registry.js';\nimport { createCommandContext } from './context.js';\nimport type { MessageBus } from '../infra/bus/index.js';\nimport type { SessionStore } from '../session/index.js';\nimport type { Config } from '../config/schema.js';\nimport { createLogger } from '../utils/logger.js';\
|
|
1
|
+
{"version":3,"file":"processor.js","names":[],"sources":["../../../src/chat-commands/processor.ts"],"sourcesContent":["/**\n * Command Processor\n *\n * Integrates the command system with AgentService.\n * Processes incoming messages and routes commands appropriately.\n */\n\nimport type { UnifiedMessage, CommandContext } from './types.js';\nimport { commandRegistry } from './registry.js';\nimport { createCommandContext } from './context.js';\nimport type { MessageBus } from '../infra/bus/index.js';\nimport type { SessionStore } from '../session/index.js';\nimport type { Config } from '../config/schema.js';\nimport { createLogger } from '../utils/logger.js';\n\nconst log = createLogger('CommandProcessor');\n\nfunction commandOutboundMetadata(message: UnifiedMessage, extra?: Record<string, unknown>): Record<string, unknown> {\n return {\n accountId: message.platformData.accountId,\n threadId: message.platformData.threadId,\n ...extra,\n };\n}\n\nexport interface CommandProcessorDeps {\n bus: MessageBus;\n sessionStore: SessionStore;\n config: Config;\n // Model management callbacks\n getCurrentModel: () => string;\n switchModel: (modelId: string) => Promise<boolean>;\n listModels: () => Promise<Array<{ id: string; name: string; provider: string }>>;\n getUsage: () => Promise<{ promptTokens: number; completionTokens: number; totalTokens: number; messageCount: number }>;\n}\n\n/**\n * Process a unified message\n * Returns true if the message was handled (command or otherwise), false if should continue to AI\n */\nexport async function processMessage(\n message: UnifiedMessage,\n deps: CommandProcessorDeps\n): Promise<boolean> {\n // If it's a command, execute it\n if (message.isCommand && message.commandName) {\n return executeCommand(message, deps);\n }\n\n // Not a command, let AI handle it\n return false;\n}\n\n/**\n * Execute a command from a unified message\n */\nasync function executeCommand(\n message: UnifiedMessage,\n deps: CommandProcessorDeps\n): Promise<boolean> {\n const { commandName, commandArgs } = message;\n \n if (!commandName) return false;\n\n log.info({ command: commandName, sessionKey: message.sessionKey }, 'Executing command');\n\n // Create command context\n const ctx = await createCommandContextFromMessage(message, deps);\n\n // Execute command\n const result = await commandRegistry.execute(commandName, ctx, commandArgs || '');\n\n // Send response if there's content\n if (result.content) {\n await deps.bus.publishOutbound({\n channel: message.source,\n chat_id: message.chatId,\n content: result.content,\n type: 'message',\n metadata: commandOutboundMetadata(message),\n });\n }\n\n return true;\n}\n\n/**\n * Create a command context from a unified message\n */\nasync function createCommandContextFromMessage(\n message: UnifiedMessage,\n deps: CommandProcessorDeps\n): Promise<CommandContext> {\n return createCommandContext({\n sessionKey: message.sessionKey,\n source: message.source,\n channelId: message.channelId,\n chatId: message.chatId,\n senderId: message.senderId,\n isGroup: message.platformData.isGroup,\n accountId: message.platformData.accountId,\n threadId: message.platformData.threadId,\n config: deps.config,\n bus: deps.bus,\n sessionStore: deps.sessionStore,\n \n // Reply handler\n replyHandler: async (text: string, options?) => {\n await deps.bus.publishOutbound({\n channel: message.source,\n chat_id: message.chatId,\n content: text,\n type: 'message',\n metadata: commandOutboundMetadata(message, {\n parseMode: options?.parseMode,\n }),\n });\n },\n\n // Typing handler\n typingHandler: async (typing: boolean) => {\n await deps.bus.publishOutbound({\n channel: message.source,\n chat_id: message.chatId,\n type: typing ? 'typing_on' : 'typing_off',\n metadata: commandOutboundMetadata(message),\n });\n },\n\n // Supported features (would be determined by channel)\n supportedFeatures: ['markdown', 'typing'],\n\n // Model management\n getCurrentModel: deps.getCurrentModel,\n switchModel: deps.switchModel,\n listModels: deps.listModels,\n getUsage: deps.getUsage,\n });\n}\n"],"mappings":";;;;;aAakD;AAElD,MAAM,MAAM,aAAa,mBAAmB;AAE5C,SAAS,wBAAwB,SAAyB,OAA0D;AAClH,QAAO;EACL,WAAW,QAAQ,aAAa;EAChC,UAAU,QAAQ,aAAa;EAC/B,GAAG;EACJ;;;;;;AAkBH,eAAsB,eACpB,SACA,MACkB;AAElB,KAAI,QAAQ,aAAa,QAAQ,YAC/B,QAAO,eAAe,SAAS,KAAK;AAItC,QAAO;;;;;AAMT,eAAe,eACb,SACA,MACkB;CAClB,MAAM,EAAE,aAAa,gBAAgB;AAErC,KAAI,CAAC,YAAa,QAAO;AAEzB,KAAI,KAAK;EAAE,SAAS;EAAa,YAAY,QAAQ;EAAY,EAAE,oBAAoB;CAGvF,MAAM,MAAM,MAAM,gCAAgC,SAAS,KAAK;CAGhE,MAAM,SAAS,MAAM,gBAAgB,QAAQ,aAAa,KAAK,eAAe,GAAG;AAGjF,KAAI,OAAO,QACT,OAAM,KAAK,IAAI,gBAAgB;EAC7B,SAAS,QAAQ;EACjB,SAAS,QAAQ;EACjB,SAAS,OAAO;EAChB,MAAM;EACN,UAAU,wBAAwB,QAAQ;EAC3C,CAAC;AAGJ,QAAO;;;;;AAMT,eAAe,gCACb,SACA,MACyB;AACzB,QAAO,qBAAqB;EAC1B,YAAY,QAAQ;EACpB,QAAQ,QAAQ;EAChB,WAAW,QAAQ;EACnB,QAAQ,QAAQ;EAChB,UAAU,QAAQ;EAClB,SAAS,QAAQ,aAAa;EAC9B,WAAW,QAAQ,aAAa;EAChC,UAAU,QAAQ,aAAa;EAC/B,QAAQ,KAAK;EACb,KAAK,KAAK;EACV,cAAc,KAAK;EAGnB,cAAc,OAAO,MAAc,YAAa;AAC9C,SAAM,KAAK,IAAI,gBAAgB;IAC7B,SAAS,QAAQ;IACjB,SAAS,QAAQ;IACjB,SAAS;IACT,MAAM;IACN,UAAU,wBAAwB,SAAS,EACzC,WAAW,SAAS,WACrB,CAAC;IACH,CAAC;;EAIJ,eAAe,OAAO,WAAoB;AACxC,SAAM,KAAK,IAAI,gBAAgB;IAC7B,SAAS,QAAQ;IACjB,SAAS,QAAQ;IACjB,MAAM,SAAS,cAAc;IAC7B,UAAU,wBAAwB,QAAQ;IAC3C,CAAC;;EAIJ,mBAAmB,CAAC,YAAY,SAAS;EAGzC,iBAAiB,KAAK;EACtB,aAAa,KAAK;EAClB,YAAY,KAAK;EACjB,UAAU,KAAK;EAChB,CAAC"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Chat-command session display helpers.
|
|
3
|
+
*
|
|
4
|
+
* Session routing is resolved from SessionMetadata, not by parsing session keys.
|
|
3
5
|
*/
|
|
4
6
|
import type { MessageSource } from './types.js';
|
|
5
7
|
export interface SessionKeyContext {
|
|
@@ -16,18 +18,4 @@ export interface SessionKeyContext {
|
|
|
16
18
|
identityLinks?: Record<string, string[]>;
|
|
17
19
|
}
|
|
18
20
|
export declare function generateSessionKey(ctx: SessionKeyContext): string;
|
|
19
|
-
export declare function parseSessionKey(sessionKey: string): {
|
|
20
|
-
source: MessageSource;
|
|
21
|
-
type: 'dm' | 'group' | 'thread' | 'direct' | 'other';
|
|
22
|
-
chatId: string;
|
|
23
|
-
threadId?: string;
|
|
24
|
-
agentId?: string;
|
|
25
|
-
accountId?: string;
|
|
26
|
-
};
|
|
27
|
-
export declare function isValidSessionKey(sessionKey: string): boolean;
|
|
28
21
|
export declare function getSessionDisplayName(sessionKey: string): string;
|
|
29
|
-
export declare function getRoutingInfo(sessionKey: string): {
|
|
30
|
-
channel: string;
|
|
31
|
-
chatId: string;
|
|
32
|
-
threadId?: string;
|
|
33
|
-
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { buildAgentMainSessionKey, buildAgentPeerSessionKey } from "../routing/agent-session-key.js";
|
|
2
|
-
import { init_session_key
|
|
2
|
+
import { init_session_key } from "../routing/session-key.js";
|
|
3
3
|
//#region src/chat-commands/session-key.ts
|
|
4
4
|
init_session_key();
|
|
5
5
|
function generateSessionKey(ctx) {
|
|
@@ -47,56 +47,10 @@ function generateSessionKey(ctx) {
|
|
|
47
47
|
if (ctx.threadId) key = `${key}:thread:${ctx.threadId.toLowerCase()}`;
|
|
48
48
|
return key;
|
|
49
49
|
}
|
|
50
|
-
function parseSessionKey(sessionKey) {
|
|
51
|
-
const parsed = parseSessionKey$1(sessionKey);
|
|
52
|
-
if (!parsed) return {
|
|
53
|
-
source: "system",
|
|
54
|
-
type: "other",
|
|
55
|
-
chatId: "unknown"
|
|
56
|
-
};
|
|
57
|
-
let type;
|
|
58
|
-
switch (parsed.peerKind) {
|
|
59
|
-
case "dm":
|
|
60
|
-
case "direct":
|
|
61
|
-
type = parsed.peerKind === "direct" && parsed.peerId === "main" ? "direct" : "dm";
|
|
62
|
-
break;
|
|
63
|
-
case "group":
|
|
64
|
-
case "channel":
|
|
65
|
-
type = parsed.threadId ? "thread" : "group";
|
|
66
|
-
break;
|
|
67
|
-
default: type = "other";
|
|
68
|
-
}
|
|
69
|
-
return {
|
|
70
|
-
source: parsed.source,
|
|
71
|
-
type,
|
|
72
|
-
chatId: parsed.peerId,
|
|
73
|
-
threadId: parsed.threadId,
|
|
74
|
-
agentId: parsed.agentId,
|
|
75
|
-
accountId: parsed.accountId
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
function isValidSessionKey(sessionKey) {
|
|
79
|
-
return parseSessionKey$1(sessionKey) !== null;
|
|
80
|
-
}
|
|
81
50
|
function getSessionDisplayName(sessionKey) {
|
|
82
|
-
|
|
83
|
-
switch (parsed.type) {
|
|
84
|
-
case "dm": return `Private Chat (${parsed.source})`;
|
|
85
|
-
case "group": return `Group (${parsed.source})`;
|
|
86
|
-
case "thread": return `Thread (${parsed.source})`;
|
|
87
|
-
case "direct": return parsed.chatId === "main" ? "Main session" : `Direct (${parsed.source})`;
|
|
88
|
-
default: return `${parsed.source}:${parsed.chatId}`;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
function getRoutingInfo(sessionKey) {
|
|
92
|
-
const parsed = parseSessionKey(sessionKey);
|
|
93
|
-
return {
|
|
94
|
-
channel: parsed.source,
|
|
95
|
-
chatId: parsed.chatId,
|
|
96
|
-
threadId: parsed.threadId
|
|
97
|
-
};
|
|
51
|
+
return sessionKey.trim() || "Session";
|
|
98
52
|
}
|
|
99
53
|
//#endregion
|
|
100
|
-
export { generateSessionKey,
|
|
54
|
+
export { generateSessionKey, getSessionDisplayName };
|
|
101
55
|
|
|
102
56
|
//# sourceMappingURL=session-key.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-key.js","names":[
|
|
1
|
+
{"version":3,"file":"session-key.js","names":[],"sources":["../../../src/chat-commands/session-key.ts"],"sourcesContent":["/**\n * Chat-command session display helpers.\n *\n * Session routing is resolved from SessionMetadata, not by parsing session keys.\n */\n\nimport type { MessageSource } from './types.js';\nimport {\n buildAgentMainSessionKey,\n buildAgentPeerSessionKey,\n} from '../routing/session-key.js';\n\nexport interface SessionKeyContext {\n source: MessageSource;\n channelId?: string;\n chatId: string;\n senderId: string;\n isGroup: boolean;\n threadId?: string;\n agentId?: string;\n accountId?: string;\n mainKey?: string;\n dmScope?: 'main' | 'per-peer' | 'per-channel-peer' | 'per-account-channel-peer';\n identityLinks?: Record<string, string[]>;\n}\n\nexport function generateSessionKey(ctx: SessionKeyContext): string {\n const effectiveAgentId = ctx.agentId ?? 'main';\n const effectiveAccountId = ctx.accountId ?? 'default';\n const channel = ctx.source === 'webui' ? 'webchat' : ctx.source;\n\n if (ctx.source === 'cli') {\n if (ctx.chatId === 'direct' || ctx.chatId === 'main') {\n return buildAgentMainSessionKey({ agentId: effectiveAgentId, mainKey: ctx.mainKey });\n }\n return buildAgentPeerSessionKey({\n agentId: effectiveAgentId,\n mainKey: ctx.mainKey,\n channel: 'cli',\n accountId: effectiveAccountId,\n peerKind: 'direct',\n peerId: ctx.chatId,\n dmScope: 'per-peer',\n });\n }\n\n if (!ctx.isGroup) {\n const key = buildAgentPeerSessionKey({\n agentId: effectiveAgentId,\n mainKey: ctx.mainKey,\n channel,\n accountId: effectiveAccountId,\n peerKind: 'direct',\n peerId: ctx.senderId,\n identityLinks: ctx.identityLinks,\n dmScope: ctx.dmScope ?? 'per-account-channel-peer',\n });\n if (ctx.threadId) {\n return `${key}:thread:${ctx.threadId.toLowerCase()}`;\n }\n return key;\n }\n\n let key = buildAgentPeerSessionKey({\n agentId: effectiveAgentId,\n mainKey: ctx.mainKey,\n channel,\n accountId: effectiveAccountId,\n peerKind: 'group',\n peerId: ctx.chatId,\n identityLinks: ctx.identityLinks,\n });\n if (ctx.threadId) {\n key = `${key}:thread:${ctx.threadId.toLowerCase()}`;\n }\n return key;\n}\n\nexport function getSessionDisplayName(sessionKey: string): string {\n const trimmed = sessionKey.trim();\n return trimmed || 'Session';\n}\n"],"mappings":";;;kBAUmC;AAgBnC,SAAgB,mBAAmB,KAAgC;CACjE,MAAM,mBAAmB,IAAI,WAAW;CACxC,MAAM,qBAAqB,IAAI,aAAa;CAC5C,MAAM,UAAU,IAAI,WAAW,UAAU,YAAY,IAAI;AAEzD,KAAI,IAAI,WAAW,OAAO;AACxB,MAAI,IAAI,WAAW,YAAY,IAAI,WAAW,OAC5C,QAAO,yBAAyB;GAAE,SAAS;GAAkB,SAAS,IAAI;GAAS,CAAC;AAEtF,SAAO,yBAAyB;GAC9B,SAAS;GACT,SAAS,IAAI;GACb,SAAS;GACT,WAAW;GACX,UAAU;GACV,QAAQ,IAAI;GACZ,SAAS;GACV,CAAC;;AAGJ,KAAI,CAAC,IAAI,SAAS;EAChB,MAAM,MAAM,yBAAyB;GACnC,SAAS;GACT,SAAS,IAAI;GACb;GACA,WAAW;GACX,UAAU;GACV,QAAQ,IAAI;GACZ,eAAe,IAAI;GACnB,SAAS,IAAI,WAAW;GACzB,CAAC;AACF,MAAI,IAAI,SACN,QAAO,GAAG,IAAI,UAAU,IAAI,SAAS,aAAa;AAEpD,SAAO;;CAGT,IAAI,MAAM,yBAAyB;EACjC,SAAS;EACT,SAAS,IAAI;EACb;EACA,WAAW;EACX,UAAU;EACV,QAAQ,IAAI;EACZ,eAAe,IAAI;EACpB,CAAC;AACF,KAAI,IAAI,SACN,OAAM,GAAG,IAAI,UAAU,IAAI,SAAS,aAAa;AAEnD,QAAO;;AAGT,SAAgB,sBAAsB,YAA4B;AAEhE,QADgB,WAAW,MACb,IAAI"}
|
|
@@ -117,6 +117,10 @@ export interface CommandContext {
|
|
|
117
117
|
senderId: string;
|
|
118
118
|
/** Whether this is a group context */
|
|
119
119
|
isGroup: boolean;
|
|
120
|
+
/** Account ID for multi-account channels, when supplied by routing metadata. */
|
|
121
|
+
accountId?: string;
|
|
122
|
+
/** Thread/topic ID for threaded channels, when supplied by routing metadata. */
|
|
123
|
+
threadId?: string;
|
|
120
124
|
/** Bot configuration */
|
|
121
125
|
config: Config;
|
|
122
126
|
/** Send a text reply */
|
|
@@ -3,8 +3,8 @@ import { loadPlaywrightCoreModule } from "../../browser/providers/playwright-doc
|
|
|
3
3
|
import { BrowserManager } from "../../browser/manager.js";
|
|
4
4
|
import { resolveBrowserBackendFromConfig } from "../../browser/backend-from-config.js";
|
|
5
5
|
import { createBrowserActionRegistry } from "../../browser/actions/registry.js";
|
|
6
|
-
import { runBrowserPipeline, validateBrowserPipeline } from "../../browser/pipeline/runner.js";
|
|
7
6
|
import { loadBrowserPipelineSource } from "../../browser/pipeline/source.js";
|
|
7
|
+
import { runBrowserPipeline, validateBrowserPipelineSource } from "../../browser/pipeline/runner.js";
|
|
8
8
|
import "../../browser/index.js";
|
|
9
9
|
//#region src/cli/commands/browser-cli-helpers.ts
|
|
10
10
|
init_loader();
|
|
@@ -57,8 +57,11 @@ async function executeBrowserCliAction(action, args) {
|
|
|
57
57
|
}
|
|
58
58
|
async function validatePipelineCli(file) {
|
|
59
59
|
let yamlSource;
|
|
60
|
+
let sourceLocation;
|
|
60
61
|
try {
|
|
61
|
-
|
|
62
|
+
const loaded = await loadBrowserPipelineSource(file);
|
|
63
|
+
yamlSource = loaded.source;
|
|
64
|
+
sourceLocation = loaded.location;
|
|
62
65
|
} catch (e) {
|
|
63
66
|
const msg = e instanceof Error ? e.message : String(e);
|
|
64
67
|
console.error(`Failed to read pipeline source: ${msg}`);
|
|
@@ -66,7 +69,7 @@ async function validatePipelineCli(file) {
|
|
|
66
69
|
return;
|
|
67
70
|
}
|
|
68
71
|
const registry = createBrowserActionRegistry();
|
|
69
|
-
const result =
|
|
72
|
+
const result = await validateBrowserPipelineSource(yamlSource, registry, sourceLocation);
|
|
70
73
|
if (result.ok) console.log(`✓ Pipeline "${result.document.name}" is valid (${result.document.pipeline.length} steps).`);
|
|
71
74
|
else {
|
|
72
75
|
console.error("✗ Pipeline validation failed:");
|
|
@@ -76,8 +79,11 @@ async function validatePipelineCli(file) {
|
|
|
76
79
|
}
|
|
77
80
|
async function runPipelineCli(file, args) {
|
|
78
81
|
let yamlSource;
|
|
82
|
+
let sourceLocation;
|
|
79
83
|
try {
|
|
80
|
-
|
|
84
|
+
const loaded = await loadBrowserPipelineSource(file);
|
|
85
|
+
yamlSource = loaded.source;
|
|
86
|
+
sourceLocation = loaded.location;
|
|
81
87
|
} catch (e) {
|
|
82
88
|
const msg = e instanceof Error ? e.message : String(e);
|
|
83
89
|
console.error(`Failed to read pipeline source: ${msg}`);
|
|
@@ -86,7 +92,7 @@ async function runPipelineCli(file, args) {
|
|
|
86
92
|
}
|
|
87
93
|
const registry = createBrowserActionRegistry();
|
|
88
94
|
const ctx = await getActionContext();
|
|
89
|
-
const result = await runBrowserPipeline(yamlSource, args, ctx, registry);
|
|
95
|
+
const result = await runBrowserPipeline(yamlSource, args, ctx, registry, { sourceLocation });
|
|
90
96
|
if (result.ok) {
|
|
91
97
|
if (result.text) console.log(result.text);
|
|
92
98
|
if (result.data && !result.text) console.log(JSON.stringify(result.data, null, 2));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-cli-helpers.js","names":[],"sources":["../../../../src/cli/commands/browser-cli-helpers.ts"],"sourcesContent":["/**\n * CLI helpers for `xopc browser` — shared runtime setup for CLI browser commands.\n */\n\nimport type { Page } from 'playwright-core';\n\nimport { BrowserManager, resolveBrowserBackendFromConfig, createBrowserActionRegistry } from '../../browser/index.js';\nimport { loadPlaywrightCoreModule } from '../../browser/providers/playwright-doctor.js';\nimport { validateBrowserPipeline, runBrowserPipeline } from '../../browser/pipeline/runner.js';\nimport { loadBrowserPipelineSource } from '../../browser/pipeline/source.js';\nimport type { BrowserActionContext } from '../../browser/actions/types.js';\nimport { loadConfig } from '../../config/loader.js';\n\nlet _manager: BrowserManager | null = null;\n/** When set, `xopc browser open --headless` overrides config for this CLI invocation. */\nlet browserCliHeadlessOverride: boolean | undefined;\n\nasync function getManager(): Promise<BrowserManager> {\n if (_manager) return _manager;\n const config = await loadConfig();\n _manager = new BrowserManager({\n getHeadless: () => {\n if (typeof browserCliHeadlessOverride === 'boolean') return browserCliHeadlessOverride;\n return config?.agents?.defaults?.browser?.headless === true;\n },\n getBackend: () => resolveBrowserBackendFromConfig(config),\n });\n return _manager;\n}\n\nasync function getActionContext(): Promise<BrowserActionContext> {\n const manager = await getManager();\n await manager.ensureConnected();\n const ext = manager.getExtensionProvider();\n const page: Page = ext ? (null as unknown as Page) : await manager.getPage('cli');\n const config = await loadConfig();\n return { page, manager, config, taskId: 'cli' };\n}\n\nexport async function executeBrowserCliAction(action: string, args: Record<string, unknown>): Promise<void> {\n const prevOverride = browserCliHeadlessOverride;\n if (typeof args.headless === 'boolean') {\n browserCliHeadlessOverride = args.headless;\n }\n try {\n const registry = createBrowserActionRegistry();\n const ctx = await getActionContext();\n\n const result = await registry.execute(action, ctx, args);\n\n if (result.ok) {\n if (result.text) console.log(result.text);\n if (result.data && !result.text) console.log(JSON.stringify(result.data, null, 2));\n } else {\n console.error(`[${result.error?.code}] ${result.error?.message}`);\n process.exitCode = 1;\n }\n\n // Close after non-persistent actions\n if (action === 'close') {\n await _manager?.shutdown();\n _manager = null;\n }\n } finally {\n browserCliHeadlessOverride = prevOverride;\n }\n}\n\nexport async function validatePipelineCli(file: string): Promise<void> {\n let yamlSource: string;\n try {\n yamlSource = (await loadBrowserPipelineSource(file)).source;\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n console.error(`Failed to read pipeline source: ${msg}`);\n process.exitCode = 1;\n return;\n }\n\n const registry = createBrowserActionRegistry();\n const result = validateBrowserPipeline(yamlSource, registry);\n\n if (result.ok) {\n console.log(`✓ Pipeline \"${result.document!.name}\" is valid (${result.document!.pipeline.length} steps).`);\n } else {\n console.error('✗ Pipeline validation failed:');\n for (const err of result.errors) {\n console.error(` ${err.path}: ${err.message}`);\n }\n process.exitCode = 1;\n }\n}\n\nexport async function runPipelineCli(file: string, args: Record<string, unknown>): Promise<void> {\n let yamlSource: string;\n try {\n yamlSource = (await loadBrowserPipelineSource(file)).source;\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n console.error(`Failed to read pipeline source: ${msg}`);\n process.exitCode = 1;\n return;\n }\n\n const registry = createBrowserActionRegistry();\n const ctx = await getActionContext();\n const result = await runBrowserPipeline(yamlSource, args, ctx, registry);\n\n if (result.ok) {\n if (result.text) console.log(result.text);\n if (result.data && !result.text) console.log(JSON.stringify(result.data, null, 2));\n } else {\n console.error(`Pipeline failed: [${result.error?.code}] ${result.error?.message}`);\n if (result.diagnostics?.snapshot) {\n console.error(`Snapshot:\\n${result.diagnostics.snapshot.slice(0, 2000)}`);\n }\n process.exitCode = 1;\n }\n\n await _manager?.shutdown();\n _manager = null;\n}\n\nexport async function doctorCli(): Promise<void> {\n console.log('Browser Doctor');\n console.log('──────────────');\n\n // Check playwright-core\n try {\n const pw = await loadPlaywrightCoreModule();\n const chromium = pw.chromium ?? (pw as any).default?.chromium;\n if (chromium) {\n console.log('✓ playwright-core installed');\n // Try to detect browsers\n const execPath = chromium.executablePath?.();\n if (execPath) {\n console.log(` Chromium path: ${execPath}`);\n } else {\n console.log(' ⚠ No default Chromium path detected. Run: npx playwright install chromium');\n }\n } else {\n console.log('✗ playwright-core chromium not available');\n }\n } catch {\n console.log('✗ playwright-core not installed');\n }\n\n // Check config\n try {\n const config = await loadConfig();\n const browser = config?.agents?.defaults?.browser;\n console.log(`\\nConfig:`);\n console.log(` enabled: ${browser?.enabled !== false}`);\n console.log(` headless: ${browser?.headless === true}`);\n console.log(` backend: ${browser?.backend ?? 'extension'}`);\n console.log(` provider: ${browser?.cloudProvider ?? 'local'}`);\n if (browser?.cdpUrl) console.log(` cdp: ${browser.cdpUrl}`);\n if (browser?.backend === 'extension' || browser?.extension) {\n const ext = browser?.extension;\n const port = ext?.port ?? 19820;\n const host = ext?.host ?? '127.0.0.1';\n console.log(`\\nExtension Bridge:`);\n console.log(` endpoint: ws://${host}:${port}/browser-ext`);\n try {\n const { browserExtDoctor } = await import('../../browser/providers/browser-ext-install.js');\n const artifacts = await browserExtDoctor();\n console.log(` artifacts: ${artifacts.installed ? '✓ installed' : '✗ not installed'}`);\n if (artifacts.extensionDir) console.log(` path: ${artifacts.extensionDir}`);\n if (artifacts.needsRefresh) console.log(` refresh: ⚠ bundled update available`);\n } catch {\n console.log(` artifacts: ⚠ could not check`);\n }\n // Try to ping the extension WS server\n try {\n const res = await fetch(`http://${host}:${port}/`);\n const data = await res.json() as { ok?: boolean; connected?: boolean };\n if (data.ok) {\n console.log(` server: ✓ running`);\n console.log(` extension: ${data.connected ? '✓ connected' : '⚠ waiting for connection'}`);\n }\n } catch {\n console.log(` server: ✗ not running (start xopc with backend: 'extension' to enable)`);\n }\n }\n } catch {\n console.log('\\n⚠ Could not load config');\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"browser-cli-helpers.js","names":[],"sources":["../../../../src/cli/commands/browser-cli-helpers.ts"],"sourcesContent":["/**\n * CLI helpers for `xopc browser` — shared runtime setup for CLI browser commands.\n */\n\nimport type { Page } from 'playwright-core';\n\nimport { BrowserManager, resolveBrowserBackendFromConfig, createBrowserActionRegistry } from '../../browser/index.js';\nimport { loadPlaywrightCoreModule } from '../../browser/providers/playwright-doctor.js';\nimport { runBrowserPipeline, validateBrowserPipelineSource } from '../../browser/pipeline/runner.js';\nimport { loadBrowserPipelineSource } from '../../browser/pipeline/source.js';\nimport type { BrowserActionContext } from '../../browser/actions/types.js';\nimport { loadConfig } from '../../config/loader.js';\n\nlet _manager: BrowserManager | null = null;\n/** When set, `xopc browser open --headless` overrides config for this CLI invocation. */\nlet browserCliHeadlessOverride: boolean | undefined;\n\nasync function getManager(): Promise<BrowserManager> {\n if (_manager) return _manager;\n const config = await loadConfig();\n _manager = new BrowserManager({\n getHeadless: () => {\n if (typeof browserCliHeadlessOverride === 'boolean') return browserCliHeadlessOverride;\n return config?.agents?.defaults?.browser?.headless === true;\n },\n getBackend: () => resolveBrowserBackendFromConfig(config),\n });\n return _manager;\n}\n\nasync function getActionContext(): Promise<BrowserActionContext> {\n const manager = await getManager();\n await manager.ensureConnected();\n const ext = manager.getExtensionProvider();\n const page: Page = ext ? (null as unknown as Page) : await manager.getPage('cli');\n const config = await loadConfig();\n return { page, manager, config, taskId: 'cli' };\n}\n\nexport async function executeBrowserCliAction(action: string, args: Record<string, unknown>): Promise<void> {\n const prevOverride = browserCliHeadlessOverride;\n if (typeof args.headless === 'boolean') {\n browserCliHeadlessOverride = args.headless;\n }\n try {\n const registry = createBrowserActionRegistry();\n const ctx = await getActionContext();\n\n const result = await registry.execute(action, ctx, args);\n\n if (result.ok) {\n if (result.text) console.log(result.text);\n if (result.data && !result.text) console.log(JSON.stringify(result.data, null, 2));\n } else {\n console.error(`[${result.error?.code}] ${result.error?.message}`);\n process.exitCode = 1;\n }\n\n // Close after non-persistent actions\n if (action === 'close') {\n await _manager?.shutdown();\n _manager = null;\n }\n } finally {\n browserCliHeadlessOverride = prevOverride;\n }\n}\n\nexport async function validatePipelineCli(file: string): Promise<void> {\n let yamlSource: string;\n let sourceLocation: string | undefined;\n try {\n const loaded = await loadBrowserPipelineSource(file);\n yamlSource = loaded.source;\n sourceLocation = loaded.location;\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n console.error(`Failed to read pipeline source: ${msg}`);\n process.exitCode = 1;\n return;\n }\n\n const registry = createBrowserActionRegistry();\n const result = await validateBrowserPipelineSource(yamlSource, registry, sourceLocation);\n\n if (result.ok) {\n console.log(`✓ Pipeline \"${result.document!.name}\" is valid (${result.document!.pipeline.length} steps).`);\n } else {\n console.error('✗ Pipeline validation failed:');\n for (const err of result.errors) {\n console.error(` ${err.path}: ${err.message}`);\n }\n process.exitCode = 1;\n }\n}\n\nexport async function runPipelineCli(file: string, args: Record<string, unknown>): Promise<void> {\n let yamlSource: string;\n let sourceLocation: string | undefined;\n try {\n const loaded = await loadBrowserPipelineSource(file);\n yamlSource = loaded.source;\n sourceLocation = loaded.location;\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n console.error(`Failed to read pipeline source: ${msg}`);\n process.exitCode = 1;\n return;\n }\n\n const registry = createBrowserActionRegistry();\n const ctx = await getActionContext();\n const result = await runBrowserPipeline(yamlSource, args, ctx, registry, { sourceLocation });\n\n if (result.ok) {\n if (result.text) console.log(result.text);\n if (result.data && !result.text) console.log(JSON.stringify(result.data, null, 2));\n } else {\n console.error(`Pipeline failed: [${result.error?.code}] ${result.error?.message}`);\n if (result.diagnostics?.snapshot) {\n console.error(`Snapshot:\\n${result.diagnostics.snapshot.slice(0, 2000)}`);\n }\n process.exitCode = 1;\n }\n\n await _manager?.shutdown();\n _manager = null;\n}\n\nexport async function doctorCli(): Promise<void> {\n console.log('Browser Doctor');\n console.log('──────────────');\n\n // Check playwright-core\n try {\n const pw = await loadPlaywrightCoreModule();\n const chromium = pw.chromium ?? (pw as any).default?.chromium;\n if (chromium) {\n console.log('✓ playwright-core installed');\n // Try to detect browsers\n const execPath = chromium.executablePath?.();\n if (execPath) {\n console.log(` Chromium path: ${execPath}`);\n } else {\n console.log(' ⚠ No default Chromium path detected. Run: npx playwright install chromium');\n }\n } else {\n console.log('✗ playwright-core chromium not available');\n }\n } catch {\n console.log('✗ playwright-core not installed');\n }\n\n // Check config\n try {\n const config = await loadConfig();\n const browser = config?.agents?.defaults?.browser;\n console.log(`\\nConfig:`);\n console.log(` enabled: ${browser?.enabled !== false}`);\n console.log(` headless: ${browser?.headless === true}`);\n console.log(` backend: ${browser?.backend ?? 'extension'}`);\n console.log(` provider: ${browser?.cloudProvider ?? 'local'}`);\n if (browser?.cdpUrl) console.log(` cdp: ${browser.cdpUrl}`);\n if (browser?.backend === 'extension' || browser?.extension) {\n const ext = browser?.extension;\n const port = ext?.port ?? 19820;\n const host = ext?.host ?? '127.0.0.1';\n console.log(`\\nExtension Bridge:`);\n console.log(` endpoint: ws://${host}:${port}/browser-ext`);\n try {\n const { browserExtDoctor } = await import('../../browser/providers/browser-ext-install.js');\n const artifacts = await browserExtDoctor();\n console.log(` artifacts: ${artifacts.installed ? '✓ installed' : '✗ not installed'}`);\n if (artifacts.extensionDir) console.log(` path: ${artifacts.extensionDir}`);\n if (artifacts.needsRefresh) console.log(` refresh: ⚠ bundled update available`);\n } catch {\n console.log(` artifacts: ⚠ could not check`);\n }\n // Try to ping the extension WS server\n try {\n const res = await fetch(`http://${host}:${port}/`);\n const data = await res.json() as { ok?: boolean; connected?: boolean };\n if (data.ok) {\n console.log(` server: ✓ running`);\n console.log(` extension: ${data.connected ? '✓ connected' : '⚠ waiting for connection'}`);\n }\n } catch {\n console.log(` server: ✗ not running (start xopc with backend: 'extension' to enable)`);\n }\n }\n } catch {\n console.log('\\n⚠ Could not load config');\n }\n}\n"],"mappings":"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"}
|
|
@@ -52,7 +52,7 @@ async function checkDatabaseSchema(ctx) {
|
|
|
52
52
|
id: "database-schema",
|
|
53
53
|
label: "Database schema",
|
|
54
54
|
status: "pass",
|
|
55
|
-
message: `SQLite schema v${status.dbVersion} (current release
|
|
55
|
+
message: `SQLite schema v${status.dbVersion} (current release v10).`,
|
|
56
56
|
hints: []
|
|
57
57
|
};
|
|
58
58
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { init_loader, loadConfig } from "../../../../config/loader.js";
|
|
2
2
|
import { requireXopcDatabase } from "../../../../storage/sqlite/connection.js";
|
|
3
3
|
import { getSqliteDatabase } from "../../../../storage/sqlite/transaction.js";
|
|
4
|
-
import {
|
|
4
|
+
import { getCurrentSessionId, listSessionMetadata } from "../../../../storage/sqlite/session-repository.js";
|
|
5
5
|
import "../../../../storage/sqlite/index.js";
|
|
6
6
|
import { existsSync } from "node:fs";
|
|
7
7
|
//#region src/cli/commands/doctor/checks/session-integrity.ts
|
|
@@ -39,18 +39,18 @@ async function checkSessionIntegrity(ctx) {
|
|
|
39
39
|
for (const failure of integrityFailures) issues.push(`database integrity: ${failure}`);
|
|
40
40
|
const { items } = listSessionMetadata({ limit: 1e5 });
|
|
41
41
|
for (const session of items) {
|
|
42
|
-
const
|
|
43
|
-
if (!
|
|
42
|
+
const sessionId = getCurrentSessionId(session.key);
|
|
43
|
+
if (!sessionId) {
|
|
44
44
|
issues.push(`missing transcript for ${session.key}`);
|
|
45
45
|
continue;
|
|
46
46
|
}
|
|
47
|
-
if (
|
|
48
|
-
if (!db.prepare(`SELECT
|
|
47
|
+
if (sessionId !== session.sessionId) issues.push(`session id mismatch for ${session.key}`);
|
|
48
|
+
if (!db.prepare(`SELECT session_id FROM transcripts WHERE session_id = ? AND status = 'active'`).get(sessionId)?.session_id) issues.push(`active transcript row missing for ${session.key}`);
|
|
49
49
|
}
|
|
50
|
-
const orphanTranscripts = db.prepare(`SELECT t.
|
|
51
|
-
LEFT JOIN sessions s ON s.
|
|
50
|
+
const orphanTranscripts = db.prepare(`SELECT t.session_id FROM transcripts t
|
|
51
|
+
LEFT JOIN sessions s ON s.session_id = t.session_id
|
|
52
52
|
WHERE t.status = 'active' AND s.session_key IS NULL`).all();
|
|
53
|
-
for (const row of orphanTranscripts) issues.push(`orphan active transcript ${row.
|
|
53
|
+
for (const row of orphanTranscripts) issues.push(`orphan active transcript ${row.session_id}`);
|
|
54
54
|
if (issues.length === 0) return {
|
|
55
55
|
id: "session-integrity",
|
|
56
56
|
label: "Sessions",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-integrity.js","names":[],"sources":["../../../../../../src/cli/commands/doctor/checks/session-integrity.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\n\nimport { loadConfig } from '../../../../config/loader.js';\nimport {\n
|
|
1
|
+
{"version":3,"file":"session-integrity.js","names":[],"sources":["../../../../../../src/cli/commands/doctor/checks/session-integrity.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\n\nimport { loadConfig } from '../../../../config/loader.js';\nimport {\n getCurrentSessionId,\n getSqliteDatabase,\n requireXopcDatabase,\n listSessionMetadata,\n} from '../../../../storage/sqlite/index.js';\nimport type { CheckResult, DoctorContext } from '../types.js';\n\nexport async function checkSessionIntegrity(ctx: DoctorContext): Promise<CheckResult> {\n if (!ctx.options.deep) {\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'skip',\n message: 'Deep mode off; session scan skipped.',\n hints: ['Run: xopc doctor --deep'],\n };\n }\n\n if (!existsSync(ctx.configPath)) {\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'skip',\n message: 'No config file; skipped.',\n hints: [],\n };\n }\n\n try {\n loadConfig(ctx.configPath);\n } catch {\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'warn',\n message: 'Config invalid; session scan skipped.',\n hints: ['Fix xopc.json before running session integrity checks.'],\n };\n }\n\n requireXopcDatabase();\n\n const issues: string[] = [];\n const db = getSqliteDatabase();\n\n const integrity = db.prepare('PRAGMA integrity_check').all() as Array<{ integrity_check: string }>;\n const integrityFailures = integrity\n .map((row) => row.integrity_check)\n .filter((value) => value !== 'ok');\n for (const failure of integrityFailures) {\n issues.push(`database integrity: ${failure}`);\n }\n\n const { items } = listSessionMetadata({ limit: 100_000 });\n\n for (const session of items) {\n const sessionId = getCurrentSessionId(session.key);\n if (!sessionId) {\n issues.push(`missing transcript for ${session.key}`);\n continue;\n }\n if (sessionId !== session.sessionId) {\n issues.push(`session id mismatch for ${session.key}`);\n }\n const transcript = db\n .prepare(`SELECT session_id FROM transcripts WHERE session_id = ? AND status = 'active'`)\n .get(sessionId) as { session_id?: string } | undefined;\n if (!transcript?.session_id) {\n issues.push(`active transcript row missing for ${session.key}`);\n }\n }\n\n const orphanTranscripts = db\n .prepare(\n `SELECT t.session_id FROM transcripts t\n LEFT JOIN sessions s ON s.session_id = t.session_id\n WHERE t.status = 'active' AND s.session_key IS NULL`,\n )\n .all() as Array<{ session_id: string }>;\n for (const row of orphanTranscripts) {\n issues.push(`orphan active transcript ${row.session_id}`);\n }\n\n if (issues.length === 0) {\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'pass',\n message: `SQLite session store OK (${items.length} session(s)).`,\n hints: [],\n };\n }\n\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'warn',\n message: `${issues.length} session integrity issue(s).`,\n hints: issues.slice(0, 8),\n };\n}\n"],"mappings":";;;;;;;aAE0D;AAS1D,eAAsB,sBAAsB,KAA0C;AACpF,KAAI,CAAC,IAAI,QAAQ,KACf,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS;EACT,OAAO,CAAC,0BAA0B;EACnC;AAGH,KAAI,CAAC,WAAW,IAAI,WAAW,CAC7B,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS;EACT,OAAO,EAAE;EACV;AAGH,KAAI;AACF,aAAW,IAAI,WAAW;SACpB;AACN,SAAO;GACL,IAAI;GACJ,OAAO;GACP,QAAQ;GACR,SAAS;GACT,OAAO,CAAC,yDAAyD;GAClE;;AAGH,sBAAqB;CAErB,MAAM,SAAmB,EAAE;CAC3B,MAAM,KAAK,mBAAmB;CAG9B,MAAM,oBADY,GAAG,QAAQ,yBAAyB,CAAC,KACpB,CAChC,KAAK,QAAQ,IAAI,gBAAgB,CACjC,QAAQ,UAAU,UAAU,KAAK;AACpC,MAAK,MAAM,WAAW,kBACpB,QAAO,KAAK,uBAAuB,UAAU;CAG/C,MAAM,EAAE,UAAU,oBAAoB,EAAE,OAAO,KAAS,CAAC;AAEzD,MAAK,MAAM,WAAW,OAAO;EAC3B,MAAM,YAAY,oBAAoB,QAAQ,IAAI;AAClD,MAAI,CAAC,WAAW;AACd,UAAO,KAAK,0BAA0B,QAAQ,MAAM;AACpD;;AAEF,MAAI,cAAc,QAAQ,UACxB,QAAO,KAAK,2BAA2B,QAAQ,MAAM;AAKvD,MAAI,CAHe,GAChB,QAAQ,gFAAgF,CACxF,IAAI,UACQ,EAAE,WACf,QAAO,KAAK,qCAAqC,QAAQ,MAAM;;CAInE,MAAM,oBAAoB,GACvB,QACC;;4DAGD,CACA,KAAK;AACR,MAAK,MAAM,OAAO,kBAChB,QAAO,KAAK,4BAA4B,IAAI,aAAa;AAG3D,KAAI,OAAO,WAAW,EACpB,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS,4BAA4B,MAAM,OAAO;EAClD,OAAO,EAAE;EACV;AAGH,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS,GAAG,OAAO,OAAO;EAC1B,OAAO,OAAO,MAAM,GAAG,EAAE;EAC1B"}
|
package/dist/src/config/rules.js
CHANGED
|
@@ -168,6 +168,11 @@ const BASE_RELOAD_RULES = [
|
|
|
168
168
|
kind: "restart",
|
|
169
169
|
description: "File share policy"
|
|
170
170
|
},
|
|
171
|
+
{
|
|
172
|
+
prefix: "gateway.siteShare",
|
|
173
|
+
kind: "restart",
|
|
174
|
+
description: "Site share policy"
|
|
175
|
+
},
|
|
171
176
|
{
|
|
172
177
|
prefix: "gateway.skillsStoreBaseUrl",
|
|
173
178
|
kind: "restart",
|