@xopcai/xopc 0.0.86 → 0.0.87
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/feishu/src/adapters/cli-login.js +3 -3
- package/dist/extensions/feishu/src/adapters/cli-login.js.map +1 -1
- package/dist/extensions/telegram/src/delivery-chat-id.d.ts +1 -1
- package/dist/extensions/telegram/src/delivery-chat-id.js +1 -1
- package/dist/extensions/telegram/src/delivery-chat-id.js.map +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +1 -0
- package/dist/extensions/telegram/src/routing-integration.js.map +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/__tests__/workflow-progress.test.js +2 -2
- package/dist/extensions/weixin/src/__tests__/workflow-progress.test.js.map +1 -1
- package/dist/extensions/weixin/src/api/api.js +2 -2
- package/dist/extensions/weixin/src/api/api.js.map +1 -1
- package/dist/extensions/weixin/src/auth/accounts.js +12 -12
- package/dist/extensions/weixin/src/auth/accounts.js.map +1 -1
- package/dist/extensions/weixin/src/delivery-to.js +2 -2
- package/dist/extensions/weixin/src/delivery-to.js.map +1 -1
- package/dist/extensions/weixin/src/messaging/debug-mode.js +5 -5
- package/dist/extensions/weixin/src/messaging/debug-mode.js.map +1 -1
- package/dist/extensions/weixin/src/messaging/inbound.js +11 -11
- package/dist/extensions/weixin/src/messaging/inbound.js.map +1 -1
- package/dist/extensions/weixin/src/storage/sync-buf.js +4 -4
- package/dist/extensions/weixin/src/storage/sync-buf.js.map +1 -1
- package/dist/extensions/weixin/src/workflow-progress.d.ts +1 -1
- package/dist/extensions/weixin/src/workflow-progress.js.map +1 -1
- package/dist/gateway/static/root/assets/{agents-mS3_HpRI.js → agents-BEAbXpuP.js} +6 -6
- package/dist/gateway/static/root/assets/{apps-page-DrfytjOb.js → apps-page-Dg8R-Szf.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-settings-BG6b9KrW.js → channels-settings-yohw9YSu.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-status-swr-Bs5kMCMI.js → channels-status-swr-BSHqqCF1.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-api-BuVcZ5zR.js → cron-api-0h_QT8U3.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-page-BMrloeFH.js → cron-page-BkfKFfFk.js} +1 -1
- package/dist/gateway/static/root/assets/{dist-CKU1OOTf.js → dist-Cmjp2APP.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-BdW_46sN.js → extension-debug-page-CFa9z_1N.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-DW47KI82.js → extension-page-BI8eaTPq.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-B-W4x2xP.js → extension-settings-page-x4BB7q1X.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-B2MYHbWg.js → fetch-DRqwef_Q.js} +1 -1
- package/dist/gateway/static/root/assets/{field-primitives-DPG-oJmx.js → field-primitives-BiNHBo2Y.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-C8dNts9i.js → heartbeat-config-api-ZRb8qhuz.js} +1 -1
- package/dist/gateway/static/root/assets/{index-BmVYculr.js → index-Cu7bKuUi.js} +96 -94
- package/dist/gateway/static/root/assets/index-a5gWIdZQ.css +1 -0
- package/dist/gateway/static/root/assets/{logs-page-sTsVWz0X.js → logs-page-BFZ8GgCv.js} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-FaG_Vlkb.js → sessions-page-CD7AfB-2.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-DuvRQW--.js → settings-form-section-DiqqVs6m.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-Bet1OerL.js → settings-page-BBOjEQW3.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-BtG2kLDh.js → share-preview-page-n1Gprylk.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page-DhUO235y.js → skills-page-CcN_gj--.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-DryYl3qD.js → theme-store-CZOh1nT3.js} +1 -1
- package/dist/gateway/static/root/assets/url-Dd8Q7kZZ.js +3 -0
- package/dist/gateway/static/root/assets/{utils-BY7bU1DT.js → utils-CkWBfxs4.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-api-key-field-CGEydndO.js → voice-api-key-field-O6awz9hi.js} +1 -1
- package/dist/gateway/static/root/index.html +5 -5
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-scope.d.ts +4 -0
- package/dist/src/agent/agent-scope.js +53 -10
- package/dist/src/agent/agent-scope.js.map +1 -1
- package/dist/src/agent/bootstrap/filter-bootstrap-files.js +2 -1
- package/dist/src/agent/bootstrap/filter-bootstrap-files.js.map +1 -1
- package/dist/src/agent/embedded/session-tool-result-guard.js +2 -1
- package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
- package/dist/src/agent/embedded/tool-result-truncation.js +2 -1
- package/dist/src/agent/embedded/tool-result-truncation.js.map +1 -1
- package/dist/src/agent/fallback/candidates.js +2 -2
- package/dist/src/agent/fallback/candidates.js.map +1 -1
- package/dist/src/agent/goals/persistent-goal-apis.d.ts +0 -2
- package/dist/src/agent/goals/persistent-goal-service.js +0 -1
- package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
- package/dist/src/agent/image/generation/normalization.js +2 -12
- package/dist/src/agent/image/generation/normalization.js.map +1 -1
- package/dist/src/agent/image/generation/provider-registry.d.ts +4 -8
- package/dist/src/agent/image/generation/provider-registry.js.map +1 -1
- package/dist/src/agent/image/generation/runtime.d.ts +2 -2
- package/dist/src/agent/image/generation/runtime.js.map +1 -1
- package/dist/src/agent/image/generation/types.d.ts +0 -18
- package/dist/src/agent/image/image-helpers.js +6 -1
- package/dist/src/agent/image/image-helpers.js.map +1 -1
- package/dist/src/agent/image/index.d.ts +1 -1
- package/dist/src/agent/inbound/inbound-loop.d.ts +5 -0
- package/dist/src/agent/inbound/inbound-loop.js +41 -10
- package/dist/src/agent/inbound/inbound-loop.js.map +1 -1
- package/dist/src/agent/inbound/turn-dispatcher.d.ts +4 -0
- package/dist/src/agent/inbound/turn-dispatcher.js +6 -4
- package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.js +2 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-names.js +2 -1
- package/dist/src/agent/mcp/bundle-mcp-names.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js +2 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js.map +1 -1
- package/dist/src/agent/mcp/mcp-transport-config.js +2 -1
- package/dist/src/agent/mcp/mcp-transport-config.js.map +1 -1
- package/dist/src/agent/mcp/mcp-transport.js +2 -1
- package/dist/src/agent/mcp/mcp-transport.js.map +1 -1
- package/dist/src/agent/media-generation/runtime-shared.js +2 -9
- package/dist/src/agent/media-generation/runtime-shared.js.map +1 -1
- package/dist/src/agent/messaging/command-handler.d.ts +6 -0
- package/dist/src/agent/messaging/command-handler.js +5 -0
- package/dist/src/agent/messaging/command-handler.js.map +1 -1
- package/dist/src/agent/prompt/safety.d.ts +0 -7
- package/dist/src/agent/prompt/safety.js +1 -20
- package/dist/src/agent/prompt/safety.js.map +1 -1
- package/dist/src/agent/service/build-direct-message-content.js +1 -1
- package/dist/src/agent/service/build-direct-message-content.js.map +1 -1
- package/dist/src/agent/service/direct-turn-helpers.d.ts +3 -1
- package/dist/src/agent/service/direct-turn-helpers.js +6 -1
- package/dist/src/agent/service/direct-turn-helpers.js.map +1 -1
- package/dist/src/agent/service/process-direct-one-shot.d.ts +4 -0
- package/dist/src/agent/service/process-direct-one-shot.js +15 -2
- package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
- package/dist/src/agent/service/process-direct-streaming.d.ts +4 -0
- package/dist/src/agent/service/process-direct-streaming.js +34 -4
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service/webchat-tts.js +1 -1
- package/dist/src/agent/service/webchat-tts.js.map +1 -1
- package/dist/src/agent/service.d.ts +8 -0
- package/dist/src/agent/service.js +21 -1
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/tools/create-share-tool.js +27 -20
- package/dist/src/agent/tools/create-share-tool.js.map +1 -1
- package/dist/src/agent/tools/factory.js +1 -1
- package/dist/src/agent/tools/index.d.ts +0 -1
- package/dist/src/agent/tools/index.js +4 -5
- package/dist/src/agent/tools/shell.js +0 -13
- package/dist/src/agent/tools/shell.js.map +1 -1
- package/dist/src/agent/tools/workflow-tool.js +7 -1
- package/dist/src/agent/tools/workflow-tool.js.map +1 -1
- package/dist/src/agent/workflow/channel-capability.d.ts +3 -3
- package/dist/src/agent/workflow/lint.d.ts +38 -0
- package/dist/src/agent/workflow/lint.js +74 -0
- package/dist/src/agent/workflow/lint.js.map +1 -0
- package/dist/src/agent/workflow/parser.js +4 -1
- package/dist/src/agent/workflow/parser.js.map +1 -1
- package/dist/src/agent/workflow/runtime.d.ts +3 -0
- package/dist/src/agent/workflow/runtime.js +76 -3
- package/dist/src/agent/workflow/runtime.js.map +1 -1
- package/dist/src/agent/workflow/types.d.ts +3 -1
- package/dist/src/browser/index.js +4 -4
- package/dist/src/browser/manager.d.ts +1 -3
- package/dist/src/browser/manager.js +0 -6
- package/dist/src/browser/manager.js.map +1 -1
- package/dist/src/browser/providers/browser-ext-install.d.ts +4 -4
- package/dist/src/browser/providers/browser-ext-install.js +38 -85
- package/dist/src/browser/providers/browser-ext-install.js.map +1 -1
- package/dist/src/browser/providers/cloakbrowser.d.ts +0 -5
- package/dist/src/browser/providers/cloakbrowser.js +2 -55
- package/dist/src/browser/providers/cloakbrowser.js.map +1 -1
- package/dist/src/channels/attachments/voice-stt-webchat.js +10 -8
- package/dist/src/channels/attachments/voice-stt-webchat.js.map +1 -1
- package/dist/src/channels/pairing/allow-from-file.js +9 -9
- package/dist/src/channels/pairing/allow-from-file.js.map +1 -1
- package/dist/src/channels/pairing/pairing-store.js +6 -6
- package/dist/src/channels/pairing/pairing-store.js.map +1 -1
- package/dist/src/chat-commands/builtins/session.js +1 -1
- package/dist/src/chat-commands/builtins/session.js.map +1 -1
- package/dist/src/chat-commands/builtins/tts.js +2 -2
- package/dist/src/chat-commands/builtins/tts.js.map +1 -1
- package/dist/src/chat-commands/context.d.ts +3 -0
- package/dist/src/chat-commands/context.js +21 -3
- package/dist/src/chat-commands/context.js.map +1 -1
- package/dist/src/chat-commands/session-key.d.ts +4 -37
- package/dist/src/chat-commands/session-key.js +49 -85
- package/dist/src/chat-commands/session-key.js.map +1 -1
- package/dist/src/chat-commands/types.d.ts +2 -0
- package/dist/src/cli/commands/agent/interactive.js +2 -2
- package/dist/src/cli/commands/agent/interactive.js.map +1 -1
- package/dist/src/cli/commands/agent/sessions.js +2 -2
- package/dist/src/cli/commands/agent/sessions.js.map +1 -1
- package/dist/src/cli/commands/agent.js +4 -5
- package/dist/src/cli/commands/agent.js.map +1 -1
- package/dist/src/cli/commands/channels.js +1 -5
- package/dist/src/cli/commands/channels.js.map +1 -1
- package/dist/src/cli/commands/gateway/lifecycle-core.js +1 -1
- package/dist/src/cli/commands/gateway/lifecycle-core.js.map +1 -1
- package/dist/src/cli/commands/gateway/logs.d.ts +9 -0
- package/dist/src/cli/commands/gateway/logs.js +50 -17
- package/dist/src/cli/commands/gateway/logs.js.map +1 -1
- package/dist/src/cli/commands/image.js +22 -21
- package/dist/src/cli/commands/image.js.map +1 -1
- package/dist/src/cli/commands/session/utils.js +2 -2
- package/dist/src/cli/commands/session/utils.js.map +1 -1
- package/dist/src/cli/commands/update.js +26 -46
- package/dist/src/cli/commands/update.js.map +1 -1
- package/dist/src/cli/utils/session.d.ts +0 -5
- package/dist/src/cli/utils/session.js +1 -6
- package/dist/src/cli/utils/session.js.map +1 -1
- package/dist/src/commands/agents.config.js +1 -1
- package/dist/src/commands/agents.config.js.map +1 -1
- package/dist/src/config/agent-profile.js +5 -27
- package/dist/src/config/agent-profile.js.map +1 -1
- package/dist/src/config/index.js +2 -2
- package/dist/src/config/model-input.js +2 -5
- package/dist/src/config/model-input.js.map +1 -1
- package/dist/src/config/schema.d.ts +201 -217
- package/dist/src/config/schema.js +54 -39
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/workspace-path-helpers.d.ts +1 -2
- package/dist/src/config/workspace-path-helpers.js.map +1 -1
- package/dist/src/daemon/install-plan.js +25 -1
- package/dist/src/daemon/install-plan.js.map +1 -1
- package/dist/src/daemon/launchd.d.ts +8 -0
- package/dist/src/daemon/launchd.js +5 -12
- package/dist/src/daemon/launchd.js.map +1 -1
- package/dist/src/daemon/schtasks.d.ts +25 -0
- package/dist/src/daemon/schtasks.js +166 -46
- package/dist/src/daemon/schtasks.js.map +1 -1
- package/dist/src/daemon/service.js +5 -4
- package/dist/src/daemon/service.js.map +1 -1
- package/dist/src/daemon/systemd.d.ts +6 -0
- package/dist/src/daemon/systemd.js +18 -3
- package/dist/src/daemon/systemd.js.map +1 -1
- package/dist/src/extensions/activation-context.js +0 -1
- package/dist/src/extensions/activation-context.js.map +1 -1
- package/dist/src/extensions/normalize-manifest.js +0 -1
- package/dist/src/extensions/normalize-manifest.js.map +1 -1
- package/dist/src/extensions/types/manifest.d.ts +0 -2
- package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
- package/dist/src/gateway/agent-builtin-tools.js +1 -0
- package/dist/src/gateway/agent-builtin-tools.js.map +1 -1
- package/dist/src/gateway/agents-admin.js +10 -2
- package/dist/src/gateway/agents-admin.js.map +1 -1
- package/dist/src/gateway/heartbeat/service.js +2 -2
- package/dist/src/gateway/heartbeat/service.js.map +1 -1
- package/dist/src/gateway/hono/app.js +1 -1
- package/dist/src/gateway/hono/lib/agent-model.d.ts +18 -10
- package/dist/src/gateway/hono/lib/agent-model.js +24 -35
- package/dist/src/gateway/hono/lib/agent-model.js.map +1 -1
- package/dist/src/gateway/hono/lib/config-payload.js +1 -1
- package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
- package/dist/src/gateway/hono/lib/safe-voice-config.js +14 -53
- package/dist/src/gateway/hono/lib/safe-voice-config.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/agents.js +17 -5
- package/dist/src/gateway/hono/routes/config-patch/agents.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/channels.js +0 -11
- package/dist/src/gateway/hono/routes/config-patch/channels.js.map +1 -1
- package/dist/src/gateway/hono/routes/goals.js +1 -1
- package/dist/src/gateway/hono/routes/goals.js.map +1 -1
- package/dist/src/gateway/hono/routes/sessions.js +28 -7
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/hono/routes/shares.js +14 -12
- package/dist/src/gateway/hono/routes/shares.js.map +1 -1
- package/dist/src/gateway/hono/routes/tunnel.js +1 -1
- package/dist/src/gateway/hono/routes/update.js +4 -2
- package/dist/src/gateway/hono/routes/update.js.map +1 -1
- package/dist/src/gateway/hono/sse.js +16 -33
- package/dist/src/gateway/hono/sse.js.map +1 -1
- package/dist/src/gateway/lock.js +10 -10
- package/dist/src/gateway/lock.js.map +1 -1
- package/dist/src/gateway/ports.js +6 -6
- package/dist/src/gateway/ports.js.map +1 -1
- package/dist/src/gateway/resolve-webchat-session-key.d.ts +19 -0
- package/dist/src/gateway/resolve-webchat-session-key.js +46 -0
- package/dist/src/gateway/resolve-webchat-session-key.js.map +1 -0
- package/dist/src/gateway/service/run-gateway-agent.js +27 -11
- package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
- package/dist/src/gateway/service/sessions-api.d.ts +3 -0
- package/dist/src/gateway/service/sessions-api.js +8 -0
- package/dist/src/gateway/service/sessions-api.js.map +1 -1
- package/dist/src/gateway/service.d.ts +0 -2
- package/dist/src/gateway/service.js +2 -7
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/session-reset-service.d.ts +20 -0
- package/dist/src/gateway/session-reset-service.js +54 -0
- package/dist/src/gateway/session-reset-service.js.map +1 -0
- package/dist/src/gateway/startup-readiness.d.ts +1 -1
- package/dist/src/gateway/startup-readiness.js +1 -0
- package/dist/src/gateway/startup-readiness.js.map +1 -1
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/infra/gateway-processes.js +2 -2
- package/dist/src/infra/gateway-processes.js.map +1 -1
- package/dist/src/infra/run-command.d.ts +16 -0
- package/dist/src/infra/run-command.js +67 -0
- package/dist/src/infra/run-command.js.map +1 -0
- package/dist/src/infra/update-global.d.ts +45 -0
- package/dist/src/infra/update-global.js +224 -0
- package/dist/src/infra/update-global.js.map +1 -0
- package/dist/src/mcp/channel-bridge.js +1 -1
- package/dist/src/mcp/channel-shared.js +2 -1
- package/dist/src/mcp/channel-shared.js.map +1 -1
- package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
- package/dist/src/providers/auth-runtime/auth-profile-store.js.map +1 -1
- package/dist/src/providers/auth-runtime/resolve-auth.js +1 -12
- package/dist/src/providers/auth-runtime/resolve-auth.js.map +1 -1
- package/dist/src/providers/auth-runtime/types.d.ts +6 -12
- package/dist/src/routing/agent-session-key.d.ts +58 -0
- package/dist/src/routing/agent-session-key.js +164 -0
- package/dist/src/routing/agent-session-key.js.map +1 -0
- package/dist/src/routing/index.d.ts +1 -1
- package/dist/src/routing/index.js +4 -2
- package/dist/src/routing/index.js.map +1 -1
- package/dist/src/routing/resolve-route.d.ts +15 -0
- package/dist/src/routing/resolve-route.js +41 -20
- package/dist/src/routing/resolve-route.js.map +1 -1
- package/dist/src/routing/resolve-tui-session-key.d.ts +25 -0
- package/dist/src/routing/resolve-tui-session-key.js +54 -0
- package/dist/src/routing/resolve-tui-session-key.js.map +1 -0
- package/dist/src/routing/session-key-utils.d.ts +24 -0
- package/dist/src/routing/session-key-utils.js +92 -0
- package/dist/src/routing/session-key-utils.js.map +1 -0
- package/dist/src/routing/session-key.d.ts +19 -49
- package/dist/src/routing/session-key.js +143 -116
- package/dist/src/routing/session-key.js.map +1 -1
- package/dist/src/session/index.d.ts +6 -0
- package/dist/src/session/index.js +7 -1
- package/dist/src/session/init-session-turn.d.ts +30 -0
- package/dist/src/session/init-session-turn.js +102 -0
- package/dist/src/session/init-session-turn.js.map +1 -0
- package/dist/src/session/lifecycle-timestamps.d.ts +8 -0
- package/dist/src/session/lifecycle-timestamps.js +16 -0
- package/dist/src/session/lifecycle-timestamps.js.map +1 -0
- package/dist/src/session/manager.d.ts +7 -1
- package/dist/src/session/manager.js +8 -1
- package/dist/src/session/manager.js.map +1 -1
- package/dist/src/session/parity/transcript-paths.js +2 -2
- package/dist/src/session/parity/transcript-paths.js.map +1 -1
- package/dist/src/session/parity/xopc-session-disk-entry.d.ts +6 -0
- package/dist/src/session/reset-policy.d.ts +32 -0
- package/dist/src/session/reset-policy.js +65 -0
- package/dist/src/session/reset-policy.js.map +1 -0
- package/dist/src/session/reset-triggers.d.ts +20 -0
- package/dist/src/session/reset-triggers.js +63 -0
- package/dist/src/session/reset-triggers.js.map +1 -0
- package/dist/src/session/reset-type.d.ts +12 -0
- package/dist/src/session/reset-type.js +25 -0
- package/dist/src/session/reset-type.js.map +1 -0
- package/dist/src/session/resolve-session.d.ts +30 -0
- package/dist/src/session/resolve-session.js +93 -0
- package/dist/src/session/resolve-session.js.map +1 -0
- package/dist/src/session/session-title.js +3 -2
- package/dist/src/session/session-title.js.map +1 -1
- package/dist/src/session/store.d.ts +11 -4
- package/dist/src/session/store.js +57 -6
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/session/transcript-events.js +2 -1
- package/dist/src/session/transcript-events.js.map +1 -1
- package/dist/src/share/share-url.d.ts +33 -0
- package/dist/src/share/share-url.js +56 -14
- package/dist/src/share/share-url.js.map +1 -1
- package/dist/src/tui/backends/embedded-backend.js +4 -9
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.js +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/components/chat-log.js +3 -3
- package/dist/src/tui/components/chat-log.js.map +1 -1
- package/dist/src/tui/theme.d.ts +0 -2
- package/dist/src/tui/theme.js +1 -3
- package/dist/src/tui/theme.js.map +1 -1
- package/dist/src/tui/tui-commands.d.ts +3 -0
- package/dist/src/tui/tui-commands.js +45 -10
- package/dist/src/tui/tui-commands.js.map +1 -1
- package/dist/src/tui/tui-keybindings-file.js +1 -21
- package/dist/src/tui/tui-keybindings-file.js.map +1 -1
- package/dist/src/tui/tui-session-actions.d.ts +28 -0
- package/dist/src/tui/tui-session-actions.js +88 -0
- package/dist/src/tui/tui-session-actions.js.map +1 -0
- package/dist/src/tui/tui.js +52 -47
- package/dist/src/tui/tui.js.map +1 -1
- package/dist/src/utils/string-coerce.d.ts +2 -0
- package/dist/src/utils/string-coerce.js +10 -1
- package/dist/src/utils/string-coerce.js.map +1 -1
- package/dist/src/voice/stt/config-slice.d.ts +2 -5
- package/dist/src/voice/stt/config-slice.js +5 -26
- package/dist/src/voice/stt/config-slice.js.map +1 -1
- package/dist/src/voice/stt/types.d.ts +1 -18
- package/dist/src/voice/stt/types.js +4 -2
- package/dist/src/voice/stt/types.js.map +1 -1
- package/dist/src/voice/tts/config-slice.d.ts +3 -7
- package/dist/src/voice/tts/config-slice.js +7 -38
- package/dist/src/voice/tts/config-slice.js.map +1 -1
- package/dist/src/voice/tts/merge-config.js +2 -48
- package/dist/src/voice/tts/merge-config.js.map +1 -1
- package/dist/src/voice/tts/providers/alibaba-speech.js +1 -1
- package/dist/src/voice/tts/providers/alibaba-speech.js.map +1 -1
- package/dist/src/voice/tts/types.d.ts +1 -29
- package/dist/src/voice/tts/types.js +19 -17
- package/dist/src/voice/tts/types.js.map +1 -1
- package/package.json +1 -4
- package/dist/gateway/static/root/assets/index-ew_2L2We.css +0 -1
- package/dist/gateway/static/root/assets/url-BwNL6Rgk.js +0 -3
- package/dist/src/agent/tools/browser-legacy-tools.d.ts +0 -17
- package/dist/src/agent/tools/browser-legacy-tools.js +0 -766
- package/dist/src/agent/tools/browser-legacy-tools.js.map +0 -1
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
//#region src/infra/run-command.ts
|
|
3
|
+
const MAX_CAPTURE_BYTES = 512 * 1024;
|
|
4
|
+
function appendCaptured(current, chunk) {
|
|
5
|
+
const next = current + chunk.toString();
|
|
6
|
+
if (next.length <= MAX_CAPTURE_BYTES) return next;
|
|
7
|
+
return next.slice(-MAX_CAPTURE_BYTES);
|
|
8
|
+
}
|
|
9
|
+
function createDefaultCommandRunner() {
|
|
10
|
+
return (argv, options) => runCommandWithTimeout(argv, options);
|
|
11
|
+
}
|
|
12
|
+
function runCommandWithTimeout(argv, options) {
|
|
13
|
+
const [command, ...args] = argv;
|
|
14
|
+
if (!command) return Promise.resolve({
|
|
15
|
+
code: 1,
|
|
16
|
+
stdout: "",
|
|
17
|
+
stderr: "empty argv"
|
|
18
|
+
});
|
|
19
|
+
return new Promise((resolve) => {
|
|
20
|
+
const child = spawn(command, args, {
|
|
21
|
+
cwd: options.cwd,
|
|
22
|
+
env: options.env ?? process.env,
|
|
23
|
+
stdio: [
|
|
24
|
+
"ignore",
|
|
25
|
+
"pipe",
|
|
26
|
+
"pipe"
|
|
27
|
+
],
|
|
28
|
+
...process.platform === "win32" ? { shell: process.env.ComSpec && process.env.ComSpec.trim() || "cmd.exe" } : {}
|
|
29
|
+
});
|
|
30
|
+
let stdout = "";
|
|
31
|
+
let stderr = "";
|
|
32
|
+
let settled = false;
|
|
33
|
+
const finish = (result) => {
|
|
34
|
+
if (settled) return;
|
|
35
|
+
settled = true;
|
|
36
|
+
clearTimeout(timeoutId);
|
|
37
|
+
resolve(result);
|
|
38
|
+
};
|
|
39
|
+
const timeoutId = setTimeout(() => {
|
|
40
|
+
child.kill("SIGTERM");
|
|
41
|
+
}, options.timeoutMs);
|
|
42
|
+
child.stdout?.on("data", (chunk) => {
|
|
43
|
+
stdout = appendCaptured(stdout, chunk);
|
|
44
|
+
});
|
|
45
|
+
child.stderr?.on("data", (chunk) => {
|
|
46
|
+
stderr = appendCaptured(stderr, chunk);
|
|
47
|
+
});
|
|
48
|
+
child.on("error", (err) => {
|
|
49
|
+
finish({
|
|
50
|
+
code: null,
|
|
51
|
+
stdout,
|
|
52
|
+
stderr: stderr || err.message
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
child.on("close", (code) => {
|
|
56
|
+
finish({
|
|
57
|
+
code,
|
|
58
|
+
stdout,
|
|
59
|
+
stderr
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
export { createDefaultCommandRunner, runCommandWithTimeout };
|
|
66
|
+
|
|
67
|
+
//# sourceMappingURL=run-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-command.js","names":[],"sources":["../../../src/infra/run-command.ts"],"sourcesContent":["// src/infra/run-command.ts\n\nimport { spawn } from 'node:child_process';\n\nexport type CommandRunResult = {\n code: number | null;\n stdout: string;\n stderr: string;\n};\n\nexport type CommandRunner = (\n argv: string[],\n options: { timeoutMs: number; cwd?: string; env?: NodeJS.ProcessEnv },\n) => Promise<CommandRunResult>;\n\nconst MAX_CAPTURE_BYTES = 512 * 1024;\n\nfunction appendCaptured(current: string, chunk: Buffer): string {\n const next = current + chunk.toString();\n if (next.length <= MAX_CAPTURE_BYTES) {\n return next;\n }\n return next.slice(-MAX_CAPTURE_BYTES);\n}\n\nexport function createDefaultCommandRunner(): CommandRunner {\n return (argv, options) => runCommandWithTimeout(argv, options);\n}\n\nexport function runCommandWithTimeout(\n argv: string[],\n options: { timeoutMs: number; cwd?: string; env?: NodeJS.ProcessEnv },\n): Promise<CommandRunResult> {\n const [command, ...args] = argv;\n if (!command) {\n return Promise.resolve({ code: 1, stdout: '', stderr: 'empty argv' });\n }\n\n return new Promise((resolve) => {\n const child = spawn(command, args, {\n cwd: options.cwd,\n env: options.env ?? process.env,\n stdio: ['ignore', 'pipe', 'pipe'],\n ...(process.platform === 'win32'\n ? { shell: (process.env.ComSpec && process.env.ComSpec.trim()) || 'cmd.exe' }\n : {}),\n });\n\n let stdout = '';\n let stderr = '';\n let settled = false;\n\n const finish = (result: CommandRunResult) => {\n if (settled) return;\n settled = true;\n clearTimeout(timeoutId);\n resolve(result);\n };\n\n const timeoutId = setTimeout(() => {\n child.kill('SIGTERM');\n }, options.timeoutMs);\n\n child.stdout?.on('data', (chunk: Buffer) => {\n stdout = appendCaptured(stdout, chunk);\n });\n child.stderr?.on('data', (chunk: Buffer) => {\n stderr = appendCaptured(stderr, chunk);\n });\n\n child.on('error', (err) => {\n finish({ code: null, stdout, stderr: stderr || err.message });\n });\n\n child.on('close', (code) => {\n finish({ code, stdout, stderr });\n });\n });\n}\n"],"mappings":";;AAeA,MAAM,oBAAoB,MAAM;AAEhC,SAAS,eAAe,SAAiB,OAAuB;CAC9D,MAAM,OAAO,UAAU,MAAM,UAAU;AACvC,KAAI,KAAK,UAAU,kBACjB,QAAO;AAET,QAAO,KAAK,MAAM,CAAC,kBAAkB;;AAGvC,SAAgB,6BAA4C;AAC1D,SAAQ,MAAM,YAAY,sBAAsB,MAAM,QAAQ;;AAGhE,SAAgB,sBACd,MACA,SAC2B;CAC3B,MAAM,CAAC,SAAS,GAAG,QAAQ;AAC3B,KAAI,CAAC,QACH,QAAO,QAAQ,QAAQ;EAAE,MAAM;EAAG,QAAQ;EAAI,QAAQ;EAAc,CAAC;AAGvE,QAAO,IAAI,SAAS,YAAY;EAC9B,MAAM,QAAQ,MAAM,SAAS,MAAM;GACjC,KAAK,QAAQ;GACb,KAAK,QAAQ,OAAO,QAAQ;GAC5B,OAAO;IAAC;IAAU;IAAQ;IAAO;GACjC,GAAI,QAAQ,aAAa,UACrB,EAAE,OAAQ,QAAQ,IAAI,WAAW,QAAQ,IAAI,QAAQ,MAAM,IAAK,WAAW,GAC3E,EAAE;GACP,CAAC;EAEF,IAAI,SAAS;EACb,IAAI,SAAS;EACb,IAAI,UAAU;EAEd,MAAM,UAAU,WAA6B;AAC3C,OAAI,QAAS;AACb,aAAU;AACV,gBAAa,UAAU;AACvB,WAAQ,OAAO;;EAGjB,MAAM,YAAY,iBAAiB;AACjC,SAAM,KAAK,UAAU;KACpB,QAAQ,UAAU;AAErB,QAAM,QAAQ,GAAG,SAAS,UAAkB;AAC1C,YAAS,eAAe,QAAQ,MAAM;IACtC;AACF,QAAM,QAAQ,GAAG,SAAS,UAAkB;AAC1C,YAAS,eAAe,QAAQ,MAAM;IACtC;AAEF,QAAM,GAAG,UAAU,QAAQ;AACzB,UAAO;IAAE,MAAM;IAAM;IAAQ,QAAQ,UAAU,IAAI;IAAS,CAAC;IAC7D;AAEF,QAAM,GAAG,UAAU,SAAS;AAC1B,UAAO;IAAE;IAAM;IAAQ;IAAQ,CAAC;IAChC;GACF"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type CommandRunner } from './run-command.js';
|
|
2
|
+
export declare const XOPC_PACKAGE_NAME = "@xopcai/xopc";
|
|
3
|
+
export type GlobalInstallManager = 'npm' | 'pnpm';
|
|
4
|
+
export type ResolvedGlobalInstallCommand = {
|
|
5
|
+
manager: GlobalInstallManager;
|
|
6
|
+
command: string;
|
|
7
|
+
};
|
|
8
|
+
export type GlobalInstallRunResult = {
|
|
9
|
+
exitCode: number;
|
|
10
|
+
stdout: string;
|
|
11
|
+
stderr: string;
|
|
12
|
+
packageManager: GlobalInstallManager;
|
|
13
|
+
usedFallback: boolean;
|
|
14
|
+
};
|
|
15
|
+
export declare function joinGlobalPackagePath(globalRoot: string): string;
|
|
16
|
+
export declare function resolveGlobalInstallCommand(manager: GlobalInstallManager, pkgRoot?: string | null): ResolvedGlobalInstallCommand;
|
|
17
|
+
export declare function createGlobalInstallEnv(env?: NodeJS.ProcessEnv): Promise<NodeJS.ProcessEnv | undefined>;
|
|
18
|
+
export declare function resolveGlobalInstallSpec(params: {
|
|
19
|
+
version: string;
|
|
20
|
+
env?: NodeJS.ProcessEnv;
|
|
21
|
+
}): string;
|
|
22
|
+
export declare function resolveGlobalRoot(managerOrCommand: GlobalInstallManager | ResolvedGlobalInstallCommand, runCommand: CommandRunner, timeoutMs: number, pkgRoot?: string | null): Promise<string | null>;
|
|
23
|
+
export declare function globalInstallArgs(managerOrCommand: GlobalInstallManager | ResolvedGlobalInstallCommand, spec: string, pkgRoot?: string | null): string[];
|
|
24
|
+
export declare function globalInstallFallbackArgs(managerOrCommand: GlobalInstallManager | ResolvedGlobalInstallCommand, spec: string, pkgRoot?: string | null): string[] | null;
|
|
25
|
+
export declare function detectGlobalInstallManagerForRoot(runCommand: CommandRunner, pkgRoot: string, timeoutMs: number): Promise<GlobalInstallManager | null>;
|
|
26
|
+
export declare function detectGlobalInstallManagerByPresence(runCommand: CommandRunner, timeoutMs: number): Promise<GlobalInstallManager | null>;
|
|
27
|
+
export declare function resolveGlobalManager(params: {
|
|
28
|
+
root: string | null;
|
|
29
|
+
timeoutMs?: number;
|
|
30
|
+
}): Promise<GlobalInstallManager>;
|
|
31
|
+
export declare function runGlobalPackageInstall(params: {
|
|
32
|
+
manager: GlobalInstallManager;
|
|
33
|
+
spec: string;
|
|
34
|
+
pkgRoot: string | null;
|
|
35
|
+
timeoutMs?: number;
|
|
36
|
+
/** Echo install output to the parent process (CLI interactive). */
|
|
37
|
+
echoToTerminal?: boolean;
|
|
38
|
+
}): Promise<GlobalInstallRunResult>;
|
|
39
|
+
export declare function formatGlobalInstallFailure(params: {
|
|
40
|
+
packageManager: GlobalInstallManager;
|
|
41
|
+
spec: string;
|
|
42
|
+
exitCode: number;
|
|
43
|
+
stderr: string;
|
|
44
|
+
usedFallback: boolean;
|
|
45
|
+
}): string;
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { createDefaultCommandRunner } from "./run-command.js";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import fs$1 from "node:fs/promises";
|
|
5
|
+
//#region src/infra/update-global.ts
|
|
6
|
+
const XOPC_PACKAGE_NAME = "@xopcai/xopc";
|
|
7
|
+
const COREPACK_ENABLE_DOWNLOAD_PROMPT_DEFAULT = "0";
|
|
8
|
+
const NPM_GLOBAL_INSTALL_QUIET_FLAGS = [
|
|
9
|
+
"--no-fund",
|
|
10
|
+
"--no-audit",
|
|
11
|
+
"--loglevel=error"
|
|
12
|
+
];
|
|
13
|
+
const NPM_GLOBAL_INSTALL_OMIT_OPTIONAL_FLAGS = ["--omit=optional", ...NPM_GLOBAL_INSTALL_QUIET_FLAGS];
|
|
14
|
+
const GLOBAL_DETECT_TIMEOUT_MS = 15e3;
|
|
15
|
+
const GLOBAL_INSTALL_TIMEOUT_MS = 2700 * 1e3;
|
|
16
|
+
async function pathExists(targetPath) {
|
|
17
|
+
try {
|
|
18
|
+
await fs$1.access(targetPath);
|
|
19
|
+
return true;
|
|
20
|
+
} catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async function tryRealpath(targetPath) {
|
|
25
|
+
try {
|
|
26
|
+
return await fs$1.realpath(targetPath);
|
|
27
|
+
} catch {
|
|
28
|
+
return path.resolve(targetPath);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function joinGlobalPackagePath(globalRoot) {
|
|
32
|
+
return path.join(globalRoot, XOPC_PACKAGE_NAME);
|
|
33
|
+
}
|
|
34
|
+
function inferNpmPrefixFromPackageRoot(pkgRoot) {
|
|
35
|
+
const trimmed = pkgRoot?.trim();
|
|
36
|
+
if (!trimmed) return null;
|
|
37
|
+
const normalized = path.resolve(trimmed);
|
|
38
|
+
const nodeModulesDir = path.dirname(normalized);
|
|
39
|
+
if (path.basename(nodeModulesDir) !== "node_modules") return null;
|
|
40
|
+
const parentDir = path.dirname(nodeModulesDir);
|
|
41
|
+
if (path.basename(parentDir) === "lib") return path.dirname(parentDir);
|
|
42
|
+
if (process.platform === "win32" && path.basename(parentDir).toLowerCase() === "npm") return parentDir;
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
function resolvePreferredNpmCommand(pkgRoot) {
|
|
46
|
+
const prefix = inferNpmPrefixFromPackageRoot(pkgRoot);
|
|
47
|
+
if (!prefix) return null;
|
|
48
|
+
const candidate = process.platform === "win32" ? path.join(prefix, "npm.cmd") : path.join(prefix, "bin", "npm");
|
|
49
|
+
return fs.existsSync(candidate) ? candidate : null;
|
|
50
|
+
}
|
|
51
|
+
function resolvePreferredGlobalManagerCommand(manager, pkgRoot) {
|
|
52
|
+
if (manager !== "npm") return manager;
|
|
53
|
+
return resolvePreferredNpmCommand(pkgRoot) ?? manager;
|
|
54
|
+
}
|
|
55
|
+
function resolveGlobalInstallCommand(manager, pkgRoot) {
|
|
56
|
+
return {
|
|
57
|
+
manager,
|
|
58
|
+
command: resolvePreferredGlobalManagerCommand(manager, pkgRoot)
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function normalizeGlobalInstallCommand(managerOrCommand, pkgRoot) {
|
|
62
|
+
return typeof managerOrCommand === "string" ? resolveGlobalInstallCommand(managerOrCommand, pkgRoot) : managerOrCommand;
|
|
63
|
+
}
|
|
64
|
+
function applyWindowsPackageInstallEnv(env) {
|
|
65
|
+
if (process.platform !== "win32") return;
|
|
66
|
+
env.NPM_CONFIG_UPDATE_NOTIFIER = "false";
|
|
67
|
+
env.NPM_CONFIG_FUND = "false";
|
|
68
|
+
env.NPM_CONFIG_AUDIT = "false";
|
|
69
|
+
}
|
|
70
|
+
function applyCorepackDownloadPromptEnv(env) {
|
|
71
|
+
if (!env.COREPACK_ENABLE_DOWNLOAD_PROMPT?.trim()) env.COREPACK_ENABLE_DOWNLOAD_PROMPT = COREPACK_ENABLE_DOWNLOAD_PROMPT_DEFAULT;
|
|
72
|
+
}
|
|
73
|
+
async function createGlobalInstallEnv(env) {
|
|
74
|
+
const sourceEnv = env ?? process.env;
|
|
75
|
+
const hasCorepack = Boolean(sourceEnv.COREPACK_ENABLE_DOWNLOAD_PROMPT?.trim());
|
|
76
|
+
if (process.platform !== "win32" && hasCorepack) return env;
|
|
77
|
+
const merged = Object.fromEntries(Object.entries(sourceEnv).filter(([, value]) => value != null).map(([key, value]) => [key, String(value)]));
|
|
78
|
+
applyWindowsPackageInstallEnv(merged);
|
|
79
|
+
applyCorepackDownloadPromptEnv(merged);
|
|
80
|
+
return merged;
|
|
81
|
+
}
|
|
82
|
+
function resolveGlobalInstallSpec(params) {
|
|
83
|
+
const override = params.env?.XOPC_UPDATE_PACKAGE_SPEC?.trim() || process.env.XOPC_UPDATE_PACKAGE_SPEC?.trim();
|
|
84
|
+
if (override) return override;
|
|
85
|
+
return `${XOPC_PACKAGE_NAME}@${params.version}`;
|
|
86
|
+
}
|
|
87
|
+
async function resolveGlobalRoot(managerOrCommand, runCommand, timeoutMs, pkgRoot) {
|
|
88
|
+
const res = await runCommand([
|
|
89
|
+
normalizeGlobalInstallCommand(managerOrCommand, pkgRoot).command,
|
|
90
|
+
"root",
|
|
91
|
+
"-g"
|
|
92
|
+
], { timeoutMs }).catch(() => null);
|
|
93
|
+
if (!res || res.code !== 0) return null;
|
|
94
|
+
return res.stdout.trim() || null;
|
|
95
|
+
}
|
|
96
|
+
function globalInstallArgs(managerOrCommand, spec, pkgRoot) {
|
|
97
|
+
const resolved = normalizeGlobalInstallCommand(managerOrCommand, pkgRoot);
|
|
98
|
+
if (resolved.manager === "pnpm") return [
|
|
99
|
+
resolved.command,
|
|
100
|
+
"add",
|
|
101
|
+
"-g",
|
|
102
|
+
spec
|
|
103
|
+
];
|
|
104
|
+
return [
|
|
105
|
+
resolved.command,
|
|
106
|
+
"install",
|
|
107
|
+
"-g",
|
|
108
|
+
spec,
|
|
109
|
+
...NPM_GLOBAL_INSTALL_QUIET_FLAGS
|
|
110
|
+
];
|
|
111
|
+
}
|
|
112
|
+
function globalInstallFallbackArgs(managerOrCommand, spec, pkgRoot) {
|
|
113
|
+
const resolved = normalizeGlobalInstallCommand(managerOrCommand, pkgRoot);
|
|
114
|
+
if (resolved.manager !== "npm") return null;
|
|
115
|
+
return [
|
|
116
|
+
resolved.command,
|
|
117
|
+
"install",
|
|
118
|
+
"-g",
|
|
119
|
+
spec,
|
|
120
|
+
...NPM_GLOBAL_INSTALL_OMIT_OPTIONAL_FLAGS
|
|
121
|
+
];
|
|
122
|
+
}
|
|
123
|
+
async function detectGlobalInstallManagerForRoot(runCommand, pkgRoot, timeoutMs) {
|
|
124
|
+
const pkgReal = await tryRealpath(pkgRoot);
|
|
125
|
+
for (const { manager, argv } of [{
|
|
126
|
+
manager: "npm",
|
|
127
|
+
argv: [
|
|
128
|
+
"npm",
|
|
129
|
+
"root",
|
|
130
|
+
"-g"
|
|
131
|
+
]
|
|
132
|
+
}, {
|
|
133
|
+
manager: "pnpm",
|
|
134
|
+
argv: [
|
|
135
|
+
"pnpm",
|
|
136
|
+
"root",
|
|
137
|
+
"-g"
|
|
138
|
+
]
|
|
139
|
+
}]) {
|
|
140
|
+
const res = await runCommand(argv, { timeoutMs }).catch(() => null);
|
|
141
|
+
if (!res || res.code !== 0) continue;
|
|
142
|
+
const globalRoot = res.stdout.trim();
|
|
143
|
+
if (!globalRoot) continue;
|
|
144
|
+
const expectedReal = await tryRealpath(joinGlobalPackagePath(await tryRealpath(globalRoot)));
|
|
145
|
+
if (path.resolve(expectedReal) === path.resolve(pkgReal)) return manager;
|
|
146
|
+
}
|
|
147
|
+
if (resolvePreferredNpmCommand(pkgRoot)) return "npm";
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
async function detectGlobalInstallManagerByPresence(runCommand, timeoutMs) {
|
|
151
|
+
for (const manager of ["npm", "pnpm"]) {
|
|
152
|
+
const root = await resolveGlobalRoot(manager, runCommand, timeoutMs);
|
|
153
|
+
if (!root) continue;
|
|
154
|
+
if (await pathExists(joinGlobalPackagePath(root))) return manager;
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
async function resolveGlobalManager(params) {
|
|
159
|
+
const runCommand = createDefaultCommandRunner();
|
|
160
|
+
const timeoutMs = params.timeoutMs ?? GLOBAL_DETECT_TIMEOUT_MS;
|
|
161
|
+
if (params.root) {
|
|
162
|
+
const detected = await detectGlobalInstallManagerForRoot(runCommand, params.root, timeoutMs);
|
|
163
|
+
if (detected) return detected;
|
|
164
|
+
}
|
|
165
|
+
return await detectGlobalInstallManagerByPresence(runCommand, timeoutMs) ?? "npm";
|
|
166
|
+
}
|
|
167
|
+
function tailOutput(text, max = 4e3) {
|
|
168
|
+
const t = text.trim();
|
|
169
|
+
if (t.length <= max) return t;
|
|
170
|
+
return t.slice(-max);
|
|
171
|
+
}
|
|
172
|
+
async function runGlobalPackageInstall(params) {
|
|
173
|
+
const timeoutMs = params.timeoutMs ?? GLOBAL_INSTALL_TIMEOUT_MS;
|
|
174
|
+
const runCommand = createDefaultCommandRunner();
|
|
175
|
+
const installEnv = await createGlobalInstallEnv();
|
|
176
|
+
const runStep = async (argv) => {
|
|
177
|
+
const result = await runCommand(argv, {
|
|
178
|
+
timeoutMs,
|
|
179
|
+
env: installEnv
|
|
180
|
+
});
|
|
181
|
+
if (params.echoToTerminal) {
|
|
182
|
+
if (result.stdout) process.stdout.write(result.stdout);
|
|
183
|
+
if (result.stderr) process.stderr.write(result.stderr);
|
|
184
|
+
}
|
|
185
|
+
return result;
|
|
186
|
+
};
|
|
187
|
+
const primary = await runStep(globalInstallArgs(params.manager, params.spec, params.pkgRoot));
|
|
188
|
+
if (primary.code === 0) return {
|
|
189
|
+
exitCode: 0,
|
|
190
|
+
stdout: primary.stdout,
|
|
191
|
+
stderr: primary.stderr,
|
|
192
|
+
packageManager: params.manager,
|
|
193
|
+
usedFallback: false
|
|
194
|
+
};
|
|
195
|
+
const fallbackArgv = globalInstallFallbackArgs(params.manager, params.spec, params.pkgRoot);
|
|
196
|
+
if (!fallbackArgv) return {
|
|
197
|
+
exitCode: primary.code ?? 1,
|
|
198
|
+
stdout: primary.stdout,
|
|
199
|
+
stderr: primary.stderr,
|
|
200
|
+
packageManager: params.manager,
|
|
201
|
+
usedFallback: false
|
|
202
|
+
};
|
|
203
|
+
const fallback = await runStep(fallbackArgv);
|
|
204
|
+
return {
|
|
205
|
+
exitCode: fallback.code ?? 1,
|
|
206
|
+
stdout: [primary.stdout, fallback.stdout].filter(Boolean).join("\n"),
|
|
207
|
+
stderr: [primary.stderr, fallback.stderr].filter(Boolean).join("\n"),
|
|
208
|
+
packageManager: params.manager,
|
|
209
|
+
usedFallback: true
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function formatGlobalInstallFailure(params) {
|
|
213
|
+
const tail = tailOutput(params.stderr);
|
|
214
|
+
return [
|
|
215
|
+
`Global install via ${params.packageManager} failed (exit ${params.exitCode}).`,
|
|
216
|
+
params.usedFallback ? "Retried with --omit=optional." : null,
|
|
217
|
+
`Try manually: ${params.packageManager} install -g ${params.spec}`,
|
|
218
|
+
tail ? `Install output:\n${tail}` : null
|
|
219
|
+
].filter(Boolean).join("\n");
|
|
220
|
+
}
|
|
221
|
+
//#endregion
|
|
222
|
+
export { XOPC_PACKAGE_NAME, createGlobalInstallEnv, detectGlobalInstallManagerByPresence, detectGlobalInstallManagerForRoot, formatGlobalInstallFailure, globalInstallArgs, globalInstallFallbackArgs, joinGlobalPackagePath, resolveGlobalInstallCommand, resolveGlobalInstallSpec, resolveGlobalManager, resolveGlobalRoot, runGlobalPackageInstall };
|
|
223
|
+
|
|
224
|
+
//# sourceMappingURL=update-global.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-global.js","names":["fs","fsSync"],"sources":["../../../src/infra/update-global.ts"],"sourcesContent":["// src/infra/update-global.ts — global npm/pnpm install detection and commands (OpenClaw-aligned)\n\nimport fsSync from 'node:fs';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport {\n createDefaultCommandRunner,\n type CommandRunner,\n type CommandRunResult,\n} from './run-command.js';\n\nexport const XOPC_PACKAGE_NAME = '@xopcai/xopc';\n\nexport type GlobalInstallManager = 'npm' | 'pnpm';\n\nexport type ResolvedGlobalInstallCommand = {\n manager: GlobalInstallManager;\n command: string;\n};\n\nconst COREPACK_ENABLE_DOWNLOAD_PROMPT_DEFAULT = '0';\nconst NPM_GLOBAL_INSTALL_QUIET_FLAGS = ['--no-fund', '--no-audit', '--loglevel=error'] as const;\nconst NPM_GLOBAL_INSTALL_OMIT_OPTIONAL_FLAGS = [\n '--omit=optional',\n ...NPM_GLOBAL_INSTALL_QUIET_FLAGS,\n] as const;\n\nconst GLOBAL_DETECT_TIMEOUT_MS = 15_000;\nconst GLOBAL_INSTALL_TIMEOUT_MS = 45 * 60 * 1000;\n\nexport type GlobalInstallRunResult = {\n exitCode: number;\n stdout: string;\n stderr: string;\n packageManager: GlobalInstallManager;\n usedFallback: boolean;\n};\n\nasync function pathExists(targetPath: string): Promise<boolean> {\n try {\n await fs.access(targetPath);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function tryRealpath(targetPath: string): Promise<string> {\n try {\n return await fs.realpath(targetPath);\n } catch {\n return path.resolve(targetPath);\n }\n}\n\nexport function joinGlobalPackagePath(globalRoot: string): string {\n return path.join(globalRoot, XOPC_PACKAGE_NAME);\n}\n\nfunction inferNpmPrefixFromPackageRoot(pkgRoot?: string | null): string | null {\n const trimmed = pkgRoot?.trim();\n if (!trimmed) return null;\n const normalized = path.resolve(trimmed);\n const nodeModulesDir = path.dirname(normalized);\n if (path.basename(nodeModulesDir) !== 'node_modules') return null;\n const parentDir = path.dirname(nodeModulesDir);\n if (path.basename(parentDir) === 'lib') {\n return path.dirname(parentDir);\n }\n if (process.platform === 'win32' && path.basename(parentDir).toLowerCase() === 'npm') {\n return parentDir;\n }\n return null;\n}\n\nfunction resolvePreferredNpmCommand(pkgRoot?: string | null): string | null {\n const prefix = inferNpmPrefixFromPackageRoot(pkgRoot);\n if (!prefix) return null;\n const candidate =\n process.platform === 'win32' ? path.join(prefix, 'npm.cmd') : path.join(prefix, 'bin', 'npm');\n return fsSync.existsSync(candidate) ? candidate : null;\n}\n\nfunction resolvePreferredGlobalManagerCommand(\n manager: GlobalInstallManager,\n pkgRoot?: string | null,\n): string {\n if (manager !== 'npm') return manager;\n return resolvePreferredNpmCommand(pkgRoot) ?? manager;\n}\n\nexport function resolveGlobalInstallCommand(\n manager: GlobalInstallManager,\n pkgRoot?: string | null,\n): ResolvedGlobalInstallCommand {\n return {\n manager,\n command: resolvePreferredGlobalManagerCommand(manager, pkgRoot),\n };\n}\n\nfunction normalizeGlobalInstallCommand(\n managerOrCommand: GlobalInstallManager | ResolvedGlobalInstallCommand,\n pkgRoot?: string | null,\n): ResolvedGlobalInstallCommand {\n return typeof managerOrCommand === 'string'\n ? resolveGlobalInstallCommand(managerOrCommand, pkgRoot)\n : managerOrCommand;\n}\n\nfunction applyWindowsPackageInstallEnv(env: Record<string, string>): void {\n if (process.platform !== 'win32') return;\n env.NPM_CONFIG_UPDATE_NOTIFIER = 'false';\n env.NPM_CONFIG_FUND = 'false';\n env.NPM_CONFIG_AUDIT = 'false';\n}\n\nfunction applyCorepackDownloadPromptEnv(env: Record<string, string>): void {\n if (!env.COREPACK_ENABLE_DOWNLOAD_PROMPT?.trim()) {\n env.COREPACK_ENABLE_DOWNLOAD_PROMPT = COREPACK_ENABLE_DOWNLOAD_PROMPT_DEFAULT;\n }\n}\n\nexport async function createGlobalInstallEnv(\n env?: NodeJS.ProcessEnv,\n): Promise<NodeJS.ProcessEnv | undefined> {\n const sourceEnv = env ?? process.env;\n const hasCorepack = Boolean(sourceEnv.COREPACK_ENABLE_DOWNLOAD_PROMPT?.trim());\n if (process.platform !== 'win32' && hasCorepack) {\n return env;\n }\n const merged = Object.fromEntries(\n Object.entries(sourceEnv)\n .filter(([, value]) => value != null)\n .map(([key, value]) => [key, String(value)]),\n ) as Record<string, string>;\n applyWindowsPackageInstallEnv(merged);\n applyCorepackDownloadPromptEnv(merged);\n return merged;\n}\n\nexport function resolveGlobalInstallSpec(params: {\n version: string;\n env?: NodeJS.ProcessEnv;\n}): string {\n const override =\n params.env?.XOPC_UPDATE_PACKAGE_SPEC?.trim() || process.env.XOPC_UPDATE_PACKAGE_SPEC?.trim();\n if (override) return override;\n return `${XOPC_PACKAGE_NAME}@${params.version}`;\n}\n\nexport async function resolveGlobalRoot(\n managerOrCommand: GlobalInstallManager | ResolvedGlobalInstallCommand,\n runCommand: CommandRunner,\n timeoutMs: number,\n pkgRoot?: string | null,\n): Promise<string | null> {\n const resolved = normalizeGlobalInstallCommand(managerOrCommand, pkgRoot);\n const argv = [resolved.command, 'root', '-g'];\n const res = await runCommand(argv, { timeoutMs }).catch(() => null);\n if (!res || res.code !== 0) return null;\n const root = res.stdout.trim();\n return root || null;\n}\n\nexport function globalInstallArgs(\n managerOrCommand: GlobalInstallManager | ResolvedGlobalInstallCommand,\n spec: string,\n pkgRoot?: string | null,\n): string[] {\n const resolved = normalizeGlobalInstallCommand(managerOrCommand, pkgRoot);\n if (resolved.manager === 'pnpm') {\n return [resolved.command, 'add', '-g', spec];\n }\n return [resolved.command, 'install', '-g', spec, ...NPM_GLOBAL_INSTALL_QUIET_FLAGS];\n}\n\nexport function globalInstallFallbackArgs(\n managerOrCommand: GlobalInstallManager | ResolvedGlobalInstallCommand,\n spec: string,\n pkgRoot?: string | null,\n): string[] | null {\n const resolved = normalizeGlobalInstallCommand(managerOrCommand, pkgRoot);\n if (resolved.manager !== 'npm') return null;\n return [resolved.command, 'install', '-g', spec, ...NPM_GLOBAL_INSTALL_OMIT_OPTIONAL_FLAGS];\n}\n\nexport async function detectGlobalInstallManagerForRoot(\n runCommand: CommandRunner,\n pkgRoot: string,\n timeoutMs: number,\n): Promise<GlobalInstallManager | null> {\n const pkgReal = await tryRealpath(pkgRoot);\n\n const candidates: Array<{ manager: GlobalInstallManager; argv: string[] }> = [\n { manager: 'npm', argv: ['npm', 'root', '-g'] },\n { manager: 'pnpm', argv: ['pnpm', 'root', '-g'] },\n ];\n\n for (const { manager, argv } of candidates) {\n const res = await runCommand(argv, { timeoutMs }).catch(() => null);\n if (!res || res.code !== 0) continue;\n const globalRoot = res.stdout.trim();\n if (!globalRoot) continue;\n const globalReal = await tryRealpath(globalRoot);\n const expected = joinGlobalPackagePath(globalReal);\n const expectedReal = await tryRealpath(expected);\n if (path.resolve(expectedReal) === path.resolve(pkgReal)) {\n return manager;\n }\n }\n\n if (resolvePreferredNpmCommand(pkgRoot)) {\n return 'npm';\n }\n\n return null;\n}\n\nexport async function detectGlobalInstallManagerByPresence(\n runCommand: CommandRunner,\n timeoutMs: number,\n): Promise<GlobalInstallManager | null> {\n for (const manager of ['npm', 'pnpm'] as const) {\n const root = await resolveGlobalRoot(manager, runCommand, timeoutMs);\n if (!root) continue;\n if (await pathExists(joinGlobalPackagePath(root))) {\n return manager;\n }\n }\n return null;\n}\n\nexport async function resolveGlobalManager(params: {\n root: string | null;\n timeoutMs?: number;\n}): Promise<GlobalInstallManager> {\n const runCommand = createDefaultCommandRunner();\n const timeoutMs = params.timeoutMs ?? GLOBAL_DETECT_TIMEOUT_MS;\n\n if (params.root) {\n const detected = await detectGlobalInstallManagerForRoot(runCommand, params.root, timeoutMs);\n if (detected) return detected;\n }\n\n const byPresence = await detectGlobalInstallManagerByPresence(runCommand, timeoutMs);\n return byPresence ?? 'npm';\n}\n\nfunction tailOutput(text: string, max = 4000): string {\n const t = text.trim();\n if (t.length <= max) return t;\n return t.slice(-max);\n}\n\nexport async function runGlobalPackageInstall(params: {\n manager: GlobalInstallManager;\n spec: string;\n pkgRoot: string | null;\n timeoutMs?: number;\n /** Echo install output to the parent process (CLI interactive). */\n echoToTerminal?: boolean;\n}): Promise<GlobalInstallRunResult> {\n const timeoutMs = params.timeoutMs ?? GLOBAL_INSTALL_TIMEOUT_MS;\n const runCommand = createDefaultCommandRunner();\n const installEnv = await createGlobalInstallEnv();\n\n const runStep = async (argv: string[]): Promise<CommandRunResult> => {\n const result = await runCommand(argv, { timeoutMs, env: installEnv });\n if (params.echoToTerminal) {\n if (result.stdout) process.stdout.write(result.stdout);\n if (result.stderr) process.stderr.write(result.stderr);\n }\n return result;\n };\n\n const primaryArgv = globalInstallArgs(params.manager, params.spec, params.pkgRoot);\n const primary = await runStep(primaryArgv);\n if (primary.code === 0) {\n return {\n exitCode: 0,\n stdout: primary.stdout,\n stderr: primary.stderr,\n packageManager: params.manager,\n usedFallback: false,\n };\n }\n\n const fallbackArgv = globalInstallFallbackArgs(params.manager, params.spec, params.pkgRoot);\n if (!fallbackArgv) {\n return {\n exitCode: primary.code ?? 1,\n stdout: primary.stdout,\n stderr: primary.stderr,\n packageManager: params.manager,\n usedFallback: false,\n };\n }\n\n const fallback = await runStep(fallbackArgv);\n return {\n exitCode: fallback.code ?? 1,\n stdout: [primary.stdout, fallback.stdout].filter(Boolean).join('\\n'),\n stderr: [primary.stderr, fallback.stderr].filter(Boolean).join('\\n'),\n packageManager: params.manager,\n usedFallback: true,\n };\n}\n\nexport function formatGlobalInstallFailure(params: {\n packageManager: GlobalInstallManager;\n spec: string;\n exitCode: number;\n stderr: string;\n usedFallback: boolean;\n}): string {\n const tail = tailOutput(params.stderr);\n const parts = [\n `Global install via ${params.packageManager} failed (exit ${params.exitCode}).`,\n params.usedFallback ? 'Retried with --omit=optional.' : null,\n `Try manually: ${params.packageManager} install -g ${params.spec}`,\n tail ? `Install output:\\n${tail}` : null,\n ].filter(Boolean);\n return parts.join('\\n');\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { init_loader, loadConfig } from "../config/loader.js";
|
|
2
|
-
import { loadUndiciRuntimeDeps } from "../infra/undici-fetch.js";
|
|
3
2
|
import { toConversation } from "./channel-shared.js";
|
|
4
3
|
import { createGatewayHttpClientFromConfig, resolveGatewayHttpBaseUrl } from "./gateway-http-client.js";
|
|
4
|
+
import { loadUndiciRuntimeDeps } from "../infra/undici-fetch.js";
|
|
5
5
|
//#region src/mcp/channel-bridge.ts
|
|
6
6
|
init_loader();
|
|
7
7
|
const QUEUE_LIMIT = 1e3;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { normalizeOptionalString } from "../utils/string-coerce.js";
|
|
1
|
+
import { init_string_coerce, normalizeOptionalString } from "../utils/string-coerce.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
//#region src/mcp/channel-shared.ts
|
|
4
|
+
init_string_coerce();
|
|
4
5
|
function normalizeMessageChannel(value) {
|
|
5
6
|
return value?.trim() || void 0;
|
|
6
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel-shared.js","names":["toText"],"sources":["../../../src/mcp/channel-shared.ts"],"sourcesContent":["import { z } from 'zod';\nimport { normalizeOptionalString as toText } from '../utils/string-coerce.js';\n\nfunction normalizeMessageChannel(value: string | undefined): string | undefined {\n return value?.trim() || undefined;\n}\n\nexport type ClaudeChannelMode = \"off\" | \"on\" | \"auto\";\n\nexport type ConversationDescriptor = {\n sessionKey: string;\n channel: string;\n to: string;\n accountId?: string;\n threadId?: string | number;\n label?: string;\n displayName?: string;\n derivedTitle?: string;\n lastMessagePreview?: string;\n updatedAt?: number | null;\n};\n\nexport type SessionRow = {\n key: string;\n channel?: string;\n lastChannel?: string;\n lastTo?: string;\n lastAccountId?: string;\n lastThreadId?: string | number;\n deliveryContext?: {\n channel?: string;\n to?: string;\n accountId?: string;\n threadId?: string | number;\n };\n origin?: {\n provider?: string;\n accountId?: string;\n threadId?: string | number;\n };\n label?: string;\n displayName?: string;\n derivedTitle?: string;\n lastMessagePreview?: string;\n updatedAt?: number | null;\n};\n\nexport type SessionListResult = {\n sessions?: SessionRow[];\n};\n\nexport type ChatHistoryResult = {\n messages?: Array<{ id?: string; role?: string; content?: unknown; [key: string]: unknown }>;\n};\n\nexport type SessionMessagePayload = {\n sessionKey?: string;\n messageId?: string;\n messageSeq?: number;\n message?: { role?: string; content?: unknown; [key: string]: unknown };\n lastChannel?: string;\n lastTo?: string;\n lastAccountId?: string;\n lastThreadId?: string | number;\n [key: string]: unknown;\n};\n\nexport type ApprovalKind = \"exec\" | \"plugin\";\nexport type ApprovalDecision = \"allow-once\" | \"allow-always\" | \"deny\";\n\nexport type PendingApproval = {\n kind: ApprovalKind;\n id: string;\n request?: Record<string, unknown>;\n createdAtMs?: number;\n expiresAtMs?: number;\n};\n\nexport type QueueEvent =\n | {\n cursor: number;\n type: \"message\";\n sessionKey: string;\n conversation?: ConversationDescriptor;\n messageId?: string;\n messageSeq?: number;\n role?: string;\n text?: string;\n raw: SessionMessagePayload;\n }\n | {\n cursor: number;\n type: \"claude_permission_request\";\n requestId: string;\n toolName: string;\n description: string;\n inputPreview: string;\n }\n | {\n cursor: number;\n type: \"exec_approval_requested\" | \"exec_approval_resolved\";\n raw: Record<string, unknown>;\n }\n | {\n cursor: number;\n type: \"plugin_approval_requested\" | \"plugin_approval_resolved\";\n raw: Record<string, unknown>;\n };\n\nexport type ClaudePermissionRequest = {\n toolName: string;\n description: string;\n inputPreview: string;\n};\n\nexport type WaitFilter = {\n afterCursor: number;\n sessionKey?: string;\n};\n\nexport const ClaudePermissionRequestSchema = z.object({\n method: z.literal(\"notifications/claude/channel/permission_request\"),\n params: z.object({\n request_id: z.string(),\n tool_name: z.string(),\n description: z.string(),\n input_preview: z.string(),\n }),\n});\n\nexport { toText };\n\nexport function resolveMessageId(entry: Record<string, unknown>): string | undefined {\n return (\n toText(entry.id) ??\n (entry.__openclaw && typeof entry.__openclaw === \"object\"\n ? toText((entry.__openclaw as { id?: unknown }).id)\n : undefined)\n );\n}\n\nexport function summarizeResult(\n label: string,\n count: number,\n): { content: Array<{ type: \"text\"; text: string }> } {\n return {\n content: [{ type: \"text\", text: `${label}: ${count}` }],\n };\n}\n\nexport function resolveConversationChannel(row: SessionRow): string | undefined {\n return normalizeMessageChannel(\n toText(row.deliveryContext?.channel) ??\n toText(row.lastChannel) ??\n toText(row.channel) ??\n toText(row.origin?.provider),\n );\n}\n\nexport function toConversation(row: SessionRow): ConversationDescriptor | null {\n const channel = resolveConversationChannel(row);\n const to = toText(row.deliveryContext?.to) ?? toText(row.lastTo);\n if (!channel || !to) {\n return null;\n }\n return {\n sessionKey: row.key,\n channel,\n to,\n accountId:\n toText(row.deliveryContext?.accountId) ??\n toText(row.lastAccountId) ??\n toText(row.origin?.accountId),\n threadId: row.deliveryContext?.threadId ?? row.lastThreadId ?? row.origin?.threadId,\n label: toText(row.label),\n displayName: toText(row.displayName),\n derivedTitle: toText(row.derivedTitle),\n lastMessagePreview: toText(row.lastMessagePreview),\n updatedAt: typeof row.updatedAt === \"number\" ? row.updatedAt : null,\n };\n}\n\nexport function matchEventFilter(event: QueueEvent, filter: WaitFilter): boolean {\n if (event.cursor <= filter.afterCursor) {\n return false;\n }\n if (!filter.sessionKey) {\n return true;\n }\n return \"sessionKey\" in event && event.sessionKey === filter.sessionKey;\n}\n\nexport function extractAttachmentsFromMessage(message: unknown): unknown[] {\n if (!message || typeof message !== \"object\") {\n return [];\n }\n const content = (message as { content?: unknown }).content;\n if (!Array.isArray(content)) {\n return [];\n }\n return content.filter((entry) => {\n if (!entry || typeof entry !== \"object\") {\n return false;\n }\n return toText((entry as { type?: unknown }).type) !== \"text\";\n });\n}\n\nexport function normalizeApprovalId(value: unknown): string | undefined {\n const id = toText(value);\n return id ? id.trim() : undefined;\n}\n"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"channel-shared.js","names":["toText"],"sources":["../../../src/mcp/channel-shared.ts"],"sourcesContent":["import { z } from 'zod';\nimport { normalizeOptionalString as toText } from '../utils/string-coerce.js';\n\nfunction normalizeMessageChannel(value: string | undefined): string | undefined {\n return value?.trim() || undefined;\n}\n\nexport type ClaudeChannelMode = \"off\" | \"on\" | \"auto\";\n\nexport type ConversationDescriptor = {\n sessionKey: string;\n channel: string;\n to: string;\n accountId?: string;\n threadId?: string | number;\n label?: string;\n displayName?: string;\n derivedTitle?: string;\n lastMessagePreview?: string;\n updatedAt?: number | null;\n};\n\nexport type SessionRow = {\n key: string;\n channel?: string;\n lastChannel?: string;\n lastTo?: string;\n lastAccountId?: string;\n lastThreadId?: string | number;\n deliveryContext?: {\n channel?: string;\n to?: string;\n accountId?: string;\n threadId?: string | number;\n };\n origin?: {\n provider?: string;\n accountId?: string;\n threadId?: string | number;\n };\n label?: string;\n displayName?: string;\n derivedTitle?: string;\n lastMessagePreview?: string;\n updatedAt?: number | null;\n};\n\nexport type SessionListResult = {\n sessions?: SessionRow[];\n};\n\nexport type ChatHistoryResult = {\n messages?: Array<{ id?: string; role?: string; content?: unknown; [key: string]: unknown }>;\n};\n\nexport type SessionMessagePayload = {\n sessionKey?: string;\n messageId?: string;\n messageSeq?: number;\n message?: { role?: string; content?: unknown; [key: string]: unknown };\n lastChannel?: string;\n lastTo?: string;\n lastAccountId?: string;\n lastThreadId?: string | number;\n [key: string]: unknown;\n};\n\nexport type ApprovalKind = \"exec\" | \"plugin\";\nexport type ApprovalDecision = \"allow-once\" | \"allow-always\" | \"deny\";\n\nexport type PendingApproval = {\n kind: ApprovalKind;\n id: string;\n request?: Record<string, unknown>;\n createdAtMs?: number;\n expiresAtMs?: number;\n};\n\nexport type QueueEvent =\n | {\n cursor: number;\n type: \"message\";\n sessionKey: string;\n conversation?: ConversationDescriptor;\n messageId?: string;\n messageSeq?: number;\n role?: string;\n text?: string;\n raw: SessionMessagePayload;\n }\n | {\n cursor: number;\n type: \"claude_permission_request\";\n requestId: string;\n toolName: string;\n description: string;\n inputPreview: string;\n }\n | {\n cursor: number;\n type: \"exec_approval_requested\" | \"exec_approval_resolved\";\n raw: Record<string, unknown>;\n }\n | {\n cursor: number;\n type: \"plugin_approval_requested\" | \"plugin_approval_resolved\";\n raw: Record<string, unknown>;\n };\n\nexport type ClaudePermissionRequest = {\n toolName: string;\n description: string;\n inputPreview: string;\n};\n\nexport type WaitFilter = {\n afterCursor: number;\n sessionKey?: string;\n};\n\nexport const ClaudePermissionRequestSchema = z.object({\n method: z.literal(\"notifications/claude/channel/permission_request\"),\n params: z.object({\n request_id: z.string(),\n tool_name: z.string(),\n description: z.string(),\n input_preview: z.string(),\n }),\n});\n\nexport { toText };\n\nexport function resolveMessageId(entry: Record<string, unknown>): string | undefined {\n return (\n toText(entry.id) ??\n (entry.__openclaw && typeof entry.__openclaw === \"object\"\n ? toText((entry.__openclaw as { id?: unknown }).id)\n : undefined)\n );\n}\n\nexport function summarizeResult(\n label: string,\n count: number,\n): { content: Array<{ type: \"text\"; text: string }> } {\n return {\n content: [{ type: \"text\", text: `${label}: ${count}` }],\n };\n}\n\nexport function resolveConversationChannel(row: SessionRow): string | undefined {\n return normalizeMessageChannel(\n toText(row.deliveryContext?.channel) ??\n toText(row.lastChannel) ??\n toText(row.channel) ??\n toText(row.origin?.provider),\n );\n}\n\nexport function toConversation(row: SessionRow): ConversationDescriptor | null {\n const channel = resolveConversationChannel(row);\n const to = toText(row.deliveryContext?.to) ?? toText(row.lastTo);\n if (!channel || !to) {\n return null;\n }\n return {\n sessionKey: row.key,\n channel,\n to,\n accountId:\n toText(row.deliveryContext?.accountId) ??\n toText(row.lastAccountId) ??\n toText(row.origin?.accountId),\n threadId: row.deliveryContext?.threadId ?? row.lastThreadId ?? row.origin?.threadId,\n label: toText(row.label),\n displayName: toText(row.displayName),\n derivedTitle: toText(row.derivedTitle),\n lastMessagePreview: toText(row.lastMessagePreview),\n updatedAt: typeof row.updatedAt === \"number\" ? row.updatedAt : null,\n };\n}\n\nexport function matchEventFilter(event: QueueEvent, filter: WaitFilter): boolean {\n if (event.cursor <= filter.afterCursor) {\n return false;\n }\n if (!filter.sessionKey) {\n return true;\n }\n return \"sessionKey\" in event && event.sessionKey === filter.sessionKey;\n}\n\nexport function extractAttachmentsFromMessage(message: unknown): unknown[] {\n if (!message || typeof message !== \"object\") {\n return [];\n }\n const content = (message as { content?: unknown }).content;\n if (!Array.isArray(content)) {\n return [];\n }\n return content.filter((entry) => {\n if (!entry || typeof entry !== \"object\") {\n return false;\n }\n return toText((entry as { type?: unknown }).type) !== \"text\";\n });\n}\n\nexport function normalizeApprovalId(value: unknown): string | undefined {\n const id = toText(value);\n return id ? id.trim() : undefined;\n}\n"],"mappings":";;;oBAC8E;AAE9E,SAAS,wBAAwB,OAA+C;AAC9E,QAAO,OAAO,MAAM,IAAI,KAAA;;AAoH1B,MAAa,gCAAgC,EAAE,OAAO;CACpD,QAAQ,EAAE,QAAQ,kDAAkD;CACpE,QAAQ,EAAE,OAAO;EACf,YAAY,EAAE,QAAQ;EACtB,WAAW,EAAE,QAAQ;EACrB,aAAa,EAAE,QAAQ;EACvB,eAAe,EAAE,QAAQ;EAC1B,CAAC;CACH,CAAC;AAIF,SAAgB,iBAAiB,OAAoD;AACnF,QACEA,wBAAO,MAAM,GAAG,KACf,MAAM,cAAc,OAAO,MAAM,eAAe,WAC7CA,wBAAQ,MAAM,WAAgC,GAAG,GACjD,KAAA;;AAIR,SAAgB,gBACd,OACA,OACoD;AACpD,QAAO,EACL,SAAS,CAAC;EAAE,MAAM;EAAQ,MAAM,GAAG,MAAM,IAAI;EAAS,CAAC,EACxD;;AAGH,SAAgB,2BAA2B,KAAqC;AAC9E,QAAO,wBACLA,wBAAO,IAAI,iBAAiB,QAAQ,IAClCA,wBAAO,IAAI,YAAY,IACvBA,wBAAO,IAAI,QAAQ,IACnBA,wBAAO,IAAI,QAAQ,SAAS,CAC/B;;AAGH,SAAgB,eAAe,KAAgD;CAC7E,MAAM,UAAU,2BAA2B,IAAI;CAC/C,MAAM,KAAKA,wBAAO,IAAI,iBAAiB,GAAG,IAAIA,wBAAO,IAAI,OAAO;AAChE,KAAI,CAAC,WAAW,CAAC,GACf,QAAO;AAET,QAAO;EACL,YAAY,IAAI;EAChB;EACA;EACA,WACEA,wBAAO,IAAI,iBAAiB,UAAU,IACtCA,wBAAO,IAAI,cAAc,IACzBA,wBAAO,IAAI,QAAQ,UAAU;EAC/B,UAAU,IAAI,iBAAiB,YAAY,IAAI,gBAAgB,IAAI,QAAQ;EAC3E,OAAOA,wBAAO,IAAI,MAAM;EACxB,aAAaA,wBAAO,IAAI,YAAY;EACpC,cAAcA,wBAAO,IAAI,aAAa;EACtC,oBAAoBA,wBAAO,IAAI,mBAAmB;EAClD,WAAW,OAAO,IAAI,cAAc,WAAW,IAAI,YAAY;EAChE;;AAGH,SAAgB,iBAAiB,OAAmB,QAA6B;AAC/E,KAAI,MAAM,UAAU,OAAO,YACzB,QAAO;AAET,KAAI,CAAC,OAAO,WACV,QAAO;AAET,QAAO,gBAAgB,SAAS,MAAM,eAAe,OAAO;;AAG9D,SAAgB,8BAA8B,SAA6B;AACzE,KAAI,CAAC,WAAW,OAAO,YAAY,SACjC,QAAO,EAAE;CAEX,MAAM,UAAW,QAAkC;AACnD,KAAI,CAAC,MAAM,QAAQ,QAAQ,CACzB,QAAO,EAAE;AAEX,QAAO,QAAQ,QAAQ,UAAU;AAC/B,MAAI,CAAC,SAAS,OAAO,UAAU,SAC7B,QAAO;AAET,SAAOA,wBAAQ,MAA6B,KAAK,KAAK;GACtD;;AAGJ,SAAgB,oBAAoB,OAAoC;CACtE,MAAM,KAAKA,wBAAO,MAAM;AACxB,QAAO,KAAK,GAAG,MAAM,GAAG,KAAA"}
|
|
@@ -206,7 +206,7 @@ function ensureDiskAuthProfileStore(agentDir) {
|
|
|
206
206
|
* store or the default store.
|
|
207
207
|
*/
|
|
208
208
|
function listProfilesForProvider(store, providerId) {
|
|
209
|
-
return (store ?? getDefaultAuthProfileStore()).list
|
|
209
|
+
return (store ?? getDefaultAuthProfileStore()).list(providerId);
|
|
210
210
|
}
|
|
211
211
|
//#endregion
|
|
212
212
|
export { DiskAuthProfileStore, NoopAuthProfileStore, ensureDiskAuthProfileStore, getDefaultAuthProfileStore, listProfilesForProvider, setDefaultAuthProfileStore };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-profile-store.js","names":[],"sources":["../../../../src/providers/auth-runtime/auth-profile-store.ts"],"sourcesContent":["/**\n * {@link AuthProfileStore} implementations.\n *\n * - {@link NoopAuthProfileStore}: returns nothing; used by tests and as a safe\n * fallback when no agent context is available.\n * - {@link DiskAuthProfileStore}: persists per-agent profiles under\n * `<stateDir>/agents/<agentId>/auth-profiles.json` with a lazy in-memory\n * cache and atomic writes. Used by the gateway and CLI to host OAuth\n * tokens (Codex / Anthropic) without leaking them through env vars.\n *\n * Capability providers stay synchronous: `getApiKeySync` / `hasCredentialSync`\n * read the cached snapshot. Async members (`save`, `refresh`) are only used\n * by vendor-specific code that explicitly opts in to OAuth flows.\n */\n\nimport { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\nimport { createLogger } from '../../utils/logger.js';\nimport type { AuthProfile, AuthProfileStore } from './types.js';\n\nconst log = createLogger('AuthProfileStore');\n\nconst STORE_FILENAME = 'auth-profiles.json';\n\nexport class NoopAuthProfileStore implements AuthProfileStore {\n getApiKeySync(): string | undefined {\n return undefined;\n }\n hasCredentialSync(): boolean {\n return false;\n }\n list(): AuthProfile[] {\n return [];\n }\n get(): AuthProfile | undefined {\n return undefined;\n }\n async save(): Promise<void> {\n /* no-op */\n }\n async refresh(profile: AuthProfile): Promise<AuthProfile> {\n return profile;\n }\n}\n\ntype DiskFile = {\n /** Schema version; bumped if we ever change the on-disk shape. */\n version: 1;\n profiles: AuthProfile[];\n};\n\nfunction emptyFile(): DiskFile {\n return { version: 1, profiles: [] };\n}\n\nfunction isDiskFile(v: unknown): v is DiskFile {\n if (!v || typeof v !== 'object') return false;\n const o = v as Record<string, unknown>;\n return o.version === 1 && Array.isArray(o.profiles);\n}\n\n/**\n * Persistent per-agent credential store.\n *\n * File layout (`<stateDir>/agents/<agentId>/auth-profiles.json`):\n *\n * ```json\n * {\n * \"version\": 1,\n * \"profiles\": [\n * { \"provider\": \"openai\", \"profileId\": \"default\", \"mode\": \"api-key\", \"apiKey\": \"sk-...\" },\n * { \"provider\": \"openai\", \"profileId\": \"codex\", \"mode\": \"oauth\",\n * \"oauthAccessToken\": \"...\", \"oauthRefreshToken\": \"...\", \"expiresAt\": 1714000000000 }\n * ]\n * }\n * ```\n *\n * - Constructor is non-blocking; the first read triggers a sync load.\n * - Writes go through a temp file + `renameSync` so partial writes never\n * leave the JSON corrupted.\n */\nexport class DiskAuthProfileStore implements AuthProfileStore {\n private readonly path: string;\n private cache: DiskFile | undefined;\n private writeChain: Promise<void> = Promise.resolve();\n\n constructor(filePath: string) {\n this.path = filePath;\n }\n\n /** Absolute path to the backing JSON file. */\n get filePath(): string {\n return this.path;\n }\n\n // --- Sync read API ------------------------------------------------------\n\n getApiKeySync(providerId: string, profile?: string): string | undefined {\n const p = this.findProfile(providerId, profile);\n if (!p) return undefined;\n if (typeof p.apiKey === 'string' && p.apiKey.length > 0) return p.apiKey;\n if (typeof p.oauthAccessToken === 'string' && p.oauthAccessToken.length > 0) {\n return p.oauthAccessToken;\n }\n return undefined;\n }\n\n hasCredentialSync(providerId: string, profile?: string): boolean {\n return Boolean(this.getApiKeySync(providerId, profile));\n }\n\n list(providerId: string): AuthProfile[] {\n const file = this.ensureLoaded();\n return file.profiles\n .filter((p) => p.provider === providerId)\n .map((p) => ({ ...p }));\n }\n\n get(providerId: string, profileId?: string): AuthProfile | undefined {\n const p = this.findProfile(providerId, profileId);\n return p ? { ...p } : undefined;\n }\n\n // --- Async write API ----------------------------------------------------\n\n /**\n * Persist a profile. Uses a serial write chain so concurrent saves cannot\n * race each other on the JSON document.\n */\n save(profile: AuthProfile): Promise<void> {\n const next = this.writeChain.then(() => {\n const file = this.ensureLoaded();\n const idx = file.profiles.findIndex(\n (p) => p.provider === profile.provider && p.profileId === profile.profileId,\n );\n if (idx >= 0) {\n file.profiles[idx] = { ...profile };\n } else {\n file.profiles.push({ ...profile });\n }\n // Only one default per provider.\n if (profile.default) {\n for (const p of file.profiles) {\n if (\n p.provider === profile.provider &&\n p.profileId !== profile.profileId &&\n p.default\n ) {\n p.default = false;\n }\n }\n }\n this.persist(file);\n });\n // Swallow rejections in the chain so a single bad write doesn't poison\n // every subsequent save attempt.\n this.writeChain = next.catch(() => undefined);\n return next;\n }\n\n /**\n * Default `refresh()` is a no-op. Vendor-specific OAuth refresh logic\n * (Codex / Anthropic) lives in `src/providers/auth-runtime/oauth.ts` and\n * calls `save()` here once it has a fresh token.\n */\n async refresh(profile: AuthProfile): Promise<AuthProfile> {\n return profile;\n }\n\n // --- Internals ----------------------------------------------------------\n\n private ensureLoaded(): DiskFile {\n if (this.cache) return this.cache;\n if (!existsSync(this.path)) {\n this.cache = emptyFile();\n return this.cache;\n }\n try {\n const raw = readFileSync(this.path, 'utf8');\n const parsed = JSON.parse(raw);\n if (isDiskFile(parsed)) {\n this.cache = { version: 1, profiles: parsed.profiles.filter(isAuthProfileLike) };\n } else {\n log.warn(\n { path: this.path, phase: 'load' },\n 'auth-profiles.json has unexpected shape; resetting to empty (file is preserved on disk)',\n );\n this.cache = emptyFile();\n }\n } catch (err) {\n log.warn(\n { err, path: this.path, phase: 'load' },\n `Failed to read auth-profiles.json: ${err instanceof Error ? err.message : String(err)}`,\n );\n this.cache = emptyFile();\n }\n return this.cache;\n }\n\n private findProfile(providerId: string, profileId?: string): AuthProfile | undefined {\n const file = this.ensureLoaded();\n const matches = file.profiles.filter((p) => p.provider === providerId);\n if (matches.length === 0) return undefined;\n const wanted = profileId?.trim();\n if (wanted) {\n return matches.find((p) => p.profileId === wanted);\n }\n return matches.find((p) => p.default) ?? matches.find((p) => p.profileId === 'default') ?? matches[0];\n }\n\n private persist(file: DiskFile): void {\n mkdirSync(dirname(this.path), { recursive: true });\n const tmp = `${this.path}.tmp-${process.pid}-${Date.now()}`;\n writeFileSync(tmp, JSON.stringify(file, null, 2), { encoding: 'utf8', mode: 0o600 });\n renameSync(tmp, this.path);\n this.cache = file;\n }\n}\n\nfunction isAuthProfileLike(v: unknown): v is AuthProfile {\n if (!v || typeof v !== 'object') return false;\n const o = v as Record<string, unknown>;\n return typeof o.provider === 'string' && typeof o.profileId === 'string' && typeof o.mode === 'string';\n}\n\n// --- Default store registry ------------------------------------------------\n\nlet defaultStore: AuthProfileStore = new NoopAuthProfileStore();\nconst diskStores = new Map<string, DiskAuthProfileStore>();\n\nexport function getDefaultAuthProfileStore(): AuthProfileStore {\n return defaultStore;\n}\n\n/**\n * Override the default store. Returns a function that restores the previous\n * store; tests typically call it in `afterEach`.\n */\nexport function setDefaultAuthProfileStore(store: AuthProfileStore): () => void {\n const prev = defaultStore;\n defaultStore = store;\n return () => {\n defaultStore = prev;\n };\n}\n\n/**\n * Get (or create) a {@link DiskAuthProfileStore} for the given agent\n * directory. Same `agentDir` always returns the same store instance so the\n * in-memory cache stays consistent within one process.\n */\nexport function ensureDiskAuthProfileStore(agentDir: string): DiskAuthProfileStore {\n const key = agentDir;\n let store = diskStores.get(key);\n if (!store) {\n store = new DiskAuthProfileStore(join(agentDir, STORE_FILENAME));\n diskStores.set(key, store);\n }\n return store;\n}\n\n/**\n * Convenience: list every profile for a provider via either an explicit\n * store or the default store.\n */\nexport function listProfilesForProvider(\n store: AuthProfileStore | undefined,\n providerId: string,\n): AuthProfile[] {\n const s = store ?? getDefaultAuthProfileStore();\n return s.list?.(providerId) ?? [];\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"auth-profile-store.js","names":[],"sources":["../../../../src/providers/auth-runtime/auth-profile-store.ts"],"sourcesContent":["/**\n * {@link AuthProfileStore} implementations.\n *\n * - {@link NoopAuthProfileStore}: returns nothing; used by tests and as a safe\n * fallback when no agent context is available.\n * - {@link DiskAuthProfileStore}: persists per-agent profiles under\n * `<stateDir>/agents/<agentId>/auth-profiles.json` with a lazy in-memory\n * cache and atomic writes. Used by the gateway and CLI to host OAuth\n * tokens (Codex / Anthropic) without leaking them through env vars.\n *\n * Capability providers stay synchronous: `getApiKeySync` / `hasCredentialSync`\n * read the cached snapshot. Async members (`save`, `refresh`) are only used\n * by vendor-specific code that explicitly opts in to OAuth flows.\n */\n\nimport { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\nimport { createLogger } from '../../utils/logger.js';\nimport type { AuthProfile, AuthProfileStore } from './types.js';\n\nconst log = createLogger('AuthProfileStore');\n\nconst STORE_FILENAME = 'auth-profiles.json';\n\nexport class NoopAuthProfileStore implements AuthProfileStore {\n getApiKeySync(): string | undefined {\n return undefined;\n }\n hasCredentialSync(): boolean {\n return false;\n }\n list(): AuthProfile[] {\n return [];\n }\n get(): AuthProfile | undefined {\n return undefined;\n }\n async save(): Promise<void> {\n /* no-op */\n }\n async refresh(profile: AuthProfile): Promise<AuthProfile> {\n return profile;\n }\n}\n\ntype DiskFile = {\n /** Schema version; bumped if we ever change the on-disk shape. */\n version: 1;\n profiles: AuthProfile[];\n};\n\nfunction emptyFile(): DiskFile {\n return { version: 1, profiles: [] };\n}\n\nfunction isDiskFile(v: unknown): v is DiskFile {\n if (!v || typeof v !== 'object') return false;\n const o = v as Record<string, unknown>;\n return o.version === 1 && Array.isArray(o.profiles);\n}\n\n/**\n * Persistent per-agent credential store.\n *\n * File layout (`<stateDir>/agents/<agentId>/auth-profiles.json`):\n *\n * ```json\n * {\n * \"version\": 1,\n * \"profiles\": [\n * { \"provider\": \"openai\", \"profileId\": \"default\", \"mode\": \"api-key\", \"apiKey\": \"sk-...\" },\n * { \"provider\": \"openai\", \"profileId\": \"codex\", \"mode\": \"oauth\",\n * \"oauthAccessToken\": \"...\", \"oauthRefreshToken\": \"...\", \"expiresAt\": 1714000000000 }\n * ]\n * }\n * ```\n *\n * - Constructor is non-blocking; the first read triggers a sync load.\n * - Writes go through a temp file + `renameSync` so partial writes never\n * leave the JSON corrupted.\n */\nexport class DiskAuthProfileStore implements AuthProfileStore {\n private readonly path: string;\n private cache: DiskFile | undefined;\n private writeChain: Promise<void> = Promise.resolve();\n\n constructor(filePath: string) {\n this.path = filePath;\n }\n\n /** Absolute path to the backing JSON file. */\n get filePath(): string {\n return this.path;\n }\n\n // --- Sync read API ------------------------------------------------------\n\n getApiKeySync(providerId: string, profile?: string): string | undefined {\n const p = this.findProfile(providerId, profile);\n if (!p) return undefined;\n if (typeof p.apiKey === 'string' && p.apiKey.length > 0) return p.apiKey;\n if (typeof p.oauthAccessToken === 'string' && p.oauthAccessToken.length > 0) {\n return p.oauthAccessToken;\n }\n return undefined;\n }\n\n hasCredentialSync(providerId: string, profile?: string): boolean {\n return Boolean(this.getApiKeySync(providerId, profile));\n }\n\n list(providerId: string): AuthProfile[] {\n const file = this.ensureLoaded();\n return file.profiles\n .filter((p) => p.provider === providerId)\n .map((p) => ({ ...p }));\n }\n\n get(providerId: string, profileId?: string): AuthProfile | undefined {\n const p = this.findProfile(providerId, profileId);\n return p ? { ...p } : undefined;\n }\n\n // --- Async write API ----------------------------------------------------\n\n /**\n * Persist a profile. Uses a serial write chain so concurrent saves cannot\n * race each other on the JSON document.\n */\n save(profile: AuthProfile): Promise<void> {\n const next = this.writeChain.then(() => {\n const file = this.ensureLoaded();\n const idx = file.profiles.findIndex(\n (p) => p.provider === profile.provider && p.profileId === profile.profileId,\n );\n if (idx >= 0) {\n file.profiles[idx] = { ...profile };\n } else {\n file.profiles.push({ ...profile });\n }\n // Only one default per provider.\n if (profile.default) {\n for (const p of file.profiles) {\n if (\n p.provider === profile.provider &&\n p.profileId !== profile.profileId &&\n p.default\n ) {\n p.default = false;\n }\n }\n }\n this.persist(file);\n });\n // Swallow rejections in the chain so a single bad write doesn't poison\n // every subsequent save attempt.\n this.writeChain = next.catch(() => undefined);\n return next;\n }\n\n /**\n * Default `refresh()` is a no-op. Vendor-specific OAuth refresh logic\n * (Codex / Anthropic) lives in `src/providers/auth-runtime/oauth.ts` and\n * calls `save()` here once it has a fresh token.\n */\n async refresh(profile: AuthProfile): Promise<AuthProfile> {\n return profile;\n }\n\n // --- Internals ----------------------------------------------------------\n\n private ensureLoaded(): DiskFile {\n if (this.cache) return this.cache;\n if (!existsSync(this.path)) {\n this.cache = emptyFile();\n return this.cache;\n }\n try {\n const raw = readFileSync(this.path, 'utf8');\n const parsed = JSON.parse(raw);\n if (isDiskFile(parsed)) {\n this.cache = { version: 1, profiles: parsed.profiles.filter(isAuthProfileLike) };\n } else {\n log.warn(\n { path: this.path, phase: 'load' },\n 'auth-profiles.json has unexpected shape; resetting to empty (file is preserved on disk)',\n );\n this.cache = emptyFile();\n }\n } catch (err) {\n log.warn(\n { err, path: this.path, phase: 'load' },\n `Failed to read auth-profiles.json: ${err instanceof Error ? err.message : String(err)}`,\n );\n this.cache = emptyFile();\n }\n return this.cache;\n }\n\n private findProfile(providerId: string, profileId?: string): AuthProfile | undefined {\n const file = this.ensureLoaded();\n const matches = file.profiles.filter((p) => p.provider === providerId);\n if (matches.length === 0) return undefined;\n const wanted = profileId?.trim();\n if (wanted) {\n return matches.find((p) => p.profileId === wanted);\n }\n return matches.find((p) => p.default) ?? matches.find((p) => p.profileId === 'default') ?? matches[0];\n }\n\n private persist(file: DiskFile): void {\n mkdirSync(dirname(this.path), { recursive: true });\n const tmp = `${this.path}.tmp-${process.pid}-${Date.now()}`;\n writeFileSync(tmp, JSON.stringify(file, null, 2), { encoding: 'utf8', mode: 0o600 });\n renameSync(tmp, this.path);\n this.cache = file;\n }\n}\n\nfunction isAuthProfileLike(v: unknown): v is AuthProfile {\n if (!v || typeof v !== 'object') return false;\n const o = v as Record<string, unknown>;\n return typeof o.provider === 'string' && typeof o.profileId === 'string' && typeof o.mode === 'string';\n}\n\n// --- Default store registry ------------------------------------------------\n\nlet defaultStore: AuthProfileStore = new NoopAuthProfileStore();\nconst diskStores = new Map<string, DiskAuthProfileStore>();\n\nexport function getDefaultAuthProfileStore(): AuthProfileStore {\n return defaultStore;\n}\n\n/**\n * Override the default store. Returns a function that restores the previous\n * store; tests typically call it in `afterEach`.\n */\nexport function setDefaultAuthProfileStore(store: AuthProfileStore): () => void {\n const prev = defaultStore;\n defaultStore = store;\n return () => {\n defaultStore = prev;\n };\n}\n\n/**\n * Get (or create) a {@link DiskAuthProfileStore} for the given agent\n * directory. Same `agentDir` always returns the same store instance so the\n * in-memory cache stays consistent within one process.\n */\nexport function ensureDiskAuthProfileStore(agentDir: string): DiskAuthProfileStore {\n const key = agentDir;\n let store = diskStores.get(key);\n if (!store) {\n store = new DiskAuthProfileStore(join(agentDir, STORE_FILENAME));\n diskStores.set(key, store);\n }\n return store;\n}\n\n/**\n * Convenience: list every profile for a provider via either an explicit\n * store or the default store.\n */\nexport function listProfilesForProvider(\n store: AuthProfileStore | undefined,\n providerId: string,\n): AuthProfile[] {\n const s = store ?? getDefaultAuthProfileStore();\n return s.list(providerId);\n}\n"],"mappings":"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"}
|
|
@@ -43,22 +43,11 @@ function resolveAuthProfileForProvider(options) {
|
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
45
|
function pickProfile(store, providerId, profileName) {
|
|
46
|
-
if (typeof store.get === "function") try {
|
|
47
|
-
return store.get(providerId, profileName);
|
|
48
|
-
} catch {}
|
|
49
|
-
let key;
|
|
50
46
|
try {
|
|
51
|
-
|
|
47
|
+
return store.get(providerId, profileName);
|
|
52
48
|
} catch {
|
|
53
49
|
return;
|
|
54
50
|
}
|
|
55
|
-
if (!key) return void 0;
|
|
56
|
-
return {
|
|
57
|
-
provider: providerId,
|
|
58
|
-
profileId: profileName ?? "default",
|
|
59
|
-
mode: "api-key",
|
|
60
|
-
apiKey: key
|
|
61
|
-
};
|
|
62
51
|
}
|
|
63
52
|
function readCfgApiKey(cfg, providerId) {
|
|
64
53
|
const providers = cfg?.providers;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-auth.js","names":[],"sources":["../../../../src/providers/auth-runtime/resolve-auth.ts"],"sourcesContent":["/**\n * Higher-level auth resolution that returns the *full* profile context, not\n * just the API key. Vendors that support multiple auth modes (e.g. OpenAI\n * api-key + Codex OAuth + Azure api-key) call this to pick the right\n * branch.\n *\n * Resolution order matches `resolveApiKeyForProvider`:\n * 1. AuthProfileStore (per-agent profile — may be OAuth)\n * 2. cfg.providers.<id>.apiKey\n * 3. PROVIDER_ENV_MAP[providerId] env vars\n *\n * Returns:\n * - `mode: 'oauth' | 'azure-key' | 'api-key'`\n * - `apiKey` (or OAuth access token) if found\n * - `profileId` when the credential came from the store\n */\n\nimport { getApiKeyFromEnv } from '../env-keys.js';\nimport { getDefaultAuthProfileStore } from './auth-profile-store.js';\nimport type { AuthProfile, ProviderAuthMode, ResolveApiKeyOptions } from './types.js';\n\nexport interface ProviderAuthResolution {\n apiKey?: string;\n mode: ProviderAuthMode;\n profileId?: string;\n /** Source bucket: 'store' | 'config' | 'env' | 'none'. */\n source: 'store' | 'config' | 'env' | 'none';\n /** Vendor metadata copied from the matched profile (azure resource etc.). */\n meta?: Record<string, unknown>;\n}\n\nexport function resolveAuthProfileForProvider(\n options: ResolveApiKeyOptions,\n): ProviderAuthResolution {\n const { providerId } = options;\n if (!providerId) {\n return { apiKey: undefined, mode: 'api-key', source: 'none' };\n }\n\n // 1. Profile store\n const store = options.store ?? getDefaultAuthProfileStore();\n const profile = pickProfile(store, providerId, options.profileName);\n if (profile) {\n const key =\n (typeof profile.apiKey === 'string' && profile.apiKey.length > 0 ? profile.apiKey : undefined) ??\n (typeof profile.oauthAccessToken === 'string' && profile.oauthAccessToken.length > 0\n ? profile.oauthAccessToken\n : undefined);\n if (key) {\n return {\n apiKey: key,\n mode: profile.mode,\n profileId: profile.profileId,\n source: 'store',\n meta: profile.meta,\n };\n }\n }\n\n // 2. cfg.providers.<id>.apiKey\n const cfgKey = readCfgApiKey(options.cfg, providerId);\n if (cfgKey) {\n const azure = readCfgAzureMeta(options.cfg, providerId);\n return {\n apiKey: cfgKey,\n mode: azure ? 'azure-key' : 'api-key',\n source: 'config',\n meta: azure,\n };\n }\n\n // 3. env\n const envKey = options.envReader\n ? readFromCustomEnv(options.envReader, providerId)\n : getApiKeyFromEnv(providerId);\n if (envKey) {\n return { apiKey: envKey, mode: 'api-key', source: 'env' };\n }\n\n return { apiKey: undefined, mode: 'api-key', source: 'none' };\n}\n\nfunction pickProfile(\n store:
|
|
1
|
+
{"version":3,"file":"resolve-auth.js","names":[],"sources":["../../../../src/providers/auth-runtime/resolve-auth.ts"],"sourcesContent":["/**\n * Higher-level auth resolution that returns the *full* profile context, not\n * just the API key. Vendors that support multiple auth modes (e.g. OpenAI\n * api-key + Codex OAuth + Azure api-key) call this to pick the right\n * branch.\n *\n * Resolution order matches `resolveApiKeyForProvider`:\n * 1. AuthProfileStore (per-agent profile — may be OAuth)\n * 2. cfg.providers.<id>.apiKey\n * 3. PROVIDER_ENV_MAP[providerId] env vars\n *\n * Returns:\n * - `mode: 'oauth' | 'azure-key' | 'api-key'`\n * - `apiKey` (or OAuth access token) if found\n * - `profileId` when the credential came from the store\n */\n\nimport { getApiKeyFromEnv } from '../env-keys.js';\nimport { getDefaultAuthProfileStore } from './auth-profile-store.js';\nimport type { AuthProfile, AuthProfileStore, ProviderAuthMode, ResolveApiKeyOptions } from './types.js';\n\nexport interface ProviderAuthResolution {\n apiKey?: string;\n mode: ProviderAuthMode;\n profileId?: string;\n /** Source bucket: 'store' | 'config' | 'env' | 'none'. */\n source: 'store' | 'config' | 'env' | 'none';\n /** Vendor metadata copied from the matched profile (azure resource etc.). */\n meta?: Record<string, unknown>;\n}\n\nexport function resolveAuthProfileForProvider(\n options: ResolveApiKeyOptions,\n): ProviderAuthResolution {\n const { providerId } = options;\n if (!providerId) {\n return { apiKey: undefined, mode: 'api-key', source: 'none' };\n }\n\n // 1. Profile store\n const store = options.store ?? getDefaultAuthProfileStore();\n const profile = pickProfile(store, providerId, options.profileName);\n if (profile) {\n const key =\n (typeof profile.apiKey === 'string' && profile.apiKey.length > 0 ? profile.apiKey : undefined) ??\n (typeof profile.oauthAccessToken === 'string' && profile.oauthAccessToken.length > 0\n ? profile.oauthAccessToken\n : undefined);\n if (key) {\n return {\n apiKey: key,\n mode: profile.mode,\n profileId: profile.profileId,\n source: 'store',\n meta: profile.meta,\n };\n }\n }\n\n // 2. cfg.providers.<id>.apiKey\n const cfgKey = readCfgApiKey(options.cfg, providerId);\n if (cfgKey) {\n const azure = readCfgAzureMeta(options.cfg, providerId);\n return {\n apiKey: cfgKey,\n mode: azure ? 'azure-key' : 'api-key',\n source: 'config',\n meta: azure,\n };\n }\n\n // 3. env\n const envKey = options.envReader\n ? readFromCustomEnv(options.envReader, providerId)\n : getApiKeyFromEnv(providerId);\n if (envKey) {\n return { apiKey: envKey, mode: 'api-key', source: 'env' };\n }\n\n return { apiKey: undefined, mode: 'api-key', source: 'none' };\n}\n\nfunction pickProfile(\n store: AuthProfileStore,\n providerId: string,\n profileName?: string,\n): AuthProfile | undefined {\n try {\n return store.get(providerId, profileName);\n } catch {\n return undefined;\n }\n}\n\nfunction readCfgApiKey(cfg: ResolveApiKeyOptions['cfg'], providerId: string): string | undefined {\n const providers = (cfg as unknown as { providers?: Record<string, unknown> } | undefined)?.providers;\n if (!providers || typeof providers !== 'object') return undefined;\n const entry = (providers as Record<string, unknown>)[providerId];\n if (!entry || typeof entry !== 'object') return undefined;\n const apiKey = (entry as Record<string, unknown>).apiKey;\n return typeof apiKey === 'string' && apiKey.length > 0 ? apiKey : undefined;\n}\n\nfunction readCfgAzureMeta(\n cfg: ResolveApiKeyOptions['cfg'],\n providerId: string,\n): Record<string, unknown> | undefined {\n const providers = (cfg as unknown as { providers?: Record<string, unknown> } | undefined)?.providers;\n if (!providers || typeof providers !== 'object') return undefined;\n const entry = (providers as Record<string, unknown>)[providerId];\n if (!entry || typeof entry !== 'object') return undefined;\n const azure = (entry as Record<string, unknown>).azure;\n return azure && typeof azure === 'object' ? (azure as Record<string, unknown>) : undefined;\n}\n\nfunction readFromCustomEnv(\n reader: (name: string) => string | undefined,\n providerId: string,\n): string | undefined {\n const fallbackName = providerId.toUpperCase().replace(/-/g, '_') + '_API_KEY';\n const v = reader(fallbackName);\n return typeof v === 'string' && v.length > 0 ? v : undefined;\n}\n"],"mappings":";;;eAiBkD;AAclD,SAAgB,8BACd,SACwB;CACxB,MAAM,EAAE,eAAe;AACvB,KAAI,CAAC,WACH,QAAO;EAAE,QAAQ,KAAA;EAAW,MAAM;EAAW,QAAQ;EAAQ;CAK/D,MAAM,UAAU,YADF,QAAQ,SAAS,4BAA4B,EACxB,YAAY,QAAQ,YAAY;AACnE,KAAI,SAAS;EACX,MAAM,OACH,OAAO,QAAQ,WAAW,YAAY,QAAQ,OAAO,SAAS,IAAI,QAAQ,SAAS,KAAA,OACnF,OAAO,QAAQ,qBAAqB,YAAY,QAAQ,iBAAiB,SAAS,IAC/E,QAAQ,mBACR,KAAA;AACN,MAAI,IACF,QAAO;GACL,QAAQ;GACR,MAAM,QAAQ;GACd,WAAW,QAAQ;GACnB,QAAQ;GACR,MAAM,QAAQ;GACf;;CAKL,MAAM,SAAS,cAAc,QAAQ,KAAK,WAAW;AACrD,KAAI,QAAQ;EACV,MAAM,QAAQ,iBAAiB,QAAQ,KAAK,WAAW;AACvD,SAAO;GACL,QAAQ;GACR,MAAM,QAAQ,cAAc;GAC5B,QAAQ;GACR,MAAM;GACP;;CAIH,MAAM,SAAS,QAAQ,YACnB,kBAAkB,QAAQ,WAAW,WAAW,GAChD,iBAAiB,WAAW;AAChC,KAAI,OACF,QAAO;EAAE,QAAQ;EAAQ,MAAM;EAAW,QAAQ;EAAO;AAG3D,QAAO;EAAE,QAAQ,KAAA;EAAW,MAAM;EAAW,QAAQ;EAAQ;;AAG/D,SAAS,YACP,OACA,YACA,aACyB;AACzB,KAAI;AACF,SAAO,MAAM,IAAI,YAAY,YAAY;SACnC;AACN;;;AAIJ,SAAS,cAAc,KAAkC,YAAwC;CAC/F,MAAM,YAAa,KAAwE;AAC3F,KAAI,CAAC,aAAa,OAAO,cAAc,SAAU,QAAO,KAAA;CACxD,MAAM,QAAS,UAAsC;AACrD,KAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO,KAAA;CAChD,MAAM,SAAU,MAAkC;AAClD,QAAO,OAAO,WAAW,YAAY,OAAO,SAAS,IAAI,SAAS,KAAA;;AAGpE,SAAS,iBACP,KACA,YACqC;CACrC,MAAM,YAAa,KAAwE;AAC3F,KAAI,CAAC,aAAa,OAAO,cAAc,SAAU,QAAO,KAAA;CACxD,MAAM,QAAS,UAAsC;AACrD,KAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO,KAAA;CAChD,MAAM,QAAS,MAAkC;AACjD,QAAO,SAAS,OAAO,UAAU,WAAY,QAAoC,KAAA;;AAGnF,SAAS,kBACP,QACA,YACoB;CAEpB,MAAM,IAAI,OADW,WAAW,aAAa,CAAC,QAAQ,MAAM,IAAI,GAAG,WACrC;AAC9B,QAAO,OAAO,MAAM,YAAY,EAAE,SAAS,IAAI,IAAI,KAAA"}
|
|
@@ -3,11 +3,6 @@
|
|
|
3
3
|
* (image / audio / video). Decoupled from the LLM-side
|
|
4
4
|
* `src/auth/credentials.ts` so capability providers do not need to
|
|
5
5
|
* `await` for every isConfigured() call.
|
|
6
|
-
*
|
|
7
|
-
* Step 4 expands {@link AuthProfileStore} from a simple key lookup into a
|
|
8
|
-
* full per-agent profile store that can hold OAuth tokens and refresh them
|
|
9
|
-
* on demand, while keeping every existing sync caller working (legacy
|
|
10
|
-
* methods remain on the interface).
|
|
11
6
|
*/
|
|
12
7
|
import type { Config } from '../../config/schema.js';
|
|
13
8
|
export interface ResolveApiKeyOptions {
|
|
@@ -58,20 +53,19 @@ export interface AuthProfile {
|
|
|
58
53
|
*
|
|
59
54
|
* Sync members ({@link getApiKeySync}, {@link hasCredentialSync}) keep
|
|
60
55
|
* `resolveApiKeyForProvider` synchronous so capability providers and tool
|
|
61
|
-
* default-model resolution stay non-blocking.
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* UI.
|
|
56
|
+
* default-model resolution stay non-blocking. {@link get} / {@link list} are
|
|
57
|
+
* required so OAuth-aware callers can branch on `mode` without falling back
|
|
58
|
+
* to the sync getters.
|
|
65
59
|
*/
|
|
66
60
|
export interface AuthProfileStore {
|
|
67
61
|
/** Synchronous lookup; returns undefined when no profile is loaded. */
|
|
68
62
|
getApiKeySync(providerId: string, profile?: string): string | undefined;
|
|
69
63
|
/** Synchronous "do we have any usable credential" check. */
|
|
70
64
|
hasCredentialSync(providerId: string, profile?: string): boolean;
|
|
71
|
-
/** All profiles for a provider
|
|
72
|
-
list
|
|
65
|
+
/** All profiles for a provider. */
|
|
66
|
+
list(providerId: string): AuthProfile[];
|
|
73
67
|
/** Single profile; defaults to `default: true` then "default" id. */
|
|
74
|
-
get
|
|
68
|
+
get(providerId: string, profileId?: string): AuthProfile | undefined;
|
|
75
69
|
/** Persist a profile; replaces any existing record with the same id. */
|
|
76
70
|
save?(profile: AuthProfile): Promise<void>;
|
|
77
71
|
/** Refresh OAuth access token; idempotent if still fresh. */
|