@xopcai/xopc 0.0.6 → 0.0.8
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/extensions/telegram/src/plugin.js +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +2 -2
- package/dist/extensions/weixin/src/api/api.js +1 -1
- package/dist/extensions/weixin/src/cdn/upload.js +1 -1
- package/dist/extensions/weixin/src/media/data-url.js +1 -1
- package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
- package/dist/extensions/weixin/src/plugin.js +1 -1
- package/dist/gateway/static/root/assets/{agents-B6s2BvpH.js → agents-BSNzJWbQ.js} +2 -2
- package/dist/gateway/static/root/assets/{agents-B6s2BvpH.js.map → agents-BSNzJWbQ.js.map} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-BtsZ5ZPx.js → apps-page-BKk9SB4D.js} +2 -2
- package/dist/gateway/static/root/assets/{apps-page-BtsZ5ZPx.js.map → apps-page-BKk9SB4D.js.map} +1 -1
- package/dist/gateway/static/root/assets/attachment-load-DXcJLSWT.js +1 -0
- package/dist/gateway/static/root/assets/{channels-settings-BUfWBEVU.js → channels-settings-_J6cQN6G.js} +2 -2
- package/dist/gateway/static/root/assets/{channels-settings-BUfWBEVU.js.map → channels-settings-_J6cQN6G.js.map} +1 -1
- package/dist/gateway/static/root/assets/{chat-agents-api-BR30M2YQ.js → chat-agents-api-DPb_0O8M.js} +2 -2
- package/dist/gateway/static/root/assets/{chat-agents-api-BR30M2YQ.js.map → chat-agents-api-DPb_0O8M.js.map} +1 -1
- package/dist/gateway/static/root/assets/{cron-page-CMTx0Mjz.js → cron-page-BUJOuuKX.js} +2 -2
- package/dist/gateway/static/root/assets/{cron-page-CMTx0Mjz.js.map → cron-page-BUJOuuKX.js.map} +1 -1
- package/dist/gateway/static/root/assets/{cron-utils-BJma9IcD.js → cron-utils-Cn0YVg8x.js} +2 -2
- package/dist/gateway/static/root/assets/{cron-utils-BJma9IcD.js.map → cron-utils-Cn0YVg8x.js.map} +1 -1
- package/dist/gateway/static/root/assets/electron-env-D9bm1FIu.js +2 -0
- package/dist/gateway/static/root/assets/electron-env-D9bm1FIu.js.map +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-BCVoNSo6.js → extension-debug-page-DTz4O5Ua.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-debug-page-BCVoNSo6.js.map → extension-debug-page-DTz4O5Ua.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-iframe-host-PWB-Pw2d.js → extension-iframe-host-Cs1Kde9o.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-iframe-host-PWB-Pw2d.js.map → extension-iframe-host-Cs1Kde9o.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-D2tTklsD.js → extension-page-G52iX0Bo.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-page-D2tTklsD.js.map → extension-page-G52iX0Bo.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-provider-BpHodVRj.js → extension-provider-CO2jxBA9.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-provider-BpHodVRj.js.map → extension-provider-CO2jxBA9.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-BEu6Xw1Z.js → extension-settings-page-D9Ul8uSt.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-settings-page-BEu6Xw1Z.js.map → extension-settings-page-D9Ul8uSt.js.map} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-C7ZFPhNj.js → gateway-config-swr-Bc8SVD15.js} +2 -2
- package/dist/gateway/static/root/assets/{gateway-config-swr-C7ZFPhNj.js.map → gateway-config-swr-Bc8SVD15.js.map} +1 -1
- package/dist/gateway/static/root/assets/index-BXUJbteW.js +16 -0
- package/dist/gateway/static/root/assets/index-BXUJbteW.js.map +1 -0
- package/dist/gateway/static/root/assets/index-CQLMxWSA.css +2 -0
- package/dist/gateway/static/root/assets/{logs-page-BpsxYdcL.js → logs-page-5V25JkQY.js} +2 -2
- package/dist/gateway/static/root/assets/{logs-page-BpsxYdcL.js.map → logs-page-5V25JkQY.js.map} +1 -1
- package/dist/gateway/static/root/assets/{model-selector-BiiDq8Pk.js → model-selector-he3aQfme.js} +2 -2
- package/dist/gateway/static/root/assets/{model-selector-BiiDq8Pk.js.map → model-selector-he3aQfme.js.map} +1 -1
- package/dist/gateway/static/root/assets/navigation-DB9S-C6S.js +2 -0
- package/dist/gateway/static/root/assets/navigation-DB9S-C6S.js.map +1 -0
- package/dist/gateway/static/root/assets/page-header-store-DJHD9Ean.js +2 -0
- package/dist/gateway/static/root/assets/{page-header-store-HcRZK5CZ.js.map → page-header-store-DJHD9Ean.js.map} +1 -1
- package/dist/gateway/static/root/assets/{session-api-DxNaAkmX.js → session-api-n-4O5d9U.js} +2 -2
- package/dist/gateway/static/root/assets/{session-api-DxNaAkmX.js.map → session-api-n-4O5d9U.js.map} +1 -1
- package/dist/gateway/static/root/assets/{session-working-directory-control-CDH-Wk4E.js → session-working-directory-control-B6dHLvbr.js} +3 -3
- package/dist/gateway/static/root/assets/{session-working-directory-control-CDH-Wk4E.js.map → session-working-directory-control-B6dHLvbr.js.map} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-5PK75r1n.js → sessions-page-rBUfTdm3.js} +2 -2
- package/dist/gateway/static/root/assets/{sessions-page-5PK75r1n.js.map → sessions-page-rBUfTdm3.js.map} +1 -1
- package/dist/gateway/static/root/assets/settings-page-B3QrJm-E.js +2 -0
- package/dist/gateway/static/root/assets/settings-page-B3QrJm-E.js.map +1 -0
- package/dist/gateway/static/root/assets/{skill-api-CxbNlOD_.js → skill-api-vxtE8kI6.js} +2 -2
- package/dist/gateway/static/root/assets/{skill-api-CxbNlOD_.js.map → skill-api-vxtE8kI6.js.map} +1 -1
- package/dist/gateway/static/root/assets/{skills-page-Dd8ZzYJb.js → skills-page-D36_O2Ub.js} +2 -2
- package/dist/gateway/static/root/assets/{skills-page-Dd8ZzYJb.js.map → skills-page-D36_O2Ub.js.map} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-CPTH77BE.js → theme-store-CmiSsYBd.js} +2 -2
- package/dist/gateway/static/root/assets/{theme-store-CPTH77BE.js.map → theme-store-CmiSsYBd.js.map} +1 -1
- package/dist/gateway/static/root/assets/url-CtSqjF9J.js +2 -0
- package/dist/gateway/static/root/assets/url-CtSqjF9J.js.map +1 -0
- package/dist/gateway/static/root/assets/{useTranslation-BEUWOMuh.js → useTranslation-DYORQ7x6.js} +2 -2
- package/dist/gateway/static/root/assets/{useTranslation-BEUWOMuh.js.map → useTranslation-DYORQ7x6.js.map} +1 -1
- package/dist/gateway/static/root/index.html +16 -16
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.js +4 -4
- package/dist/src/agent/context/workspace-seed.js +2 -2
- package/dist/src/agent/image/index.d.ts +0 -1
- package/dist/src/agent/image/index.js +1 -2
- package/dist/src/agent/ipc/bus.js +1 -1
- package/dist/src/agent/memory/plugin-discovery.js +1 -1
- package/dist/src/agent/models/manager.js +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +1 -1
- package/dist/src/agent/service.js +3 -3
- package/dist/src/agent/skills/hub-hash.js +1 -1
- package/dist/src/agent/skills/hub-pull.js +1 -1
- package/dist/src/agent/skills/index.js +1 -1
- package/dist/src/agent/skills/skill-manager.js +1 -1
- package/dist/src/agent/tools/browser/tools.js +2 -2
- package/dist/src/agent/tools/browser/tools.js.map +1 -1
- package/dist/src/agent/tools/factory.js +1 -1
- package/dist/src/agent/tools/image-generate-tool.js +1 -1
- package/dist/src/agent/tools/image-tool.js +2 -2
- package/dist/src/agent/tools/image-tool.js.map +1 -1
- package/dist/src/agent/tools/index.d.ts +1 -1
- package/dist/src/agent/tools/index.js +2 -2
- package/dist/src/agent/tools/read.d.ts +0 -2
- package/dist/src/agent/tools/read.js +1 -3
- package/dist/src/agent/tools/read.js.map +1 -1
- package/dist/src/agent/tools/send-media.js +1 -1
- package/dist/src/auth/sync-provider-auth.js +1 -1
- package/dist/src/channels/plugin-types.d.ts +14 -0
- package/dist/src/cli/commands/agent.js +1 -1
- package/dist/src/cli/commands/doctor/checks/channel-config.d.ts +2 -0
- package/dist/src/cli/commands/doctor/checks/channel-config.js +113 -0
- package/dist/src/cli/commands/doctor/checks/channel-config.js.map +1 -0
- package/dist/src/cli/commands/doctor/checks/channel-plugins.d.ts +2 -0
- package/dist/src/cli/commands/doctor/checks/channel-plugins.js +47 -0
- package/dist/src/cli/commands/doctor/checks/channel-plugins.js.map +1 -0
- package/dist/src/cli/commands/doctor/checks/config-health.d.ts +2 -0
- package/dist/src/cli/commands/doctor/checks/config-health.js +82 -0
- package/dist/src/cli/commands/doctor/checks/config-health.js.map +1 -0
- package/dist/src/cli/commands/doctor/checks/cron-health.d.ts +2 -0
- package/dist/src/cli/commands/doctor/checks/cron-health.js +116 -0
- package/dist/src/cli/commands/doctor/checks/cron-health.js.map +1 -0
- package/dist/src/cli/commands/doctor/checks/gateway-health.d.ts +2 -0
- package/dist/src/cli/commands/doctor/checks/gateway-health.js +64 -0
- package/dist/src/cli/commands/doctor/checks/gateway-health.js.map +1 -0
- package/dist/src/cli/commands/doctor/checks/gateway-service.d.ts +2 -0
- package/dist/src/cli/commands/doctor/checks/gateway-service.js +64 -0
- package/dist/src/cli/commands/doctor/checks/gateway-service.js.map +1 -0
- package/dist/src/cli/commands/doctor/checks/node-version.d.ts +2 -0
- package/dist/src/cli/commands/doctor/checks/node-version.js +33 -0
- package/dist/src/cli/commands/doctor/checks/node-version.js.map +1 -0
- package/dist/src/cli/commands/doctor/checks/provider-auth.d.ts +2 -0
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +91 -0
- package/dist/src/cli/commands/doctor/checks/provider-auth.js.map +1 -0
- package/dist/src/cli/commands/doctor/checks/security-audit.d.ts +2 -0
- package/dist/src/cli/commands/doctor/checks/security-audit.js +85 -0
- package/dist/src/cli/commands/doctor/checks/security-audit.js.map +1 -0
- package/dist/src/cli/commands/doctor/checks/session-integrity.d.ts +2 -0
- package/dist/src/cli/commands/doctor/checks/session-integrity.js +118 -0
- package/dist/src/cli/commands/doctor/checks/session-integrity.js.map +1 -0
- package/dist/src/cli/commands/doctor/checks/state-integrity.d.ts +2 -0
- package/dist/src/cli/commands/doctor/checks/state-integrity.js +99 -0
- package/dist/src/cli/commands/doctor/checks/state-integrity.js.map +1 -0
- package/dist/src/cli/commands/doctor/checks/version-check.d.ts +2 -0
- package/dist/src/cli/commands/doctor/checks/version-check.js +71 -0
- package/dist/src/cli/commands/doctor/checks/version-check.js.map +1 -0
- package/dist/src/cli/commands/doctor/checks/workspace-status.d.ts +2 -0
- package/dist/src/cli/commands/doctor/checks/workspace-status.js +73 -0
- package/dist/src/cli/commands/doctor/checks/workspace-status.js.map +1 -0
- package/dist/src/cli/commands/doctor/flow.d.ts +9 -0
- package/dist/src/cli/commands/doctor/flow.js +51 -0
- package/dist/src/cli/commands/doctor/flow.js.map +1 -0
- package/dist/src/cli/commands/doctor/format.d.ts +6 -0
- package/dist/src/cli/commands/doctor/format.js +61 -0
- package/dist/src/cli/commands/doctor/format.js.map +1 -0
- package/dist/src/cli/commands/doctor/index.js +44 -0
- package/dist/src/cli/commands/doctor/index.js.map +1 -0
- package/dist/src/cli/commands/doctor/types.d.ts +20 -0
- package/dist/src/cli/commands/doctor/types.js +1 -0
- package/dist/src/cli/commands/init.js +2 -2
- package/dist/src/cli/index.d.ts +1 -1
- package/dist/src/cli/index.js +1 -1
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/utils/init-workspace.js +1 -1
- package/dist/src/config/index.js +3 -3
- package/dist/src/config/loader.js +1 -1
- package/dist/src/config/models-json.d.ts +15 -15
- package/dist/src/config/models-json.js +1 -1
- package/dist/src/config/profile.js +1 -1
- package/dist/src/config/schema.d.ts +0 -105
- package/dist/src/config/schema.js +3 -40
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/cron/executor.js +2 -2
- package/dist/src/daemon/launchd.js +2 -2
- package/dist/src/daemon/launchd.js.map +1 -1
- package/dist/src/daemon/systemd.js +2 -2
- package/dist/src/daemon/systemd.js.map +1 -1
- package/dist/src/extensions/loader.js +1 -1
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/hono/lib/static-ui.js +1 -1
- package/dist/src/gateway/hono/routes/doctor.d.ts +3 -0
- package/dist/src/gateway/hono/routes/doctor.js +35 -0
- package/dist/src/gateway/hono/routes/doctor.js.map +1 -0
- package/dist/src/gateway/hono/routes/index.js +2 -0
- package/dist/src/gateway/hono/routes/index.js.map +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +2 -2
- package/dist/src/gateway/hono/sse.js +2 -2
- package/dist/src/gateway/lock.js +1 -1
- package/dist/src/gateway/ports.js +98 -3
- package/dist/src/gateway/ports.js.map +1 -1
- package/dist/src/gateway/service.d.ts +0 -4
- package/dist/src/gateway/service.js +4 -23
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/routing/bindings.js +1 -1
- package/dist/src/routing/index.d.ts +1 -1
- package/dist/src/routing/index.js +2 -2
- package/dist/src/routing/index.js.map +1 -1
- package/dist/src/routing/resolve-route.js +1 -1
- package/dist/src/routing/session-key.d.ts +0 -5
- package/dist/src/routing/session-key.js +1 -27
- package/dist/src/routing/session-key.js.map +1 -1
- package/dist/src/session/session-title.js +1 -1
- package/dist/src/session/store.js +2 -6
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/session/types.d.ts +0 -10
- package/dist/src/session/types.js.map +1 -1
- package/package.json +1 -2
- package/dist/gateway/static/root/assets/attachment-load-6pRlDPZ8.js +0 -1
- package/dist/gateway/static/root/assets/index-DBZ5eXW5.js +0 -16
- package/dist/gateway/static/root/assets/index-DBZ5eXW5.js.map +0 -1
- package/dist/gateway/static/root/assets/index-KsVMH-Jo.css +0 -2
- package/dist/gateway/static/root/assets/navigation-BpLKd2Ca.js +0 -2
- package/dist/gateway/static/root/assets/navigation-BpLKd2Ca.js.map +0 -1
- package/dist/gateway/static/root/assets/page-header-store-HcRZK5CZ.js +0 -2
- package/dist/gateway/static/root/assets/preference-select-fields-B4AJBqUY.js +0 -2
- package/dist/gateway/static/root/assets/preference-select-fields-B4AJBqUY.js.map +0 -1
- package/dist/gateway/static/root/assets/settings-page-BvSj0JqX.js +0 -2
- package/dist/gateway/static/root/assets/settings-page-BvSj0JqX.js.map +0 -1
- package/dist/gateway/static/root/assets/url-QmwQTJ-j.js +0 -2
- package/dist/gateway/static/root/assets/url-QmwQTJ-j.js.map +0 -1
- package/dist/src/acp/commands.d.ts +0 -11
- package/dist/src/acp/commands.js +0 -17
- package/dist/src/acp/commands.js.map +0 -1
- package/dist/src/acp/control-plane/identity-reconcile.d.ts +0 -36
- package/dist/src/acp/control-plane/identity-reconcile.js +0 -124
- package/dist/src/acp/control-plane/identity-reconcile.js.map +0 -1
- package/dist/src/acp/control-plane/index.d.ts +0 -10
- package/dist/src/acp/control-plane/index.js +0 -6
- package/dist/src/acp/control-plane/manager.d.ts +0 -86
- package/dist/src/acp/control-plane/manager.js +0 -502
- package/dist/src/acp/control-plane/manager.js.map +0 -1
- package/dist/src/acp/control-plane/manager.types.d.ts +0 -125
- package/dist/src/acp/control-plane/manager.types.js +0 -14
- package/dist/src/acp/control-plane/manager.types.js.map +0 -1
- package/dist/src/acp/control-plane/manager.utils.d.ts +0 -29
- package/dist/src/acp/control-plane/manager.utils.js +0 -46
- package/dist/src/acp/control-plane/manager.utils.js.map +0 -1
- package/dist/src/acp/control-plane/runtime-cache-manager.d.ts +0 -49
- package/dist/src/acp/control-plane/runtime-cache-manager.js +0 -155
- package/dist/src/acp/control-plane/runtime-cache-manager.js.map +0 -1
- package/dist/src/acp/control-plane/runtime-cache.d.ts +0 -45
- package/dist/src/acp/control-plane/runtime-cache.js +0 -58
- package/dist/src/acp/control-plane/runtime-cache.js.map +0 -1
- package/dist/src/acp/control-plane/runtime-options.d.ts +0 -30
- package/dist/src/acp/control-plane/runtime-options.js +0 -92
- package/dist/src/acp/control-plane/runtime-options.js.map +0 -1
- package/dist/src/acp/control-plane/session-actor-queue.d.ts +0 -22
- package/dist/src/acp/control-plane/session-actor-queue.js +0 -70
- package/dist/src/acp/control-plane/session-actor-queue.js.map +0 -1
- package/dist/src/acp/control-plane/session-lifecycle-manager.d.ts +0 -59
- package/dist/src/acp/control-plane/session-lifecycle-manager.js +0 -209
- package/dist/src/acp/control-plane/session-lifecycle-manager.js.map +0 -1
- package/dist/src/acp/control-plane/session-store.d.ts +0 -39
- package/dist/src/acp/control-plane/session-store.js +0 -149
- package/dist/src/acp/control-plane/session-store.js.map +0 -1
- package/dist/src/acp/control-plane/turn-manager.d.ts +0 -40
- package/dist/src/acp/control-plane/turn-manager.js +0 -134
- package/dist/src/acp/control-plane/turn-manager.js.map +0 -1
- package/dist/src/acp/event-mapper.d.ts +0 -48
- package/dist/src/acp/event-mapper.js +0 -94
- package/dist/src/acp/event-mapper.js.map +0 -1
- package/dist/src/acp/index.d.ts +0 -10
- package/dist/src/acp/index.js +0 -5
- package/dist/src/acp/meta.d.ts +0 -15
- package/dist/src/acp/meta.js +0 -36
- package/dist/src/acp/meta.js.map +0 -1
- package/dist/src/acp/routing-integration.d.ts +0 -37
- package/dist/src/acp/routing-integration.js +0 -58
- package/dist/src/acp/routing-integration.js.map +0 -1
- package/dist/src/acp/runtime/backends/index.d.ts +0 -4
- package/dist/src/acp/runtime/backends/index.js +0 -2
- package/dist/src/acp/runtime/backends/local.d.ts +0 -136
- package/dist/src/acp/runtime/backends/local.js +0 -603
- package/dist/src/acp/runtime/backends/local.js.map +0 -1
- package/dist/src/acp/runtime/error-text.d.ts +0 -16
- package/dist/src/acp/runtime/error-text.js +0 -40
- package/dist/src/acp/runtime/error-text.js.map +0 -1
- package/dist/src/acp/runtime/errors.d.ts +0 -31
- package/dist/src/acp/runtime/errors.js +0 -47
- package/dist/src/acp/runtime/errors.js.map +0 -1
- package/dist/src/acp/runtime/index.d.ts +0 -7
- package/dist/src/acp/runtime/index.js +0 -4
- package/dist/src/acp/runtime/registry.d.ts +0 -35
- package/dist/src/acp/runtime/registry.js +0 -85
- package/dist/src/acp/runtime/registry.js.map +0 -1
- package/dist/src/acp/runtime/session-identity.d.ts +0 -35
- package/dist/src/acp/runtime/session-identity.js +0 -134
- package/dist/src/acp/runtime/session-identity.js.map +0 -1
- package/dist/src/acp/runtime/types.d.ts +0 -214
- package/dist/src/acp/secret-file.d.ts +0 -7
- package/dist/src/acp/secret-file.js +0 -19
- package/dist/src/acp/secret-file.js.map +0 -1
- package/dist/src/acp/server.d.ts +0 -48
- package/dist/src/acp/server.js +0 -300
- package/dist/src/acp/server.js.map +0 -1
- package/dist/src/acp/session.d.ts +0 -29
- package/dist/src/acp/session.js +0 -30
- package/dist/src/acp/session.js.map +0 -1
- package/dist/src/acp/types.d.ts +0 -39
- package/dist/src/acp/types.js +0 -13
- package/dist/src/acp/types.js.map +0 -1
- package/dist/src/agent/image/describe-images.d.ts +0 -18
- package/dist/src/agent/image/describe-images.js +0 -19
- package/dist/src/agent/image/describe-images.js.map +0 -1
- package/dist/src/cli/commands/acp.d.ts +0 -4
- package/dist/src/cli/commands/acp.js +0 -200
- package/dist/src/cli/commands/acp.js.map +0 -1
- /package/dist/src/{acp/runtime/types.js → cli/commands/doctor/index.d.ts} +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { init_loader, loadConfig } from "../../../../config/loader.js";
|
|
2
|
+
import { resolveGatewayService } from "../../../../daemon/service.js";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
//#region src/cli/commands/doctor/checks/gateway-service.ts
|
|
5
|
+
init_loader();
|
|
6
|
+
async function checkGatewayService(ctx) {
|
|
7
|
+
if (!existsSync(ctx.configPath)) return {
|
|
8
|
+
id: "gateway-service",
|
|
9
|
+
label: "Gateway service",
|
|
10
|
+
status: "skip",
|
|
11
|
+
message: "No config file; skipped.",
|
|
12
|
+
hints: []
|
|
13
|
+
};
|
|
14
|
+
try {
|
|
15
|
+
loadConfig(ctx.configPath);
|
|
16
|
+
} catch {
|
|
17
|
+
return {
|
|
18
|
+
id: "gateway-service",
|
|
19
|
+
label: "Gateway service",
|
|
20
|
+
status: "skip",
|
|
21
|
+
message: "Config could not be loaded; skipped.",
|
|
22
|
+
hints: []
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
let service;
|
|
26
|
+
try {
|
|
27
|
+
service = await resolveGatewayService();
|
|
28
|
+
} catch (e) {
|
|
29
|
+
return {
|
|
30
|
+
id: "gateway-service",
|
|
31
|
+
label: "Gateway service",
|
|
32
|
+
status: "skip",
|
|
33
|
+
message: `Service backend unavailable: ${e instanceof Error ? e.message : String(e)}`,
|
|
34
|
+
hints: []
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const env = { ...process.env };
|
|
38
|
+
if (!await service.isLoaded({ env })) return {
|
|
39
|
+
id: "gateway-service",
|
|
40
|
+
label: "Gateway service",
|
|
41
|
+
status: "warn",
|
|
42
|
+
message: "Gateway is not installed as a system service.",
|
|
43
|
+
hints: ["Install: xopc gateway install (or your platform equivalent)"]
|
|
44
|
+
};
|
|
45
|
+
const runtime = await service.getRuntime({ env });
|
|
46
|
+
if (runtime.status === "running" && runtime.pid) return {
|
|
47
|
+
id: "gateway-service",
|
|
48
|
+
label: "Gateway service",
|
|
49
|
+
status: "pass",
|
|
50
|
+
message: `Gateway service is running (PID ${runtime.pid}).`,
|
|
51
|
+
hints: [service.label]
|
|
52
|
+
};
|
|
53
|
+
return {
|
|
54
|
+
id: "gateway-service",
|
|
55
|
+
label: "Gateway service",
|
|
56
|
+
status: "warn",
|
|
57
|
+
message: `Gateway service is installed but not running (status: ${runtime.status}).`,
|
|
58
|
+
hints: ["Start: xopc gateway start"]
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
export { checkGatewayService };
|
|
63
|
+
|
|
64
|
+
//# sourceMappingURL=gateway-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateway-service.js","names":[],"sources":["../../../../../../src/cli/commands/doctor/checks/gateway-service.ts"],"sourcesContent":["import { loadConfig } from '../../../../config/loader.js';\nimport { existsSync } from 'node:fs';\nimport { resolveGatewayService } from '../../../../daemon/service.js';\nimport type { CheckResult, DoctorContext } from '../types.js';\n\nexport async function checkGatewayService(ctx: DoctorContext): Promise<CheckResult> {\n if (!existsSync(ctx.configPath)) {\n return {\n id: 'gateway-service',\n label: 'Gateway service',\n status: 'skip',\n message: 'No config file; skipped.',\n hints: [],\n };\n }\n\n try {\n loadConfig(ctx.configPath);\n } catch {\n return {\n id: 'gateway-service',\n label: 'Gateway service',\n status: 'skip',\n message: 'Config could not be loaded; skipped.',\n hints: [],\n };\n }\n\n let service;\n try {\n service = await resolveGatewayService();\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n return {\n id: 'gateway-service',\n label: 'Gateway service',\n status: 'skip',\n message: `Service backend unavailable: ${msg}`,\n hints: [],\n };\n }\n\n const env: Record<string, string | undefined> = { ...process.env };\n const loaded = await service.isLoaded({ env });\n if (!loaded) {\n return {\n id: 'gateway-service',\n label: 'Gateway service',\n status: 'warn',\n message: 'Gateway is not installed as a system service.',\n hints: ['Install: xopc gateway install (or your platform equivalent)'],\n };\n }\n\n const runtime = await service.getRuntime({ env });\n if (runtime.status === 'running' && runtime.pid) {\n return {\n id: 'gateway-service',\n label: 'Gateway service',\n status: 'pass',\n message: `Gateway service is running (PID ${runtime.pid}).`,\n hints: [service.label],\n };\n }\n\n return {\n id: 'gateway-service',\n label: 'Gateway service',\n status: 'warn',\n message: `Gateway service is installed but not running (status: ${runtime.status}).`,\n hints: ['Start: xopc gateway start'],\n };\n}\n"],"mappings":";;;;aAA0D;AAK1D,eAAsB,oBAAoB,KAA0C;AAClF,KAAI,CAAC,WAAW,IAAI,WAAW,CAC7B,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS;EACT,OAAO,EAAE;EACV;AAGH,KAAI;AACF,aAAW,IAAI,WAAW;SACpB;AACN,SAAO;GACL,IAAI;GACJ,OAAO;GACP,QAAQ;GACR,SAAS;GACT,OAAO,EAAE;GACV;;CAGH,IAAI;AACJ,KAAI;AACF,YAAU,MAAM,uBAAuB;UAChC,GAAG;AAEV,SAAO;GACL,IAAI;GACJ,OAAO;GACP,QAAQ;GACR,SAAS,gCALC,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE;GAMpD,OAAO,EAAE;GACV;;CAGH,MAAM,MAA0C,EAAE,GAAG,QAAQ,KAAK;AAElE,KAAI,CADW,MAAM,QAAQ,SAAS,EAAE,KAAK,CAAC,CAE5C,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS;EACT,OAAO,CAAC,8DAA8D;EACvE;CAGH,MAAM,UAAU,MAAM,QAAQ,WAAW,EAAE,KAAK,CAAC;AACjD,KAAI,QAAQ,WAAW,aAAa,QAAQ,IAC1C,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS,mCAAmC,QAAQ,IAAI;EACxD,OAAO,CAAC,QAAQ,MAAM;EACvB;AAGH,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS,yDAAyD,QAAQ,OAAO;EACjF,OAAO,CAAC,4BAA4B;EACrC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/cli/commands/doctor/checks/node-version.ts
|
|
2
|
+
function parseNodeMajorVersion() {
|
|
3
|
+
const match = process.version.match(/^v(\d+)/);
|
|
4
|
+
return match ? parseInt(match[1], 10) : 0;
|
|
5
|
+
}
|
|
6
|
+
async function checkNodeVersion(_ctx) {
|
|
7
|
+
const major = parseNodeMajorVersion();
|
|
8
|
+
if (major === 0) return {
|
|
9
|
+
id: "node-version",
|
|
10
|
+
label: "Node.js",
|
|
11
|
+
status: "warn",
|
|
12
|
+
message: "Could not parse Node.js version.",
|
|
13
|
+
hints: [`process.version=${process.version}`]
|
|
14
|
+
};
|
|
15
|
+
if (major < 22) return {
|
|
16
|
+
id: "node-version",
|
|
17
|
+
label: "Node.js",
|
|
18
|
+
status: "fail",
|
|
19
|
+
message: `Node ${major} is below the required minimum (22).`,
|
|
20
|
+
hints: ["Install Node.js 22+ from https://nodejs.org/"]
|
|
21
|
+
};
|
|
22
|
+
return {
|
|
23
|
+
id: "node-version",
|
|
24
|
+
label: "Node.js",
|
|
25
|
+
status: "pass",
|
|
26
|
+
message: `Node.js ${process.version} meets the project requirement (>= 22).`,
|
|
27
|
+
hints: []
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { checkNodeVersion };
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=node-version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-version.js","names":[],"sources":["../../../../../../src/cli/commands/doctor/checks/node-version.ts"],"sourcesContent":["import type { CheckResult, DoctorContext } from '../types.js';\n\nfunction parseNodeMajorVersion(): number {\n const match = process.version.match(/^v(\\d+)/);\n return match ? parseInt(match[1]!, 10) : 0;\n}\n\nexport async function checkNodeVersion(_ctx: DoctorContext): Promise<CheckResult> {\n const major = parseNodeMajorVersion();\n if (major === 0) {\n return {\n id: 'node-version',\n label: 'Node.js',\n status: 'warn',\n message: 'Could not parse Node.js version.',\n hints: [`process.version=${process.version}`],\n };\n }\n if (major < 22) {\n return {\n id: 'node-version',\n label: 'Node.js',\n status: 'fail',\n message: `Node ${major} is below the required minimum (22).`,\n hints: ['Install Node.js 22+ from https://nodejs.org/'],\n };\n }\n return {\n id: 'node-version',\n label: 'Node.js',\n status: 'pass',\n message: `Node.js ${process.version} meets the project requirement (>= 22).`,\n hints: [],\n };\n}\n"],"mappings":";AAEA,SAAS,wBAAgC;CACvC,MAAM,QAAQ,QAAQ,QAAQ,MAAM,UAAU;AAC9C,QAAO,QAAQ,SAAS,MAAM,IAAK,GAAG,GAAG;;AAG3C,eAAsB,iBAAiB,MAA2C;CAChF,MAAM,QAAQ,uBAAuB;AACrC,KAAI,UAAU,EACZ,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS;EACT,OAAO,CAAC,mBAAmB,QAAQ,UAAU;EAC9C;AAEH,KAAI,QAAQ,GACV,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS,QAAQ,MAAM;EACvB,OAAO,CAAC,+CAA+C;EACxD;AAEH,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS,WAAW,QAAQ,QAAQ;EACpC,OAAO,EAAE;EACV"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { getAgentDefaultModelRef, init_schema, parseModelRef } from "../../../../config/schema.js";
|
|
2
|
+
import { init_loader, loadConfig } from "../../../../config/loader.js";
|
|
3
|
+
import { PROVIDER_ENV_MAP, getApiKeyFromEnv, init_env_keys } from "../../../../providers/env-keys.js";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
//#region src/cli/commands/doctor/checks/provider-auth.ts
|
|
6
|
+
init_loader();
|
|
7
|
+
init_schema();
|
|
8
|
+
init_env_keys();
|
|
9
|
+
function collectProviderIdsFromConfig(cfg) {
|
|
10
|
+
const ids = /* @__PURE__ */ new Set();
|
|
11
|
+
const addRef = (ref) => {
|
|
12
|
+
if (!ref?.trim()) return;
|
|
13
|
+
const parsed = parseModelRef(ref.trim());
|
|
14
|
+
if (parsed) ids.add(parsed.provider.toLowerCase());
|
|
15
|
+
};
|
|
16
|
+
addRef(getAgentDefaultModelRef(cfg));
|
|
17
|
+
const raw = cfg.agents?.defaults?.model;
|
|
18
|
+
if (raw && typeof raw === "object" && "fallbacks" in raw && Array.isArray(raw.fallbacks)) for (const f of raw.fallbacks) addRef(typeof f === "string" ? f : void 0);
|
|
19
|
+
const list = cfg.agents?.list;
|
|
20
|
+
if (Array.isArray(list)) for (const e of list) {
|
|
21
|
+
const m = e?.model;
|
|
22
|
+
if (typeof m === "string") addRef(m);
|
|
23
|
+
else if (m && typeof m === "object" && "primary" in m) {
|
|
24
|
+
addRef(typeof m.primary === "string" ? m.primary : void 0);
|
|
25
|
+
const fb = m.fallbacks;
|
|
26
|
+
if (Array.isArray(fb)) for (const f of fb) addRef(f);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const img = cfg.agents?.defaults?.imageModel;
|
|
30
|
+
if (typeof img === "string") addRef(img);
|
|
31
|
+
else if (img && typeof img === "object" && "primary" in img) addRef(typeof img.primary === "string" ? img.primary : void 0);
|
|
32
|
+
const ss = cfg.agents?.defaults?.sessionSearch?.summaryModel;
|
|
33
|
+
if (typeof ss === "string") addRef(ss);
|
|
34
|
+
return ids;
|
|
35
|
+
}
|
|
36
|
+
function anyProviderEnvPresent() {
|
|
37
|
+
for (const vars of Object.values(PROVIDER_ENV_MAP)) for (const v of vars) if (process.env[v]?.trim()) return true;
|
|
38
|
+
for (const [k, val] of Object.entries(process.env)) {
|
|
39
|
+
if (!val?.trim()) continue;
|
|
40
|
+
if (k.endsWith("_API_KEY") || k.endsWith("_TOKEN")) return true;
|
|
41
|
+
}
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
async function checkProviderAuth(ctx) {
|
|
45
|
+
if (!existsSync(ctx.configPath)) return {
|
|
46
|
+
id: "provider-auth",
|
|
47
|
+
label: "Provider auth",
|
|
48
|
+
status: "skip",
|
|
49
|
+
message: "No config file; skipped.",
|
|
50
|
+
hints: []
|
|
51
|
+
};
|
|
52
|
+
let cfg;
|
|
53
|
+
try {
|
|
54
|
+
cfg = loadConfig(ctx.configPath);
|
|
55
|
+
} catch {
|
|
56
|
+
return {
|
|
57
|
+
id: "provider-auth",
|
|
58
|
+
label: "Provider auth",
|
|
59
|
+
status: "skip",
|
|
60
|
+
message: "Config could not be loaded; skipped.",
|
|
61
|
+
hints: []
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const fromConfig = collectProviderIdsFromConfig(cfg);
|
|
65
|
+
const checkIds = fromConfig.size > 0 ? [...fromConfig] : Object.keys(PROVIDER_ENV_MAP);
|
|
66
|
+
for (const id of checkIds) if (getApiKeyFromEnv(id)?.trim()) return {
|
|
67
|
+
id: "provider-auth",
|
|
68
|
+
label: "Provider auth",
|
|
69
|
+
status: "pass",
|
|
70
|
+
message: "At least one LLM provider API key is available.",
|
|
71
|
+
hints: []
|
|
72
|
+
};
|
|
73
|
+
if (anyProviderEnvPresent()) return {
|
|
74
|
+
id: "provider-auth",
|
|
75
|
+
label: "Provider auth",
|
|
76
|
+
status: "pass",
|
|
77
|
+
message: "Environment contains provider credentials.",
|
|
78
|
+
hints: []
|
|
79
|
+
};
|
|
80
|
+
return {
|
|
81
|
+
id: "provider-auth",
|
|
82
|
+
label: "Provider auth",
|
|
83
|
+
status: "warn",
|
|
84
|
+
message: "No API keys detected for configured providers.",
|
|
85
|
+
hints: ["Set keys via: xopc auth set <provider> <key>", "Or export the provider env vars from the pi-ai docs."]
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
//#endregion
|
|
89
|
+
export { checkProviderAuth };
|
|
90
|
+
|
|
91
|
+
//# sourceMappingURL=provider-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-auth.js","names":[],"sources":["../../../../../../src/cli/commands/doctor/checks/provider-auth.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\n\nimport { loadConfig } from '../../../../config/loader.js';\nimport type { Config } from '../../../../config/schema.js';\nimport { parseModelRef, getAgentDefaultModelRef } from '../../../../config/schema.js';\nimport { getApiKeyFromEnv, PROVIDER_ENV_MAP } from '../../../../providers/env-keys.js';\nimport type { CheckResult, DoctorContext } from '../types.js';\n\nfunction collectProviderIdsFromConfig(cfg: Config): Set<string> {\n const ids = new Set<string>();\n\n const addRef = (ref: string | undefined) => {\n if (!ref?.trim()) return;\n const parsed = parseModelRef(ref.trim());\n if (parsed) ids.add(parsed.provider.toLowerCase());\n };\n\n addRef(getAgentDefaultModelRef(cfg));\n\n const raw = cfg.agents?.defaults?.model;\n if (raw && typeof raw === 'object' && 'fallbacks' in raw && Array.isArray(raw.fallbacks)) {\n for (const f of raw.fallbacks) {\n addRef(typeof f === 'string' ? f : undefined);\n }\n }\n\n const list = cfg.agents?.list;\n if (Array.isArray(list)) {\n for (const e of list) {\n const m = e?.model;\n if (typeof m === 'string') addRef(m);\n else if (m && typeof m === 'object' && 'primary' in m) {\n addRef(typeof m.primary === 'string' ? m.primary : undefined);\n const fb = (m as { fallbacks?: string[] }).fallbacks;\n if (Array.isArray(fb)) {\n for (const f of fb) addRef(f);\n }\n }\n }\n }\n\n const img = cfg.agents?.defaults?.imageModel;\n if (typeof img === 'string') addRef(img);\n else if (img && typeof img === 'object' && 'primary' in img) {\n addRef(typeof img.primary === 'string' ? img.primary : undefined);\n }\n\n const ss = cfg.agents?.defaults?.sessionSearch?.summaryModel;\n if (typeof ss === 'string') addRef(ss);\n\n return ids;\n}\n\nfunction anyProviderEnvPresent(): boolean {\n for (const vars of Object.values(PROVIDER_ENV_MAP)) {\n for (const v of vars) {\n if (process.env[v]?.trim()) return true;\n }\n }\n for (const [k, val] of Object.entries(process.env)) {\n if (!val?.trim()) continue;\n if (k.endsWith('_API_KEY') || k.endsWith('_TOKEN')) return true;\n }\n return false;\n}\n\nexport async function checkProviderAuth(ctx: DoctorContext): Promise<CheckResult> {\n if (!existsSync(ctx.configPath)) {\n return {\n id: 'provider-auth',\n label: 'Provider auth',\n status: 'skip',\n message: 'No config file; skipped.',\n hints: [],\n };\n }\n\n let cfg: Config;\n try {\n cfg = loadConfig(ctx.configPath);\n } catch {\n return {\n id: 'provider-auth',\n label: 'Provider auth',\n status: 'skip',\n message: 'Config could not be loaded; skipped.',\n hints: [],\n };\n }\n\n const fromConfig = collectProviderIdsFromConfig(cfg);\n const checkIds = fromConfig.size > 0 ? [...fromConfig] : Object.keys(PROVIDER_ENV_MAP);\n\n for (const id of checkIds) {\n const key = getApiKeyFromEnv(id);\n if (key?.trim()) {\n return {\n id: 'provider-auth',\n label: 'Provider auth',\n status: 'pass',\n message: 'At least one LLM provider API key is available.',\n hints: [],\n };\n }\n }\n\n if (anyProviderEnvPresent()) {\n return {\n id: 'provider-auth',\n label: 'Provider auth',\n status: 'pass',\n message: 'Environment contains provider credentials.',\n hints: [],\n };\n }\n\n return {\n id: 'provider-auth',\n label: 'Provider auth',\n status: 'warn',\n message: 'No API keys detected for configured providers.',\n hints: ['Set keys via: xopc auth set <provider> <key>', 'Or export the provider env vars from the pi-ai docs.'],\n };\n}\n"],"mappings":";;;;;aAE0D;aAE4B;eACC;AAGvF,SAAS,6BAA6B,KAA0B;CAC9D,MAAM,sBAAM,IAAI,KAAa;CAE7B,MAAM,UAAU,QAA4B;AAC1C,MAAI,CAAC,KAAK,MAAM,CAAE;EAClB,MAAM,SAAS,cAAc,IAAI,MAAM,CAAC;AACxC,MAAI,OAAQ,KAAI,IAAI,OAAO,SAAS,aAAa,CAAC;;AAGpD,QAAO,wBAAwB,IAAI,CAAC;CAEpC,MAAM,MAAM,IAAI,QAAQ,UAAU;AAClC,KAAI,OAAO,OAAO,QAAQ,YAAY,eAAe,OAAO,MAAM,QAAQ,IAAI,UAAU,CACtF,MAAK,MAAM,KAAK,IAAI,UAClB,QAAO,OAAO,MAAM,WAAW,IAAI,KAAA,EAAU;CAIjD,MAAM,OAAO,IAAI,QAAQ;AACzB,KAAI,MAAM,QAAQ,KAAK,CACrB,MAAK,MAAM,KAAK,MAAM;EACpB,MAAM,IAAI,GAAG;AACb,MAAI,OAAO,MAAM,SAAU,QAAO,EAAE;WAC3B,KAAK,OAAO,MAAM,YAAY,aAAa,GAAG;AACrD,UAAO,OAAO,EAAE,YAAY,WAAW,EAAE,UAAU,KAAA,EAAU;GAC7D,MAAM,KAAM,EAA+B;AAC3C,OAAI,MAAM,QAAQ,GAAG,CACnB,MAAK,MAAM,KAAK,GAAI,QAAO,EAAE;;;CAMrC,MAAM,MAAM,IAAI,QAAQ,UAAU;AAClC,KAAI,OAAO,QAAQ,SAAU,QAAO,IAAI;UAC/B,OAAO,OAAO,QAAQ,YAAY,aAAa,IACtD,QAAO,OAAO,IAAI,YAAY,WAAW,IAAI,UAAU,KAAA,EAAU;CAGnE,MAAM,KAAK,IAAI,QAAQ,UAAU,eAAe;AAChD,KAAI,OAAO,OAAO,SAAU,QAAO,GAAG;AAEtC,QAAO;;AAGT,SAAS,wBAAiC;AACxC,MAAK,MAAM,QAAQ,OAAO,OAAO,iBAAiB,CAChD,MAAK,MAAM,KAAK,KACd,KAAI,QAAQ,IAAI,IAAI,MAAM,CAAE,QAAO;AAGvC,MAAK,MAAM,CAAC,GAAG,QAAQ,OAAO,QAAQ,QAAQ,IAAI,EAAE;AAClD,MAAI,CAAC,KAAK,MAAM,CAAE;AAClB,MAAI,EAAE,SAAS,WAAW,IAAI,EAAE,SAAS,SAAS,CAAE,QAAO;;AAE7D,QAAO;;AAGT,eAAsB,kBAAkB,KAA0C;AAChF,KAAI,CAAC,WAAW,IAAI,WAAW,CAC7B,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS;EACT,OAAO,EAAE;EACV;CAGH,IAAI;AACJ,KAAI;AACF,QAAM,WAAW,IAAI,WAAW;SAC1B;AACN,SAAO;GACL,IAAI;GACJ,OAAO;GACP,QAAQ;GACR,SAAS;GACT,OAAO,EAAE;GACV;;CAGH,MAAM,aAAa,6BAA6B,IAAI;CACpD,MAAM,WAAW,WAAW,OAAO,IAAI,CAAC,GAAG,WAAW,GAAG,OAAO,KAAK,iBAAiB;AAEtF,MAAK,MAAM,MAAM,SAEf,KADY,iBAAiB,GAAG,EACvB,MAAM,CACb,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS;EACT,OAAO,EAAE;EACV;AAIL,KAAI,uBAAuB,CACzB,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS;EACT,OAAO,EAAE;EACV;AAGH,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS;EACT,OAAO,CAAC,gDAAgD,uDAAuD;EAChH"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { init_loader, loadConfig } from "../../../../config/loader.js";
|
|
2
|
+
import { existsSync, statSync } from "node:fs";
|
|
3
|
+
//#region src/cli/commands/doctor/checks/security-audit.ts
|
|
4
|
+
init_loader();
|
|
5
|
+
function isLoopbackHost(host) {
|
|
6
|
+
const normalized = host.trim().toLowerCase();
|
|
7
|
+
return normalized === "127.0.0.1" || normalized === "localhost" || normalized === "::1" || normalized === "0:0:0:0:0:0:0:1";
|
|
8
|
+
}
|
|
9
|
+
function isAllInterfaces(host) {
|
|
10
|
+
const n = host.trim();
|
|
11
|
+
return n === "0.0.0.0" || n === "::" || n === "*";
|
|
12
|
+
}
|
|
13
|
+
async function checkSecurityAudit(ctx) {
|
|
14
|
+
if (!existsSync(ctx.configPath)) return {
|
|
15
|
+
id: "security-audit",
|
|
16
|
+
label: "Security",
|
|
17
|
+
status: "skip",
|
|
18
|
+
message: "No config file; skipped.",
|
|
19
|
+
hints: []
|
|
20
|
+
};
|
|
21
|
+
let cfg;
|
|
22
|
+
try {
|
|
23
|
+
cfg = loadConfig(ctx.configPath);
|
|
24
|
+
} catch {
|
|
25
|
+
return {
|
|
26
|
+
id: "security-audit",
|
|
27
|
+
label: "Security",
|
|
28
|
+
status: "skip",
|
|
29
|
+
message: "Config could not be loaded; skipped.",
|
|
30
|
+
hints: []
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const hints = [];
|
|
34
|
+
const host = cfg.gateway?.host?.trim() || "127.0.0.1";
|
|
35
|
+
const auth = cfg.gateway?.auth;
|
|
36
|
+
const mode = auth?.mode ?? "token";
|
|
37
|
+
const token = auth?.token?.trim() ?? "";
|
|
38
|
+
if (isAllInterfaces(host) && (mode === "none" || !token)) return {
|
|
39
|
+
id: "security-audit",
|
|
40
|
+
label: "Security",
|
|
41
|
+
status: "fail",
|
|
42
|
+
message: "Gateway is bound to all interfaces without token authentication (critical).",
|
|
43
|
+
hints: ["Set gateway.host to 127.0.0.1 or enable gateway.auth (token).", "Do not expose an unauthenticated gateway on the network."]
|
|
44
|
+
};
|
|
45
|
+
if (isAllInterfaces(host) && mode !== "none" && token) hints.push("Listening on all network interfaces; prefer 127.0.0.1 or firewall rules if the token could leak.");
|
|
46
|
+
if (!isLoopbackHost(host) && !isAllInterfaces(host)) {
|
|
47
|
+
if (mode === "none" || !token) return {
|
|
48
|
+
id: "security-audit",
|
|
49
|
+
label: "Security",
|
|
50
|
+
status: "fail",
|
|
51
|
+
message: "Gateway is reachable on a non-loopback address without authentication.",
|
|
52
|
+
hints: ["Use gateway.auth.mode \"token\" and set gateway.auth.token, or bind to loopback only."]
|
|
53
|
+
};
|
|
54
|
+
hints.push("Non-loopback bind is safer with a strong token and firewall rules.");
|
|
55
|
+
}
|
|
56
|
+
if (isLoopbackHost(host) && (mode === "none" || !token)) return {
|
|
57
|
+
id: "security-audit",
|
|
58
|
+
label: "Security",
|
|
59
|
+
status: "warn",
|
|
60
|
+
message: "Gateway has no token auth (loopback only).",
|
|
61
|
+
hints: ["Consider gateway.auth.token for defense in depth."]
|
|
62
|
+
};
|
|
63
|
+
if (token.length > 0 && token.length < 16) hints.push("Auth token is shorter than 16 characters; use a longer random token.");
|
|
64
|
+
if (process.platform !== "win32") try {
|
|
65
|
+
if (statSync(ctx.configPath).mode & 63) hints.push("Config file is group/world-readable; consider chmod 600 (contains secrets).");
|
|
66
|
+
} catch {}
|
|
67
|
+
if (hints.length > 0) return {
|
|
68
|
+
id: "security-audit",
|
|
69
|
+
label: "Security",
|
|
70
|
+
status: "warn",
|
|
71
|
+
message: "Non-critical security recommendations.",
|
|
72
|
+
hints
|
|
73
|
+
};
|
|
74
|
+
return {
|
|
75
|
+
id: "security-audit",
|
|
76
|
+
label: "Security",
|
|
77
|
+
status: "pass",
|
|
78
|
+
message: "No critical gateway exposure issues detected.",
|
|
79
|
+
hints: []
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
//#endregion
|
|
83
|
+
export { checkSecurityAudit };
|
|
84
|
+
|
|
85
|
+
//# sourceMappingURL=security-audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security-audit.js","names":[],"sources":["../../../../../../src/cli/commands/doctor/checks/security-audit.ts"],"sourcesContent":["import { existsSync, statSync } from 'node:fs';\n\nimport { loadConfig } from '../../../../config/loader.js';\nimport type { Config } from '../../../../config/schema.js';\nimport type { CheckResult, DoctorContext } from '../types.js';\n\nfunction isLoopbackHost(host: string): boolean {\n const normalized = host.trim().toLowerCase();\n return (\n normalized === '127.0.0.1' ||\n normalized === 'localhost' ||\n normalized === '::1' ||\n normalized === '0:0:0:0:0:0:0:1'\n );\n}\n\nfunction isAllInterfaces(host: string): boolean {\n const n = host.trim();\n return n === '0.0.0.0' || n === '::' || n === '*';\n}\n\nexport async function checkSecurityAudit(ctx: DoctorContext): Promise<CheckResult> {\n if (!existsSync(ctx.configPath)) {\n return {\n id: 'security-audit',\n label: 'Security',\n status: 'skip',\n message: 'No config file; skipped.',\n hints: [],\n };\n }\n\n let cfg: Config;\n try {\n cfg = loadConfig(ctx.configPath);\n } catch {\n return {\n id: 'security-audit',\n label: 'Security',\n status: 'skip',\n message: 'Config could not be loaded; skipped.',\n hints: [],\n };\n }\n\n const hints: string[] = [];\n const host = cfg.gateway?.host?.trim() || '127.0.0.1';\n const auth = cfg.gateway?.auth;\n const mode = auth?.mode ?? 'token';\n const token = auth?.token?.trim() ?? '';\n\n if (isAllInterfaces(host) && (mode === 'none' || !token)) {\n return {\n id: 'security-audit',\n label: 'Security',\n status: 'fail',\n message: 'Gateway is bound to all interfaces without token authentication (critical).',\n hints: [\n 'Set gateway.host to 127.0.0.1 or enable gateway.auth (token).',\n 'Do not expose an unauthenticated gateway on the network.',\n ],\n };\n }\n\n if (isAllInterfaces(host) && mode !== 'none' && token) {\n hints.push('Listening on all network interfaces; prefer 127.0.0.1 or firewall rules if the token could leak.');\n }\n\n if (!isLoopbackHost(host) && !isAllInterfaces(host)) {\n if (mode === 'none' || !token) {\n return {\n id: 'security-audit',\n label: 'Security',\n status: 'fail',\n message: 'Gateway is reachable on a non-loopback address without authentication.',\n hints: ['Use gateway.auth.mode \"token\" and set gateway.auth.token, or bind to loopback only.'],\n };\n }\n hints.push('Non-loopback bind is safer with a strong token and firewall rules.');\n }\n\n if (isLoopbackHost(host) && (mode === 'none' || !token)) {\n return {\n id: 'security-audit',\n label: 'Security',\n status: 'warn',\n message: 'Gateway has no token auth (loopback only).',\n hints: ['Consider gateway.auth.token for defense in depth.'],\n };\n }\n\n if (token.length > 0 && token.length < 16) {\n hints.push('Auth token is shorter than 16 characters; use a longer random token.');\n }\n\n if (process.platform !== 'win32') {\n try {\n const st = statSync(ctx.configPath);\n const perms = st.mode & 0o777;\n if (perms & 0o077) {\n hints.push('Config file is group/world-readable; consider chmod 600 (contains secrets).');\n }\n } catch {\n /* ignore */\n }\n }\n\n if (hints.length > 0) {\n return {\n id: 'security-audit',\n label: 'Security',\n status: 'warn',\n message: 'Non-critical security recommendations.',\n hints,\n };\n }\n\n return {\n id: 'security-audit',\n label: 'Security',\n status: 'pass',\n message: 'No critical gateway exposure issues detected.',\n hints: [],\n };\n}\n"],"mappings":";;;aAE0D;AAI1D,SAAS,eAAe,MAAuB;CAC7C,MAAM,aAAa,KAAK,MAAM,CAAC,aAAa;AAC5C,QACE,eAAe,eACf,eAAe,eACf,eAAe,SACf,eAAe;;AAInB,SAAS,gBAAgB,MAAuB;CAC9C,MAAM,IAAI,KAAK,MAAM;AACrB,QAAO,MAAM,aAAa,MAAM,QAAQ,MAAM;;AAGhD,eAAsB,mBAAmB,KAA0C;AACjF,KAAI,CAAC,WAAW,IAAI,WAAW,CAC7B,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS;EACT,OAAO,EAAE;EACV;CAGH,IAAI;AACJ,KAAI;AACF,QAAM,WAAW,IAAI,WAAW;SAC1B;AACN,SAAO;GACL,IAAI;GACJ,OAAO;GACP,QAAQ;GACR,SAAS;GACT,OAAO,EAAE;GACV;;CAGH,MAAM,QAAkB,EAAE;CAC1B,MAAM,OAAO,IAAI,SAAS,MAAM,MAAM,IAAI;CAC1C,MAAM,OAAO,IAAI,SAAS;CAC1B,MAAM,OAAO,MAAM,QAAQ;CAC3B,MAAM,QAAQ,MAAM,OAAO,MAAM,IAAI;AAErC,KAAI,gBAAgB,KAAK,KAAK,SAAS,UAAU,CAAC,OAChD,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS;EACT,OAAO,CACL,iEACA,2DACD;EACF;AAGH,KAAI,gBAAgB,KAAK,IAAI,SAAS,UAAU,MAC9C,OAAM,KAAK,mGAAmG;AAGhH,KAAI,CAAC,eAAe,KAAK,IAAI,CAAC,gBAAgB,KAAK,EAAE;AACnD,MAAI,SAAS,UAAU,CAAC,MACtB,QAAO;GACL,IAAI;GACJ,OAAO;GACP,QAAQ;GACR,SAAS;GACT,OAAO,CAAC,wFAAsF;GAC/F;AAEH,QAAM,KAAK,qEAAqE;;AAGlF,KAAI,eAAe,KAAK,KAAK,SAAS,UAAU,CAAC,OAC/C,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS;EACT,OAAO,CAAC,oDAAoD;EAC7D;AAGH,KAAI,MAAM,SAAS,KAAK,MAAM,SAAS,GACrC,OAAM,KAAK,uEAAuE;AAGpF,KAAI,QAAQ,aAAa,QACvB,KAAI;AAGF,MAFW,SAAS,IAAI,WAAW,CAClB,OAAA,GAEf,OAAM,KAAK,8EAA8E;SAErF;AAKV,KAAI,MAAM,SAAS,EACjB,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS;EACT;EACD;AAGH,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS;EACT,OAAO,EAAE;EACV"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { init_agent_scope, resolveDefaultAgentId } from "../../../../agent/agent-scope.js";
|
|
2
|
+
import { init_paths, resolveSessionsDir, resolveSessionsIndexPath } from "../../../../config/paths.js";
|
|
3
|
+
import { init_loader, loadConfig } from "../../../../config/loader.js";
|
|
4
|
+
import { resolveSessionShardRelativePath } from "../../../../session/shard-path.js";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
7
|
+
//#region src/cli/commands/doctor/checks/session-integrity.ts
|
|
8
|
+
init_agent_scope();
|
|
9
|
+
init_loader();
|
|
10
|
+
init_paths();
|
|
11
|
+
function sanitizeSessionKeyToFileStem(key) {
|
|
12
|
+
return key.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
13
|
+
}
|
|
14
|
+
function findSessionFileInDir(baseDir, safeStem) {
|
|
15
|
+
if (!existsSync(baseDir)) return false;
|
|
16
|
+
const entries = readdirSync(baseDir, { withFileTypes: true });
|
|
17
|
+
for (const entry of entries) {
|
|
18
|
+
if (entry.isFile() && entry.name === `${safeStem}.json`) return true;
|
|
19
|
+
if (entry.isDirectory() && entry.name !== "archive") {
|
|
20
|
+
if (findSessionFileInDir(join(baseDir, entry.name), safeStem)) return true;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
function transcriptExists(sessionsDir, key) {
|
|
26
|
+
const safeStem = sanitizeSessionKeyToFileStem(key);
|
|
27
|
+
if (existsSync(join(sessionsDir, resolveSessionShardRelativePath(key), `${safeStem}.json`))) return true;
|
|
28
|
+
return findSessionFileInDir(sessionsDir, safeStem);
|
|
29
|
+
}
|
|
30
|
+
async function checkSessionIntegrity(ctx) {
|
|
31
|
+
if (!ctx.options.deep) return {
|
|
32
|
+
id: "session-integrity",
|
|
33
|
+
label: "Sessions",
|
|
34
|
+
status: "skip",
|
|
35
|
+
message: "Deep mode off; session scan skipped.",
|
|
36
|
+
hints: ["Run: xopc doctor --deep"]
|
|
37
|
+
};
|
|
38
|
+
if (!existsSync(ctx.configPath)) return {
|
|
39
|
+
id: "session-integrity",
|
|
40
|
+
label: "Sessions",
|
|
41
|
+
status: "skip",
|
|
42
|
+
message: "No config file; skipped.",
|
|
43
|
+
hints: []
|
|
44
|
+
};
|
|
45
|
+
let config;
|
|
46
|
+
try {
|
|
47
|
+
config = loadConfig(ctx.configPath);
|
|
48
|
+
} catch {
|
|
49
|
+
return {
|
|
50
|
+
id: "session-integrity",
|
|
51
|
+
label: "Sessions",
|
|
52
|
+
status: "skip",
|
|
53
|
+
message: "Config could not be loaded; skipped.",
|
|
54
|
+
hints: []
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const agentId = resolveDefaultAgentId(config);
|
|
58
|
+
const indexPath = resolveSessionsIndexPath(config, agentId);
|
|
59
|
+
const sessionsDir = resolveSessionsDir(config, agentId);
|
|
60
|
+
if (!existsSync(sessionsDir)) return {
|
|
61
|
+
id: "session-integrity",
|
|
62
|
+
label: "Sessions",
|
|
63
|
+
status: "warn",
|
|
64
|
+
message: "Sessions directory is missing.",
|
|
65
|
+
hints: [sessionsDir]
|
|
66
|
+
};
|
|
67
|
+
if (!existsSync(indexPath)) return {
|
|
68
|
+
id: "session-integrity",
|
|
69
|
+
label: "Sessions",
|
|
70
|
+
status: "warn",
|
|
71
|
+
message: "Session index file is missing.",
|
|
72
|
+
hints: [indexPath]
|
|
73
|
+
};
|
|
74
|
+
let index;
|
|
75
|
+
try {
|
|
76
|
+
index = JSON.parse(readFileSync(indexPath, "utf-8"));
|
|
77
|
+
} catch {
|
|
78
|
+
return {
|
|
79
|
+
id: "session-integrity",
|
|
80
|
+
label: "Sessions",
|
|
81
|
+
status: "warn",
|
|
82
|
+
message: "Session index is not valid JSON.",
|
|
83
|
+
hints: [indexPath]
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const sample = [...Array.isArray(index.sessions) ? index.sessions : []].sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()).slice(0, 20);
|
|
87
|
+
if (sample.length === 0) return {
|
|
88
|
+
id: "session-integrity",
|
|
89
|
+
label: "Sessions",
|
|
90
|
+
status: "pass",
|
|
91
|
+
message: "Session index is valid; no sessions to sample.",
|
|
92
|
+
hints: []
|
|
93
|
+
};
|
|
94
|
+
const missing = [];
|
|
95
|
+
for (const s of sample) {
|
|
96
|
+
const key = s.key?.trim();
|
|
97
|
+
if (!key) continue;
|
|
98
|
+
if (!transcriptExists(sessionsDir, key)) missing.push(key);
|
|
99
|
+
}
|
|
100
|
+
if (missing.length > 0) return {
|
|
101
|
+
id: "session-integrity",
|
|
102
|
+
label: "Sessions",
|
|
103
|
+
status: "warn",
|
|
104
|
+
message: `${missing.length} of ${sample.length} sampled session transcripts are missing on disk.`,
|
|
105
|
+
hints: missing.slice(0, 5).map((k) => `Missing transcript for: ${k}`)
|
|
106
|
+
};
|
|
107
|
+
return {
|
|
108
|
+
id: "session-integrity",
|
|
109
|
+
label: "Sessions",
|
|
110
|
+
status: "pass",
|
|
111
|
+
message: `Sampled ${sample.length} recent session(s); transcript files are present.`,
|
|
112
|
+
hints: []
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
//#endregion
|
|
116
|
+
export { checkSessionIntegrity };
|
|
117
|
+
|
|
118
|
+
//# sourceMappingURL=session-integrity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-integrity.js","names":[],"sources":["../../../../../../src/cli/commands/doctor/checks/session-integrity.ts"],"sourcesContent":["import { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { resolveDefaultAgentId } from '../../../../agent/agent-scope.js';\nimport { loadConfig } from '../../../../config/loader.js';\nimport { resolveSessionsDir, resolveSessionsIndexPath } from '../../../../config/paths.js';\nimport { resolveSessionShardRelativePath } from '../../../../session/shard-path.js';\nimport type { SessionIndex, SessionMetadata } from '../../../../session/types.js';\nimport type { CheckResult, DoctorContext } from '../types.js';\n\nfunction sanitizeSessionKeyToFileStem(key: string): string {\n return key.replace(/[^a-zA-Z0-9_-]/g, '_');\n}\n\nfunction findSessionFileInDir(baseDir: string, safeStem: string): boolean {\n if (!existsSync(baseDir)) return false;\n const entries = readdirSync(baseDir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isFile() && entry.name === `${safeStem}.json`) return true;\n if (entry.isDirectory() && entry.name !== 'archive') {\n if (findSessionFileInDir(join(baseDir, entry.name), safeStem)) return true;\n }\n }\n return false;\n}\n\nfunction transcriptExists(sessionsDir: string, key: string): boolean {\n const safeStem = sanitizeSessionKeyToFileStem(key);\n const shard = resolveSessionShardRelativePath(key);\n const primary = join(sessionsDir, shard, `${safeStem}.json`);\n if (existsSync(primary)) return true;\n return findSessionFileInDir(sessionsDir, safeStem);\n}\n\nexport async function checkSessionIntegrity(ctx: DoctorContext): Promise<CheckResult> {\n if (!ctx.options.deep) {\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'skip',\n message: 'Deep mode off; session scan skipped.',\n hints: ['Run: xopc doctor --deep'],\n };\n }\n\n if (!existsSync(ctx.configPath)) {\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'skip',\n message: 'No config file; skipped.',\n hints: [],\n };\n }\n\n let config;\n try {\n config = loadConfig(ctx.configPath);\n } catch {\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'skip',\n message: 'Config could not be loaded; skipped.',\n hints: [],\n };\n }\n\n const agentId = resolveDefaultAgentId(config);\n const indexPath = resolveSessionsIndexPath(config, agentId);\n const sessionsDir = resolveSessionsDir(config, agentId);\n\n if (!existsSync(sessionsDir)) {\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'warn',\n message: 'Sessions directory is missing.',\n hints: [sessionsDir],\n };\n }\n\n if (!existsSync(indexPath)) {\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'warn',\n message: 'Session index file is missing.',\n hints: [indexPath],\n };\n }\n\n let index: SessionIndex;\n try {\n index = JSON.parse(readFileSync(indexPath, 'utf-8')) as SessionIndex;\n } catch {\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'warn',\n message: 'Session index is not valid JSON.',\n hints: [indexPath],\n };\n }\n\n const sessions: SessionMetadata[] = Array.isArray(index.sessions) ? index.sessions : [];\n const sorted = [...sessions].sort(\n (a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime(),\n );\n const sample = sorted.slice(0, 20);\n if (sample.length === 0) {\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'pass',\n message: 'Session index is valid; no sessions to sample.',\n hints: [],\n };\n }\n\n const missing: string[] = [];\n for (const s of sample) {\n const key = s.key?.trim();\n if (!key) continue;\n if (!transcriptExists(sessionsDir, key)) {\n missing.push(key);\n }\n }\n\n if (missing.length > 0) {\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'warn',\n message: `${missing.length} of ${sample.length} sampled session transcripts are missing on disk.`,\n hints: missing.slice(0, 5).map((k) => `Missing transcript for: ${k}`),\n };\n }\n\n return {\n id: 'session-integrity',\n label: 'Sessions',\n status: 'pass',\n message: `Sampled ${sample.length} recent session(s); transcript files are present.`,\n hints: [],\n };\n}\n"],"mappings":";;;;;;;kBAGyE;aACf;YACiC;AAK3F,SAAS,6BAA6B,KAAqB;AACzD,QAAO,IAAI,QAAQ,mBAAmB,IAAI;;AAG5C,SAAS,qBAAqB,SAAiB,UAA2B;AACxE,KAAI,CAAC,WAAW,QAAQ,CAAE,QAAO;CACjC,MAAM,UAAU,YAAY,SAAS,EAAE,eAAe,MAAM,CAAC;AAC7D,MAAK,MAAM,SAAS,SAAS;AAC3B,MAAI,MAAM,QAAQ,IAAI,MAAM,SAAS,GAAG,SAAS,OAAQ,QAAO;AAChE,MAAI,MAAM,aAAa,IAAI,MAAM,SAAS;OACpC,qBAAqB,KAAK,SAAS,MAAM,KAAK,EAAE,SAAS,CAAE,QAAO;;;AAG1E,QAAO;;AAGT,SAAS,iBAAiB,aAAqB,KAAsB;CACnE,MAAM,WAAW,6BAA6B,IAAI;AAGlD,KAAI,WADY,KAAK,aADP,gCAAgC,IAAI,EACT,GAAG,SAAS,OAAO,CACrC,CAAE,QAAO;AAChC,QAAO,qBAAqB,aAAa,SAAS;;AAGpD,eAAsB,sBAAsB,KAA0C;AACpF,KAAI,CAAC,IAAI,QAAQ,KACf,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS;EACT,OAAO,CAAC,0BAA0B;EACnC;AAGH,KAAI,CAAC,WAAW,IAAI,WAAW,CAC7B,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS;EACT,OAAO,EAAE;EACV;CAGH,IAAI;AACJ,KAAI;AACF,WAAS,WAAW,IAAI,WAAW;SAC7B;AACN,SAAO;GACL,IAAI;GACJ,OAAO;GACP,QAAQ;GACR,SAAS;GACT,OAAO,EAAE;GACV;;CAGH,MAAM,UAAU,sBAAsB,OAAO;CAC7C,MAAM,YAAY,yBAAyB,QAAQ,QAAQ;CAC3D,MAAM,cAAc,mBAAmB,QAAQ,QAAQ;AAEvD,KAAI,CAAC,WAAW,YAAY,CAC1B,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS;EACT,OAAO,CAAC,YAAY;EACrB;AAGH,KAAI,CAAC,WAAW,UAAU,CACxB,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS;EACT,OAAO,CAAC,UAAU;EACnB;CAGH,IAAI;AACJ,KAAI;AACF,UAAQ,KAAK,MAAM,aAAa,WAAW,QAAQ,CAAC;SAC9C;AACN,SAAO;GACL,IAAI;GACJ,OAAO;GACP,QAAQ;GACR,SAAS;GACT,OAAO,CAAC,UAAU;GACnB;;CAOH,MAAM,SAHS,CAAC,GADoB,MAAM,QAAQ,MAAM,SAAS,GAAG,MAAM,WAAW,EAAE,CAC3D,CAAC,MAC1B,GAAG,MAAM,IAAI,KAAK,EAAE,UAAU,CAAC,SAAS,GAAG,IAAI,KAAK,EAAE,UAAU,CAAC,SAAS,CAC5E,CACqB,MAAM,GAAG,GAAG;AAClC,KAAI,OAAO,WAAW,EACpB,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS;EACT,OAAO,EAAE;EACV;CAGH,MAAM,UAAoB,EAAE;AAC5B,MAAK,MAAM,KAAK,QAAQ;EACtB,MAAM,MAAM,EAAE,KAAK,MAAM;AACzB,MAAI,CAAC,IAAK;AACV,MAAI,CAAC,iBAAiB,aAAa,IAAI,CACrC,SAAQ,KAAK,IAAI;;AAIrB,KAAI,QAAQ,SAAS,EACnB,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS,GAAG,QAAQ,OAAO,MAAM,OAAO,OAAO;EAC/C,OAAO,QAAQ,MAAM,GAAG,EAAE,CAAC,KAAK,MAAM,2BAA2B,IAAI;EACtE;AAGH,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS,WAAW,OAAO,OAAO;EAClC,OAAO,EAAE;EACV"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { accessSync, chmodSync, constants, existsSync, mkdirSync, statSync } from "node:fs";
|
|
3
|
+
//#region src/cli/commands/doctor/checks/state-integrity.ts
|
|
4
|
+
function isWritable(dir) {
|
|
5
|
+
try {
|
|
6
|
+
accessSync(dir, constants.W_OK);
|
|
7
|
+
return true;
|
|
8
|
+
} catch {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
async function checkStateIntegrity(ctx) {
|
|
13
|
+
const root = ctx.stateDir;
|
|
14
|
+
const hints = [];
|
|
15
|
+
if (!existsSync(root)) {
|
|
16
|
+
if (ctx.options.fix) try {
|
|
17
|
+
mkdirSync(root, {
|
|
18
|
+
recursive: true,
|
|
19
|
+
mode: 448
|
|
20
|
+
});
|
|
21
|
+
if (process.platform !== "win32") chmodSync(root, 448);
|
|
22
|
+
return {
|
|
23
|
+
id: "state-integrity",
|
|
24
|
+
label: "State directory",
|
|
25
|
+
status: "pass",
|
|
26
|
+
message: "Created state directory with safe permissions.",
|
|
27
|
+
hints: [root],
|
|
28
|
+
fixed: true
|
|
29
|
+
};
|
|
30
|
+
} catch (e) {
|
|
31
|
+
return {
|
|
32
|
+
id: "state-integrity",
|
|
33
|
+
label: "State directory",
|
|
34
|
+
status: "fail",
|
|
35
|
+
message: `State directory missing and could not create: ${e instanceof Error ? e.message : String(e)}`,
|
|
36
|
+
hints: [root]
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
id: "state-integrity",
|
|
41
|
+
label: "State directory",
|
|
42
|
+
status: "fail",
|
|
43
|
+
message: "State directory does not exist.",
|
|
44
|
+
hints: [
|
|
45
|
+
`Expected: ${root}`,
|
|
46
|
+
"Run: xopc init",
|
|
47
|
+
"Or: xopc doctor --fix"
|
|
48
|
+
]
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (!isWritable(root)) return {
|
|
52
|
+
id: "state-integrity",
|
|
53
|
+
label: "State directory",
|
|
54
|
+
status: "fail",
|
|
55
|
+
message: "State directory is not writable.",
|
|
56
|
+
hints: [root]
|
|
57
|
+
};
|
|
58
|
+
if (process.platform !== "win32") try {
|
|
59
|
+
if ((statSync(root).mode & 511) !== 448) {
|
|
60
|
+
if (ctx.options.fix) {
|
|
61
|
+
chmodSync(root, 448);
|
|
62
|
+
return {
|
|
63
|
+
id: "state-integrity",
|
|
64
|
+
label: "State directory",
|
|
65
|
+
status: "pass",
|
|
66
|
+
message: "State directory permissions set to 700.",
|
|
67
|
+
hints: [root],
|
|
68
|
+
fixed: true
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
id: "state-integrity",
|
|
73
|
+
label: "State directory",
|
|
74
|
+
status: "warn",
|
|
75
|
+
message: "State directory permissions are not 700 (recommended for privacy).",
|
|
76
|
+
hints: [root, "Run: xopc doctor --fix"]
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
} catch {}
|
|
80
|
+
const agentsDir = join(root, "agents");
|
|
81
|
+
if (!existsSync(agentsDir) && ctx.options.fix) try {
|
|
82
|
+
mkdirSync(agentsDir, {
|
|
83
|
+
recursive: true,
|
|
84
|
+
mode: 448
|
|
85
|
+
});
|
|
86
|
+
hints.push(`Created: ${agentsDir}`);
|
|
87
|
+
} catch {}
|
|
88
|
+
return {
|
|
89
|
+
id: "state-integrity",
|
|
90
|
+
label: "State directory",
|
|
91
|
+
status: "pass",
|
|
92
|
+
message: "State directory exists and is usable.",
|
|
93
|
+
hints: hints.length ? hints : [root]
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
export { checkStateIntegrity };
|
|
98
|
+
|
|
99
|
+
//# sourceMappingURL=state-integrity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-integrity.js","names":[],"sources":["../../../../../../src/cli/commands/doctor/checks/state-integrity.ts"],"sourcesContent":["import { existsSync, mkdirSync, chmodSync, accessSync, constants, statSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport type { CheckResult, DoctorContext } from '../types.js';\n\nfunction isWritable(dir: string): boolean {\n try {\n accessSync(dir, constants.W_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function checkStateIntegrity(ctx: DoctorContext): Promise<CheckResult> {\n const root = ctx.stateDir;\n const hints: string[] = [];\n\n if (!existsSync(root)) {\n if (ctx.options.fix) {\n try {\n mkdirSync(root, { recursive: true, mode: 0o700 });\n if (process.platform !== 'win32') {\n chmodSync(root, 0o700);\n }\n return {\n id: 'state-integrity',\n label: 'State directory',\n status: 'pass',\n message: 'Created state directory with safe permissions.',\n hints: [root],\n fixed: true,\n };\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n return {\n id: 'state-integrity',\n label: 'State directory',\n status: 'fail',\n message: `State directory missing and could not create: ${msg}`,\n hints: [root],\n };\n }\n }\n return {\n id: 'state-integrity',\n label: 'State directory',\n status: 'fail',\n message: 'State directory does not exist.',\n hints: [`Expected: ${root}`, 'Run: xopc init', 'Or: xopc doctor --fix'],\n };\n }\n\n if (!isWritable(root)) {\n return {\n id: 'state-integrity',\n label: 'State directory',\n status: 'fail',\n message: 'State directory is not writable.',\n hints: [root],\n };\n }\n\n if (process.platform !== 'win32') {\n try {\n const mode = statSync(root).mode & 0o777;\n if (mode !== 0o700) {\n if (ctx.options.fix) {\n chmodSync(root, 0o700);\n return {\n id: 'state-integrity',\n label: 'State directory',\n status: 'pass',\n message: 'State directory permissions set to 700.',\n hints: [root],\n fixed: true,\n };\n }\n return {\n id: 'state-integrity',\n label: 'State directory',\n status: 'warn',\n message: 'State directory permissions are not 700 (recommended for privacy).',\n hints: [root, 'Run: xopc doctor --fix'],\n };\n }\n } catch {\n /* ignore stat errors */\n }\n }\n\n const agentsDir = join(root, 'agents');\n if (!existsSync(agentsDir) && ctx.options.fix) {\n try {\n mkdirSync(agentsDir, { recursive: true, mode: 0o700 });\n hints.push(`Created: ${agentsDir}`);\n } catch {\n /* best-effort */\n }\n }\n\n return {\n id: 'state-integrity',\n label: 'State directory',\n status: 'pass',\n message: 'State directory exists and is usable.',\n hints: hints.length ? hints : [root],\n };\n}\n"],"mappings":";;;AAKA,SAAS,WAAW,KAAsB;AACxC,KAAI;AACF,aAAW,KAAK,UAAU,KAAK;AAC/B,SAAO;SACD;AACN,SAAO;;;AAIX,eAAsB,oBAAoB,KAA0C;CAClF,MAAM,OAAO,IAAI;CACjB,MAAM,QAAkB,EAAE;AAE1B,KAAI,CAAC,WAAW,KAAK,EAAE;AACrB,MAAI,IAAI,QAAQ,IACd,KAAI;AACF,aAAU,MAAM;IAAE,WAAW;IAAM,MAAM;IAAO,CAAC;AACjD,OAAI,QAAQ,aAAa,QACvB,WAAU,MAAM,IAAM;AAExB,UAAO;IACL,IAAI;IACJ,OAAO;IACP,QAAQ;IACR,SAAS;IACT,OAAO,CAAC,KAAK;IACb,OAAO;IACR;WACM,GAAG;AAEV,UAAO;IACL,IAAI;IACJ,OAAO;IACP,QAAQ;IACR,SAAS,iDALC,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE;IAMpD,OAAO,CAAC,KAAK;IACd;;AAGL,SAAO;GACL,IAAI;GACJ,OAAO;GACP,QAAQ;GACR,SAAS;GACT,OAAO;IAAC,aAAa;IAAQ;IAAkB;IAAwB;GACxE;;AAGH,KAAI,CAAC,WAAW,KAAK,CACnB,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS;EACT,OAAO,CAAC,KAAK;EACd;AAGH,KAAI,QAAQ,aAAa,QACvB,KAAI;AAEF,OADa,SAAS,KAAK,CAAC,OAAO,SACtB,KAAO;AAClB,OAAI,IAAI,QAAQ,KAAK;AACnB,cAAU,MAAM,IAAM;AACtB,WAAO;KACL,IAAI;KACJ,OAAO;KACP,QAAQ;KACR,SAAS;KACT,OAAO,CAAC,KAAK;KACb,OAAO;KACR;;AAEH,UAAO;IACL,IAAI;IACJ,OAAO;IACP,QAAQ;IACR,SAAS;IACT,OAAO,CAAC,MAAM,yBAAyB;IACxC;;SAEG;CAKV,MAAM,YAAY,KAAK,MAAM,SAAS;AACtC,KAAI,CAAC,WAAW,UAAU,IAAI,IAAI,QAAQ,IACxC,KAAI;AACF,YAAU,WAAW;GAAE,WAAW;GAAM,MAAM;GAAO,CAAC;AACtD,QAAM,KAAK,YAAY,YAAY;SAC7B;AAKV,QAAO;EACL,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,SAAS;EACT,OAAO,MAAM,SAAS,QAAQ,CAAC,KAAK;EACrC"}
|