@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schtasks.js","names":[],"sources":["../../../src/daemon/schtasks.ts"],"sourcesContent":["/**\n * Scheduled Task Service - Windows service management via schtasks\n *\n * Aligned with OpenClaw Windows implementation:\n * - Task with ONLOGON trigger for persistence\n * - RepetitionInterval for keep-alive behavior\n * - Proper start/stop/restart lifecycle\n */\n\nimport { spawn, spawnSync } from 'node:child_process';\nimport { mkdirSync, readFileSync, writeFileSync, rmSync } from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { createLogger } from '../utils/logger.js';\nimport { resolveGatewayWindowsTaskName } from './constants.js';\nimport type {\n GatewayService,\n GatewayServiceInstallArgs,\n GatewayServiceControlArgs,\n GatewayServiceEnvArgs,\n GatewayServiceRuntime,\n GatewayServiceCommandConfig,\n GatewayServiceEnv,\n GatewayServiceRestartResult,\n} from './types.js';\n\nconst log = createLogger('SchtasksService');\n\n// ─── Resolution ───\n\nfunction resolveProfileFromEnv(env?: GatewayServiceEnv): string | undefined {\n return env?.XOPC_PROFILE?.trim() || undefined;\n}\n\nfunction resolveTaskName(env?: GatewayServiceEnv): string {\n return resolveGatewayWindowsTaskName(resolveProfileFromEnv(env));\n}\n\n// ─── Command Execution ───\n\ninterface SchtasksResult {\n stdout: string;\n stderr: string;\n exitCode: number | null;\n}\n\nasync function schtasks(args: string[]): Promise<SchtasksResult> {\n return new Promise<SchtasksResult>((resolve, reject) => {\n const child = spawn('schtasks', args, {\n stdio: ['ignore', 'pipe', 'pipe'],\n shell: true,\n });\n\n let stdout = '';\n let stderr = '';\n\n child.stdout?.on('data', (data) => { stdout += data.toString(); });\n child.stderr?.on('data', (data) => { stderr += data.toString(); });\n\n child.on('close', (code) => {\n resolve({ stdout, stderr, exitCode: code });\n });\n child.on('error', (err) => {\n reject(new Error(`schtasks spawn failed: ${err.message}`));\n });\n });\n}\n\nasync function schtasksExec(args: string[]): Promise<string> {\n const result = await schtasks(args);\n if (result.exitCode !== 0) {\n const detail = result.stderr.trim() || result.stdout.trim();\n throw new Error(`schtasks failed (exit ${result.exitCode}): ${detail}`);\n }\n return result.stdout;\n}\n\n// ─── Environment Sidecar ───\n// schtasks does not natively support per-task environment variables.\n// We persist them in a JSON sidecar so readCommand can return them\n// for version-mismatch detection and other diagnostics.\n\nfunction resolveTaskEnvSidecarPath(taskName: string): string {\n const configDir = path.join(os.homedir(), '.xopc', 'daemon');\n return path.join(configDir, `${taskName}.env.json`);\n}\n\nfunction writeTaskEnvSidecar(taskName: string, environment: Record<string, string>): void {\n const sidecarPath = resolveTaskEnvSidecarPath(taskName);\n try {\n mkdirSync(path.dirname(sidecarPath), { recursive: true });\n writeFileSync(sidecarPath, JSON.stringify(environment, null, 2), 'utf8');\n } catch (err) {\n log.warn({ err, sidecarPath }, 'Failed to write task environment sidecar');\n }\n}\n\nfunction readTaskEnvSidecar(taskName: string): Record<string, string> | undefined {\n const sidecarPath = resolveTaskEnvSidecarPath(taskName);\n try {\n const raw = readFileSync(sidecarPath, 'utf8');\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, string>;\n }\n } catch {\n // Sidecar missing or corrupt — not fatal\n }\n return undefined;\n}\n\nfunction removeTaskEnvSidecar(taskName: string): void {\n const sidecarPath = resolveTaskEnvSidecarPath(taskName);\n try {\n rmSync(sidecarPath, { force: true });\n } catch {\n // Best-effort\n }\n}\n\n// ─── Availability Check ───\n\nexport function isSchtasksAvailable(): boolean {\n if (process.platform !== 'win32') return false;\n try {\n const result = spawnSync('schtasks', ['/query', '/?'], {\n stdio: ['ignore', 'ignore', 'ignore'],\n shell: true,\n timeout: 3000,\n });\n return result.status === 0;\n } catch {\n return false;\n }\n}\n\n// ─── Service Implementation ───\n\nexport const schtasksService: GatewayService = {\n label: resolveGatewayWindowsTaskName(),\n loadedText: 'Scheduled Task (installed)',\n notLoadedText: 'Scheduled Task (not installed)',\n\n async install(args: GatewayServiceInstallArgs): Promise<void> {\n const taskName = resolveTaskName(args.env);\n const program = args.programArguments[0];\n const programArgs = args.programArguments.slice(1).join(' ');\n\n // Delete existing task first (ignore errors)\n try {\n await schtasks(['/delete', '/tn', taskName, '/f']);\n } catch {\n // Ignore\n }\n\n // Create task with ONLOGON trigger\n const createArgs = [\n '/create',\n '/tn', taskName,\n '/tr', `\"${program}\" ${programArgs}`,\n '/sc', 'ONLOGON',\n '/rl', 'LIMITED',\n '/f',\n ];\n\n await schtasksExec(createArgs);\n\n // Persist environment variables in a sidecar file\n // (schtasks does not support per-task env vars natively)\n if (args.environment && Object.keys(args.environment).length > 0) {\n writeTaskEnvSidecar(taskName, args.environment);\n }\n\n args.stdout?.write(`Created scheduled task: ${taskName}\\n`);\n args.stdout?.write(` Program: ${program}\\n`);\n args.stdout?.write(` Args: ${programArgs}\\n`);\n\n log.info({ taskName }, 'Scheduled task installed');\n },\n\n async uninstall(args: GatewayServiceControlArgs): Promise<void> {\n const taskName = resolveTaskName(args.env);\n\n // Stop if running\n try {\n await schtasks(['/end', '/tn', taskName]);\n } catch {\n // Ignore\n }\n\n // Delete task\n try {\n await schtasksExec(['/delete', '/tn', taskName, '/f']);\n args.stdout?.write(`Deleted scheduled task: ${taskName}\\n`);\n } catch (err) {\n log.debug({ err }, 'Uninstall task not found');\n }\n\n // Clean up environment sidecar\n removeTaskEnvSidecar(taskName);\n\n log.info({ taskName }, 'Scheduled task uninstalled');\n },\n\n async stop(args: GatewayServiceControlArgs): Promise<void> {\n const taskName = resolveTaskName(args.env);\n\n try {\n await schtasksExec(['/end', '/tn', taskName]);\n } catch {\n log.debug('Task not running');\n }\n\n if (args.disable) {\n try {\n await schtasksExec(['/change', '/tn', taskName, '/disable']);\n } catch {\n // Ignore\n }\n }\n\n log.info('Scheduled task stopped');\n },\n\n async restart(args: GatewayServiceControlArgs): Promise<GatewayServiceRestartResult> {\n const taskName = resolveTaskName(args.env);\n\n // End current run\n try {\n await schtasks(['/end', '/tn', taskName]);\n } catch {\n // Ignore\n }\n\n // Small delay for process cleanup\n await new Promise((resolve) => setTimeout(resolve, 500));\n\n // Start new run\n await schtasksExec(['/run', '/tn', taskName]);\n\n log.info('Scheduled task restarted');\n return { outcome: 'restarted' };\n },\n\n async isLoaded(args: GatewayServiceEnvArgs): Promise<boolean> {\n const taskName = resolveTaskName(args.env);\n const result = await schtasks(['/query', '/tn', taskName]);\n return result.exitCode === 0;\n },\n\n async readRuntime(env?: GatewayServiceEnv): Promise<GatewayServiceRuntime> {\n const taskName = resolveTaskName(env);\n\n try {\n const result = await schtasks(['/query', '/tn', taskName, '/fo', 'list', '/v']);\n if (result.exitCode !== 0) {\n return { status: 'unknown' };\n }\n\n const output = result.stdout;\n let status: 'running' | 'stopped' | 'unknown' = 'unknown';\n\n const statusMatch = output.match(/Status:\\s*(\\w+)/i);\n if (statusMatch) {\n const statusStr = statusMatch[1].toLowerCase();\n if (statusStr === 'running') {\n status = 'running';\n } else if (statusStr === 'ready' || statusStr === 'disabled') {\n status = 'stopped';\n }\n }\n\n // Parse last result code\n let lastExitStatus: number | undefined;\n const resultMatch = output.match(/Last Result:\\s*(\\d+)/i);\n if (resultMatch) {\n lastExitStatus = parseInt(resultMatch[1], 10);\n }\n\n return { status, lastExitStatus };\n } catch {\n return { status: 'unknown' };\n }\n },\n\n async readCommand(env?: GatewayServiceEnv): Promise<GatewayServiceCommandConfig | null> {\n const taskName = resolveTaskName(env);\n\n try {\n const result = await schtasks(['/query', '/tn', taskName, '/fo', 'list', '/v']);\n if (result.exitCode !== 0) return null;\n\n const output = result.stdout;\n const taskRunMatch = output.match(/Task To Run:\\s*(.+)/i);\n const workDirMatch = output.match(/Start In:\\s*(.+)/i);\n\n if (!taskRunMatch) return null;\n\n const taskRun = taskRunMatch[1].trim();\n // Handle quoted program path\n let programArguments: string[];\n if (taskRun.startsWith('\"')) {\n const closeQuote = taskRun.indexOf('\"', 1);\n if (closeQuote > 0) {\n const program = taskRun.slice(1, closeQuote);\n const rest = taskRun.slice(closeQuote + 1).trim();\n programArguments = [program, ...rest.split(/\\s+/).filter(Boolean)];\n } else {\n programArguments = taskRun.split(/\\s+/);\n }\n } else {\n programArguments = taskRun.split(/\\s+/);\n }\n\n // Read environment from sidecar file (schtasks has no native env support)\n const environment = readTaskEnvSidecar(taskName);\n\n return {\n programArguments,\n workingDirectory: workDirMatch?.[1]?.trim() || undefined,\n environment,\n };\n } catch {\n return null;\n }\n },\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"schtasks.js","names":[],"sources":["../../../src/daemon/schtasks.ts"],"sourcesContent":["/**\n * Scheduled Task Service - Windows service management via schtasks\n *\n * Aligned with OpenClaw Windows implementation:\n * - Task with ONLOGON trigger for persistence\n * - RepetitionInterval for keep-alive behavior\n * - Proper start/stop/restart lifecycle\n */\n\nimport { spawn, spawnSync } from 'node:child_process';\nimport { mkdirSync, readFileSync, writeFileSync, rmSync } from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\n\nimport { createLogger } from '../utils/logger.js';\nimport { resolveGatewayWindowsTaskName } from './constants.js';\nimport type {\n GatewayService,\n GatewayServiceInstallArgs,\n GatewayServiceControlArgs,\n GatewayServiceEnvArgs,\n GatewayServiceRuntime,\n GatewayServiceCommandConfig,\n GatewayServiceEnv,\n GatewayServiceRestartResult,\n} from './types.js';\n\nconst log = createLogger('SchtasksService');\n\n// ─── Resolution ───\n\nfunction resolveProfileFromEnv(env?: GatewayServiceEnv): string | undefined {\n return env?.XOPC_PROFILE?.trim() || undefined;\n}\n\nfunction resolveTaskName(env?: GatewayServiceEnv): string {\n return resolveGatewayWindowsTaskName(resolveProfileFromEnv(env));\n}\n\n// ─── Command Execution ───\n\ninterface SchtasksResult {\n stdout: string;\n stderr: string;\n exitCode: number | null;\n}\n\nasync function schtasks(args: string[]): Promise<SchtasksResult> {\n return new Promise<SchtasksResult>((resolve, reject) => {\n const child = spawn('schtasks', args, {\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n let stdout = '';\n let stderr = '';\n\n child.stdout?.on('data', (data) => { stdout += data.toString(); });\n child.stderr?.on('data', (data) => { stderr += data.toString(); });\n\n child.on('close', (code) => {\n resolve({ stdout, stderr, exitCode: code });\n });\n child.on('error', (err) => {\n reject(new Error(`schtasks spawn failed: ${err.message}`));\n });\n });\n}\n\nasync function schtasksExec(args: string[]): Promise<string> {\n const result = await schtasks(args);\n if (result.exitCode !== 0) {\n const detail = result.stderr.trim() || result.stdout.trim();\n throw new Error(`schtasks failed (exit ${result.exitCode}): ${detail}`);\n }\n return result.stdout;\n}\n\n// ─── Environment Sidecar ───\n// schtasks does not natively support per-task environment variables.\n// We persist them in a JSON sidecar so readCommand can return them\n// for version-mismatch detection and other diagnostics.\n\nfunction resolveTaskDaemonDir(): string {\n return path.join(os.homedir(), '.xopc', 'daemon');\n}\n\nfunction resolveTaskEnvSidecarPath(taskName: string): string {\n return path.join(resolveTaskDaemonDir(), `${taskName}.env.json`);\n}\n\nfunction resolveTaskCommandSidecarPath(taskName: string): string {\n return path.join(resolveTaskDaemonDir(), `${taskName}.command.json`);\n}\n\nfunction resolveTaskWrapperPath(taskName: string): string {\n return path.join(resolveTaskDaemonDir(), `${taskName}.cmd`);\n}\n\nfunction resolveTaskXmlPath(taskName: string): string {\n return path.join(resolveTaskDaemonDir(), `${taskName}.xml`);\n}\n\nfunction escapeCmdSetValue(value: string): string {\n return value\n .replace(/\\^/g, '^^')\n .replace(/%/g, '%%')\n .replace(/\"/g, '^\"')\n .replace(/&/g, '^&')\n .replace(/</g, '^<')\n .replace(/>/g, '^>')\n .replace(/\\|/g, '^|');\n}\n\nfunction quoteCmdArg(value: string): string {\n return `\"${value.replace(/\"/g, '\\\\\"')}\"`;\n}\n\nfunction escapeXmlValue(value: string): string {\n return value\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\nfunction buildTaskWrapperContent(params: {\n programArguments: string[];\n workingDirectory?: string;\n environment?: Record<string, string>;\n}): string {\n const lines = ['@echo off'];\n for (const [key, value] of Object.entries(params.environment ?? {})) {\n lines.push(`set \"${key}=${escapeCmdSetValue(value)}\"`);\n }\n if (params.workingDirectory) {\n lines.push(`cd /d ${quoteCmdArg(params.workingDirectory)}`);\n }\n lines.push(params.programArguments.map(quoteCmdArg).join(' '));\n return `${lines.join('\\r\\n')}\\r\\n`;\n}\n\nfunction buildTaskXml(params: {\n description: string;\n wrapperPath: string;\n workingDirectory?: string;\n}): string {\n const escapedDescription = escapeXmlValue(params.description);\n const escapedWrapperPath = escapeXmlValue(params.wrapperPath);\n const escapedWorkingDirectory = params.workingDirectory ? escapeXmlValue(params.workingDirectory) : '';\n const workingDirectoryXml = escapedWorkingDirectory\n ? `\\n <WorkingDirectory>${escapedWorkingDirectory}</WorkingDirectory>`\n : '';\n\n return `<?xml version=\"1.0\" encoding=\"UTF-16\"?>\n<Task version=\"1.4\" xmlns=\"http://schemas.microsoft.com/windows/2004/02/mit/task\">\n <RegistrationInfo>\n <Description>${escapedDescription}</Description>\n </RegistrationInfo>\n <Triggers>\n <LogonTrigger>\n <Enabled>true</Enabled>\n </LogonTrigger>\n </Triggers>\n <Principals>\n <Principal id=\"Author\">\n <LogonType>InteractiveToken</LogonType>\n <RunLevel>LeastPrivilege</RunLevel>\n </Principal>\n </Principals>\n <Settings>\n <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>\n <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>\n <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>\n <AllowHardTerminate>true</AllowHardTerminate>\n <StartWhenAvailable>true</StartWhenAvailable>\n <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>\n <IdleSettings>\n <StopOnIdleEnd>false</StopOnIdleEnd>\n <RestartOnIdle>false</RestartOnIdle>\n </IdleSettings>\n <AllowStartOnDemand>true</AllowStartOnDemand>\n <Enabled>true</Enabled>\n <Hidden>false</Hidden>\n <RunOnlyIfIdle>false</RunOnlyIfIdle>\n <WakeToRun>false</WakeToRun>\n <ExecutionTimeLimit>PT0S</ExecutionTimeLimit>\n <Priority>7</Priority>\n <RestartOnFailure>\n <Interval>PT1M</Interval>\n <Count>999</Count>\n </RestartOnFailure>\n </Settings>\n <Actions Context=\"Author\">\n <Exec>\n <Command>${escapedWrapperPath}</Command>${workingDirectoryXml}\n </Exec>\n </Actions>\n</Task>\n`;\n}\n\nfunction writeTaskEnvSidecar(taskName: string, environment: Record<string, string>): void {\n const sidecarPath = resolveTaskEnvSidecarPath(taskName);\n try {\n mkdirSync(path.dirname(sidecarPath), { recursive: true });\n writeFileSync(sidecarPath, JSON.stringify(environment, null, 2), 'utf8');\n } catch (err) {\n log.warn({ err, sidecarPath }, 'Failed to write task environment sidecar');\n }\n}\n\nfunction readTaskEnvSidecar(taskName: string): Record<string, string> | undefined {\n const sidecarPath = resolveTaskEnvSidecarPath(taskName);\n try {\n const raw = readFileSync(sidecarPath, 'utf8');\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, string>;\n }\n } catch {\n // Sidecar missing or corrupt — not fatal\n }\n return undefined;\n}\n\nfunction writeTaskCommandSidecar(taskName: string, args: GatewayServiceInstallArgs): void {\n const sidecarPath = resolveTaskCommandSidecarPath(taskName);\n try {\n writeFileSync(sidecarPath, JSON.stringify({\n programArguments: args.programArguments,\n workingDirectory: args.workingDirectory,\n }, null, 2), 'utf8');\n } catch (err) {\n log.warn({ err, sidecarPath }, 'Failed to write task command sidecar');\n }\n}\n\nfunction readTaskCommandSidecar(taskName: string): Pick<GatewayServiceCommandConfig, 'programArguments' | 'workingDirectory'> | null {\n const sidecarPath = resolveTaskCommandSidecarPath(taskName);\n try {\n const raw = readFileSync(sidecarPath, 'utf8');\n const parsed = JSON.parse(raw);\n if (\n parsed\n && typeof parsed === 'object'\n && Array.isArray(parsed.programArguments)\n && parsed.programArguments.every((arg: unknown) => typeof arg === 'string')\n ) {\n return {\n programArguments: parsed.programArguments,\n workingDirectory: typeof parsed.workingDirectory === 'string' ? parsed.workingDirectory : undefined,\n };\n }\n } catch {\n // Sidecar missing or corrupt — not fatal\n }\n return null;\n}\n\nfunction writeTaskSupportFiles(taskName: string, args: GatewayServiceInstallArgs): {\n wrapperPath: string;\n xmlPath: string;\n} {\n const wrapperPath = resolveTaskWrapperPath(taskName);\n const xmlPath = resolveTaskXmlPath(taskName);\n mkdirSync(resolveTaskDaemonDir(), { recursive: true });\n writeFileSync(wrapperPath, buildTaskWrapperContent({\n programArguments: args.programArguments,\n workingDirectory: args.workingDirectory,\n environment: args.environment,\n }), 'utf8');\n writeFileSync(xmlPath, buildTaskXml({\n description: args.description || 'xopc Gateway Service',\n wrapperPath,\n workingDirectory: args.workingDirectory,\n }), 'utf16le');\n writeTaskEnvSidecar(taskName, args.environment ?? {});\n writeTaskCommandSidecar(taskName, args);\n return { wrapperPath, xmlPath };\n}\n\nfunction removeTaskSupportFiles(taskName: string): void {\n for (const filePath of [\n resolveTaskEnvSidecarPath(taskName),\n resolveTaskCommandSidecarPath(taskName),\n resolveTaskWrapperPath(taskName),\n resolveTaskXmlPath(taskName),\n ]) {\n try {\n rmSync(filePath, { force: true });\n } catch {\n // Best-effort\n }\n }\n}\n\nexport const schtasksTestInternals = {\n buildTaskWrapperContent,\n buildTaskXml,\n escapeCmdSetValue,\n quoteCmdArg,\n resolveTaskCommandSidecarPath,\n resolveTaskWrapperPath,\n resolveTaskXmlPath,\n};\n\n// ─── Availability Check ───\n\nexport function isSchtasksAvailable(): boolean {\n if (process.platform !== 'win32') return false;\n try {\n const result = spawnSync('schtasks', ['/query', '/?'], {\n stdio: ['ignore', 'ignore', 'ignore'],\n timeout: 3000,\n });\n return result.status === 0;\n } catch {\n return false;\n }\n}\n\n// ─── Service Implementation ───\n\nexport const schtasksService: GatewayService = {\n label: resolveGatewayWindowsTaskName(),\n loadedText: 'Scheduled Task (installed)',\n notLoadedText: 'Scheduled Task (not installed)',\n\n async install(args: GatewayServiceInstallArgs): Promise<void> {\n const taskName = resolveTaskName(args.env);\n\n // Delete existing task first (ignore errors)\n try {\n await schtasks(['/delete', '/tn', taskName, '/f']);\n } catch {\n // Ignore\n }\n\n const { wrapperPath, xmlPath } = writeTaskSupportFiles(taskName, args);\n await schtasksExec(['/create', '/tn', taskName, '/xml', xmlPath, '/f']);\n\n args.stdout?.write(`Created scheduled task: ${taskName}\\n`);\n args.stdout?.write(` Wrapper: ${wrapperPath}\\n`);\n args.stdout?.write(` Command: ${args.programArguments.join(' ')}\\n`);\n\n log.info({ taskName, wrapperPath }, 'Scheduled task installed');\n },\n\n async uninstall(args: GatewayServiceControlArgs): Promise<void> {\n const taskName = resolveTaskName(args.env);\n\n // Stop if running\n try {\n await schtasks(['/end', '/tn', taskName]);\n } catch {\n // Ignore\n }\n\n // Delete task\n try {\n await schtasksExec(['/delete', '/tn', taskName, '/f']);\n args.stdout?.write(`Deleted scheduled task: ${taskName}\\n`);\n } catch (err) {\n log.debug({ err }, 'Uninstall task not found');\n }\n\n // Clean up support files\n removeTaskSupportFiles(taskName);\n\n log.info({ taskName }, 'Scheduled task uninstalled');\n },\n\n async stop(args: GatewayServiceControlArgs): Promise<void> {\n const taskName = resolveTaskName(args.env);\n\n try {\n await schtasksExec(['/end', '/tn', taskName]);\n } catch {\n log.debug('Task not running');\n }\n\n if (args.disable) {\n try {\n await schtasksExec(['/change', '/tn', taskName, '/disable']);\n } catch {\n // Ignore\n }\n }\n\n log.info('Scheduled task stopped');\n },\n\n async restart(args: GatewayServiceControlArgs): Promise<GatewayServiceRestartResult> {\n const taskName = resolveTaskName(args.env);\n\n // End current run\n try {\n await schtasks(['/end', '/tn', taskName]);\n } catch {\n // Ignore\n }\n\n // Small delay for process cleanup\n await new Promise((resolve) => setTimeout(resolve, 500));\n\n // Start new run\n await schtasksExec(['/run', '/tn', taskName]);\n\n log.info('Scheduled task restarted');\n return { outcome: 'restarted' };\n },\n\n async isLoaded(args: GatewayServiceEnvArgs): Promise<boolean> {\n const taskName = resolveTaskName(args.env);\n const result = await schtasks(['/query', '/tn', taskName]);\n return result.exitCode === 0;\n },\n\n async readRuntime(env?: GatewayServiceEnv): Promise<GatewayServiceRuntime> {\n const taskName = resolveTaskName(env);\n\n try {\n const result = await schtasks(['/query', '/tn', taskName, '/fo', 'list', '/v']);\n if (result.exitCode !== 0) {\n return { status: 'unknown' };\n }\n\n const output = result.stdout;\n let status: 'running' | 'stopped' | 'unknown' = 'unknown';\n\n const statusMatch = output.match(/Status:\\s*(\\w+)/i);\n if (statusMatch) {\n const statusStr = statusMatch[1].toLowerCase();\n if (statusStr === 'running') {\n status = 'running';\n } else if (statusStr === 'ready' || statusStr === 'disabled') {\n status = 'stopped';\n }\n }\n\n // Parse last result code\n let lastExitStatus: number | undefined;\n const resultMatch = output.match(/Last Result:\\s*(\\d+)/i);\n if (resultMatch) {\n lastExitStatus = parseInt(resultMatch[1], 10);\n }\n\n return { status, lastExitStatus };\n } catch {\n return { status: 'unknown' };\n }\n },\n\n async readCommand(env?: GatewayServiceEnv): Promise<GatewayServiceCommandConfig | null> {\n const taskName = resolveTaskName(env);\n\n try {\n const result = await schtasks(['/query', '/tn', taskName, '/fo', 'list', '/v']);\n if (result.exitCode !== 0) return null;\n\n const commandSidecar = readTaskCommandSidecar(taskName);\n if (!commandSidecar) return null;\n\n return {\n programArguments: commandSidecar.programArguments,\n workingDirectory: commandSidecar.workingDirectory,\n environment: readTaskEnvSidecar(taskName),\n };\n } catch {\n return null;\n }\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;;aAckD;AAalD,MAAM,MAAM,aAAa,kBAAkB;AAI3C,SAAS,sBAAsB,KAA6C;AAC1E,QAAO,KAAK,cAAc,MAAM,IAAI,KAAA;;AAGtC,SAAS,gBAAgB,KAAiC;AACxD,QAAO,8BAA8B,sBAAsB,IAAI,CAAC;;AAWlE,eAAe,SAAS,MAAyC;AAC/D,QAAO,IAAI,SAAyB,SAAS,WAAW;EACtD,MAAM,QAAQ,MAAM,YAAY,MAAM,EACpC,OAAO;GAAC;GAAU;GAAQ;GAAO,EAClC,CAAC;EAEF,IAAI,SAAS;EACb,IAAI,SAAS;AAEb,QAAM,QAAQ,GAAG,SAAS,SAAS;AAAE,aAAU,KAAK,UAAU;IAAI;AAClE,QAAM,QAAQ,GAAG,SAAS,SAAS;AAAE,aAAU,KAAK,UAAU;IAAI;AAElE,QAAM,GAAG,UAAU,SAAS;AAC1B,WAAQ;IAAE;IAAQ;IAAQ,UAAU;IAAM,CAAC;IAC3C;AACF,QAAM,GAAG,UAAU,QAAQ;AACzB,0BAAO,IAAI,MAAM,0BAA0B,IAAI,UAAU,CAAC;IAC1D;GACF;;AAGJ,eAAe,aAAa,MAAiC;CAC3D,MAAM,SAAS,MAAM,SAAS,KAAK;AACnC,KAAI,OAAO,aAAa,GAAG;EACzB,MAAM,SAAS,OAAO,OAAO,MAAM,IAAI,OAAO,OAAO,MAAM;AAC3D,QAAM,IAAI,MAAM,yBAAyB,OAAO,SAAS,KAAK,SAAS;;AAEzE,QAAO,OAAO;;AAQhB,SAAS,uBAA+B;AACtC,QAAO,KAAK,KAAK,GAAG,SAAS,EAAE,SAAS,SAAS;;AAGnD,SAAS,0BAA0B,UAA0B;AAC3D,QAAO,KAAK,KAAK,sBAAsB,EAAE,GAAG,SAAS,WAAW;;AAGlE,SAAS,8BAA8B,UAA0B;AAC/D,QAAO,KAAK,KAAK,sBAAsB,EAAE,GAAG,SAAS,eAAe;;AAGtE,SAAS,uBAAuB,UAA0B;AACxD,QAAO,KAAK,KAAK,sBAAsB,EAAE,GAAG,SAAS,MAAM;;AAG7D,SAAS,mBAAmB,UAA0B;AACpD,QAAO,KAAK,KAAK,sBAAsB,EAAE,GAAG,SAAS,MAAM;;AAG7D,SAAS,kBAAkB,OAAuB;AAChD,QAAO,MACJ,QAAQ,OAAO,KAAK,CACpB,QAAQ,MAAM,KAAK,CACnB,QAAQ,MAAM,MAAK,CACnB,QAAQ,MAAM,KAAK,CACnB,QAAQ,MAAM,KAAK,CACnB,QAAQ,MAAM,KAAK,CACnB,QAAQ,OAAO,KAAK;;AAGzB,SAAS,YAAY,OAAuB;AAC1C,QAAO,IAAI,MAAM,QAAQ,MAAM,OAAM,CAAC;;AAGxC,SAAS,eAAe,OAAuB;AAC7C,QAAO,MACJ,QAAQ,MAAM,QAAQ,CACtB,QAAQ,MAAM,OAAO,CACrB,QAAQ,MAAM,OAAO,CACrB,QAAQ,MAAM,SAAS,CACvB,QAAQ,MAAM,SAAS;;AAG5B,SAAS,wBAAwB,QAItB;CACT,MAAM,QAAQ,CAAC,YAAY;AAC3B,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,eAAe,EAAE,CAAC,CACjE,OAAM,KAAK,QAAQ,IAAI,GAAG,kBAAkB,MAAM,CAAC,GAAG;AAExD,KAAI,OAAO,iBACT,OAAM,KAAK,SAAS,YAAY,OAAO,iBAAiB,GAAG;AAE7D,OAAM,KAAK,OAAO,iBAAiB,IAAI,YAAY,CAAC,KAAK,IAAI,CAAC;AAC9D,QAAO,GAAG,MAAM,KAAK,OAAO,CAAC;;AAG/B,SAAS,aAAa,QAIX;CACT,MAAM,qBAAqB,eAAe,OAAO,YAAY;CAC7D,MAAM,qBAAqB,eAAe,OAAO,YAAY;CAC7D,MAAM,0BAA0B,OAAO,mBAAmB,eAAe,OAAO,iBAAiB,GAAG;AAKpG,QAAO;;;mBAGU,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsCrB,mBAAmB,YA7CN,0BACxB,6BAA6B,wBAAwB,uBACrD,GA2C8D;;;;;;AAOpE,SAAS,oBAAoB,UAAkB,aAA2C;CACxF,MAAM,cAAc,0BAA0B,SAAS;AACvD,KAAI;AACF,YAAU,KAAK,QAAQ,YAAY,EAAE,EAAE,WAAW,MAAM,CAAC;AACzD,gBAAc,aAAa,KAAK,UAAU,aAAa,MAAM,EAAE,EAAE,OAAO;UACjE,KAAK;AACZ,MAAI,KAAK;GAAE;GAAK;GAAa,EAAE,2CAA2C;;;AAI9E,SAAS,mBAAmB,UAAsD;CAChF,MAAM,cAAc,0BAA0B,SAAS;AACvD,KAAI;EACF,MAAM,MAAM,aAAa,aAAa,OAAO;EAC7C,MAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,MAAI,UAAU,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,OAAO,CAChE,QAAO;SAEH;;AAMV,SAAS,wBAAwB,UAAkB,MAAuC;CACxF,MAAM,cAAc,8BAA8B,SAAS;AAC3D,KAAI;AACF,gBAAc,aAAa,KAAK,UAAU;GACxC,kBAAkB,KAAK;GACvB,kBAAkB,KAAK;GACxB,EAAE,MAAM,EAAE,EAAE,OAAO;UACb,KAAK;AACZ,MAAI,KAAK;GAAE;GAAK;GAAa,EAAE,uCAAuC;;;AAI1E,SAAS,uBAAuB,UAAqG;CACnI,MAAM,cAAc,8BAA8B,SAAS;AAC3D,KAAI;EACF,MAAM,MAAM,aAAa,aAAa,OAAO;EAC7C,MAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,MACE,UACG,OAAO,WAAW,YAClB,MAAM,QAAQ,OAAO,iBAAiB,IACtC,OAAO,iBAAiB,OAAO,QAAiB,OAAO,QAAQ,SAAS,CAE3E,QAAO;GACL,kBAAkB,OAAO;GACzB,kBAAkB,OAAO,OAAO,qBAAqB,WAAW,OAAO,mBAAmB,KAAA;GAC3F;SAEG;AAGR,QAAO;;AAGT,SAAS,sBAAsB,UAAkB,MAG/C;CACA,MAAM,cAAc,uBAAuB,SAAS;CACpD,MAAM,UAAU,mBAAmB,SAAS;AAC5C,WAAU,sBAAsB,EAAE,EAAE,WAAW,MAAM,CAAC;AACtD,eAAc,aAAa,wBAAwB;EACjD,kBAAkB,KAAK;EACvB,kBAAkB,KAAK;EACvB,aAAa,KAAK;EACnB,CAAC,EAAE,OAAO;AACX,eAAc,SAAS,aAAa;EAClC,aAAa,KAAK,eAAe;EACjC;EACA,kBAAkB,KAAK;EACxB,CAAC,EAAE,UAAU;AACd,qBAAoB,UAAU,KAAK,eAAe,EAAE,CAAC;AACrD,yBAAwB,UAAU,KAAK;AACvC,QAAO;EAAE;EAAa;EAAS;;AAGjC,SAAS,uBAAuB,UAAwB;AACtD,MAAK,MAAM,YAAY;EACrB,0BAA0B,SAAS;EACnC,8BAA8B,SAAS;EACvC,uBAAuB,SAAS;EAChC,mBAAmB,SAAS;EAC7B,CACC,KAAI;AACF,SAAO,UAAU,EAAE,OAAO,MAAM,CAAC;SAC3B;;AAMZ,MAAa,wBAAwB;CACnC;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAID,SAAgB,sBAA+B;AAC7C,KAAI,QAAQ,aAAa,QAAS,QAAO;AACzC,KAAI;AAKF,SAJe,UAAU,YAAY,CAAC,UAAU,KAAK,EAAE;GACrD,OAAO;IAAC;IAAU;IAAU;IAAS;GACrC,SAAS;GACV,CACY,CAAC,WAAW;SACnB;AACN,SAAO;;;AAMX,MAAa,kBAAkC;CAC7C,OAAO,+BAA+B;CACtC,YAAY;CACZ,eAAe;CAEf,MAAM,QAAQ,MAAgD;EAC5D,MAAM,WAAW,gBAAgB,KAAK,IAAI;AAG1C,MAAI;AACF,SAAM,SAAS;IAAC;IAAW;IAAO;IAAU;IAAK,CAAC;UAC5C;EAIR,MAAM,EAAE,aAAa,YAAY,sBAAsB,UAAU,KAAK;AACtE,QAAM,aAAa;GAAC;GAAW;GAAO;GAAU;GAAQ;GAAS;GAAK,CAAC;AAEvE,OAAK,QAAQ,MAAM,2BAA2B,SAAS,IAAI;AAC3D,OAAK,QAAQ,MAAM,cAAc,YAAY,IAAI;AACjD,OAAK,QAAQ,MAAM,cAAc,KAAK,iBAAiB,KAAK,IAAI,CAAC,IAAI;AAErE,MAAI,KAAK;GAAE;GAAU;GAAa,EAAE,2BAA2B;;CAGjE,MAAM,UAAU,MAAgD;EAC9D,MAAM,WAAW,gBAAgB,KAAK,IAAI;AAG1C,MAAI;AACF,SAAM,SAAS;IAAC;IAAQ;IAAO;IAAS,CAAC;UACnC;AAKR,MAAI;AACF,SAAM,aAAa;IAAC;IAAW;IAAO;IAAU;IAAK,CAAC;AACtD,QAAK,QAAQ,MAAM,2BAA2B,SAAS,IAAI;WACpD,KAAK;AACZ,OAAI,MAAM,EAAE,KAAK,EAAE,2BAA2B;;AAIhD,yBAAuB,SAAS;AAEhC,MAAI,KAAK,EAAE,UAAU,EAAE,6BAA6B;;CAGtD,MAAM,KAAK,MAAgD;EACzD,MAAM,WAAW,gBAAgB,KAAK,IAAI;AAE1C,MAAI;AACF,SAAM,aAAa;IAAC;IAAQ;IAAO;IAAS,CAAC;UACvC;AACN,OAAI,MAAM,mBAAmB;;AAG/B,MAAI,KAAK,QACP,KAAI;AACF,SAAM,aAAa;IAAC;IAAW;IAAO;IAAU;IAAW,CAAC;UACtD;AAKV,MAAI,KAAK,yBAAyB;;CAGpC,MAAM,QAAQ,MAAuE;EACnF,MAAM,WAAW,gBAAgB,KAAK,IAAI;AAG1C,MAAI;AACF,SAAM,SAAS;IAAC;IAAQ;IAAO;IAAS,CAAC;UACnC;AAKR,QAAM,IAAI,SAAS,YAAY,WAAW,SAAS,IAAI,CAAC;AAGxD,QAAM,aAAa;GAAC;GAAQ;GAAO;GAAS,CAAC;AAE7C,MAAI,KAAK,2BAA2B;AACpC,SAAO,EAAE,SAAS,aAAa;;CAGjC,MAAM,SAAS,MAA+C;AAG5D,UAAO,MADc,SAAS;GAAC;GAAU;GADxB,gBAAgB,KAAK,IACkB;GAAC,CAAC,EAC5C,aAAa;;CAG7B,MAAM,YAAY,KAAyD;EACzE,MAAM,WAAW,gBAAgB,IAAI;AAErC,MAAI;GACF,MAAM,SAAS,MAAM,SAAS;IAAC;IAAU;IAAO;IAAU;IAAO;IAAQ;IAAK,CAAC;AAC/E,OAAI,OAAO,aAAa,EACtB,QAAO,EAAE,QAAQ,WAAW;GAG9B,MAAM,SAAS,OAAO;GACtB,IAAI,SAA4C;GAEhD,MAAM,cAAc,OAAO,MAAM,mBAAmB;AACpD,OAAI,aAAa;IACf,MAAM,YAAY,YAAY,GAAG,aAAa;AAC9C,QAAI,cAAc,UAChB,UAAS;aACA,cAAc,WAAW,cAAc,WAChD,UAAS;;GAKb,IAAI;GACJ,MAAM,cAAc,OAAO,MAAM,wBAAwB;AACzD,OAAI,YACF,kBAAiB,SAAS,YAAY,IAAI,GAAG;AAG/C,UAAO;IAAE;IAAQ;IAAgB;UAC3B;AACN,UAAO,EAAE,QAAQ,WAAW;;;CAIhC,MAAM,YAAY,KAAsE;EACtF,MAAM,WAAW,gBAAgB,IAAI;AAErC,MAAI;AAEF,QAAI,MADiB,SAAS;IAAC;IAAU;IAAO;IAAU;IAAO;IAAQ;IAAK,CAAC,EACpE,aAAa,EAAG,QAAO;GAElC,MAAM,iBAAiB,uBAAuB,SAAS;AACvD,OAAI,CAAC,eAAgB,QAAO;AAE5B,UAAO;IACL,kBAAkB,eAAe;IACjC,kBAAkB,eAAe;IACjC,aAAa,mBAAmB,SAAS;IAC1C;UACK;AACN,UAAO;;;CAGZ"}
|
|
@@ -59,14 +59,15 @@ function isDaemonAvailable() {
|
|
|
59
59
|
async function startGatewayService(params) {
|
|
60
60
|
const { service, env } = params;
|
|
61
61
|
const serviceEnv = env || process.env;
|
|
62
|
-
|
|
62
|
+
const initialState = await gatherServiceState(service, serviceEnv);
|
|
63
|
+
if (!initialState.installed) return {
|
|
63
64
|
outcome: "missing-install",
|
|
64
|
-
state:
|
|
65
|
+
state: initialState
|
|
65
66
|
};
|
|
66
|
-
const issues = detectStartRepairIssues(
|
|
67
|
+
const issues = detectStartRepairIssues(initialState.command);
|
|
67
68
|
if (issues.length > 0) return {
|
|
68
69
|
outcome: "repair-required",
|
|
69
|
-
state:
|
|
70
|
+
state: initialState,
|
|
70
71
|
issues
|
|
71
72
|
};
|
|
72
73
|
const restartResult = await service.restart({ env: serviceEnv });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","names":[],"sources":["../../../src/daemon/service.ts"],"sourcesContent":["/**\n * Daemon Service Abstraction - Cross-platform service management\n *\n * Provides:\n * - Platform-specific service resolution (launchd / systemd / schtasks)\n * - Availability detection\n * - Unified start logic with repair detection\n */\n\nimport { existsSync } from 'node:fs';\nimport { createLogger } from '../utils/logger.js';\nimport { PACKAGE_VERSION } from '../package-version.js';\nimport { SERVICE_VERSION_ENV_KEY } from './constants.js';\nimport type {\n GatewayService,\n GatewayServiceEnv,\n GatewayServiceState,\n GatewayServiceStartResult,\n GatewayServiceStartRepairIssue,\n} from './types.js';\n\nconst log = createLogger('DaemonService');\n\nlet _isDaemonAvailable: boolean | null = null;\n\n// ─── Service Resolution ───\n\nexport async function resolveGatewayService(): Promise<GatewayService> {\n const platform = process.platform;\n\n if (platform === 'darwin') {\n const { launchdService } = await import('./launchd.js');\n return launchdService;\n }\n\n if (platform === 'linux') {\n const { systemdService } = await import('./systemd.js');\n return systemdService;\n }\n\n if (platform === 'win32') {\n const { schtasksService } = await import('./schtasks.js');\n return schtasksService;\n }\n\n throw new Error(`Unsupported platform for daemon services: ${platform}`);\n}\n\n// ─── Availability ───\n\nexport async function isDaemonAvailableAsync(): Promise<boolean> {\n if (_isDaemonAvailable !== null) {\n return _isDaemonAvailable;\n }\n\n const platform = process.platform;\n\n try {\n if (platform === 'darwin') {\n const { isLaunchdAvailable } = await import('./launchd.js');\n _isDaemonAvailable = isLaunchdAvailable();\n } else if (platform === 'linux') {\n const { isSystemdAvailable } = await import('./systemd.js');\n _isDaemonAvailable = isSystemdAvailable();\n } else if (platform === 'win32') {\n const { isSchtasksAvailable } = await import('./schtasks.js');\n _isDaemonAvailable = isSchtasksAvailable();\n } else {\n _isDaemonAvailable = false;\n }\n } catch (err) {\n log.error({ err }, 'Failed to check daemon availability');\n _isDaemonAvailable = false;\n }\n\n return _isDaemonAvailable!;\n}\n\nexport function isDaemonAvailable(): boolean {\n const platform = process.platform;\n return platform === 'linux' || platform === 'darwin' || platform === 'win32';\n}\n\n// ─── Start with Repair Detection ───\n\nexport async function startGatewayService(params: {\n service: GatewayService;\n env?: GatewayServiceEnv;\n}): Promise<GatewayServiceStartResult> {\n const { service, env } = params;\n const serviceEnv = env || process.env;\n\n
|
|
1
|
+
{"version":3,"file":"service.js","names":[],"sources":["../../../src/daemon/service.ts"],"sourcesContent":["/**\n * Daemon Service Abstraction - Cross-platform service management\n *\n * Provides:\n * - Platform-specific service resolution (launchd / systemd / schtasks)\n * - Availability detection\n * - Unified start logic with repair detection\n */\n\nimport { existsSync } from 'node:fs';\nimport { createLogger } from '../utils/logger.js';\nimport { PACKAGE_VERSION } from '../package-version.js';\nimport { SERVICE_VERSION_ENV_KEY } from './constants.js';\nimport type {\n GatewayService,\n GatewayServiceEnv,\n GatewayServiceState,\n GatewayServiceStartResult,\n GatewayServiceStartRepairIssue,\n} from './types.js';\n\nconst log = createLogger('DaemonService');\n\nlet _isDaemonAvailable: boolean | null = null;\n\n// ─── Service Resolution ───\n\nexport async function resolveGatewayService(): Promise<GatewayService> {\n const platform = process.platform;\n\n if (platform === 'darwin') {\n const { launchdService } = await import('./launchd.js');\n return launchdService;\n }\n\n if (platform === 'linux') {\n const { systemdService } = await import('./systemd.js');\n return systemdService;\n }\n\n if (platform === 'win32') {\n const { schtasksService } = await import('./schtasks.js');\n return schtasksService;\n }\n\n throw new Error(`Unsupported platform for daemon services: ${platform}`);\n}\n\n// ─── Availability ───\n\nexport async function isDaemonAvailableAsync(): Promise<boolean> {\n if (_isDaemonAvailable !== null) {\n return _isDaemonAvailable;\n }\n\n const platform = process.platform;\n\n try {\n if (platform === 'darwin') {\n const { isLaunchdAvailable } = await import('./launchd.js');\n _isDaemonAvailable = isLaunchdAvailable();\n } else if (platform === 'linux') {\n const { isSystemdAvailable } = await import('./systemd.js');\n _isDaemonAvailable = isSystemdAvailable();\n } else if (platform === 'win32') {\n const { isSchtasksAvailable } = await import('./schtasks.js');\n _isDaemonAvailable = isSchtasksAvailable();\n } else {\n _isDaemonAvailable = false;\n }\n } catch (err) {\n log.error({ err }, 'Failed to check daemon availability');\n _isDaemonAvailable = false;\n }\n\n return _isDaemonAvailable!;\n}\n\nexport function isDaemonAvailable(): boolean {\n const platform = process.platform;\n return platform === 'linux' || platform === 'darwin' || platform === 'win32';\n}\n\n// ─── Start with Repair Detection ───\n\nexport async function startGatewayService(params: {\n service: GatewayService;\n env?: GatewayServiceEnv;\n}): Promise<GatewayServiceStartResult> {\n const { service, env } = params;\n const serviceEnv = env || process.env;\n\n const initialState = await gatherServiceState(service, serviceEnv);\n if (!initialState.installed) {\n return { outcome: 'missing-install', state: initialState };\n }\n\n // Read command to check for repair issues. On macOS, a stopped LaunchAgent can\n // be installed on disk but not loaded into launchd yet.\n const issues = detectStartRepairIssues(initialState.command);\n\n if (issues.length > 0) {\n return { outcome: 'repair-required', state: initialState, issues };\n }\n\n // Start via restart (which handles both cold-start and running scenarios)\n const restartResult = await service.restart({ env: serviceEnv });\n const state = await gatherServiceState(service, serviceEnv);\n\n return {\n outcome: restartResult.outcome === 'restarted' ? 'started' : 'scheduled',\n state,\n };\n}\n\nfunction detectStartRepairIssues(\n command: { programArguments: string[]; environment?: Record<string, string> } | null,\n): GatewayServiceStartRepairIssue[] {\n const issues: GatewayServiceStartRepairIssue[] = [];\n\n if (!command || command.programArguments.length === 0) {\n issues.push({ code: 'missing-program', message: 'Service command configuration is missing' });\n return issues;\n }\n\n const program = command.programArguments[0];\n\n // Check if program exists on disk\n if (!existsSync(program)) {\n issues.push({\n code: 'missing-program',\n message: `Service program not found: ${program}`,\n });\n return issues;\n }\n\n // Check version mismatch\n const serviceVersion = command.environment?.[SERVICE_VERSION_ENV_KEY];\n if (serviceVersion && serviceVersion !== PACKAGE_VERSION) {\n issues.push({\n code: 'version-mismatch',\n message: `Service version ${serviceVersion} does not match current ${PACKAGE_VERSION}`,\n });\n }\n\n return issues;\n}\n\n// ─── State Gathering ───\n\nasync function gatherServiceState(\n service: GatewayService,\n env: GatewayServiceEnv,\n): Promise<GatewayServiceState> {\n const [loaded, runtime, command] = await Promise.all([\n service.isLoaded({ env }),\n service.readRuntime(env),\n service.readCommand(env),\n ]);\n\n return {\n installed: loaded || command !== null,\n loaded,\n running: runtime.status === 'running',\n env,\n command,\n runtime,\n };\n}\n\n// ─── Display Helpers ───\n\nexport function getPlatformName(): string {\n switch (process.platform) {\n case 'darwin':\n return 'macOS (launchd)';\n case 'linux':\n return 'Linux (systemd)';\n case 'win32':\n return 'Windows (Task Scheduler)';\n default:\n return process.platform;\n }\n}\n\nexport function getServiceLabel(): string {\n return 'xopc-gateway';\n}\n\n/** Describe what a restart operation will do on the current platform */\nexport function describeGatewayServiceRestart(): string {\n switch (process.platform) {\n case 'darwin':\n return 'launchctl kickstart -k (LaunchAgent restart)';\n case 'linux':\n return 'systemctl --user restart (systemd restart)';\n case 'win32':\n return 'schtasks /end + /run (Scheduled Task restart)';\n default:\n return 'platform restart';\n }\n}\n"],"mappings":"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"}
|
|
@@ -9,6 +9,12 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { GatewayService, GatewayServiceEnv } from './types.js';
|
|
11
11
|
export declare function resolveSystemdUserUnitPath(env?: GatewayServiceEnv): string;
|
|
12
|
+
export declare function buildSystemdUnit(params: {
|
|
13
|
+
description: string;
|
|
14
|
+
programArguments: string[];
|
|
15
|
+
workingDirectory?: string;
|
|
16
|
+
environment: Record<string, string>;
|
|
17
|
+
}): string;
|
|
12
18
|
export declare function isSystemdAvailable(): boolean;
|
|
13
19
|
export declare function enableLinger(): Promise<void>;
|
|
14
20
|
export declare const systemdService: GatewayService;
|
|
@@ -27,9 +27,17 @@ function resolveServiceName(env) {
|
|
|
27
27
|
function resolveSystemdUserUnitPath(env) {
|
|
28
28
|
return resolveSystemdUnitPath(resolveProfileFromEnv(env));
|
|
29
29
|
}
|
|
30
|
+
function escapeSystemdUnitValue(value) {
|
|
31
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/%/g, "%%");
|
|
32
|
+
}
|
|
33
|
+
function quoteSystemdExecArg(arg) {
|
|
34
|
+
const escapedArg = escapeSystemdUnitValue(arg);
|
|
35
|
+
if (/^[A-Za-z0-9_@%+=:,./-]+$/.test(arg)) return escapedArg;
|
|
36
|
+
return `"${escapedArg}"`;
|
|
37
|
+
}
|
|
30
38
|
function buildSystemdUnit(params) {
|
|
31
|
-
const envLines = Object.entries(params.environment).map(([
|
|
32
|
-
const execStart = params.programArguments.join(" ");
|
|
39
|
+
const envLines = Object.entries(params.environment).map(([key, value]) => `Environment="${key}=${escapeSystemdUnitValue(value)}"`).join("\n");
|
|
40
|
+
const execStart = params.programArguments.map(quoteSystemdExecArg).join(" ");
|
|
33
41
|
let unit = `[Unit]
|
|
34
42
|
Description=${params.description}
|
|
35
43
|
After=network-online.target
|
|
@@ -157,6 +165,13 @@ const systemdService = {
|
|
|
157
165
|
args.stdout?.write(`Written: ${unitPath}\n`);
|
|
158
166
|
await systemctlExec(["daemon-reload"]);
|
|
159
167
|
await systemctlExec(["enable", serviceName]);
|
|
168
|
+
try {
|
|
169
|
+
await enableLinger();
|
|
170
|
+
} catch (err) {
|
|
171
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
172
|
+
args.stdout?.write(`Warning: ${message}\n`);
|
|
173
|
+
log.warn({ err }, "Systemd user linger is not enabled; gateway may stop after logout");
|
|
174
|
+
}
|
|
160
175
|
log.info({
|
|
161
176
|
serviceName,
|
|
162
177
|
unitPath
|
|
@@ -251,6 +266,6 @@ const systemdService = {
|
|
|
251
266
|
}
|
|
252
267
|
};
|
|
253
268
|
//#endregion
|
|
254
|
-
export { enableLinger, isSystemdAvailable, resolveSystemdUserUnitPath, systemdService };
|
|
269
|
+
export { buildSystemdUnit, enableLinger, isSystemdAvailable, resolveSystemdUserUnitPath, systemdService };
|
|
255
270
|
|
|
256
271
|
//# sourceMappingURL=systemd.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"systemd.js","names":["resolveUnitPathFromConstants","constants"],"sources":["../../../src/daemon/systemd.ts"],"sourcesContent":["/**\n * Systemd Service - Linux user service management\n *\n * Aligned with OpenClaw systemd implementation:\n * - Restart=always with RestartPreventExitStatus=78\n * - StartLimitBurst/StartLimitIntervalSec for rate limiting\n * - KillMode=control-group\n * - network-online.target dependency\n */\n\nimport { writeFile, mkdir, readFile, rm, access, constants } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { spawn, spawnSync } from 'node:child_process';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { createLogger } from '../utils/logger.js';\nimport {\n resolveGatewaySystemdServiceName,\n resolveSystemdUnitPath as resolveUnitPathFromConstants,\n SYSTEMD_RESTART_SEC,\n SYSTEMD_START_LIMIT_BURST,\n SYSTEMD_START_LIMIT_INTERVAL_SEC,\n} from './constants.js';\nimport type {\n GatewayService,\n GatewayServiceInstallArgs,\n GatewayServiceControlArgs,\n GatewayServiceEnvArgs,\n GatewayServiceRuntime,\n GatewayServiceCommandConfig,\n GatewayServiceEnv,\n GatewayServiceRestartResult,\n} from './types.js';\n\nconst log = createLogger('SystemdService');\n\n// ─── Path Resolution ───\n\nfunction resolveProfileFromEnv(env?: GatewayServiceEnv): string | undefined {\n return env?.XOPC_PROFILE?.trim() || undefined;\n}\n\nfunction resolveServiceName(env?: GatewayServiceEnv): string {\n return resolveGatewaySystemdServiceName(resolveProfileFromEnv(env));\n}\n\nexport function resolveSystemdUserUnitPath(env?: GatewayServiceEnv): string {\n return resolveUnitPathFromConstants(resolveProfileFromEnv(env));\n}\n\n// ─── Unit File Generation ───\n\nfunction buildSystemdUnit(params: {\n description: string;\n programArguments: string[];\n workingDirectory?: string;\n environment: Record<string, string>;\n}): string {\n const envLines = Object.entries(params.environment)\n .map(([k, v]) => `Environment=\"${k}=${v}\"`)\n .join('\\n');\n\n const execStart = params.programArguments.join(' ');\n\n let unit = `[Unit]\nDescription=${params.description}\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nExecStart=${execStart}\n`;\n\n if (params.workingDirectory) {\n unit += `WorkingDirectory=${params.workingDirectory}\\n`;\n }\n\n if (envLines) {\n unit += `${envLines}\\n`;\n }\n\n unit += `Restart=always\nRestartSec=${SYSTEMD_RESTART_SEC}\nRestartPreventExitStatus=78\nKillMode=control-group\nStartLimitBurst=${SYSTEMD_START_LIMIT_BURST}\nStartLimitIntervalSec=${SYSTEMD_START_LIMIT_INTERVAL_SEC}\n\n[Install]\nWantedBy=default.target\n`;\n\n return unit;\n}\n\n// ─── systemctl Execution ───\n\ninterface SystemctlResult {\n stdout: string;\n stderr: string;\n exitCode: number | null;\n}\n\nasync function systemctl(args: string[]): Promise<SystemctlResult> {\n return new Promise<SystemctlResult>((resolve, reject) => {\n const child = spawn('systemctl', ['--user', ...args], {\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n let stdout = '';\n let stderr = '';\n\n child.stdout?.on('data', (data) => { stdout += data.toString(); });\n child.stderr?.on('data', (data) => { stderr += data.toString(); });\n\n child.on('close', (code) => {\n resolve({ stdout, stderr, exitCode: code });\n });\n child.on('error', (err) => {\n reject(new Error(`systemctl spawn failed: ${err.message}`));\n });\n });\n}\n\nasync function systemctlExec(args: string[]): Promise<void> {\n const result = await systemctl(args);\n if (result.exitCode !== 0) {\n const detail = result.stderr.trim() || result.stdout.trim();\n throw new Error(`systemctl ${args.join(' ')} failed (exit ${result.exitCode}): ${detail}`);\n }\n}\n\n// ─── Availability Check ───\n\nexport function isSystemdAvailable(): boolean {\n if (process.platform !== 'linux') return false;\n try {\n const result = spawnSync('systemctl', ['--user', '--version'], {\n stdio: ['ignore', 'pipe', 'ignore'],\n timeout: 3000,\n });\n return result.status === 0;\n } catch {\n return false;\n }\n}\n\n// ─── Linger Management ───\n\nfunction getUsername(): string {\n return os.userInfo().username;\n}\n\nasync function isLingerEnabled(): Promise<boolean> {\n try {\n const lingerPath = `/var/lib/systemd/linger/${getUsername()}`;\n await access(lingerPath, constants.F_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function enableLinger(): Promise<void> {\n if (!isSystemdAvailable()) {\n throw new Error('systemd is not available');\n }\n\n const alreadyEnabled = await isLingerEnabled();\n if (alreadyEnabled) {\n log.info('User lingering already enabled');\n return;\n }\n\n const result = spawnSync('loginctl', ['enable-linger', getUsername()], {\n stdio: ['ignore', 'pipe', 'pipe'],\n timeout: 5000,\n });\n\n if (result.status !== 0) {\n log.warn(\n { command: `loginctl enable-linger ${getUsername()}` },\n 'Failed to enable systemd user linger; gateway may not survive logout',\n );\n throw new Error(\n `Failed to enable user lingering. Run: sudo loginctl enable-linger ${getUsername()}`,\n );\n }\n\n log.info('Enabled user lingering');\n}\n\n// ─── Unit File Parsing ───\n\nfunction parseUnitEnvironment(content: string): Record<string, string> {\n const environment: Record<string, string> = {};\n const matches = content.matchAll(/^Environment=\"([^=]+)=(.*)\"/gm);\n for (const match of matches) {\n environment[match[1]] = match[2];\n }\n return environment;\n}\n\n// ─── Service Implementation ───\n\nexport const systemdService: GatewayService = {\n label: resolveGatewaySystemdServiceName(),\n loadedText: 'systemd (enabled)',\n notLoadedText: 'systemd (not installed)',\n\n async install(args: GatewayServiceInstallArgs): Promise<void> {\n const serviceName = resolveServiceName(args.env);\n const unitPath = resolveSystemdUserUnitPath(args.env);\n\n // Ensure directory exists\n await mkdir(path.dirname(unitPath), { recursive: true });\n\n // Build environment\n const environment: Record<string, string> = {};\n if (args.environment) {\n Object.assign(environment, args.environment);\n }\n\n // Build unit content\n const description = args.description || 'xopc Gateway Service';\n const unit = buildSystemdUnit({\n description,\n programArguments: args.programArguments,\n workingDirectory: args.workingDirectory,\n environment,\n });\n\n // Write unit file\n await writeFile(unitPath, unit, 'utf8');\n args.stdout?.write(`Written: ${unitPath}\\n`);\n\n // Reload systemd daemon\n await systemctlExec(['daemon-reload']);\n\n // Enable service\n await systemctlExec(['enable', serviceName]);\n\n log.info({ serviceName, unitPath }, 'Systemd service installed and enabled');\n },\n\n async uninstall(args: GatewayServiceControlArgs): Promise<void> {\n const serviceName = resolveServiceName(args.env);\n const unitPath = resolveSystemdUserUnitPath(args.env);\n\n // Stop if running\n try {\n await systemctlExec(['stop', serviceName]);\n } catch {\n // Ignore\n }\n\n // Disable service\n try {\n await systemctlExec(['disable', serviceName]);\n } catch {\n // Ignore\n }\n\n // Remove unit file\n if (existsSync(unitPath)) {\n await rm(unitPath);\n args.stdout?.write(`Removed: ${unitPath}\\n`);\n }\n\n // Reload daemon\n await systemctlExec(['daemon-reload']);\n\n log.info({ serviceName, unitPath }, 'Systemd service uninstalled');\n },\n\n async stop(args: GatewayServiceControlArgs): Promise<void> {\n const serviceName = resolveServiceName(args.env);\n\n if (args.disable) {\n // Stop + disable: prevents restart\n await systemctlExec(['stop', serviceName]);\n await systemctlExec(['disable', serviceName]);\n log.info('Systemd service stopped and disabled');\n } else {\n await systemctlExec(['stop', serviceName]);\n log.info('Systemd service stopped');\n }\n },\n\n async restart(args: GatewayServiceControlArgs): Promise<GatewayServiceRestartResult> {\n const serviceName = resolveServiceName(args.env);\n await systemctlExec(['restart', serviceName]);\n log.info('Systemd service restarted');\n return { outcome: 'restarted' };\n },\n\n async isLoaded(args: GatewayServiceEnvArgs): Promise<boolean> {\n const serviceName = resolveServiceName(args.env);\n const result = await systemctl(['is-enabled', serviceName]);\n return result.exitCode === 0;\n },\n\n async readRuntime(env?: GatewayServiceEnv): Promise<GatewayServiceRuntime> {\n const serviceName = resolveServiceName(env);\n\n try {\n const result = await systemctl([\n 'show', serviceName,\n '--property=ActiveState,MainPID,ExecMainStatus',\n ]);\n\n if (result.exitCode !== 0) {\n return { status: 'unknown' };\n }\n\n const lines = result.stdout.trim().split('\\n');\n let status: 'running' | 'stopped' | 'unknown' = 'unknown';\n let pid: number | undefined;\n let lastExitStatus: number | undefined;\n\n for (const line of lines) {\n const eqIdx = line.indexOf('=');\n if (eqIdx < 0) continue;\n const key = line.slice(0, eqIdx);\n const value = line.slice(eqIdx + 1);\n\n if (key === 'ActiveState') {\n status = value === 'active' ? 'running' : value === 'inactive' ? 'stopped' : 'unknown';\n } else if (key === 'MainPID') {\n const parsed = parseInt(value, 10);\n if (parsed > 0) pid = parsed;\n } else if (key === 'ExecMainStatus') {\n lastExitStatus = parseInt(value, 10);\n }\n }\n\n return { status, pid, lastExitStatus };\n } catch {\n return { status: 'unknown' };\n }\n },\n\n async readCommand(env?: GatewayServiceEnv): Promise<GatewayServiceCommandConfig | null> {\n const unitPath = resolveSystemdUserUnitPath(env);\n if (!existsSync(unitPath)) return null;\n\n const content = await readFile(unitPath, 'utf8');\n const execStartMatch = content.match(/^ExecStart=(.+)$/m);\n const workDirMatch = content.match(/^WorkingDirectory=(.+)$/m);\n\n if (!execStartMatch) return null;\n\n const execStart = execStartMatch[1].trim();\n const programArguments = execStart.split(/\\s+/);\n const environment = parseUnitEnvironment(content);\n\n return {\n programArguments,\n workingDirectory: workDirMatch?.[1],\n environment,\n sourcePath: unitPath,\n };\n },\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"systemd.js","names":["resolveUnitPathFromConstants","constants"],"sources":["../../../src/daemon/systemd.ts"],"sourcesContent":["/**\n * Systemd Service - Linux user service management\n *\n * Aligned with OpenClaw systemd implementation:\n * - Restart=always with RestartPreventExitStatus=78\n * - StartLimitBurst/StartLimitIntervalSec for rate limiting\n * - KillMode=control-group\n * - network-online.target dependency\n */\n\nimport { writeFile, mkdir, readFile, rm, access, constants } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { spawn, spawnSync } from 'node:child_process';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { createLogger } from '../utils/logger.js';\nimport {\n resolveGatewaySystemdServiceName,\n resolveSystemdUnitPath as resolveUnitPathFromConstants,\n SYSTEMD_RESTART_SEC,\n SYSTEMD_START_LIMIT_BURST,\n SYSTEMD_START_LIMIT_INTERVAL_SEC,\n} from './constants.js';\nimport type {\n GatewayService,\n GatewayServiceInstallArgs,\n GatewayServiceControlArgs,\n GatewayServiceEnvArgs,\n GatewayServiceRuntime,\n GatewayServiceCommandConfig,\n GatewayServiceEnv,\n GatewayServiceRestartResult,\n} from './types.js';\n\nconst log = createLogger('SystemdService');\n\n// ─── Path Resolution ───\n\nfunction resolveProfileFromEnv(env?: GatewayServiceEnv): string | undefined {\n return env?.XOPC_PROFILE?.trim() || undefined;\n}\n\nfunction resolveServiceName(env?: GatewayServiceEnv): string {\n return resolveGatewaySystemdServiceName(resolveProfileFromEnv(env));\n}\n\nexport function resolveSystemdUserUnitPath(env?: GatewayServiceEnv): string {\n return resolveUnitPathFromConstants(resolveProfileFromEnv(env));\n}\n\n// ─── Unit File Generation ───\n\nfunction escapeSystemdUnitValue(value: string): string {\n return value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\"/g, '\\\\\"')\n .replace(/%/g, '%%');\n}\n\nfunction quoteSystemdExecArg(arg: string): string {\n const escapedArg = escapeSystemdUnitValue(arg);\n if (/^[A-Za-z0-9_@%+=:,./-]+$/.test(arg)) {\n return escapedArg;\n }\n return `\"${escapedArg}\"`;\n}\n\nexport function buildSystemdUnit(params: {\n description: string;\n programArguments: string[];\n workingDirectory?: string;\n environment: Record<string, string>;\n}): string {\n const envLines = Object.entries(params.environment)\n .map(([key, value]) => `Environment=\"${key}=${escapeSystemdUnitValue(value)}\"`)\n .join('\\n');\n\n const execStart = params.programArguments.map(quoteSystemdExecArg).join(' ');\n\n let unit = `[Unit]\nDescription=${params.description}\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nExecStart=${execStart}\n`;\n\n if (params.workingDirectory) {\n unit += `WorkingDirectory=${params.workingDirectory}\\n`;\n }\n\n if (envLines) {\n unit += `${envLines}\\n`;\n }\n\n unit += `Restart=always\nRestartSec=${SYSTEMD_RESTART_SEC}\nRestartPreventExitStatus=78\nKillMode=control-group\nStartLimitBurst=${SYSTEMD_START_LIMIT_BURST}\nStartLimitIntervalSec=${SYSTEMD_START_LIMIT_INTERVAL_SEC}\n\n[Install]\nWantedBy=default.target\n`;\n\n return unit;\n}\n\n// ─── systemctl Execution ───\n\ninterface SystemctlResult {\n stdout: string;\n stderr: string;\n exitCode: number | null;\n}\n\nasync function systemctl(args: string[]): Promise<SystemctlResult> {\n return new Promise<SystemctlResult>((resolve, reject) => {\n const child = spawn('systemctl', ['--user', ...args], {\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n let stdout = '';\n let stderr = '';\n\n child.stdout?.on('data', (data) => { stdout += data.toString(); });\n child.stderr?.on('data', (data) => { stderr += data.toString(); });\n\n child.on('close', (code) => {\n resolve({ stdout, stderr, exitCode: code });\n });\n child.on('error', (err) => {\n reject(new Error(`systemctl spawn failed: ${err.message}`));\n });\n });\n}\n\nasync function systemctlExec(args: string[]): Promise<void> {\n const result = await systemctl(args);\n if (result.exitCode !== 0) {\n const detail = result.stderr.trim() || result.stdout.trim();\n throw new Error(`systemctl ${args.join(' ')} failed (exit ${result.exitCode}): ${detail}`);\n }\n}\n\n// ─── Availability Check ───\n\nexport function isSystemdAvailable(): boolean {\n if (process.platform !== 'linux') return false;\n try {\n const result = spawnSync('systemctl', ['--user', '--version'], {\n stdio: ['ignore', 'pipe', 'ignore'],\n timeout: 3000,\n });\n return result.status === 0;\n } catch {\n return false;\n }\n}\n\n// ─── Linger Management ───\n\nfunction getUsername(): string {\n return os.userInfo().username;\n}\n\nasync function isLingerEnabled(): Promise<boolean> {\n try {\n const lingerPath = `/var/lib/systemd/linger/${getUsername()}`;\n await access(lingerPath, constants.F_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function enableLinger(): Promise<void> {\n if (!isSystemdAvailable()) {\n throw new Error('systemd is not available');\n }\n\n const alreadyEnabled = await isLingerEnabled();\n if (alreadyEnabled) {\n log.info('User lingering already enabled');\n return;\n }\n\n const result = spawnSync('loginctl', ['enable-linger', getUsername()], {\n stdio: ['ignore', 'pipe', 'pipe'],\n timeout: 5000,\n });\n\n if (result.status !== 0) {\n log.warn(\n { command: `loginctl enable-linger ${getUsername()}` },\n 'Failed to enable systemd user linger; gateway may not survive logout',\n );\n throw new Error(\n `Failed to enable user lingering. Run: sudo loginctl enable-linger ${getUsername()}`,\n );\n }\n\n log.info('Enabled user lingering');\n}\n\n// ─── Unit File Parsing ───\n\nfunction parseUnitEnvironment(content: string): Record<string, string> {\n const environment: Record<string, string> = {};\n const matches = content.matchAll(/^Environment=\"([^=]+)=(.*)\"/gm);\n for (const match of matches) {\n environment[match[1]] = match[2];\n }\n return environment;\n}\n\n// ─── Service Implementation ───\n\nexport const systemdService: GatewayService = {\n label: resolveGatewaySystemdServiceName(),\n loadedText: 'systemd (enabled)',\n notLoadedText: 'systemd (not installed)',\n\n async install(args: GatewayServiceInstallArgs): Promise<void> {\n const serviceName = resolveServiceName(args.env);\n const unitPath = resolveSystemdUserUnitPath(args.env);\n\n // Ensure directory exists\n await mkdir(path.dirname(unitPath), { recursive: true });\n\n // Build environment\n const environment: Record<string, string> = {};\n if (args.environment) {\n Object.assign(environment, args.environment);\n }\n\n // Build unit content\n const description = args.description || 'xopc Gateway Service';\n const unit = buildSystemdUnit({\n description,\n programArguments: args.programArguments,\n workingDirectory: args.workingDirectory,\n environment,\n });\n\n // Write unit file\n await writeFile(unitPath, unit, 'utf8');\n args.stdout?.write(`Written: ${unitPath}\\n`);\n\n // Reload systemd daemon\n await systemctlExec(['daemon-reload']);\n\n // Enable service\n await systemctlExec(['enable', serviceName]);\n\n try {\n await enableLinger();\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n args.stdout?.write(`Warning: ${message}\\n`);\n log.warn({ err }, 'Systemd user linger is not enabled; gateway may stop after logout');\n }\n\n log.info({ serviceName, unitPath }, 'Systemd service installed and enabled');\n },\n\n async uninstall(args: GatewayServiceControlArgs): Promise<void> {\n const serviceName = resolveServiceName(args.env);\n const unitPath = resolveSystemdUserUnitPath(args.env);\n\n // Stop if running\n try {\n await systemctlExec(['stop', serviceName]);\n } catch {\n // Ignore\n }\n\n // Disable service\n try {\n await systemctlExec(['disable', serviceName]);\n } catch {\n // Ignore\n }\n\n // Remove unit file\n if (existsSync(unitPath)) {\n await rm(unitPath);\n args.stdout?.write(`Removed: ${unitPath}\\n`);\n }\n\n // Reload daemon\n await systemctlExec(['daemon-reload']);\n\n log.info({ serviceName, unitPath }, 'Systemd service uninstalled');\n },\n\n async stop(args: GatewayServiceControlArgs): Promise<void> {\n const serviceName = resolveServiceName(args.env);\n\n if (args.disable) {\n // Stop + disable: prevents restart\n await systemctlExec(['stop', serviceName]);\n await systemctlExec(['disable', serviceName]);\n log.info('Systemd service stopped and disabled');\n } else {\n await systemctlExec(['stop', serviceName]);\n log.info('Systemd service stopped');\n }\n },\n\n async restart(args: GatewayServiceControlArgs): Promise<GatewayServiceRestartResult> {\n const serviceName = resolveServiceName(args.env);\n await systemctlExec(['restart', serviceName]);\n log.info('Systemd service restarted');\n return { outcome: 'restarted' };\n },\n\n async isLoaded(args: GatewayServiceEnvArgs): Promise<boolean> {\n const serviceName = resolveServiceName(args.env);\n const result = await systemctl(['is-enabled', serviceName]);\n return result.exitCode === 0;\n },\n\n async readRuntime(env?: GatewayServiceEnv): Promise<GatewayServiceRuntime> {\n const serviceName = resolveServiceName(env);\n\n try {\n const result = await systemctl([\n 'show', serviceName,\n '--property=ActiveState,MainPID,ExecMainStatus',\n ]);\n\n if (result.exitCode !== 0) {\n return { status: 'unknown' };\n }\n\n const lines = result.stdout.trim().split('\\n');\n let status: 'running' | 'stopped' | 'unknown' = 'unknown';\n let pid: number | undefined;\n let lastExitStatus: number | undefined;\n\n for (const line of lines) {\n const eqIdx = line.indexOf('=');\n if (eqIdx < 0) continue;\n const key = line.slice(0, eqIdx);\n const value = line.slice(eqIdx + 1);\n\n if (key === 'ActiveState') {\n status = value === 'active' ? 'running' : value === 'inactive' ? 'stopped' : 'unknown';\n } else if (key === 'MainPID') {\n const parsed = parseInt(value, 10);\n if (parsed > 0) pid = parsed;\n } else if (key === 'ExecMainStatus') {\n lastExitStatus = parseInt(value, 10);\n }\n }\n\n return { status, pid, lastExitStatus };\n } catch {\n return { status: 'unknown' };\n }\n },\n\n async readCommand(env?: GatewayServiceEnv): Promise<GatewayServiceCommandConfig | null> {\n const unitPath = resolveSystemdUserUnitPath(env);\n if (!existsSync(unitPath)) return null;\n\n const content = await readFile(unitPath, 'utf8');\n const execStartMatch = content.match(/^ExecStart=(.+)$/m);\n const workDirMatch = content.match(/^WorkingDirectory=(.+)$/m);\n\n if (!execStartMatch) return null;\n\n const execStart = execStartMatch[1].trim();\n const programArguments = execStart.split(/\\s+/);\n const environment = parseUnitEnvironment(content);\n\n return {\n programArguments,\n workingDirectory: workDirMatch?.[1],\n environment,\n sourcePath: unitPath,\n };\n },\n};\n"],"mappings":"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"}
|
|
@@ -94,7 +94,6 @@ function defaultModelId(config) {
|
|
|
94
94
|
const defaults = agents.defaults;
|
|
95
95
|
if (!isRecord(defaults)) return void 0;
|
|
96
96
|
const model = defaults.model;
|
|
97
|
-
if (typeof model === "string" && model.trim().length > 0) return model;
|
|
98
97
|
if (isRecord(model)) {
|
|
99
98
|
const primary = model.primary;
|
|
100
99
|
if (typeof primary === "string" && primary.trim().length > 0) return primary;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activation-context.js","names":["root"],"sources":["../../../src/extensions/activation-context.ts"],"sourcesContent":["/**\n * Build ActivationContext from app config + optional overrides.\n */\n\nimport type { Config } from '../config/config-surface.js';\nimport { mergeSttConfigFromAppConfig } from '../channels/attachments/voice-stt-webchat.js';\nimport { collectSttProviderConfigEntries } from '../voice/stt/config-slice.js';\nimport { isSttProviderConfigured } from '../voice/stt/list-providers.js';\nimport { collectTtsProviderConfigEntries } from '../voice/tts/config-slice.js';\nimport { isProviderConfigured } from '../voice/tts/factory.js';\nimport { mergeTtsConfigFromAppConfig } from '../voice/tts/merge-config.js';\nimport { isProviderConfiguredSync } from '../providers/index.js';\nimport { PROVIDER_ENV_MAP } from '../providers/env-keys.js';\nimport type { ActivationContext } from './activation-planner.js';\n\nfunction isRecord(x: unknown): x is Record<string, unknown> {\n return typeof x === 'object' && x !== null && !Array.isArray(x);\n}\n\nfunction telegramConfigured(ch: Record<string, unknown> | undefined): boolean {\n if (!ch) return false;\n if (ch.enabled === true) return true;\n const accounts = ch.accounts;\n if (isRecord(accounts)) {\n for (const acc of Object.values(accounts)) {\n if (!isRecord(acc)) continue;\n if (acc.enabled === false) continue;\n if (typeof acc.botToken === 'string' && acc.botToken.trim().length > 0) return true;\n }\n }\n return false;\n}\n\nfunction weixinConfigured(ch: Record<string, unknown> | undefined): boolean {\n if (!ch) return false;\n if (ch.enabled === true) return true;\n const accounts = ch.accounts;\n if (isRecord(accounts) && Object.keys(accounts).length > 0) {\n for (const acc of Object.values(accounts)) {\n if (isRecord(acc) && acc.enabled === false) continue;\n return true;\n }\n }\n return false;\n}\n\n/**\n * Derive configured channel plugin ids from `channels.*` config.\n */\nexport function collectConfiguredChannelIds(config: unknown): string[] | undefined {\n const root = config as Record<string, unknown> | undefined;\n const channels = root?.channels;\n if (!isRecord(channels)) return undefined;\n\n const ids: string[] = [];\n\n if (telegramConfigured(channels.telegram as Record<string, unknown> | undefined)) {\n ids.push('telegram');\n }\n if (weixinConfigured(channels.weixin as Record<string, unknown> | undefined)) {\n ids.push('weixin');\n }\n\n for (const [key, value] of Object.entries(channels)) {\n if (key === 'telegram' || key === 'weixin') continue;\n if (isRecord(value) && value.enabled === true && !ids.includes(key)) {\n ids.push(key);\n }\n }\n\n return ids.length ? ids : undefined;\n}\n\nfunction collectConfiguredLlmProviderIds(config: unknown): string[] {\n const root = config as Record<string, unknown> | undefined;\n const candidateIds = new Set<string>(Object.keys(PROVIDER_ENV_MAP));\n const providers = root?.providers;\n if (isRecord(providers)) {\n for (const key of Object.keys(providers)) {\n candidateIds.add(key);\n }\n }\n const ids: string[] = [];\n for (const key of candidateIds) {\n if (isProviderConfiguredSync(key)) {\n ids.push(key);\n }\n }\n return ids;\n}\n\nfunction collectConfiguredSpeechProviderIds(config: unknown): string[] {\n const root = config as Record<string, unknown> | undefined;\n const messages = root?.messages;\n if (!isRecord(messages) || !isRecord(messages.tts)) {\n return [];\n }\n\n const ttsConfig = mergeTtsConfigFromAppConfig(messages.tts);\n const ids = new Set<string>();\n const primary = ttsConfig.provider?.trim();\n if (primary && isProviderConfigured(primary, ttsConfig)) {\n ids.add(primary);\n }\n for (const providerId of Object.keys(collectTtsProviderConfigEntries(ttsConfig))) {\n if (isProviderConfigured(providerId, ttsConfig)) {\n ids.add(providerId);\n }\n }\n return [...ids];\n}\n\nfunction collectConfiguredMediaUnderstandingProviderIds(config: unknown): string[] {\n const root = config as Record<string, unknown> | undefined;\n const tools = root?.tools;\n if (!isRecord(tools) || !isRecord(tools.media)) {\n return [];\n }\n\n const sttConfig = mergeSttConfigFromAppConfig(\n tools.media.audio as Parameters<typeof mergeSttConfigFromAppConfig>[0],\n tools.media as Parameters<typeof mergeSttConfigFromAppConfig>[1],\n );\n const ids = new Set<string>();\n const primary = sttConfig.provider?.trim();\n if (primary && isSttProviderConfigured(primary, sttConfig)) {\n ids.add(primary);\n }\n for (const providerId of Object.keys(collectSttProviderConfigEntries(sttConfig))) {\n if (isSttProviderConfigured(providerId, sttConfig)) {\n ids.add(providerId);\n }\n }\n return [...ids];\n}\n\n/**\n * Derive configured provider ids for extension activation (LLM + speech + STT).\n */\nexport function collectConfiguredProviderIds(config: unknown): string[] | undefined {\n const ids = new Set<string>([\n ...collectConfiguredLlmProviderIds(config),\n ...collectConfiguredSpeechProviderIds(config),\n ...collectConfiguredMediaUnderstandingProviderIds(config),\n ]);\n return ids.size > 0 ? [...ids] : undefined;\n}\n\nfunction defaultModelId(config: unknown): string | undefined {\n const root = config as Record<string, unknown> | undefined;\n const agents = root?.agents;\n if (!isRecord(agents)) return undefined;\n const defaults = agents.defaults;\n if (!isRecord(defaults)) return undefined;\n const model = defaults.model;\n if (typeof model === 'string' && model.trim().length > 0) return model;\n if (isRecord(model)) {\n const primary = model.primary;\n if (typeof primary === 'string' && primary.trim().length > 0) return primary;\n }\n return undefined;\n}\n\n/**\n * Merge partial activation context over values inferred from loaded app config.\n */\nexport function mergeActivationContext(\n appConfig: Config | Record<string, unknown> | undefined,\n partial?: Partial<ActivationContext>,\n): ActivationContext {\n const ext = appConfig && isRecord((appConfig as Record<string, unknown>).extensions)\n ? ((appConfig as Record<string, unknown>).extensions as Record<string, unknown>)\n : undefined;\n\n const base: ActivationContext = {\n enabledIds: Array.isArray(ext?.enabled)\n ? ext!.enabled.filter((x): x is string => typeof x === 'string')\n : undefined,\n disabledIds: Array.isArray(ext?.disabled)\n ? ext!.disabled.filter((x): x is string => typeof x === 'string')\n : undefined,\n requestedModelId: defaultModelId(appConfig),\n configuredProviderIds: collectConfiguredProviderIds(appConfig),\n configuredChannelIds: collectConfiguredChannelIds(appConfig),\n env: process.env,\n };\n\n return {\n env: partial?.env ?? base.env,\n enabledIds: partial?.enabledIds !== undefined ? partial.enabledIds : base.enabledIds,\n disabledIds: partial?.disabledIds !== undefined ? partial.disabledIds : base.disabledIds,\n requestedModelId:\n partial?.requestedModelId !== undefined ? partial.requestedModelId : base.requestedModelId,\n configuredProviderIds:\n partial?.configuredProviderIds !== undefined\n ? partial.configuredProviderIds\n : base.configuredProviderIds,\n configuredChannelIds:\n partial?.configuredChannelIds !== undefined\n ? partial.configuredChannelIds\n : base.configuredChannelIds,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"activation-context.js","names":["root"],"sources":["../../../src/extensions/activation-context.ts"],"sourcesContent":["/**\n * Build ActivationContext from app config + optional overrides.\n */\n\nimport type { Config } from '../config/config-surface.js';\nimport { mergeSttConfigFromAppConfig } from '../channels/attachments/voice-stt-webchat.js';\nimport { collectSttProviderConfigEntries } from '../voice/stt/config-slice.js';\nimport { isSttProviderConfigured } from '../voice/stt/list-providers.js';\nimport { collectTtsProviderConfigEntries } from '../voice/tts/config-slice.js';\nimport { isProviderConfigured } from '../voice/tts/factory.js';\nimport { mergeTtsConfigFromAppConfig } from '../voice/tts/merge-config.js';\nimport { isProviderConfiguredSync } from '../providers/index.js';\nimport { PROVIDER_ENV_MAP } from '../providers/env-keys.js';\nimport type { ActivationContext } from './activation-planner.js';\n\nfunction isRecord(x: unknown): x is Record<string, unknown> {\n return typeof x === 'object' && x !== null && !Array.isArray(x);\n}\n\nfunction telegramConfigured(ch: Record<string, unknown> | undefined): boolean {\n if (!ch) return false;\n if (ch.enabled === true) return true;\n const accounts = ch.accounts;\n if (isRecord(accounts)) {\n for (const acc of Object.values(accounts)) {\n if (!isRecord(acc)) continue;\n if (acc.enabled === false) continue;\n if (typeof acc.botToken === 'string' && acc.botToken.trim().length > 0) return true;\n }\n }\n return false;\n}\n\nfunction weixinConfigured(ch: Record<string, unknown> | undefined): boolean {\n if (!ch) return false;\n if (ch.enabled === true) return true;\n const accounts = ch.accounts;\n if (isRecord(accounts) && Object.keys(accounts).length > 0) {\n for (const acc of Object.values(accounts)) {\n if (isRecord(acc) && acc.enabled === false) continue;\n return true;\n }\n }\n return false;\n}\n\n/**\n * Derive configured channel plugin ids from `channels.*` config.\n */\nexport function collectConfiguredChannelIds(config: unknown): string[] | undefined {\n const root = config as Record<string, unknown> | undefined;\n const channels = root?.channels;\n if (!isRecord(channels)) return undefined;\n\n const ids: string[] = [];\n\n if (telegramConfigured(channels.telegram as Record<string, unknown> | undefined)) {\n ids.push('telegram');\n }\n if (weixinConfigured(channels.weixin as Record<string, unknown> | undefined)) {\n ids.push('weixin');\n }\n\n for (const [key, value] of Object.entries(channels)) {\n if (key === 'telegram' || key === 'weixin') continue;\n if (isRecord(value) && value.enabled === true && !ids.includes(key)) {\n ids.push(key);\n }\n }\n\n return ids.length ? ids : undefined;\n}\n\nfunction collectConfiguredLlmProviderIds(config: unknown): string[] {\n const root = config as Record<string, unknown> | undefined;\n const candidateIds = new Set<string>(Object.keys(PROVIDER_ENV_MAP));\n const providers = root?.providers;\n if (isRecord(providers)) {\n for (const key of Object.keys(providers)) {\n candidateIds.add(key);\n }\n }\n const ids: string[] = [];\n for (const key of candidateIds) {\n if (isProviderConfiguredSync(key)) {\n ids.push(key);\n }\n }\n return ids;\n}\n\nfunction collectConfiguredSpeechProviderIds(config: unknown): string[] {\n const root = config as Record<string, unknown> | undefined;\n const messages = root?.messages;\n if (!isRecord(messages) || !isRecord(messages.tts)) {\n return [];\n }\n\n const ttsConfig = mergeTtsConfigFromAppConfig(messages.tts);\n const ids = new Set<string>();\n const primary = ttsConfig.provider?.trim();\n if (primary && isProviderConfigured(primary, ttsConfig)) {\n ids.add(primary);\n }\n for (const providerId of Object.keys(collectTtsProviderConfigEntries(ttsConfig))) {\n if (isProviderConfigured(providerId, ttsConfig)) {\n ids.add(providerId);\n }\n }\n return [...ids];\n}\n\nfunction collectConfiguredMediaUnderstandingProviderIds(config: unknown): string[] {\n const root = config as Record<string, unknown> | undefined;\n const tools = root?.tools;\n if (!isRecord(tools) || !isRecord(tools.media)) {\n return [];\n }\n\n const sttConfig = mergeSttConfigFromAppConfig(\n tools.media.audio as Parameters<typeof mergeSttConfigFromAppConfig>[0],\n tools.media as Parameters<typeof mergeSttConfigFromAppConfig>[1],\n );\n const ids = new Set<string>();\n const primary = sttConfig.provider?.trim();\n if (primary && isSttProviderConfigured(primary, sttConfig)) {\n ids.add(primary);\n }\n for (const providerId of Object.keys(collectSttProviderConfigEntries(sttConfig))) {\n if (isSttProviderConfigured(providerId, sttConfig)) {\n ids.add(providerId);\n }\n }\n return [...ids];\n}\n\n/**\n * Derive configured provider ids for extension activation (LLM + speech + STT).\n */\nexport function collectConfiguredProviderIds(config: unknown): string[] | undefined {\n const ids = new Set<string>([\n ...collectConfiguredLlmProviderIds(config),\n ...collectConfiguredSpeechProviderIds(config),\n ...collectConfiguredMediaUnderstandingProviderIds(config),\n ]);\n return ids.size > 0 ? [...ids] : undefined;\n}\n\nfunction defaultModelId(config: unknown): string | undefined {\n const root = config as Record<string, unknown> | undefined;\n const agents = root?.agents;\n if (!isRecord(agents)) return undefined;\n const defaults = agents.defaults;\n if (!isRecord(defaults)) return undefined;\n const model = defaults.model;\n if (isRecord(model)) {\n const primary = model.primary;\n if (typeof primary === 'string' && primary.trim().length > 0) return primary;\n }\n return undefined;\n}\n\n/**\n * Merge partial activation context over values inferred from loaded app config.\n */\nexport function mergeActivationContext(\n appConfig: Config | Record<string, unknown> | undefined,\n partial?: Partial<ActivationContext>,\n): ActivationContext {\n const ext = appConfig && isRecord((appConfig as Record<string, unknown>).extensions)\n ? ((appConfig as Record<string, unknown>).extensions as Record<string, unknown>)\n : undefined;\n\n const base: ActivationContext = {\n enabledIds: Array.isArray(ext?.enabled)\n ? ext!.enabled.filter((x): x is string => typeof x === 'string')\n : undefined,\n disabledIds: Array.isArray(ext?.disabled)\n ? ext!.disabled.filter((x): x is string => typeof x === 'string')\n : undefined,\n requestedModelId: defaultModelId(appConfig),\n configuredProviderIds: collectConfiguredProviderIds(appConfig),\n configuredChannelIds: collectConfiguredChannelIds(appConfig),\n env: process.env,\n };\n\n return {\n env: partial?.env ?? base.env,\n enabledIds: partial?.enabledIds !== undefined ? partial.enabledIds : base.enabledIds,\n disabledIds: partial?.disabledIds !== undefined ? partial.disabledIds : base.disabledIds,\n requestedModelId:\n partial?.requestedModelId !== undefined ? partial.requestedModelId : base.requestedModelId,\n configuredProviderIds:\n partial?.configuredProviderIds !== undefined\n ? partial.configuredProviderIds\n : base.configuredProviderIds,\n configuredChannelIds:\n partial?.configuredChannelIds !== undefined\n ? partial.configuredChannelIds\n : base.configuredChannelIds,\n };\n}\n"],"mappings":"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"}
|
|
@@ -54,7 +54,6 @@ function normalizeExtensionManifest(raw) {
|
|
|
54
54
|
configSchema: isRecord(raw.configSchema) ? raw.configSchema : void 0,
|
|
55
55
|
dependencies: isRecord(raw.dependencies) ? raw.dependencies : void 0,
|
|
56
56
|
enabledByDefault: typeof raw.enabledByDefault === "boolean" ? raw.enabledByDefault : void 0,
|
|
57
|
-
legacyExtensionIds: Array.isArray(raw.legacyExtensionIds) ? raw.legacyExtensionIds.filter((x) => typeof x === "string") : void 0,
|
|
58
57
|
providers: Array.isArray(raw.providers) ? raw.providers.filter((x) => typeof x === "string") : void 0,
|
|
59
58
|
speechProviders: Array.isArray(raw.speechProviders) ? raw.speechProviders.filter((x) => typeof x === "string") : void 0,
|
|
60
59
|
mediaUnderstandingProviders: Array.isArray(raw.mediaUnderstandingProviders) ? raw.mediaUnderstandingProviders.filter((x) => typeof x === "string") : void 0,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalize-manifest.js","names":[],"sources":["../../../src/extensions/normalize-manifest.ts"],"sourcesContent":["import type {\n ActivationDeclaration,\n ChatWidgetContribution,\n ChatWidgetMatch,\n CommandContribution,\n ContractDeclaration,\n EnginesDeclaration,\n ExtensionManifest,\n ExtensionManifestCommand,\n ExtensionUiContributions,\n ExtensionUiManifest,\n ExtensionUiPermission,\n ModelSupportDeclaration,\n PageContribution,\n ProviderAuthChoice,\n SettingsPanelContribution,\n SetupDeclaration,\n SidebarPanelContribution,\n StatusBarItemContribution,\n} from './types/manifest.js';\nimport type { ExtensionKind } from './types/core.js';\n\nfunction isRecord(x: unknown): x is Record<string, unknown> {\n return typeof x === 'object' && x !== null && !Array.isArray(x);\n}\n\nfunction normalizeReload(raw: unknown): ExtensionManifest['reload'] {\n if (!isRecord(raw)) return undefined;\n const configPrefixes = Array.isArray(raw.configPrefixes)\n ? raw.configPrefixes.filter((x): x is string => typeof x === 'string')\n : undefined;\n const supportsHotReload =\n typeof raw.supportsHotReload === 'boolean' ? raw.supportsHotReload : undefined;\n if (!configPrefixes?.length && supportsHotReload === undefined) return undefined;\n return {\n ...(configPrefixes?.length ? { configPrefixes } : {}),\n ...(supportsHotReload !== undefined ? { supportsHotReload } : {}),\n };\n}\n\nfunction normalizeEngines(raw: unknown): EnginesDeclaration | undefined {\n if (!isRecord(raw)) return undefined;\n const xopc = typeof raw.xopc === 'string' && raw.xopc.length > 0 ? raw.xopc : undefined;\n if (!xopc) return undefined;\n return { xopc };\n}\n\nfunction normalizeManifestCommands(raw: unknown): ExtensionManifestCommand[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const out: ExtensionManifestCommand[] = [];\n for (const item of raw) {\n if (!isRecord(item)) continue;\n const name = typeof item.name === 'string' ? item.name.trim() : '';\n const description = typeof item.description === 'string' ? item.description : '';\n if (!name || !description) continue;\n const aliases = Array.isArray(item.aliases)\n ? item.aliases.filter((x): x is string => typeof x === 'string')\n : undefined;\n const scope = Array.isArray(item.scope)\n ? item.scope.filter(\n (x): x is 'global' | 'private' | 'group' =>\n x === 'global' || x === 'private' || x === 'group',\n )\n : undefined;\n const examples = Array.isArray(item.examples)\n ? item.examples.filter((x): x is string => typeof x === 'string')\n : undefined;\n out.push({\n name,\n description,\n ...(aliases?.length ? { aliases } : {}),\n ...(scope?.length ? { scope } : {}),\n ...(examples?.length ? { examples } : {}),\n });\n }\n return out.length > 0 ? out : undefined;\n}\n\n/**\n * Normalize raw JSON manifest into ExtensionManifest with stable optional fields.\n */\nexport function normalizeExtensionManifest(raw: Record<string, unknown>): ExtensionManifest {\n const id = String(raw.id ?? '');\n return {\n id,\n name: typeof raw.name === 'string' && raw.name.length > 0 ? raw.name : id,\n description: typeof raw.description === 'string' ? raw.description : undefined,\n version: typeof raw.version === 'string' ? raw.version : undefined,\n kind: raw.kind as ExtensionKind | undefined,\n main: typeof raw.main === 'string' ? raw.main : undefined,\n configSchema: isRecord(raw.configSchema) ? (raw.configSchema as Record<string, unknown>) : undefined,\n dependencies: isRecord(raw.dependencies) ? (raw.dependencies as Record<string, string>) : undefined,\n\n enabledByDefault: typeof raw.enabledByDefault === 'boolean' ? raw.enabledByDefault : undefined,\n legacyExtensionIds: Array.isArray(raw.legacyExtensionIds)\n ? raw.legacyExtensionIds.filter((x): x is string => typeof x === 'string')\n : undefined,\n\n providers: Array.isArray(raw.providers)\n ? raw.providers.filter((x): x is string => typeof x === 'string')\n : undefined,\n speechProviders: Array.isArray(raw.speechProviders)\n ? raw.speechProviders.filter((x): x is string => typeof x === 'string')\n : undefined,\n mediaUnderstandingProviders: Array.isArray(raw.mediaUnderstandingProviders)\n ? raw.mediaUnderstandingProviders.filter((x): x is string => typeof x === 'string')\n : undefined,\n providerAuthEnvVars: normalizeStringArrayMap(raw.providerAuthEnvVars),\n providerAuthChoices: normalizeProviderAuthChoices(raw.providerAuthChoices),\n modelSupport: normalizeModelSupport(raw.modelSupport),\n autoEnableWhenConfiguredProviders: Array.isArray(raw.autoEnableWhenConfiguredProviders)\n ? raw.autoEnableWhenConfiguredProviders.filter((x): x is string => typeof x === 'string')\n : undefined,\n\n channels: Array.isArray(raw.channels)\n ? raw.channels.filter((x): x is string => typeof x === 'string')\n : undefined,\n channelEnvVars: normalizeStringArrayMap(raw.channelEnvVars),\n\n activation: normalizeActivation(raw.activation),\n contracts: normalizeContracts(raw.contracts),\n setup: normalizeSetup(raw.setup),\n reload: normalizeReload(raw.reload),\n engines: normalizeEngines(raw.engines),\n commands: normalizeManifestCommands(raw.commands),\n ui: normalizeUiManifest(raw.ui),\n };\n}\n\nconst VALID_UI_PERMISSIONS = new Set<ExtensionUiPermission>([\n 'agent.send',\n 'agent.subscribe',\n 'session.read',\n 'session.write',\n 'config.read',\n 'config.write',\n 'storage',\n 'notification',\n 'clipboard',\n 'theme',\n 'workspace.read',\n 'workspace.write',\n]);\n\nexport function normalizeUiManifest(raw: unknown): ExtensionUiManifest | undefined {\n if (raw === undefined || raw === null) return undefined;\n if (!isRecord(raw)) return undefined;\n const main = typeof raw.main === 'string' && raw.main.length > 0 ? raw.main : undefined;\n const icon = typeof raw.icon === 'string' && raw.icon.length > 0 ? raw.icon : undefined;\n let permissions: ExtensionUiPermission[] | undefined;\n if (Array.isArray(raw.permissions)) {\n const p = raw.permissions.filter(\n (x): x is ExtensionUiPermission =>\n typeof x === 'string' && VALID_UI_PERMISSIONS.has(x as ExtensionUiPermission),\n );\n permissions = p.length ? p : undefined;\n }\n const contributions = normalizeUiContributions(raw.contributions);\n if (!main && !icon && !permissions && !contributions) return undefined;\n return {\n ...(main !== undefined ? { main } : {}),\n ...(icon !== undefined ? { icon } : {}),\n ...(permissions !== undefined ? { permissions } : {}),\n ...(contributions !== undefined ? { contributions } : {}),\n };\n}\n\nfunction normalizeUiContributions(raw: unknown): ExtensionUiContributions | undefined {\n if (!isRecord(raw)) return undefined;\n const sidebarPanels = normalizeSidebarPanels(raw.sidebarPanels);\n const settingsPanels = normalizeSettingsPanels(raw.settingsPanels);\n const chatWidgets = normalizeChatWidgets(raw.chatWidgets);\n const pages = normalizePages(raw.pages);\n const commands = normalizeCommands(raw.commands);\n const statusBarItems = normalizeStatusBarItems(raw.statusBarItems);\n const out: ExtensionUiContributions = {\n ...(sidebarPanels ? { sidebarPanels } : {}),\n ...(settingsPanels ? { settingsPanels } : {}),\n ...(chatWidgets ? { chatWidgets } : {}),\n ...(pages ? { pages } : {}),\n ...(commands ? { commands } : {}),\n ...(statusBarItems ? { statusBarItems } : {}),\n };\n return Object.keys(out).length ? out : undefined;\n}\n\nfunction normalizeSidebarPanels(raw: unknown): SidebarPanelContribution[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const out: SidebarPanelContribution[] = [];\n for (const item of raw) {\n if (!isRecord(item)) continue;\n const id = item.id;\n const title = item.title;\n const entrypoint = item.entrypoint;\n if (typeof id !== 'string' || typeof title !== 'string' || typeof entrypoint !== 'string') {\n continue;\n }\n out.push({\n id,\n title,\n entrypoint,\n icon: typeof item.icon === 'string' ? item.icon : undefined,\n defaultVisible: typeof item.defaultVisible === 'boolean' ? item.defaultVisible : undefined,\n when: typeof item.when === 'string' && item.when.length > 0 ? item.when : undefined,\n });\n }\n return out.length ? out : undefined;\n}\n\nfunction normalizeSettingsPanels(raw: unknown): SettingsPanelContribution[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const out: SettingsPanelContribution[] = [];\n for (const item of raw) {\n if (!isRecord(item)) continue;\n const id = item.id;\n const title = item.title;\n const entrypoint = item.entrypoint;\n if (typeof id !== 'string' || typeof title !== 'string' || typeof entrypoint !== 'string') {\n continue;\n }\n out.push({\n id,\n title,\n entrypoint,\n order: typeof item.order === 'number' ? item.order : undefined,\n });\n }\n return out.length ? out : undefined;\n}\n\nfunction normalizeChatWidgetMatch(raw: unknown): ChatWidgetMatch | undefined {\n if (!isRecord(raw)) return undefined;\n const toolName = typeof raw.toolName === 'string' ? raw.toolName : undefined;\n const contentType = typeof raw.contentType === 'string' ? raw.contentType : undefined;\n let metadata: Record<string, unknown> | undefined;\n if (isRecord(raw.metadata)) {\n metadata = { ...raw.metadata };\n }\n if (!toolName && !contentType && !metadata) return undefined;\n return { toolName, contentType, metadata };\n}\n\nfunction normalizeChatWidgets(raw: unknown): ChatWidgetContribution[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const out: ChatWidgetContribution[] = [];\n for (const item of raw) {\n if (!isRecord(item)) continue;\n const id = item.id;\n const title = item.title;\n const entrypoint = item.entrypoint;\n if (typeof id !== 'string' || typeof title !== 'string' || typeof entrypoint !== 'string') {\n continue;\n }\n const match = normalizeChatWidgetMatch(item.match);\n if (!match) continue;\n out.push({\n id,\n title,\n entrypoint,\n match,\n maxHeight: typeof item.maxHeight === 'number' ? item.maxHeight : undefined,\n interactive: typeof item.interactive === 'boolean' ? item.interactive : undefined,\n });\n }\n return out.length ? out : undefined;\n}\n\nfunction normalizePages(raw: unknown): PageContribution[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const out: PageContribution[] = [];\n for (const item of raw) {\n if (!isRecord(item)) continue;\n const id = item.id;\n const title = item.title;\n const path = item.path;\n const entrypoint = item.entrypoint;\n if (\n typeof id !== 'string' ||\n typeof title !== 'string' ||\n typeof path !== 'string' ||\n typeof entrypoint !== 'string'\n ) {\n continue;\n }\n out.push({\n id,\n title,\n path,\n entrypoint,\n showInNav: typeof item.showInNav === 'boolean' ? item.showInNav : undefined,\n navIcon: typeof item.navIcon === 'string' ? item.navIcon : undefined,\n when: typeof item.when === 'string' && item.when.length > 0 ? item.when : undefined,\n });\n }\n return out.length ? out : undefined;\n}\n\nfunction normalizeCommands(raw: unknown): CommandContribution[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const out: CommandContribution[] = [];\n for (const item of raw) {\n if (!isRecord(item)) continue;\n const id = item.id;\n const title = item.title;\n if (typeof id !== 'string' || typeof title !== 'string') continue;\n out.push({\n id,\n title,\n shortcut: typeof item.shortcut === 'string' ? item.shortcut : undefined,\n opensPanel: typeof item.opensPanel === 'string' ? item.opensPanel : undefined,\n chatAlias:\n typeof item.chatAlias === 'string' && item.chatAlias.length > 0 ? item.chatAlias : undefined,\n when: typeof item.when === 'string' && item.when.length > 0 ? item.when : undefined,\n });\n }\n return out.length ? out : undefined;\n}\n\nfunction normalizeStatusBarItems(raw: unknown): StatusBarItemContribution[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const out: StatusBarItemContribution[] = [];\n for (const item of raw) {\n if (!isRecord(item)) continue;\n const id = item.id;\n const entrypoint = item.entrypoint;\n if (typeof id !== 'string' || typeof entrypoint !== 'string') continue;\n const position = item.position;\n out.push({\n id,\n entrypoint,\n position: position === 'left' || position === 'right' ? position : undefined,\n width: typeof item.width === 'number' ? item.width : undefined,\n when: typeof item.when === 'string' && item.when.length > 0 ? item.when : undefined,\n });\n }\n return out.length ? out : undefined;\n}\n\nfunction normalizeStringArrayMap(\n raw: unknown,\n): Record<string, string[]> | undefined {\n if (!isRecord(raw)) return undefined;\n const out: Record<string, string[]> = {};\n for (const [k, v] of Object.entries(raw)) {\n if (Array.isArray(v)) {\n const arr = v.filter((x): x is string => typeof x === 'string');\n if (arr.length) out[k] = arr;\n }\n }\n return Object.keys(out).length ? out : undefined;\n}\n\nfunction normalizeProviderAuthChoices(raw: unknown): ProviderAuthChoice[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const out: ProviderAuthChoice[] = [];\n for (const item of raw) {\n if (!isRecord(item)) continue;\n const provider = item.provider;\n const method = item.method;\n const choiceId = item.choiceId;\n const choiceLabel = item.choiceLabel;\n if (\n typeof provider !== 'string' ||\n typeof choiceId !== 'string' ||\n typeof choiceLabel !== 'string' ||\n (method !== 'api-key' && method !== 'oauth' && method !== 'cli' && method !== 'env')\n ) {\n continue;\n }\n out.push({\n provider,\n method,\n choiceId,\n choiceLabel,\n choiceHint: typeof item.choiceHint === 'string' ? item.choiceHint : undefined,\n groupId: typeof item.groupId === 'string' ? item.groupId : undefined,\n groupLabel: typeof item.groupLabel === 'string' ? item.groupLabel : undefined,\n groupHint: typeof item.groupHint === 'string' ? item.groupHint : undefined,\n cliFlag: typeof item.cliFlag === 'string' ? item.cliFlag : undefined,\n cliOption: typeof item.cliOption === 'string' ? item.cliOption : undefined,\n cliDescription: typeof item.cliDescription === 'string' ? item.cliDescription : undefined,\n });\n }\n return out.length ? out : undefined;\n}\n\nfunction normalizeModelSupport(raw: unknown): ModelSupportDeclaration | undefined {\n if (!isRecord(raw)) return undefined;\n const modelPrefixes = Array.isArray(raw.modelPrefixes)\n ? raw.modelPrefixes.filter((x): x is string => typeof x === 'string')\n : undefined;\n const modelPatterns = Array.isArray(raw.modelPatterns)\n ? raw.modelPatterns.filter((x): x is string => typeof x === 'string')\n : undefined;\n if (!modelPrefixes?.length && !modelPatterns?.length) return undefined;\n return { modelPrefixes, modelPatterns };\n}\n\nfunction normalizeActivation(raw: unknown): ActivationDeclaration | undefined {\n if (!isRecord(raw)) return undefined;\n const onStartup = typeof raw.onStartup === 'boolean' ? raw.onStartup : undefined;\n const onProviders = Array.isArray(raw.onProviders)\n ? raw.onProviders.filter((x): x is string => typeof x === 'string')\n : undefined;\n const onCommands = Array.isArray(raw.onCommands)\n ? raw.onCommands.filter((x): x is string => typeof x === 'string')\n : undefined;\n const onChannels = Array.isArray(raw.onChannels)\n ? raw.onChannels.filter((x): x is string => typeof x === 'string')\n : undefined;\n const capRaw = raw.onCapabilities;\n const onCapabilities = Array.isArray(capRaw)\n ? capRaw.filter(\n (x): x is 'provider' | 'channel' | 'tool' | 'hook' =>\n x === 'provider' || x === 'channel' || x === 'tool' || x === 'hook',\n )\n : undefined;\n if (\n onStartup === undefined &&\n !onProviders?.length &&\n !onCommands?.length &&\n !onChannels?.length &&\n !onCapabilities?.length\n ) {\n return undefined;\n }\n return { onStartup, onProviders, onCommands, onChannels, onCapabilities };\n}\n\nfunction normalizeContracts(raw: unknown): ContractDeclaration | undefined {\n if (!isRecord(raw)) return undefined;\n const pick = (k: string) =>\n Array.isArray(raw[k]) ? raw[k].filter((x: unknown): x is string => typeof x === 'string') : undefined;\n const c: ContractDeclaration = {\n mediaUnderstandingProviders: pick('mediaUnderstandingProviders'),\n speechProviders: pick('speechProviders'),\n imageGenerationProviders: pick('imageGenerationProviders'),\n webSearchProviders: pick('webSearchProviders'),\n memoryProviders: pick('memoryProviders'),\n };\n if (\n !c.mediaUnderstandingProviders?.length &&\n !c.speechProviders?.length &&\n !c.imageGenerationProviders?.length &&\n !c.webSearchProviders?.length &&\n !c.memoryProviders?.length\n ) {\n return undefined;\n }\n return c;\n}\n\nfunction normalizeSetup(raw: unknown): SetupDeclaration | undefined {\n if (!isRecord(raw)) return undefined;\n const requiresRuntime = typeof raw.requiresRuntime === 'boolean' ? raw.requiresRuntime : undefined;\n let providers: SetupDeclaration['providers'];\n if (Array.isArray(raw.providers)) {\n providers = [];\n for (const p of raw.providers) {\n if (!isRecord(p) || typeof p.id !== 'string') continue;\n providers.push({\n id: p.id,\n authMethods: Array.isArray(p.authMethods)\n ? p.authMethods.filter((x): x is string => typeof x === 'string')\n : undefined,\n envVars: Array.isArray(p.envVars)\n ? p.envVars.filter((x): x is string => typeof x === 'string')\n : undefined,\n });\n }\n if (providers.length === 0) providers = undefined;\n }\n if (!providers && requiresRuntime === undefined) return undefined;\n return { providers, requiresRuntime };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"normalize-manifest.js","names":[],"sources":["../../../src/extensions/normalize-manifest.ts"],"sourcesContent":["import type {\n ActivationDeclaration,\n ChatWidgetContribution,\n ChatWidgetMatch,\n CommandContribution,\n ContractDeclaration,\n EnginesDeclaration,\n ExtensionManifest,\n ExtensionManifestCommand,\n ExtensionUiContributions,\n ExtensionUiManifest,\n ExtensionUiPermission,\n ModelSupportDeclaration,\n PageContribution,\n ProviderAuthChoice,\n SettingsPanelContribution,\n SetupDeclaration,\n SidebarPanelContribution,\n StatusBarItemContribution,\n} from './types/manifest.js';\nimport type { ExtensionKind } from './types/core.js';\n\nfunction isRecord(x: unknown): x is Record<string, unknown> {\n return typeof x === 'object' && x !== null && !Array.isArray(x);\n}\n\nfunction normalizeReload(raw: unknown): ExtensionManifest['reload'] {\n if (!isRecord(raw)) return undefined;\n const configPrefixes = Array.isArray(raw.configPrefixes)\n ? raw.configPrefixes.filter((x): x is string => typeof x === 'string')\n : undefined;\n const supportsHotReload =\n typeof raw.supportsHotReload === 'boolean' ? raw.supportsHotReload : undefined;\n if (!configPrefixes?.length && supportsHotReload === undefined) return undefined;\n return {\n ...(configPrefixes?.length ? { configPrefixes } : {}),\n ...(supportsHotReload !== undefined ? { supportsHotReload } : {}),\n };\n}\n\nfunction normalizeEngines(raw: unknown): EnginesDeclaration | undefined {\n if (!isRecord(raw)) return undefined;\n const xopc = typeof raw.xopc === 'string' && raw.xopc.length > 0 ? raw.xopc : undefined;\n if (!xopc) return undefined;\n return { xopc };\n}\n\nfunction normalizeManifestCommands(raw: unknown): ExtensionManifestCommand[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const out: ExtensionManifestCommand[] = [];\n for (const item of raw) {\n if (!isRecord(item)) continue;\n const name = typeof item.name === 'string' ? item.name.trim() : '';\n const description = typeof item.description === 'string' ? item.description : '';\n if (!name || !description) continue;\n const aliases = Array.isArray(item.aliases)\n ? item.aliases.filter((x): x is string => typeof x === 'string')\n : undefined;\n const scope = Array.isArray(item.scope)\n ? item.scope.filter(\n (x): x is 'global' | 'private' | 'group' =>\n x === 'global' || x === 'private' || x === 'group',\n )\n : undefined;\n const examples = Array.isArray(item.examples)\n ? item.examples.filter((x): x is string => typeof x === 'string')\n : undefined;\n out.push({\n name,\n description,\n ...(aliases?.length ? { aliases } : {}),\n ...(scope?.length ? { scope } : {}),\n ...(examples?.length ? { examples } : {}),\n });\n }\n return out.length > 0 ? out : undefined;\n}\n\n/**\n * Normalize raw JSON manifest into ExtensionManifest with stable optional fields.\n */\nexport function normalizeExtensionManifest(raw: Record<string, unknown>): ExtensionManifest {\n const id = String(raw.id ?? '');\n return {\n id,\n name: typeof raw.name === 'string' && raw.name.length > 0 ? raw.name : id,\n description: typeof raw.description === 'string' ? raw.description : undefined,\n version: typeof raw.version === 'string' ? raw.version : undefined,\n kind: raw.kind as ExtensionKind | undefined,\n main: typeof raw.main === 'string' ? raw.main : undefined,\n configSchema: isRecord(raw.configSchema) ? (raw.configSchema as Record<string, unknown>) : undefined,\n dependencies: isRecord(raw.dependencies) ? (raw.dependencies as Record<string, string>) : undefined,\n\n enabledByDefault: typeof raw.enabledByDefault === 'boolean' ? raw.enabledByDefault : undefined,\n\n providers: Array.isArray(raw.providers)\n ? raw.providers.filter((x): x is string => typeof x === 'string')\n : undefined,\n speechProviders: Array.isArray(raw.speechProviders)\n ? raw.speechProviders.filter((x): x is string => typeof x === 'string')\n : undefined,\n mediaUnderstandingProviders: Array.isArray(raw.mediaUnderstandingProviders)\n ? raw.mediaUnderstandingProviders.filter((x): x is string => typeof x === 'string')\n : undefined,\n providerAuthEnvVars: normalizeStringArrayMap(raw.providerAuthEnvVars),\n providerAuthChoices: normalizeProviderAuthChoices(raw.providerAuthChoices),\n modelSupport: normalizeModelSupport(raw.modelSupport),\n autoEnableWhenConfiguredProviders: Array.isArray(raw.autoEnableWhenConfiguredProviders)\n ? raw.autoEnableWhenConfiguredProviders.filter((x): x is string => typeof x === 'string')\n : undefined,\n\n channels: Array.isArray(raw.channels)\n ? raw.channels.filter((x): x is string => typeof x === 'string')\n : undefined,\n channelEnvVars: normalizeStringArrayMap(raw.channelEnvVars),\n\n activation: normalizeActivation(raw.activation),\n contracts: normalizeContracts(raw.contracts),\n setup: normalizeSetup(raw.setup),\n reload: normalizeReload(raw.reload),\n engines: normalizeEngines(raw.engines),\n commands: normalizeManifestCommands(raw.commands),\n ui: normalizeUiManifest(raw.ui),\n };\n}\n\nconst VALID_UI_PERMISSIONS = new Set<ExtensionUiPermission>([\n 'agent.send',\n 'agent.subscribe',\n 'session.read',\n 'session.write',\n 'config.read',\n 'config.write',\n 'storage',\n 'notification',\n 'clipboard',\n 'theme',\n 'workspace.read',\n 'workspace.write',\n]);\n\nexport function normalizeUiManifest(raw: unknown): ExtensionUiManifest | undefined {\n if (raw === undefined || raw === null) return undefined;\n if (!isRecord(raw)) return undefined;\n const main = typeof raw.main === 'string' && raw.main.length > 0 ? raw.main : undefined;\n const icon = typeof raw.icon === 'string' && raw.icon.length > 0 ? raw.icon : undefined;\n let permissions: ExtensionUiPermission[] | undefined;\n if (Array.isArray(raw.permissions)) {\n const p = raw.permissions.filter(\n (x): x is ExtensionUiPermission =>\n typeof x === 'string' && VALID_UI_PERMISSIONS.has(x as ExtensionUiPermission),\n );\n permissions = p.length ? p : undefined;\n }\n const contributions = normalizeUiContributions(raw.contributions);\n if (!main && !icon && !permissions && !contributions) return undefined;\n return {\n ...(main !== undefined ? { main } : {}),\n ...(icon !== undefined ? { icon } : {}),\n ...(permissions !== undefined ? { permissions } : {}),\n ...(contributions !== undefined ? { contributions } : {}),\n };\n}\n\nfunction normalizeUiContributions(raw: unknown): ExtensionUiContributions | undefined {\n if (!isRecord(raw)) return undefined;\n const sidebarPanels = normalizeSidebarPanels(raw.sidebarPanels);\n const settingsPanels = normalizeSettingsPanels(raw.settingsPanels);\n const chatWidgets = normalizeChatWidgets(raw.chatWidgets);\n const pages = normalizePages(raw.pages);\n const commands = normalizeCommands(raw.commands);\n const statusBarItems = normalizeStatusBarItems(raw.statusBarItems);\n const out: ExtensionUiContributions = {\n ...(sidebarPanels ? { sidebarPanels } : {}),\n ...(settingsPanels ? { settingsPanels } : {}),\n ...(chatWidgets ? { chatWidgets } : {}),\n ...(pages ? { pages } : {}),\n ...(commands ? { commands } : {}),\n ...(statusBarItems ? { statusBarItems } : {}),\n };\n return Object.keys(out).length ? out : undefined;\n}\n\nfunction normalizeSidebarPanels(raw: unknown): SidebarPanelContribution[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const out: SidebarPanelContribution[] = [];\n for (const item of raw) {\n if (!isRecord(item)) continue;\n const id = item.id;\n const title = item.title;\n const entrypoint = item.entrypoint;\n if (typeof id !== 'string' || typeof title !== 'string' || typeof entrypoint !== 'string') {\n continue;\n }\n out.push({\n id,\n title,\n entrypoint,\n icon: typeof item.icon === 'string' ? item.icon : undefined,\n defaultVisible: typeof item.defaultVisible === 'boolean' ? item.defaultVisible : undefined,\n when: typeof item.when === 'string' && item.when.length > 0 ? item.when : undefined,\n });\n }\n return out.length ? out : undefined;\n}\n\nfunction normalizeSettingsPanels(raw: unknown): SettingsPanelContribution[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const out: SettingsPanelContribution[] = [];\n for (const item of raw) {\n if (!isRecord(item)) continue;\n const id = item.id;\n const title = item.title;\n const entrypoint = item.entrypoint;\n if (typeof id !== 'string' || typeof title !== 'string' || typeof entrypoint !== 'string') {\n continue;\n }\n out.push({\n id,\n title,\n entrypoint,\n order: typeof item.order === 'number' ? item.order : undefined,\n });\n }\n return out.length ? out : undefined;\n}\n\nfunction normalizeChatWidgetMatch(raw: unknown): ChatWidgetMatch | undefined {\n if (!isRecord(raw)) return undefined;\n const toolName = typeof raw.toolName === 'string' ? raw.toolName : undefined;\n const contentType = typeof raw.contentType === 'string' ? raw.contentType : undefined;\n let metadata: Record<string, unknown> | undefined;\n if (isRecord(raw.metadata)) {\n metadata = { ...raw.metadata };\n }\n if (!toolName && !contentType && !metadata) return undefined;\n return { toolName, contentType, metadata };\n}\n\nfunction normalizeChatWidgets(raw: unknown): ChatWidgetContribution[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const out: ChatWidgetContribution[] = [];\n for (const item of raw) {\n if (!isRecord(item)) continue;\n const id = item.id;\n const title = item.title;\n const entrypoint = item.entrypoint;\n if (typeof id !== 'string' || typeof title !== 'string' || typeof entrypoint !== 'string') {\n continue;\n }\n const match = normalizeChatWidgetMatch(item.match);\n if (!match) continue;\n out.push({\n id,\n title,\n entrypoint,\n match,\n maxHeight: typeof item.maxHeight === 'number' ? item.maxHeight : undefined,\n interactive: typeof item.interactive === 'boolean' ? item.interactive : undefined,\n });\n }\n return out.length ? out : undefined;\n}\n\nfunction normalizePages(raw: unknown): PageContribution[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const out: PageContribution[] = [];\n for (const item of raw) {\n if (!isRecord(item)) continue;\n const id = item.id;\n const title = item.title;\n const path = item.path;\n const entrypoint = item.entrypoint;\n if (\n typeof id !== 'string' ||\n typeof title !== 'string' ||\n typeof path !== 'string' ||\n typeof entrypoint !== 'string'\n ) {\n continue;\n }\n out.push({\n id,\n title,\n path,\n entrypoint,\n showInNav: typeof item.showInNav === 'boolean' ? item.showInNav : undefined,\n navIcon: typeof item.navIcon === 'string' ? item.navIcon : undefined,\n when: typeof item.when === 'string' && item.when.length > 0 ? item.when : undefined,\n });\n }\n return out.length ? out : undefined;\n}\n\nfunction normalizeCommands(raw: unknown): CommandContribution[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const out: CommandContribution[] = [];\n for (const item of raw) {\n if (!isRecord(item)) continue;\n const id = item.id;\n const title = item.title;\n if (typeof id !== 'string' || typeof title !== 'string') continue;\n out.push({\n id,\n title,\n shortcut: typeof item.shortcut === 'string' ? item.shortcut : undefined,\n opensPanel: typeof item.opensPanel === 'string' ? item.opensPanel : undefined,\n chatAlias:\n typeof item.chatAlias === 'string' && item.chatAlias.length > 0 ? item.chatAlias : undefined,\n when: typeof item.when === 'string' && item.when.length > 0 ? item.when : undefined,\n });\n }\n return out.length ? out : undefined;\n}\n\nfunction normalizeStatusBarItems(raw: unknown): StatusBarItemContribution[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const out: StatusBarItemContribution[] = [];\n for (const item of raw) {\n if (!isRecord(item)) continue;\n const id = item.id;\n const entrypoint = item.entrypoint;\n if (typeof id !== 'string' || typeof entrypoint !== 'string') continue;\n const position = item.position;\n out.push({\n id,\n entrypoint,\n position: position === 'left' || position === 'right' ? position : undefined,\n width: typeof item.width === 'number' ? item.width : undefined,\n when: typeof item.when === 'string' && item.when.length > 0 ? item.when : undefined,\n });\n }\n return out.length ? out : undefined;\n}\n\nfunction normalizeStringArrayMap(\n raw: unknown,\n): Record<string, string[]> | undefined {\n if (!isRecord(raw)) return undefined;\n const out: Record<string, string[]> = {};\n for (const [k, v] of Object.entries(raw)) {\n if (Array.isArray(v)) {\n const arr = v.filter((x): x is string => typeof x === 'string');\n if (arr.length) out[k] = arr;\n }\n }\n return Object.keys(out).length ? out : undefined;\n}\n\nfunction normalizeProviderAuthChoices(raw: unknown): ProviderAuthChoice[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const out: ProviderAuthChoice[] = [];\n for (const item of raw) {\n if (!isRecord(item)) continue;\n const provider = item.provider;\n const method = item.method;\n const choiceId = item.choiceId;\n const choiceLabel = item.choiceLabel;\n if (\n typeof provider !== 'string' ||\n typeof choiceId !== 'string' ||\n typeof choiceLabel !== 'string' ||\n (method !== 'api-key' && method !== 'oauth' && method !== 'cli' && method !== 'env')\n ) {\n continue;\n }\n out.push({\n provider,\n method,\n choiceId,\n choiceLabel,\n choiceHint: typeof item.choiceHint === 'string' ? item.choiceHint : undefined,\n groupId: typeof item.groupId === 'string' ? item.groupId : undefined,\n groupLabel: typeof item.groupLabel === 'string' ? item.groupLabel : undefined,\n groupHint: typeof item.groupHint === 'string' ? item.groupHint : undefined,\n cliFlag: typeof item.cliFlag === 'string' ? item.cliFlag : undefined,\n cliOption: typeof item.cliOption === 'string' ? item.cliOption : undefined,\n cliDescription: typeof item.cliDescription === 'string' ? item.cliDescription : undefined,\n });\n }\n return out.length ? out : undefined;\n}\n\nfunction normalizeModelSupport(raw: unknown): ModelSupportDeclaration | undefined {\n if (!isRecord(raw)) return undefined;\n const modelPrefixes = Array.isArray(raw.modelPrefixes)\n ? raw.modelPrefixes.filter((x): x is string => typeof x === 'string')\n : undefined;\n const modelPatterns = Array.isArray(raw.modelPatterns)\n ? raw.modelPatterns.filter((x): x is string => typeof x === 'string')\n : undefined;\n if (!modelPrefixes?.length && !modelPatterns?.length) return undefined;\n return { modelPrefixes, modelPatterns };\n}\n\nfunction normalizeActivation(raw: unknown): ActivationDeclaration | undefined {\n if (!isRecord(raw)) return undefined;\n const onStartup = typeof raw.onStartup === 'boolean' ? raw.onStartup : undefined;\n const onProviders = Array.isArray(raw.onProviders)\n ? raw.onProviders.filter((x): x is string => typeof x === 'string')\n : undefined;\n const onCommands = Array.isArray(raw.onCommands)\n ? raw.onCommands.filter((x): x is string => typeof x === 'string')\n : undefined;\n const onChannels = Array.isArray(raw.onChannels)\n ? raw.onChannels.filter((x): x is string => typeof x === 'string')\n : undefined;\n const capRaw = raw.onCapabilities;\n const onCapabilities = Array.isArray(capRaw)\n ? capRaw.filter(\n (x): x is 'provider' | 'channel' | 'tool' | 'hook' =>\n x === 'provider' || x === 'channel' || x === 'tool' || x === 'hook',\n )\n : undefined;\n if (\n onStartup === undefined &&\n !onProviders?.length &&\n !onCommands?.length &&\n !onChannels?.length &&\n !onCapabilities?.length\n ) {\n return undefined;\n }\n return { onStartup, onProviders, onCommands, onChannels, onCapabilities };\n}\n\nfunction normalizeContracts(raw: unknown): ContractDeclaration | undefined {\n if (!isRecord(raw)) return undefined;\n const pick = (k: string) =>\n Array.isArray(raw[k]) ? raw[k].filter((x: unknown): x is string => typeof x === 'string') : undefined;\n const c: ContractDeclaration = {\n mediaUnderstandingProviders: pick('mediaUnderstandingProviders'),\n speechProviders: pick('speechProviders'),\n imageGenerationProviders: pick('imageGenerationProviders'),\n webSearchProviders: pick('webSearchProviders'),\n memoryProviders: pick('memoryProviders'),\n };\n if (\n !c.mediaUnderstandingProviders?.length &&\n !c.speechProviders?.length &&\n !c.imageGenerationProviders?.length &&\n !c.webSearchProviders?.length &&\n !c.memoryProviders?.length\n ) {\n return undefined;\n }\n return c;\n}\n\nfunction normalizeSetup(raw: unknown): SetupDeclaration | undefined {\n if (!isRecord(raw)) return undefined;\n const requiresRuntime = typeof raw.requiresRuntime === 'boolean' ? raw.requiresRuntime : undefined;\n let providers: SetupDeclaration['providers'];\n if (Array.isArray(raw.providers)) {\n providers = [];\n for (const p of raw.providers) {\n if (!isRecord(p) || typeof p.id !== 'string') continue;\n providers.push({\n id: p.id,\n authMethods: Array.isArray(p.authMethods)\n ? p.authMethods.filter((x): x is string => typeof x === 'string')\n : undefined,\n envVars: Array.isArray(p.envVars)\n ? p.envVars.filter((x): x is string => typeof x === 'string')\n : undefined,\n });\n }\n if (providers.length === 0) providers = undefined;\n }\n if (!providers && requiresRuntime === undefined) return undefined;\n return { providers, requiresRuntime };\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Extension manifest — control-plane metadata (readable without loading extension code).
|
|
3
|
-
* New fields are optional for backward compatibility.
|
|
4
3
|
*/
|
|
5
4
|
import type { ExtensionKind } from './core.js';
|
|
6
5
|
/** Declared in `engines` in the extension manifest (e.g. VSCode-style). */
|
|
@@ -18,7 +17,6 @@ export interface ExtensionManifest {
|
|
|
18
17
|
configSchema?: Record<string, unknown>;
|
|
19
18
|
dependencies?: Record<string, string>;
|
|
20
19
|
enabledByDefault?: boolean;
|
|
21
|
-
legacyExtensionIds?: string[];
|
|
22
20
|
providers?: string[];
|
|
23
21
|
/** Speech/TTS provider ids implemented by this extension. */
|
|
24
22
|
speechProviders?: string[];
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* Built-in agent tool `name` values for gateway admin UI (disable toggles).
|
|
3
3
|
* Extension tools are not listed; users can still add arbitrary strings in config.
|
|
4
4
|
*/
|
|
5
|
-
export declare const GATEWAY_BUILTIN_TOOL_IDS: readonly ["read_file", "write_file", "edit_file", "list_dir", "grep", "find", "shell", "web_search", "web_fetch", "send_message", "send_media", "memory_search", "memory_get", "curated_memory", "session_search", "image", "image_generate", "extensions", "bundle-mcp"];
|
|
5
|
+
export declare const GATEWAY_BUILTIN_TOOL_IDS: readonly ["read_file", "write_file", "edit_file", "list_dir", "grep", "find", "shell", "web_search", "web_fetch", "send_message", "send_media", "memory_search", "memory_get", "curated_memory", "session_search", "image", "image_generate", "browser_use", "extensions", "bundle-mcp"];
|
|
6
6
|
export type GatewayBuiltinToolId = (typeof GATEWAY_BUILTIN_TOOL_IDS)[number];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-builtin-tools.js","names":[],"sources":["../../../src/gateway/agent-builtin-tools.ts"],"sourcesContent":["/**\n * Built-in agent tool `name` values for gateway admin UI (disable toggles).\n * Extension tools are not listed; users can still add arbitrary strings in config.\n */\nexport const GATEWAY_BUILTIN_TOOL_IDS = [\n 'read_file',\n 'write_file',\n 'edit_file',\n 'list_dir',\n 'grep',\n 'find',\n 'shell',\n 'web_search',\n 'web_fetch',\n 'send_message',\n 'send_media',\n 'memory_search',\n 'memory_get',\n 'curated_memory',\n 'session_search',\n 'image',\n 'image_generate',\n 'extensions',\n 'bundle-mcp',\n] as const;\n\nexport type GatewayBuiltinToolId = (typeof GATEWAY_BUILTIN_TOOL_IDS)[number];\n"],"mappings":";;;;;AAIA,MAAa,2BAA2B;CACtC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD"}
|
|
1
|
+
{"version":3,"file":"agent-builtin-tools.js","names":[],"sources":["../../../src/gateway/agent-builtin-tools.ts"],"sourcesContent":["/**\n * Built-in agent tool `name` values for gateway admin UI (disable toggles).\n * Extension tools are not listed; users can still add arbitrary strings in config.\n */\nexport const GATEWAY_BUILTIN_TOOL_IDS = [\n 'read_file',\n 'write_file',\n 'edit_file',\n 'list_dir',\n 'grep',\n 'find',\n 'shell',\n 'web_search',\n 'web_fetch',\n 'send_message',\n 'send_media',\n 'memory_search',\n 'memory_get',\n 'curated_memory',\n 'session_search',\n 'image',\n 'image_generate',\n 'browser_use',\n 'extensions',\n 'bundle-mcp',\n] as const;\n\nexport type GatewayBuiltinToolId = (typeof GATEWAY_BUILTIN_TOOL_IDS)[number];\n"],"mappings":";;;;;AAIA,MAAa,2BAA2B;CACtC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD"}
|
|
@@ -238,8 +238,16 @@ function prepareUpdateAgent(cfg, agentIdRaw, body) {
|
|
|
238
238
|
const w = body.workspace.trim();
|
|
239
239
|
if (w) entry.workspace = resolveUserPath(w);
|
|
240
240
|
}
|
|
241
|
-
if (body.model !== void 0) if (body.model === null
|
|
242
|
-
else
|
|
241
|
+
if (body.model !== void 0) if (body.model === null) delete entry.model;
|
|
242
|
+
else {
|
|
243
|
+
const trimmed = String(body.model).trim();
|
|
244
|
+
if (!trimmed) return {
|
|
245
|
+
ok: false,
|
|
246
|
+
error: "model must be a non-empty string or null",
|
|
247
|
+
status: 400
|
|
248
|
+
};
|
|
249
|
+
entry.model = { primary: trimmed };
|
|
250
|
+
}
|
|
243
251
|
if (body.agentDir !== void 0) if (body.agentDir === null || String(body.agentDir).trim() === "") delete entry.agentDir;
|
|
244
252
|
else entry.agentDir = String(body.agentDir).trim();
|
|
245
253
|
if (body.skills !== void 0) if (body.skills === null) delete entry.skills;
|