comisai 1.0.33 → 1.0.36
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/node_modules/@comis/agent/dist/background/auto-background-middleware.d.ts +11 -1
- package/node_modules/@comis/agent/dist/background/auto-background-middleware.js +21 -4
- package/node_modules/@comis/agent/dist/background/background-task-manager.d.ts +2 -2
- package/node_modules/@comis/agent/dist/background/background-task-manager.js +61 -20
- package/node_modules/@comis/agent/dist/background/background-task-persistence.js +10 -3
- package/node_modules/@comis/agent/dist/background/background-task-types.d.ts +10 -3
- package/node_modules/@comis/agent/dist/background/background-task-types.js +1 -1
- package/node_modules/@comis/agent/dist/background/completion-formatter.d.ts +39 -0
- package/node_modules/@comis/agent/dist/background/completion-formatter.js +77 -0
- package/node_modules/@comis/agent/dist/background/completion-runner.d.ts +53 -0
- package/node_modules/@comis/agent/dist/background/completion-runner.js +151 -0
- package/node_modules/@comis/agent/dist/background/index.d.ts +4 -0
- package/node_modules/@comis/agent/dist/background/index.js +2 -0
- package/node_modules/@comis/agent/dist/bridge/bridge-metrics.d.ts +17 -2
- package/node_modules/@comis/agent/dist/bridge/bridge-metrics.js +14 -2
- package/node_modules/@comis/agent/dist/bridge/pi-event-bridge.d.ts +23 -23
- package/node_modules/@comis/agent/dist/bridge/pi-event-bridge.js +72 -60
- package/node_modules/@comis/agent/dist/bridge/thinking-block-hash-invariant.d.ts +6 -7
- package/node_modules/@comis/agent/dist/bridge/thinking-block-hash-invariant.js +24 -25
- package/node_modules/@comis/agent/dist/budget/cost-tracker.d.ts +1 -1
- package/node_modules/@comis/agent/dist/context-engine/constants.d.ts +5 -5
- package/node_modules/@comis/agent/dist/context-engine/constants.js +12 -12
- package/node_modules/@comis/agent/dist/context-engine/context-engine.js +13 -4
- package/node_modules/@comis/agent/dist/context-engine/dag-annotator.d.ts +1 -2
- package/node_modules/@comis/agent/dist/context-engine/dag-annotator.js +1 -2
- package/node_modules/@comis/agent/dist/context-engine/llm-compaction.js +20 -16
- package/node_modules/@comis/agent/dist/context-engine/rehydration.js +6 -6
- package/node_modules/@comis/agent/dist/context-engine/signature-replay-scrubber.d.ts +12 -12
- package/node_modules/@comis/agent/dist/context-engine/signature-replay-scrubber.js +36 -22
- package/node_modules/@comis/agent/dist/context-engine/types-core.d.ts +15 -0
- package/node_modules/@comis/agent/dist/executor/cache-break-detection.d.ts +6 -6
- package/node_modules/@comis/agent/dist/executor/cache-break-detection.js +8 -8
- package/node_modules/@comis/agent/dist/executor/executor-context-engine-setup.d.ts +16 -0
- package/node_modules/@comis/agent/dist/executor/executor-context-engine-setup.js +46 -5
- package/node_modules/@comis/agent/dist/executor/executor-post-execution.d.ts +30 -0
- package/node_modules/@comis/agent/dist/executor/executor-post-execution.js +17 -1
- package/node_modules/@comis/agent/dist/executor/executor-prompt-runner.js +1 -1
- package/node_modules/@comis/agent/dist/executor/executor-response-filter.d.ts +7 -6
- package/node_modules/@comis/agent/dist/executor/executor-response-filter.js +9 -42
- package/node_modules/@comis/agent/dist/executor/executor-tool-assembly.js +2 -3
- package/node_modules/@comis/agent/dist/executor/gemini-cache-injector.d.ts +2 -2
- package/node_modules/@comis/agent/dist/executor/gemini-cache-injector.js +4 -4
- package/node_modules/@comis/agent/dist/executor/phase-filter.d.ts +2 -2
- package/node_modules/@comis/agent/dist/executor/phase-filter.js +5 -7
- package/node_modules/@comis/agent/dist/executor/pi-executor.d.ts +13 -0
- package/node_modules/@comis/agent/dist/executor/pi-executor.js +71 -6
- package/node_modules/@comis/agent/dist/executor/post-batch-continuation.js +7 -7
- package/node_modules/@comis/agent/dist/executor/stream-wrappers/request-body-injector.d.ts +1 -1
- package/node_modules/@comis/agent/dist/executor/stream-wrappers/request-body-injector.js +1 -1
- package/node_modules/@comis/agent/dist/executor/tool-deferral.d.ts +2 -2
- package/node_modules/@comis/agent/dist/executor/tool-deferral.js +7 -7
- package/node_modules/@comis/agent/dist/index.d.ts +17 -0
- package/node_modules/@comis/agent/dist/index.js +32 -11
- package/node_modules/@comis/agent/dist/model/auth-provider.d.ts +25 -2
- package/node_modules/@comis/agent/dist/model/auth-provider.js +6 -0
- package/node_modules/@comis/agent/dist/model/compaction-model-resolver.d.ts +3 -3
- package/node_modules/@comis/agent/dist/model/compaction-model-resolver.js +3 -3
- package/node_modules/@comis/agent/dist/model/oauth-credential-store-file.d.ts +37 -0
- package/node_modules/@comis/agent/dist/model/oauth-credential-store-file.js +279 -0
- package/node_modules/@comis/agent/dist/model/oauth-credential-store-selector.d.ts +49 -0
- package/node_modules/@comis/agent/dist/model/oauth-credential-store-selector.js +50 -0
- package/node_modules/@comis/agent/dist/model/oauth-device-code.d.ts +57 -0
- package/node_modules/@comis/agent/dist/model/oauth-device-code.js +302 -0
- package/node_modules/@comis/agent/dist/model/oauth-env.d.ts +33 -0
- package/node_modules/@comis/agent/dist/model/oauth-env.js +38 -0
- package/node_modules/@comis/agent/dist/model/oauth-errors.d.ts +41 -0
- package/node_modules/@comis/agent/dist/model/oauth-errors.js +88 -0
- package/node_modules/@comis/agent/dist/model/oauth-identity.d.ts +53 -0
- package/node_modules/@comis/agent/dist/model/oauth-identity.js +141 -0
- package/node_modules/@comis/agent/dist/model/oauth-login-runner.d.ts +99 -0
- package/node_modules/@comis/agent/dist/model/oauth-login-runner.js +374 -0
- package/node_modules/@comis/agent/dist/model/oauth-tls-preflight.d.ts +58 -0
- package/node_modules/@comis/agent/dist/model/oauth-tls-preflight.js +82 -0
- package/node_modules/@comis/agent/dist/model/oauth-token-manager.d.ts +86 -16
- package/node_modules/@comis/agent/dist/model/oauth-token-manager.js +961 -66
- package/node_modules/@comis/agent/dist/model/operation-model-defaults.d.ts +9 -4
- package/node_modules/@comis/agent/dist/model/operation-model-defaults.js +36 -9
- package/node_modules/@comis/agent/dist/model/resolve-provider-api-key.d.ts +48 -0
- package/node_modules/@comis/agent/dist/model/resolve-provider-api-key.js +66 -0
- package/node_modules/@comis/agent/dist/provider/capabilities.d.ts +5 -5
- package/node_modules/@comis/agent/dist/provider/capabilities.js +10 -23
- package/node_modules/@comis/agent/dist/safety/tool-output-safety.js +3 -3
- package/node_modules/@comis/agent/dist/session/comis-session-manager.d.ts +1 -1
- package/node_modules/@comis/agent/dist/session/comis-session-manager.js +1 -1
- package/node_modules/@comis/agent/dist/spawn/narrative-caster.d.ts +10 -0
- package/node_modules/@comis/agent/dist/spawn/narrative-caster.js +5 -1
- package/node_modules/@comis/agent/package.json +1 -1
- package/node_modules/@comis/channels/dist/email/email-adapter.js +6 -6
- package/node_modules/@comis/channels/dist/email/imap-lifecycle.js +7 -7
- package/node_modules/@comis/channels/dist/shared/deliver-to-channel.js +12 -10
- package/node_modules/@comis/channels/dist/telegram/telegram-adapter.js +1 -1
- package/node_modules/@comis/channels/package.json +1 -1
- package/node_modules/@comis/cli/dist/cli.js +2 -0
- package/node_modules/@comis/cli/dist/commands/agent.d.ts +3 -3
- package/node_modules/@comis/cli/dist/commands/agent.js +46 -3
- package/node_modules/@comis/cli/dist/commands/auth.d.ts +37 -0
- package/node_modules/@comis/cli/dist/commands/auth.js +433 -0
- package/node_modules/@comis/cli/dist/commands/doctor.d.ts +4 -1
- package/node_modules/@comis/cli/dist/commands/doctor.js +20 -5
- package/node_modules/@comis/cli/dist/doctor/checks/oauth-health.d.ts +39 -0
- package/node_modules/@comis/cli/dist/doctor/checks/oauth-health.js +399 -0
- package/node_modules/@comis/cli/dist/doctor/types.d.ts +19 -0
- package/node_modules/@comis/cli/dist/index.d.ts +1 -0
- package/node_modules/@comis/cli/dist/index.js +10 -4
- package/node_modules/@comis/cli/dist/output/relative-time.d.ts +23 -0
- package/node_modules/@comis/cli/dist/output/relative-time.js +36 -0
- package/node_modules/@comis/cli/dist/wizard/non-interactive.js +17 -8
- package/node_modules/@comis/cli/dist/wizard/steps/03-provider.js +2 -1
- package/node_modules/@comis/cli/dist/wizard/steps/04-credentials.js +223 -34
- package/node_modules/@comis/cli/dist/wizard/steps/10-write-config.js +14 -0
- package/node_modules/@comis/cli/dist/wizard/steps/11-daemon-start.js +3 -3
- package/node_modules/@comis/cli/dist/wizard/types.d.ts +7 -0
- package/node_modules/@comis/cli/package.json +1 -1
- package/node_modules/@comis/core/dist/bootstrap.d.ts +1 -1
- package/node_modules/@comis/core/dist/config/env-substitution.d.ts +66 -0
- package/node_modules/@comis/core/dist/config/env-substitution.js +115 -0
- package/node_modules/@comis/core/dist/config/index.d.ts +3 -1
- package/node_modules/@comis/core/dist/config/index.js +2 -1
- package/node_modules/@comis/core/dist/config/loader.js +61 -0
- package/node_modules/@comis/core/dist/config/managed-sections.d.ts +3 -3
- package/node_modules/@comis/core/dist/config/managed-sections.js +10 -5
- package/node_modules/@comis/core/dist/config/schema-agent.d.ts +4 -0
- package/node_modules/@comis/core/dist/config/schema-agent.js +16 -1
- package/node_modules/@comis/core/dist/config/schema-background-tasks.d.ts +7 -0
- package/node_modules/@comis/core/dist/config/schema-background-tasks.js +7 -0
- package/node_modules/@comis/core/dist/config/schema-delivery.d.ts +2 -0
- package/node_modules/@comis/core/dist/config/schema-delivery.js +2 -0
- package/node_modules/@comis/core/dist/config/schema-gemini-cache.d.ts +0 -2
- package/node_modules/@comis/core/dist/config/schema-gemini-cache.js +0 -2
- package/node_modules/@comis/core/dist/config/schema-oauth.d.ts +23 -0
- package/node_modules/@comis/core/dist/config/schema-oauth.js +19 -0
- package/node_modules/@comis/core/dist/config/schema-skills.d.ts +6 -8
- package/node_modules/@comis/core/dist/config/schema-skills.js +3 -4
- package/node_modules/@comis/core/dist/config/schema.d.ts +10 -0
- package/node_modules/@comis/core/dist/config/schema.js +3 -0
- package/node_modules/@comis/core/dist/domain/background-task-origin.d.ts +39 -0
- package/node_modules/@comis/core/dist/domain/background-task-origin.js +39 -0
- package/node_modules/@comis/core/dist/event-bus/events-infra.d.ts +71 -2
- package/node_modules/@comis/core/dist/exports/config.d.ts +2 -2
- package/node_modules/@comis/core/dist/exports/config.js +1 -1
- package/node_modules/@comis/core/dist/exports/domain.d.ts +2 -0
- package/node_modules/@comis/core/dist/exports/domain.js +1 -0
- package/node_modules/@comis/core/dist/exports/ports.d.ts +2 -2
- package/node_modules/@comis/core/dist/exports/ports.js +1 -1
- package/node_modules/@comis/core/dist/ports/delivery-queue.d.ts +23 -0
- package/node_modules/@comis/core/dist/ports/delivery-queue.js +2 -0
- package/node_modules/@comis/core/dist/ports/index.d.ts +2 -0
- package/node_modules/@comis/core/dist/ports/index.js +1 -0
- package/node_modules/@comis/core/dist/ports/oauth-credential-store.d.ts +64 -0
- package/node_modules/@comis/core/dist/ports/oauth-credential-store.js +37 -0
- package/node_modules/@comis/core/dist/tool-metadata.d.ts +20 -0
- package/node_modules/@comis/core/package.json +1 -1
- package/node_modules/@comis/daemon/dist/daemon-types.d.ts +23 -3
- package/node_modules/@comis/daemon/dist/daemon.js +82 -19
- package/node_modules/@comis/daemon/dist/health/watchdog.js +18 -3
- package/node_modules/@comis/daemon/dist/index.d.ts +2 -0
- package/node_modules/@comis/daemon/dist/index.js +5 -0
- package/node_modules/@comis/daemon/dist/observability/channel-health-logger.js +3 -3
- package/node_modules/@comis/daemon/dist/observability/delivery-queue-logger.js +1 -1
- package/node_modules/@comis/daemon/dist/rpc/agent-handlers.d.ts +22 -1
- package/node_modules/@comis/daemon/dist/rpc/agent-handlers.js +84 -21
- package/node_modules/@comis/daemon/dist/rpc/agent-inline-workspace.js +2 -2
- package/node_modules/@comis/daemon/dist/rpc/config-handlers.d.ts +9 -1
- package/node_modules/@comis/daemon/dist/rpc/config-handlers.js +104 -23
- package/node_modules/@comis/daemon/dist/rpc/credential-resolver.d.ts +30 -1
- package/node_modules/@comis/daemon/dist/rpc/credential-resolver.js +74 -11
- package/node_modules/@comis/daemon/dist/rpc/mcp-handlers.d.ts +8 -0
- package/node_modules/@comis/daemon/dist/rpc/mcp-handlers.js +22 -8
- package/node_modules/@comis/daemon/dist/rpc/provider-handlers.js +9 -12
- package/node_modules/@comis/daemon/dist/rpc/rpc-dispatch.d.ts +1 -0
- package/node_modules/@comis/daemon/dist/rpc/rpc-dispatch.js +27 -2
- package/node_modules/@comis/daemon/dist/setup-docker-restart-warn.js +0 -1
- package/node_modules/@comis/daemon/dist/wiring/index.d.ts +2 -0
- package/node_modules/@comis/daemon/dist/wiring/index.js +1 -0
- package/node_modules/@comis/daemon/dist/wiring/oauth-preflight.d.ts +21 -0
- package/node_modules/@comis/daemon/dist/wiring/oauth-preflight.js +134 -0
- package/node_modules/@comis/daemon/dist/wiring/setup-agents.d.ts +46 -1
- package/node_modules/@comis/daemon/dist/wiring/setup-agents.js +127 -3
- package/node_modules/@comis/daemon/dist/wiring/setup-background-completion-runner.d.ts +39 -0
- package/node_modules/@comis/daemon/dist/wiring/setup-background-completion-runner.js +32 -0
- package/node_modules/@comis/daemon/dist/wiring/setup-background-tasks.d.ts +10 -3
- package/node_modules/@comis/daemon/dist/wiring/setup-background-tasks.js +11 -5
- package/node_modules/@comis/daemon/dist/wiring/setup-channels.js +20 -1
- package/node_modules/@comis/daemon/dist/wiring/setup-cross-session.js +1 -1
- package/node_modules/@comis/daemon/dist/wiring/setup-delivery.d.ts +14 -5
- package/node_modules/@comis/daemon/dist/wiring/setup-delivery.js +52 -19
- package/node_modules/@comis/daemon/dist/wiring/setup-schedulers.js +4 -0
- package/node_modules/@comis/daemon/package.json +1 -1
- package/node_modules/@comis/gateway/dist/index.d.ts +2 -0
- package/node_modules/@comis/gateway/dist/index.js +2 -0
- package/node_modules/@comis/gateway/dist/oauth/oauth-callback-route.d.ts +66 -0
- package/node_modules/@comis/gateway/dist/oauth/oauth-callback-route.js +212 -0
- package/node_modules/@comis/gateway/dist/server/hono-server.d.ts +14 -0
- package/node_modules/@comis/gateway/dist/server/hono-server.js +10 -0
- package/node_modules/@comis/gateway/package.json +1 -1
- package/node_modules/@comis/infra/dist/logging/log-fields.d.ts +23 -0
- package/node_modules/@comis/infra/package.json +1 -1
- package/node_modules/@comis/memory/dist/compaction.d.ts +3 -5
- package/node_modules/@comis/memory/dist/compaction.js +2 -3
- package/node_modules/@comis/memory/dist/delivery-queue-adapter.d.ts +2 -2
- package/node_modules/@comis/memory/dist/delivery-queue-adapter.js +49 -1
- package/node_modules/@comis/memory/dist/index.d.ts +2 -0
- package/node_modules/@comis/memory/dist/index.js +3 -0
- package/node_modules/@comis/memory/dist/memory-api.d.ts +1 -1
- package/node_modules/@comis/memory/dist/memory-api.js +1 -1
- package/node_modules/@comis/memory/dist/oauth-profile-schema.d.ts +17 -0
- package/node_modules/@comis/memory/dist/oauth-profile-schema.js +33 -0
- package/node_modules/@comis/memory/dist/oauth-profile-store-encrypted.d.ts +27 -0
- package/node_modules/@comis/memory/dist/oauth-profile-store-encrypted.js +144 -0
- package/node_modules/@comis/memory/dist/session-store.d.ts +1 -1
- package/node_modules/@comis/memory/dist/session-store.js +1 -1
- package/node_modules/@comis/memory/dist/sqlite-secret-store.d.ts +29 -3
- package/node_modules/@comis/memory/dist/sqlite-secret-store.js +11 -3
- package/node_modules/@comis/memory/package.json +1 -1
- package/node_modules/@comis/scheduler/dist/execution/execution-lock.d.ts +13 -0
- package/node_modules/@comis/scheduler/dist/execution/execution-lock.js +1 -1
- package/node_modules/@comis/scheduler/dist/execution/index.d.ts +2 -0
- package/node_modules/@comis/scheduler/dist/execution/index.js +2 -0
- package/node_modules/@comis/scheduler/dist/heartbeat/agent-heartbeat-source.js +1 -1
- package/node_modules/@comis/scheduler/dist/index.d.ts +2 -0
- package/node_modules/@comis/scheduler/dist/index.js +2 -0
- package/node_modules/@comis/scheduler/package.json +1 -1
- package/node_modules/@comis/shared/package.json +1 -1
- package/node_modules/@comis/skills/dist/bridge/schema-validator.d.ts +38 -0
- package/node_modules/@comis/skills/dist/bridge/schema-validator.js +169 -0
- package/node_modules/@comis/skills/dist/bridge/tool-metadata-enforcement.js +12 -0
- package/node_modules/@comis/skills/dist/bridge/tool-metadata-registry.js +130 -0
- package/node_modules/@comis/skills/dist/builtin/exec-diagnostics.d.ts +32 -0
- package/node_modules/@comis/skills/dist/builtin/exec-diagnostics.js +127 -0
- package/node_modules/@comis/skills/dist/builtin/exec-security.js +38 -0
- package/node_modules/@comis/skills/dist/builtin/exec-tool.js +9 -0
- package/node_modules/@comis/skills/dist/builtin/file-tools/grep-tool.js +6 -6
- package/node_modules/@comis/skills/dist/builtin/platform/agents-manage-tool.d.ts +5 -4
- package/node_modules/@comis/skills/dist/builtin/platform/agents-manage-tool.js +38 -27
- package/node_modules/@comis/skills/dist/builtin/platform/background-tasks-tool.d.ts +4 -1
- package/node_modules/@comis/skills/dist/builtin/platform/background-tasks-tool.js +3 -3
- package/node_modules/@comis/skills/dist/builtin/platform/cron-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/gateway-tool.js +6 -6
- package/node_modules/@comis/skills/dist/builtin/platform/mcp-manage-tool.d.ts +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/mcp-manage-tool.js +9 -9
- package/node_modules/@comis/skills/dist/builtin/sandbox/bwrap-provider.d.ts +11 -0
- package/node_modules/@comis/skills/dist/builtin/sandbox/bwrap-provider.js +114 -1
- package/node_modules/@comis/skills/dist/builtin/sandbox/detect-provider.js +40 -15
- package/node_modules/@comis/skills/dist/media/ssrf-fetcher.d.ts +7 -0
- package/node_modules/@comis/skills/dist/media/ssrf-fetcher.js +9 -2
- package/node_modules/@comis/skills/package.json +1 -1
- package/node_modules/@comis/web/dist/assets/{agent-detail-71BSbSfD.js → agent-detail-q8t1NB7w.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{agent-editor-CTSDZhwT.js → agent-editor-B46io5gv.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{agent-list-BEhni2ea.js → agent-list-DQ6g2Rcx.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{billing-view-DVP1IvVs.js → billing-view-IWPR8LgF.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{channel-detail-N_YK74xC.js → channel-detail-DlNNZuuC.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{channel-list-DRk6ZJaF.js → channel-list-DhGwxiMc.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{chat-console-Dm-GtSf9.js → chat-console-Nv6fM3Rc.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{config-editor-CIferYX6.js → config-editor-BYKuJF76.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{context-dag-browser-CL84rXXM.js → context-dag-browser-ClNEtzYE.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{context-engine-B1HOTEZv.js → context-engine-BZJ6HChd.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{delivery-view-Y6JKYVFw.js → delivery-view-Cb7I3vGu.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{diagnostics-view-DWV1UQjz.js → diagnostics-view-9u9Lyu5a.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{ic-chat-message-DfSERzzg.js → ic-chat-message-BFt3cVpx.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{ic-connection-dot-CXyhlJup.js → ic-connection-dot-y77LZ3Gu.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{ic-tool-call-DNmwTjek.js → ic-tool-call-qt6w1NQl.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{index-CBr0Tm9_.js → index-8Tg9oc-C.js} +2 -2
- package/node_modules/@comis/web/dist/assets/{mcp-management-BaH2-vox.js → mcp-management-69dtH_kY.js} +2 -2
- package/node_modules/@comis/web/dist/assets/{media-config-CZLshJoN.js → media-config-BdjLj5c1.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{media-test-C9NUWgo_.js → media-test-DuPqrixi.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{memory-inspector-D_fmTcRN.js → memory-inspector-B-Pepbq-.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{message-center-BBFlNCZn.js → message-center-B7l0yNYY.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{models-BytGLm99.js → models-JHFHuv5S.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{observe-view-VXtHqaqq.js → observe-view-r8mqhy4O.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{pipeline-builder-CfXczlfJ.js → pipeline-builder-XjkiZRcR.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{pipeline-history-CPmXFnbe.js → pipeline-history-CZqJv_Hj.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{pipeline-history-detail-DcueTMs9.js → pipeline-history-detail-BEFGMoDy.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{pipeline-list-B-xG5WZh.js → pipeline-list-B6q5LvO1.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{pipeline-monitor-pnIOYaSY.js → pipeline-monitor-BNomXjVL.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{scheduler-BtUIFHhA.js → scheduler-BJEjcGKA.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{security-C8mWRq2y.js → security-2G1jhBfV.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{session-detail-DgdkO5ka.js → session-detail-DmVPzFBR.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{session-list-DcylcfTn.js → session-list-CsqMQoHs.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{setup-wizard-BP5yjsuL.js → setup-wizard-CAdM-gSP.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{skills-DXt1bX8Z.js → skills-2ODqKaWr.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{subagents-C7YbUHXY.js → subagents-BFlwfTbD.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{workspace-manager-DP6pW4wa.js → workspace-manager--CbOx_dI.js} +1 -1
- package/node_modules/@comis/web/dist/index.html +1 -1
- package/node_modules/@comis/web/package.json +1 -1
- package/package.json +17 -16
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* Encrypted SQLite-backed OAuthCredentialStorePort adapter.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors credential-mapping-store's factory pattern (takes a pre-opened
|
|
6
|
+
* Database instance, does NOT open its own). The lifecycle is owned by
|
|
7
|
+
* the caller — we share the existing secrets.db connection to keep all
|
|
8
|
+
* encrypted-at-rest data in one DB file.
|
|
9
|
+
*
|
|
10
|
+
* The entire OAuthProfile JSON payload is encrypted as one AES-256-GCM
|
|
11
|
+
* blob per row. One ciphertext+iv+authTag+salt set per profile. Atomic
|
|
12
|
+
* update — no half-rotated state where access changes but refresh doesn't.
|
|
13
|
+
*
|
|
14
|
+
* Denormalized expires_at column stays in sync on every write so the
|
|
15
|
+
* doctor can query expiring profiles without decrypting any blob.
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
import { ok, err, fromPromise } from "@comis/shared";
|
|
20
|
+
import { validateProfileId } from "@comis/core";
|
|
21
|
+
import { initOAuthProfileSchema } from "./oauth-profile-schema.js";
|
|
22
|
+
const SCHEMA_VERSION = 1;
|
|
23
|
+
/**
|
|
24
|
+
* Create an encrypted OAuthCredentialStorePort backed by a shared SQLite DB.
|
|
25
|
+
*
|
|
26
|
+
* The adapter does NOT own the db lifecycle — the caller supplies an
|
|
27
|
+
* already-open Database (typically the secrets.db chain). Initializes its
|
|
28
|
+
* own oauth_profiles table via initOAuthProfileSchema (idempotent).
|
|
29
|
+
*/
|
|
30
|
+
export function createOAuthProfileStoreEncrypted(db, crypto) {
|
|
31
|
+
initOAuthProfileSchema(db);
|
|
32
|
+
const upsertStmt = db.prepare(`
|
|
33
|
+
INSERT INTO oauth_profiles (
|
|
34
|
+
profile_id, provider, identity,
|
|
35
|
+
credentials_ciphertext, credentials_iv, credentials_auth_tag, credentials_salt,
|
|
36
|
+
expires_at, version, created_at, updated_at
|
|
37
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
38
|
+
ON CONFLICT(profile_id) DO UPDATE SET
|
|
39
|
+
provider = excluded.provider,
|
|
40
|
+
identity = excluded.identity,
|
|
41
|
+
credentials_ciphertext = excluded.credentials_ciphertext,
|
|
42
|
+
credentials_iv = excluded.credentials_iv,
|
|
43
|
+
credentials_auth_tag = excluded.credentials_auth_tag,
|
|
44
|
+
credentials_salt = excluded.credentials_salt,
|
|
45
|
+
expires_at = excluded.expires_at,
|
|
46
|
+
version = excluded.version,
|
|
47
|
+
updated_at = excluded.updated_at
|
|
48
|
+
`);
|
|
49
|
+
const getStmt = db.prepare("SELECT * FROM oauth_profiles WHERE profile_id = ?");
|
|
50
|
+
const deleteStmt = db.prepare("DELETE FROM oauth_profiles WHERE profile_id = ?");
|
|
51
|
+
const listAllStmt = db.prepare("SELECT * FROM oauth_profiles");
|
|
52
|
+
const listByProviderStmt = db.prepare("SELECT * FROM oauth_profiles WHERE provider = ?");
|
|
53
|
+
const existsStmt = db.prepare("SELECT 1 FROM oauth_profiles WHERE profile_id = ?");
|
|
54
|
+
function rowToProfile(row) {
|
|
55
|
+
if (row.version !== SCHEMA_VERSION) {
|
|
56
|
+
return err(new Error("OAuth profile store version mismatch: expected " +
|
|
57
|
+
SCHEMA_VERSION +
|
|
58
|
+
", got " +
|
|
59
|
+
String(row.version) +
|
|
60
|
+
". Hint: drop the oauth_profiles table and re-run `comis auth login` to recreate. Stored profiles for unknown schema versions cannot be migrated."));
|
|
61
|
+
}
|
|
62
|
+
const decryptResult = crypto.decrypt({
|
|
63
|
+
ciphertext: row.credentials_ciphertext,
|
|
64
|
+
iv: row.credentials_iv,
|
|
65
|
+
authTag: row.credentials_auth_tag,
|
|
66
|
+
salt: row.credentials_salt,
|
|
67
|
+
});
|
|
68
|
+
if (!decryptResult.ok)
|
|
69
|
+
return err(decryptResult.error);
|
|
70
|
+
let parsed;
|
|
71
|
+
try {
|
|
72
|
+
parsed = JSON.parse(decryptResult.value);
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
return err(new Error("OAuth profile decryption produced invalid JSON: " + String(e)));
|
|
76
|
+
}
|
|
77
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
78
|
+
return err(new Error("OAuth profile decryption produced non-object payload"));
|
|
79
|
+
}
|
|
80
|
+
return ok(parsed);
|
|
81
|
+
}
|
|
82
|
+
const port = {
|
|
83
|
+
async get(profileId) {
|
|
84
|
+
const validation = validateProfileId(profileId);
|
|
85
|
+
if (!validation.ok)
|
|
86
|
+
return err(validation.error);
|
|
87
|
+
return fromPromise((async () => {
|
|
88
|
+
const row = getStmt.get(profileId);
|
|
89
|
+
if (!row)
|
|
90
|
+
return undefined;
|
|
91
|
+
const r = rowToProfile(row);
|
|
92
|
+
if (!r.ok)
|
|
93
|
+
throw r.error;
|
|
94
|
+
return r.value;
|
|
95
|
+
})());
|
|
96
|
+
},
|
|
97
|
+
async set(profileId, profile) {
|
|
98
|
+
const validation = validateProfileId(profileId);
|
|
99
|
+
if (!validation.ok)
|
|
100
|
+
return err(validation.error);
|
|
101
|
+
const fullProfile = { ...profile, profileId, version: SCHEMA_VERSION };
|
|
102
|
+
const payload = JSON.stringify(fullProfile);
|
|
103
|
+
const encryptResult = crypto.encrypt(payload);
|
|
104
|
+
if (!encryptResult.ok)
|
|
105
|
+
return err(encryptResult.error);
|
|
106
|
+
const enc = encryptResult.value;
|
|
107
|
+
const now = Date.now();
|
|
108
|
+
return fromPromise((async () => {
|
|
109
|
+
upsertStmt.run(profileId, validation.value.provider, validation.value.identity, enc.ciphertext, enc.iv, enc.authTag, enc.salt, fullProfile.expires, SCHEMA_VERSION, now, now);
|
|
110
|
+
})());
|
|
111
|
+
},
|
|
112
|
+
async delete(profileId) {
|
|
113
|
+
const validation = validateProfileId(profileId);
|
|
114
|
+
if (!validation.ok)
|
|
115
|
+
return err(validation.error);
|
|
116
|
+
return fromPromise((async () => {
|
|
117
|
+
const result = deleteStmt.run(profileId);
|
|
118
|
+
return result.changes > 0;
|
|
119
|
+
})());
|
|
120
|
+
},
|
|
121
|
+
async list(filter) {
|
|
122
|
+
return fromPromise((async () => {
|
|
123
|
+
const rows = filter?.provider
|
|
124
|
+
? listByProviderStmt.all(filter.provider)
|
|
125
|
+
: listAllStmt.all();
|
|
126
|
+
const profiles = [];
|
|
127
|
+
for (const row of rows) {
|
|
128
|
+
const r = rowToProfile(row);
|
|
129
|
+
if (!r.ok)
|
|
130
|
+
throw r.error;
|
|
131
|
+
profiles.push(r.value);
|
|
132
|
+
}
|
|
133
|
+
return profiles;
|
|
134
|
+
})());
|
|
135
|
+
},
|
|
136
|
+
async has(profileId) {
|
|
137
|
+
const validation = validateProfileId(profileId);
|
|
138
|
+
if (!validation.ok)
|
|
139
|
+
return err(validation.error);
|
|
140
|
+
return fromPromise((async () => existsStmt.get(profileId) !== undefined)());
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
return Object.freeze(port);
|
|
144
|
+
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* prepared statements. Sessions survive process restarts since they are
|
|
6
6
|
* stored in SQLite.
|
|
7
7
|
*
|
|
8
|
-
* Factory function pattern (createSessionStore) consistent with
|
|
8
|
+
* Factory function pattern (createSessionStore) consistent with
|
|
9
9
|
* createSecretManager for minimal public surface area.
|
|
10
10
|
*/
|
|
11
11
|
import type Database from "better-sqlite3";
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* prepared statements. Sessions survive process restarts since they are
|
|
7
7
|
* stored in SQLite.
|
|
8
8
|
*
|
|
9
|
-
* Factory function pattern (createSessionStore) consistent with
|
|
9
|
+
* Factory function pattern (createSessionStore) consistent with
|
|
10
10
|
* createSecretManager for minimal public surface area.
|
|
11
11
|
*/
|
|
12
12
|
import { formatSessionKey } from "@comis/core";
|
|
@@ -10,7 +10,32 @@
|
|
|
10
10
|
*
|
|
11
11
|
* Persists encrypted secrets across daemon restarts.
|
|
12
12
|
*/
|
|
13
|
+
import type Database from "better-sqlite3";
|
|
13
14
|
import type { SecretStorePort, SecretsCrypto } from "@comis/core";
|
|
15
|
+
/**
|
|
16
|
+
* Concrete return type of createSqliteSecretStore.
|
|
17
|
+
*
|
|
18
|
+
* Implements SecretStorePort and additionally exposes the underlying
|
|
19
|
+
* better-sqlite3 handle for adapters that need to share the same
|
|
20
|
+
* connection (e.g., the encrypted OAuth profile store).
|
|
21
|
+
*
|
|
22
|
+
* The `db` field is intentionally additive — `SecretStorePort` itself is
|
|
23
|
+
* unchanged and remains the canonical port boundary. Consumers that only
|
|
24
|
+
* need port-level operations should accept `SecretStorePort`, not
|
|
25
|
+
* `SqliteSecretStoreHandle`.
|
|
26
|
+
*/
|
|
27
|
+
export interface SqliteSecretStoreHandle extends SecretStorePort {
|
|
28
|
+
/**
|
|
29
|
+
* Underlying better-sqlite3 handle.
|
|
30
|
+
*
|
|
31
|
+
* Use for sharing the connection with sibling tables in the same DB
|
|
32
|
+
* file (e.g., `oauth_profiles` alongside `secrets`). Eliminates the
|
|
33
|
+
* dual-handle hazard (close-order, schema-init double-execution,
|
|
34
|
+
* prepared-statement cache fragmentation) that two separate handles
|
|
35
|
+
* to the same WAL-mode SQLite file would introduce.
|
|
36
|
+
*/
|
|
37
|
+
readonly db: Database.Database;
|
|
38
|
+
}
|
|
14
39
|
/**
|
|
15
40
|
* Create a SqliteSecretStore bound to the given database path.
|
|
16
41
|
*
|
|
@@ -22,11 +47,12 @@ import type { SecretStorePort, SecretsCrypto } from "@comis/core";
|
|
|
22
47
|
* 5. Validate canary (master key mismatch detection)
|
|
23
48
|
* 6. Second chmod pass (SQLite may create WAL/SHM during canary)
|
|
24
49
|
* 7. Prepare all SQL statements once
|
|
25
|
-
* 8. Return frozen SecretStorePort
|
|
50
|
+
* 8. Return frozen SqliteSecretStoreHandle (SecretStorePort + db field)
|
|
26
51
|
*
|
|
27
52
|
* @param dbPath - Absolute path to the secrets.db file
|
|
28
53
|
* @param crypto - SecretsCrypto engine bound to the current master key
|
|
29
|
-
* @returns SecretStorePort
|
|
54
|
+
* @returns SqliteSecretStoreHandle — a SecretStorePort that also exposes
|
|
55
|
+
* the underlying better-sqlite3 handle on `.db`
|
|
30
56
|
* @throws Error if schema init, canary validation, or DB open fails
|
|
31
57
|
*/
|
|
32
|
-
export declare function createSqliteSecretStore(dbPath: string, crypto: SecretsCrypto):
|
|
58
|
+
export declare function createSqliteSecretStore(dbPath: string, crypto: SecretsCrypto): SqliteSecretStoreHandle;
|
|
@@ -25,11 +25,12 @@ import { openSqliteDatabase, chmodDbFiles } from "./sqlite-adapter-base.js";
|
|
|
25
25
|
* 5. Validate canary (master key mismatch detection)
|
|
26
26
|
* 6. Second chmod pass (SQLite may create WAL/SHM during canary)
|
|
27
27
|
* 7. Prepare all SQL statements once
|
|
28
|
-
* 8. Return frozen SecretStorePort
|
|
28
|
+
* 8. Return frozen SqliteSecretStoreHandle (SecretStorePort + db field)
|
|
29
29
|
*
|
|
30
30
|
* @param dbPath - Absolute path to the secrets.db file
|
|
31
31
|
* @param crypto - SecretsCrypto engine bound to the current master key
|
|
32
|
-
* @returns SecretStorePort
|
|
32
|
+
* @returns SqliteSecretStoreHandle — a SecretStorePort that also exposes
|
|
33
|
+
* the underlying better-sqlite3 handle on `.db`
|
|
33
34
|
* @throws Error if schema init, canary validation, or DB open fails
|
|
34
35
|
*/
|
|
35
36
|
export function createSqliteSecretStore(dbPath, crypto) {
|
|
@@ -149,5 +150,12 @@ export function createSqliteSecretStore(dbPath, crypto) {
|
|
|
149
150
|
db.close();
|
|
150
151
|
},
|
|
151
152
|
};
|
|
152
|
-
return
|
|
153
|
+
// Expose the underlying db handle on the factory return so the encrypted
|
|
154
|
+
// OAuth profile adapter (oauth-profile-store-encrypted) can share this same
|
|
155
|
+
// connection rather than opening a second handle to the same secrets.db
|
|
156
|
+
// file. The SecretStorePort surface itself is unchanged — consumers that
|
|
157
|
+
// only need port-level operations should accept SecretStorePort, not
|
|
158
|
+
// SqliteSecretStoreHandle.
|
|
159
|
+
const handle = { ...store, db };
|
|
160
|
+
return Object.freeze(handle);
|
|
153
161
|
}
|
|
@@ -14,6 +14,19 @@ export interface ExecutionLockOptions {
|
|
|
14
14
|
updateMs: number;
|
|
15
15
|
/** Callback when lock is compromised (e.g., external release). */
|
|
16
16
|
onCompromised?: (err: Error) => void;
|
|
17
|
+
/**
|
|
18
|
+
* Optional lock-acquisition retry budget. Forwarded to proper-lockfile's
|
|
19
|
+
* own retry option (uses a built-in incremental backoff). When undefined
|
|
20
|
+
* (default), retries: 0 — fail fast on contention. Lets the OAuth manager
|
|
21
|
+
* wait for a sibling refresh to complete (concurrent-refresh acceptance)
|
|
22
|
+
* without callers having to roll their own retry loop.
|
|
23
|
+
*/
|
|
24
|
+
retries?: number | {
|
|
25
|
+
retries: number;
|
|
26
|
+
minTimeout?: number;
|
|
27
|
+
maxTimeout?: number;
|
|
28
|
+
factor?: number;
|
|
29
|
+
};
|
|
17
30
|
}
|
|
18
31
|
/**
|
|
19
32
|
* Acquire a file lock, execute the function, and release the lock.
|
|
@@ -41,7 +41,7 @@ export async function withExecutionLock(lockPath, fn, options) {
|
|
|
41
41
|
release = await lockfile.lock(lockPath, {
|
|
42
42
|
stale: opts.staleMs,
|
|
43
43
|
update: opts.updateMs,
|
|
44
|
-
retries: 0,
|
|
44
|
+
retries: opts.retries ?? 0,
|
|
45
45
|
onCompromised: opts.onCompromised ?? (() => { }),
|
|
46
46
|
});
|
|
47
47
|
}
|
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
export { createExecutionTracker } from "./execution-tracker.js";
|
|
2
2
|
export type { ExecutionTracker, ExecutionLogEntry } from "./execution-tracker.js";
|
|
3
|
+
export { withExecutionLock, isLocked } from "./execution-lock.js";
|
|
4
|
+
export type { ExecutionLockOptions } from "./execution-lock.js";
|
|
@@ -158,7 +158,7 @@ export function createAgentHeartbeatSource(deps) {
|
|
|
158
158
|
},
|
|
159
159
|
};
|
|
160
160
|
// 9. Resolve model (for logging)
|
|
161
|
-
const model = resolveHeartbeatModel(undefined, // per-agent heartbeat model
|
|
161
|
+
const model = resolveHeartbeatModel(undefined, // per-agent heartbeat model not in schema
|
|
162
162
|
undefined, // global heartbeat model not yet in schema
|
|
163
163
|
agentConfig.model);
|
|
164
164
|
logger.info({ agentId, trigger, model, channelType: msg.channelType }, "Heartbeat run starting");
|
|
@@ -7,6 +7,8 @@ export { createCronScheduler } from "./cron/index.js";
|
|
|
7
7
|
export type { CronScheduler } from "./cron/index.js";
|
|
8
8
|
export { createExecutionTracker } from "./execution/index.js";
|
|
9
9
|
export type { ExecutionTracker, ExecutionLogEntry } from "./execution/index.js";
|
|
10
|
+
export { withExecutionLock, isLocked } from "./execution/execution-lock.js";
|
|
11
|
+
export type { ExecutionLockOptions } from "./execution/execution-lock.js";
|
|
10
12
|
export { HEARTBEAT_OK_TOKEN, createHeartbeatRunner } from "./heartbeat/index.js";
|
|
11
13
|
export type { HeartbeatCheckResult, HeartbeatSourcePort, HeartbeatRunner } from "./heartbeat/index.js";
|
|
12
14
|
export { resolveEffectiveHeartbeatConfig } from "./heartbeat/index.js";
|
|
@@ -7,6 +7,8 @@ export { createCronStore } from "./cron/index.js";
|
|
|
7
7
|
export { createCronScheduler } from "./cron/index.js";
|
|
8
8
|
// Execution safety
|
|
9
9
|
export { createExecutionTracker } from "./execution/index.js";
|
|
10
|
+
// File-based execution lock (consumed by @comis/agent OAuth file adapter + token manager)
|
|
11
|
+
export { withExecutionLock, isLocked } from "./execution/execution-lock.js";
|
|
10
12
|
// Heartbeat monitoring
|
|
11
13
|
export { HEARTBEAT_OK_TOKEN, createHeartbeatRunner } from "./heartbeat/index.js";
|
|
12
14
|
// Per-agent heartbeat config resolution
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic tool-entry schema validator.
|
|
3
|
+
*
|
|
4
|
+
* Pre-flight, action-aware shape gate that runs BEFORE per-tool
|
|
5
|
+
* `validateInput`. Catches malformed shapes such as
|
|
6
|
+
* `mcp_manage({action:"connect", server_name:"yfinance"})` at the
|
|
7
|
+
* tool-entry boundary and produces a self-correcting message:
|
|
8
|
+
*
|
|
9
|
+
* "[invalid_value] unknown key 'server_name' -- did you mean 'name'?.
|
|
10
|
+
* missing for action='connect': transport.
|
|
11
|
+
* valid keys: action, name, transport, command, args, url, headers"
|
|
12
|
+
*
|
|
13
|
+
* Generic by construction: every per-tool branch lives in the metadata
|
|
14
|
+
* registered via `registerToolMetadata({ validActions, validKeys,
|
|
15
|
+
* requiredByAction })`. This file contains zero tool-name conditionals.
|
|
16
|
+
*
|
|
17
|
+
* Reuses `levenshteinSimilarity` from
|
|
18
|
+
* ../builtin/file/path-suggest.js -- DO NOT duplicate the helper.
|
|
19
|
+
*
|
|
20
|
+
* Returns a single error string on failure (matches the
|
|
21
|
+
* `validateInput` contract used by `wrapWithMetadataEnforcement`),
|
|
22
|
+
* `undefined` on success. Caller prepends `[invalid_value]`.
|
|
23
|
+
*
|
|
24
|
+
* @module
|
|
25
|
+
*/
|
|
26
|
+
import type { ComisToolMetadata } from "@comis/core";
|
|
27
|
+
/**
|
|
28
|
+
* Validate tool-entry shape against registered metadata.
|
|
29
|
+
*
|
|
30
|
+
* @param params - Raw params object as the SDK would pass to `execute()`.
|
|
31
|
+
* @param meta - Metadata returned from `getToolMetadata(toolName)`. May be
|
|
32
|
+
* undefined or missing the entry-shape fields -- in either case this
|
|
33
|
+
* function returns undefined (no-op) so existing tools without
|
|
34
|
+
* registered shape metadata pass through unchanged.
|
|
35
|
+
* @returns A single error string when validation fails (caller prepends
|
|
36
|
+
* `[invalid_value]`), or `undefined` when validation passes / is skipped.
|
|
37
|
+
*/
|
|
38
|
+
export declare function validateToolEntry(params: unknown, meta: ComisToolMetadata | undefined): string | undefined;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* Generic tool-entry schema validator.
|
|
4
|
+
*
|
|
5
|
+
* Pre-flight, action-aware shape gate that runs BEFORE per-tool
|
|
6
|
+
* `validateInput`. Catches malformed shapes such as
|
|
7
|
+
* `mcp_manage({action:"connect", server_name:"yfinance"})` at the
|
|
8
|
+
* tool-entry boundary and produces a self-correcting message:
|
|
9
|
+
*
|
|
10
|
+
* "[invalid_value] unknown key 'server_name' -- did you mean 'name'?.
|
|
11
|
+
* missing for action='connect': transport.
|
|
12
|
+
* valid keys: action, name, transport, command, args, url, headers"
|
|
13
|
+
*
|
|
14
|
+
* Generic by construction: every per-tool branch lives in the metadata
|
|
15
|
+
* registered via `registerToolMetadata({ validActions, validKeys,
|
|
16
|
+
* requiredByAction })`. This file contains zero tool-name conditionals.
|
|
17
|
+
*
|
|
18
|
+
* Reuses `levenshteinSimilarity` from
|
|
19
|
+
* ../builtin/file/path-suggest.js -- DO NOT duplicate the helper.
|
|
20
|
+
*
|
|
21
|
+
* Returns a single error string on failure (matches the
|
|
22
|
+
* `validateInput` contract used by `wrapWithMetadataEnforcement`),
|
|
23
|
+
* `undefined` on success. Caller prepends `[invalid_value]`.
|
|
24
|
+
*
|
|
25
|
+
* @module
|
|
26
|
+
*/
|
|
27
|
+
import { levenshteinSimilarity } from "../builtin/file/path-suggest.js";
|
|
28
|
+
/**
|
|
29
|
+
* Min similarity for did-you-mean suggestion. Below this we say "unknown"
|
|
30
|
+
* with no suggestion to avoid misleading the LLM.
|
|
31
|
+
*
|
|
32
|
+
* We score with `tokenAwareSimilarity` (max of full-string similarity and
|
|
33
|
+
* the best per-token similarity after splitting on `_`/`-`). This catches
|
|
34
|
+
* payloads like `server_name -> name` (token "name" matches exactly,
|
|
35
|
+
* score 1.0) without spurious matches against short unrelated keys (`x`,
|
|
36
|
+
* `srver` -> max < 0.3 across all candidates in the 7-key mcp_manage
|
|
37
|
+
* shape, well below threshold).
|
|
38
|
+
*
|
|
39
|
+
* 0.5 was chosen empirically: `conect -> connect` scores 0.857 (fires);
|
|
40
|
+
* `srver -> headers` scores 0.286 (does not fire); the closest false
|
|
41
|
+
* positive across the manage-tool corpus is below 0.5.
|
|
42
|
+
*/
|
|
43
|
+
const SUGGEST_THRESHOLD = 0.5;
|
|
44
|
+
/**
|
|
45
|
+
* Validate tool-entry shape against registered metadata.
|
|
46
|
+
*
|
|
47
|
+
* @param params - Raw params object as the SDK would pass to `execute()`.
|
|
48
|
+
* @param meta - Metadata returned from `getToolMetadata(toolName)`. May be
|
|
49
|
+
* undefined or missing the entry-shape fields -- in either case this
|
|
50
|
+
* function returns undefined (no-op) so existing tools without
|
|
51
|
+
* registered shape metadata pass through unchanged.
|
|
52
|
+
* @returns A single error string when validation fails (caller prepends
|
|
53
|
+
* `[invalid_value]`), or `undefined` when validation passes / is skipped.
|
|
54
|
+
*/
|
|
55
|
+
export function validateToolEntry(params, meta) {
|
|
56
|
+
// Skip if no entry-shape metadata registered.
|
|
57
|
+
if (meta === undefined
|
|
58
|
+
|| (meta.validActions === undefined
|
|
59
|
+
&& meta.validKeys === undefined
|
|
60
|
+
&& meta.requiredByAction === undefined)) {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
// Shape gate: params MUST be a plain object. Reject null, primitives,
|
|
64
|
+
// and arrays. (Arrays would otherwise pass typeof === "object".)
|
|
65
|
+
if (params === null || typeof params !== "object" || Array.isArray(params)) {
|
|
66
|
+
return "params must be an object";
|
|
67
|
+
}
|
|
68
|
+
const p = params;
|
|
69
|
+
const segments = [];
|
|
70
|
+
// Action gate.
|
|
71
|
+
let action;
|
|
72
|
+
if (meta.validActions !== undefined) {
|
|
73
|
+
const raw = p.action;
|
|
74
|
+
if (raw === undefined) {
|
|
75
|
+
segments.push(`Missing required parameter: action. valid actions: ${meta.validActions.join(", ")}`);
|
|
76
|
+
}
|
|
77
|
+
else if (typeof raw !== "string") {
|
|
78
|
+
segments.push("action must be a string");
|
|
79
|
+
}
|
|
80
|
+
else if (!meta.validActions.includes(raw)) {
|
|
81
|
+
const suggestion = bestMatch(raw, meta.validActions);
|
|
82
|
+
const didYouMean = suggestion !== undefined ? ` -- did you mean '${suggestion}'?` : "";
|
|
83
|
+
segments.push(`invalid action '${raw}'${didYouMean}. valid actions: ${meta.validActions.join(", ")}`);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
action = raw;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
else if (typeof p.action === "string") {
|
|
90
|
+
// No validActions registered but the tool still uses an action field
|
|
91
|
+
// (rare). Use it for requiredByAction lookup.
|
|
92
|
+
action = p.action;
|
|
93
|
+
}
|
|
94
|
+
// Unknown-key gate.
|
|
95
|
+
if (meta.validKeys !== undefined) {
|
|
96
|
+
const validSet = new Set(meta.validKeys);
|
|
97
|
+
const unknowns = [];
|
|
98
|
+
for (const key of Object.keys(p)) {
|
|
99
|
+
if (!validSet.has(key))
|
|
100
|
+
unknowns.push(key);
|
|
101
|
+
}
|
|
102
|
+
if (unknowns.length > 0) {
|
|
103
|
+
const parts = unknowns.map((k) => {
|
|
104
|
+
const suggestion = bestMatch(k, meta.validKeys);
|
|
105
|
+
return suggestion !== undefined
|
|
106
|
+
? `unknown key '${k}' -- did you mean '${suggestion}'?`
|
|
107
|
+
: `unknown key '${k}'`;
|
|
108
|
+
});
|
|
109
|
+
segments.push(parts.join("; "));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Required-fields gate (only when we have a known action).
|
|
113
|
+
if (action !== undefined && meta.requiredByAction !== undefined) {
|
|
114
|
+
const required = meta.requiredByAction[action];
|
|
115
|
+
if (required !== undefined && required.length > 0) {
|
|
116
|
+
const missing = required.filter((k) => !(k in p) || p[k] === undefined);
|
|
117
|
+
if (missing.length > 0) {
|
|
118
|
+
segments.push(`missing for action='${action}': ${missing.join(", ")}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (segments.length === 0)
|
|
123
|
+
return undefined;
|
|
124
|
+
// Always append valid-keys list when registered -- closes the LLM's
|
|
125
|
+
// self-correction loop in one turn.
|
|
126
|
+
if (meta.validKeys !== undefined) {
|
|
127
|
+
segments.push(`valid keys: ${meta.validKeys.join(", ")}`);
|
|
128
|
+
}
|
|
129
|
+
return segments.join(". ");
|
|
130
|
+
}
|
|
131
|
+
/** Pick the best-matching candidate above SUGGEST_THRESHOLD, or undefined. */
|
|
132
|
+
function bestMatch(input, candidates) {
|
|
133
|
+
let best;
|
|
134
|
+
const lowered = input.toLowerCase();
|
|
135
|
+
for (const candidate of candidates) {
|
|
136
|
+
const score = tokenAwareSimilarity(lowered, candidate.toLowerCase());
|
|
137
|
+
if (score >= SUGGEST_THRESHOLD && (best === undefined || score > best.score)) {
|
|
138
|
+
best = { value: candidate, score };
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return best?.value;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Token-aware similarity: max of full-string similarity and the best
|
|
145
|
+
* per-token similarity after splitting `input` on `_`/`-`.
|
|
146
|
+
*
|
|
147
|
+
* Plain Levenshtein on full strings misses snake_case key suggestions:
|
|
148
|
+
* `server_name` vs `name` is similarity 0.36, well below any reasonable
|
|
149
|
+
* threshold. Splitting on `_` exposes the `name` token (similarity 1.0
|
|
150
|
+
* vs `name`), which is the LLM-self-correction signal we want to surface.
|
|
151
|
+
*
|
|
152
|
+
* Inputs are assumed lowercased by the caller.
|
|
153
|
+
*/
|
|
154
|
+
function tokenAwareSimilarity(input, candidate) {
|
|
155
|
+
let best = levenshteinSimilarity(input, candidate);
|
|
156
|
+
// Split on '_' or '-' (skill, manage-tool, snake_case conventions). Empty
|
|
157
|
+
// tokens are dropped so leading/trailing/double-separators do not produce
|
|
158
|
+
// 0-length strings that would skew similarity to 1.0 against an empty
|
|
159
|
+
// candidate (defensive -- candidate is non-empty in practice).
|
|
160
|
+
const tokens = input.split(/[_-]+/);
|
|
161
|
+
for (const t of tokens) {
|
|
162
|
+
if (t.length === 0)
|
|
163
|
+
continue;
|
|
164
|
+
const score = levenshteinSimilarity(t, candidate);
|
|
165
|
+
if (score > best)
|
|
166
|
+
best = score;
|
|
167
|
+
}
|
|
168
|
+
return best;
|
|
169
|
+
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* @module
|
|
12
12
|
*/
|
|
13
13
|
import { getToolMetadata, truncateContentBlocks } from "@comis/core";
|
|
14
|
+
import { validateToolEntry } from "./schema-validator.js";
|
|
14
15
|
/**
|
|
15
16
|
* Check whether a tool result's content is effectively empty.
|
|
16
17
|
*
|
|
@@ -60,6 +61,17 @@ export function wrapWithMetadataEnforcement(tool) {
|
|
|
60
61
|
...tool,
|
|
61
62
|
async execute(toolCallId, params, signal, onUpdate) {
|
|
62
63
|
const meta = getToolMetadata(tool.name);
|
|
64
|
+
// Generic tool-entry schema validation (260504-cac).
|
|
65
|
+
// Runs BEFORE per-tool validateInput so action-shape errors short-circuit
|
|
66
|
+
// before tool-specific business rules. Skips silently when the tool has
|
|
67
|
+
// not registered validActions / validKeys / requiredByAction.
|
|
68
|
+
const schemaError = validateToolEntry(params, meta);
|
|
69
|
+
if (schemaError !== undefined) {
|
|
70
|
+
const err = new Error(`[invalid_value] ${schemaError}`);
|
|
71
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- match existing errorKind propagation pattern
|
|
72
|
+
err.errorKind = "validation";
|
|
73
|
+
throw err;
|
|
74
|
+
}
|
|
63
75
|
// Pre-flight validation
|
|
64
76
|
if (meta?.validateInput) {
|
|
65
77
|
const validationError = await meta.validateInput(params);
|