comisai 1.0.34 → 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/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
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
/**
|
|
3
|
-
* Agent management commands: list, create, configure, delete, models.
|
|
3
|
+
* Agent management commands: list, create, configure, delete, models, set-oauth-profile.
|
|
4
4
|
*
|
|
5
|
-
* Provides `comis agent [list|create|configure|delete|models]`
|
|
6
|
-
* for managing agent configurations via the daemon RPC interface.
|
|
5
|
+
* Provides `comis agent [list|create|configure|delete|models|set-oauth-profile]`
|
|
6
|
+
* subcommands for managing agent configurations via the daemon RPC interface.
|
|
7
7
|
*
|
|
8
8
|
* @module
|
|
9
9
|
*/
|
|
10
|
+
import { validateProfileId } from "@comis/core";
|
|
10
11
|
import { ensureWorkspace, resolveWorkspaceDir } from "@comis/agent";
|
|
11
12
|
import chalk from "chalk";
|
|
12
13
|
import { withClient } from "../client/rpc-client.js";
|
|
@@ -127,6 +128,48 @@ export function registerAgentCommand(program) {
|
|
|
127
128
|
process.exit(1);
|
|
128
129
|
}
|
|
129
130
|
});
|
|
131
|
+
// agent set-oauth-profile <agentId> <profileId>
|
|
132
|
+
//
|
|
133
|
+
// Pin a per-agent OAuth profile preference. The provider is derived from
|
|
134
|
+
// the profile-id's `<provider>:<identity>` portion — there is NO separate
|
|
135
|
+
// --provider flag (single-source-of-truth). Validation runs client-side
|
|
136
|
+
// via validateProfileId; the daemon's agents.update handler additionally
|
|
137
|
+
// rejects unknown profile IDs via OAuthCredentialStore.has(). Daemon
|
|
138
|
+
// errors substring-matching "not found" are surfaced verbatim with
|
|
139
|
+
// exit 1; format violations exit 2.
|
|
140
|
+
agent
|
|
141
|
+
.command("set-oauth-profile <agentId> <profileId>")
|
|
142
|
+
.description("Set the OAuth profile preference for an agent (provider derived from profile-id)")
|
|
143
|
+
.action(async (agentId, profileId) => {
|
|
144
|
+
const validated = validateProfileId(profileId);
|
|
145
|
+
if (!validated.ok) {
|
|
146
|
+
error(`Invalid profile ID: ${validated.error.message}. Expected format: <provider>:<identity>.`);
|
|
147
|
+
process.exit(2);
|
|
148
|
+
}
|
|
149
|
+
const { provider } = validated.value;
|
|
150
|
+
try {
|
|
151
|
+
await withSpinner(`Setting OAuth profile for "${agentId}"...`, () => withClient(async (client) => {
|
|
152
|
+
return await client.call("agents.update", {
|
|
153
|
+
agentId,
|
|
154
|
+
config: { oauthProfiles: { [provider]: profileId } },
|
|
155
|
+
});
|
|
156
|
+
}));
|
|
157
|
+
success(`Set agent ${agentId} oauthProfiles[${provider}] = ${profileId}`);
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
161
|
+
// The daemon's PROFILE_NOT_FOUND surfaces with "not found" in the
|
|
162
|
+
// message. Substring-match to surface as exit 1 with the daemon's
|
|
163
|
+
// actionable wording (which already names the profile and references
|
|
164
|
+
// `comis auth list`).
|
|
165
|
+
if (msg.includes("not found")) {
|
|
166
|
+
error(msg);
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
error(`Failed to set oauth profile: ${msg}`);
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
130
173
|
// agent delete <name>
|
|
131
174
|
agent
|
|
132
175
|
.command("delete <name>")
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `comis auth` CLI command tree.
|
|
3
|
+
*
|
|
4
|
+
* Four subcommands operating directly against the OAuthCredentialStorePort
|
|
5
|
+
* (no daemon RPC — store is the IPC primitive between CLI and daemon, with
|
|
6
|
+
* the daemon picking up changes via the chokidar watcher):
|
|
7
|
+
*
|
|
8
|
+
* - `comis auth login` — interactive OAuth login (browser + manual paste).
|
|
9
|
+
* Accepts `--profile <id>` to override the storage
|
|
10
|
+
* key; the user-supplied id replaces the
|
|
11
|
+
* JWT-derived `<provider>:<email>` while the
|
|
12
|
+
* identity fields on the persisted profile remain
|
|
13
|
+
* JWT-derived. Provider portion of `--profile` must
|
|
14
|
+
* equal `--provider` or the command exits 2.
|
|
15
|
+
* - `comis auth list` — list stored profiles in a 5-column table; supports
|
|
16
|
+
* `--provider <id>` filter — pure client-side string
|
|
17
|
+
* match, no validation against pi-ai's known list.
|
|
18
|
+
* - `comis auth logout` — remove a profile by ID
|
|
19
|
+
* - `comis auth status` — per-provider summary (count + nextExpiry); supports
|
|
20
|
+
* `--provider <id>` filter with the same semantics
|
|
21
|
+
* as `auth list`.
|
|
22
|
+
*
|
|
23
|
+
* Only `--provider openai-codex` is supported for `auth login` today. Other
|
|
24
|
+
* providers ship later. The `--provider` filter on `list` / `status` is
|
|
25
|
+
* unconstrained because the filter is purely cosmetic.
|
|
26
|
+
*
|
|
27
|
+
* All commands run in the CLI process; the local OAuth callback server
|
|
28
|
+
* (pi-ai's hardcoded localhost:1455) binds to the user's interactive
|
|
29
|
+
* machine — daemon may be on a remote host.
|
|
30
|
+
*
|
|
31
|
+
* @module
|
|
32
|
+
*/
|
|
33
|
+
import type { Command } from "commander";
|
|
34
|
+
/**
|
|
35
|
+
* Register the `auth` command group on the program.
|
|
36
|
+
*/
|
|
37
|
+
export declare function registerAuthCommand(program: Command): void;
|
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* `comis auth` CLI command tree.
|
|
4
|
+
*
|
|
5
|
+
* Four subcommands operating directly against the OAuthCredentialStorePort
|
|
6
|
+
* (no daemon RPC — store is the IPC primitive between CLI and daemon, with
|
|
7
|
+
* the daemon picking up changes via the chokidar watcher):
|
|
8
|
+
*
|
|
9
|
+
* - `comis auth login` — interactive OAuth login (browser + manual paste).
|
|
10
|
+
* Accepts `--profile <id>` to override the storage
|
|
11
|
+
* key; the user-supplied id replaces the
|
|
12
|
+
* JWT-derived `<provider>:<email>` while the
|
|
13
|
+
* identity fields on the persisted profile remain
|
|
14
|
+
* JWT-derived. Provider portion of `--profile` must
|
|
15
|
+
* equal `--provider` or the command exits 2.
|
|
16
|
+
* - `comis auth list` — list stored profiles in a 5-column table; supports
|
|
17
|
+
* `--provider <id>` filter — pure client-side string
|
|
18
|
+
* match, no validation against pi-ai's known list.
|
|
19
|
+
* - `comis auth logout` — remove a profile by ID
|
|
20
|
+
* - `comis auth status` — per-provider summary (count + nextExpiry); supports
|
|
21
|
+
* `--provider <id>` filter with the same semantics
|
|
22
|
+
* as `auth list`.
|
|
23
|
+
*
|
|
24
|
+
* Only `--provider openai-codex` is supported for `auth login` today. Other
|
|
25
|
+
* providers ship later. The `--provider` filter on `list` / `status` is
|
|
26
|
+
* unconstrained because the filter is purely cosmetic.
|
|
27
|
+
*
|
|
28
|
+
* All commands run in the CLI process; the local OAuth callback server
|
|
29
|
+
* (pi-ai's hardcoded localhost:1455) binds to the user's interactive
|
|
30
|
+
* machine — daemon may be on a remote host.
|
|
31
|
+
*
|
|
32
|
+
* @module
|
|
33
|
+
*/
|
|
34
|
+
import { homedir } from "node:os";
|
|
35
|
+
import open from "open";
|
|
36
|
+
import { loadConfigFile, validateConfig, safePath, validateProfileId, } from "@comis/core";
|
|
37
|
+
import { selectOAuthCredentialStore, loginOpenAICodexOAuth, isRemoteEnvironment, redactEmailForLog, } from "@comis/agent";
|
|
38
|
+
import { createLogger } from "@comis/infra";
|
|
39
|
+
import { error, info, success } from "../output/format.js";
|
|
40
|
+
import { renderTable } from "../output/table.js";
|
|
41
|
+
import { formatRelativeExpiry } from "../output/relative-time.js";
|
|
42
|
+
import { createClackAdapter } from "../wizard/clack-adapter.js";
|
|
43
|
+
const PROVIDER_OPENAI_CODEX = "openai-codex";
|
|
44
|
+
const ACTIVE_THRESHOLD_MS = 5 * 60_000; // 5 minutes — match status logic
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// OAuthError discrimination helpers.
|
|
47
|
+
//
|
|
48
|
+
// `exitOnOAuthError` translates a structured OAuthError into stderr output +
|
|
49
|
+
// exit code 1; `isOAuthError` is a defensive type guard so the catch blocks
|
|
50
|
+
// can route OAuthError values through the structured handler while letting
|
|
51
|
+
// generic JS errors fall through to the existing `Failed to ${verb}: ${msg}`
|
|
52
|
+
// pattern.
|
|
53
|
+
//
|
|
54
|
+
// Per CLAUDE.md "Logging" — CLI uses `format.ts` (stderr/stdout) NOT Pino;
|
|
55
|
+
// this is the documented exception. The literal "Re-authenticate with: comis
|
|
56
|
+
// auth login --provider <providerId>" line is the acceptance literal the
|
|
57
|
+
// integration test grep-asserts (test/integration/oauth-refresh-token-reused.test.ts).
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
/**
|
|
60
|
+
* Translate a structured OAuthError into stderr output + exit code 1.
|
|
61
|
+
*
|
|
62
|
+
* When `errorKind === "refresh_token_reused"`, the CLI prints the canonical
|
|
63
|
+
* re-login command with exit code 1. Other errorKinds (invalid_grant, etc.)
|
|
64
|
+
* get tailored messages; unknown OAuthErrors fall through to the generic
|
|
65
|
+
* shape.
|
|
66
|
+
*
|
|
67
|
+
* Returns `never` — always exits the process.
|
|
68
|
+
*/
|
|
69
|
+
function exitOnOAuthError(err) {
|
|
70
|
+
if (err.errorKind === "refresh_token_reused") {
|
|
71
|
+
error("Refresh token was reused. The OpenAI account has been auto-locked for security.");
|
|
72
|
+
info(`Re-authenticate with: comis auth login --provider ${err.providerId}`);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
if (err.errorKind === "invalid_grant") {
|
|
76
|
+
const profileSlug = err.profileId ?? "unknown";
|
|
77
|
+
error(`Refresh token was rejected by OpenAI (invalid_grant) for profile "${profileSlug}".`);
|
|
78
|
+
info(`Re-authenticate with: comis auth login --provider ${err.providerId}`);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
error(`OAuthError (${err.code}): ${err.message}`);
|
|
82
|
+
if (err.hint)
|
|
83
|
+
info(err.hint);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Type guard: detect an OAuthError shape on a caught unknown value.
|
|
88
|
+
* Distinguishes the structured error from generic JS errors so the CLI can
|
|
89
|
+
* route through `exitOnOAuthError` (above). Match against the 5 known
|
|
90
|
+
* `OAuthError.code` values to avoid false positives on third-party errors
|
|
91
|
+
* that happen to carry `code`/`providerId`/`message` keys.
|
|
92
|
+
*/
|
|
93
|
+
function isOAuthError(value) {
|
|
94
|
+
if (!value || typeof value !== "object")
|
|
95
|
+
return false;
|
|
96
|
+
const v = value;
|
|
97
|
+
return (typeof v.code === "string" &&
|
|
98
|
+
typeof v.message === "string" &&
|
|
99
|
+
typeof v.providerId === "string" &&
|
|
100
|
+
[
|
|
101
|
+
"NO_PROVIDER",
|
|
102
|
+
"NO_CREDENTIALS",
|
|
103
|
+
"REFRESH_FAILED",
|
|
104
|
+
"STORE_FAILED",
|
|
105
|
+
"PROFILE_NOT_FOUND",
|
|
106
|
+
].includes(v.code));
|
|
107
|
+
}
|
|
108
|
+
// Module-scoped logger. The CLI process runs short-lived commands; one
|
|
109
|
+
// logger instance is shared across all 4 subcommands. Per CLAUDE.md, every
|
|
110
|
+
// log call also sets `submodule: "auth-cli"` for filterability.
|
|
111
|
+
const logger = createLogger({ name: "auth-cli" });
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
// Internal: open the OAuth credential store using the same selector the
|
|
114
|
+
// daemon uses. Reads appConfig.oauth.storage from the user's config file
|
|
115
|
+
// with safe defaults when no config exists (e.g., daemon never set up).
|
|
116
|
+
//
|
|
117
|
+
// Both loadConfigFile and validateConfig are Result-typed (per @comis/core),
|
|
118
|
+
// so this function never throws — config errors fall through to the file
|
|
119
|
+
// adapter default, which is the safe operator-friendly behavior for a
|
|
120
|
+
// freshly-installed CLI.
|
|
121
|
+
// ---------------------------------------------------------------------------
|
|
122
|
+
function openOAuthStoreFromConfig() {
|
|
123
|
+
const dataDir = safePath(homedir(), ".comis");
|
|
124
|
+
// eslint-disable-next-line no-restricted-syntax -- CLI bootstrap before SecretManager
|
|
125
|
+
const envPaths = process.env.COMIS_CONFIG_PATHS;
|
|
126
|
+
const configPath = envPaths?.split(",")[0] ?? safePath(homedir(), ".comis", "config.yaml");
|
|
127
|
+
const loadResult = loadConfigFile(configPath);
|
|
128
|
+
if (!loadResult.ok) {
|
|
129
|
+
// No config file → default to file storage (the file adapter creates
|
|
130
|
+
// ~/.comis/auth-profiles.json on first set).
|
|
131
|
+
return selectOAuthCredentialStore({ storage: "file", dataDir });
|
|
132
|
+
}
|
|
133
|
+
const validateResult = validateConfig(loadResult.value);
|
|
134
|
+
if (!validateResult.ok) {
|
|
135
|
+
// Invalid config — fail fast with a clear hint pointing at the daemon
|
|
136
|
+
// bootstrap message that surfaces the same Zod issue.
|
|
137
|
+
error(`Failed to load config: ${validateResult.error.message}. ` +
|
|
138
|
+
"Hint: run `comis configure` or fix the YAML at " +
|
|
139
|
+
`${configPath} before retrying.`);
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
const storage = validateResult.value.oauth.storage;
|
|
143
|
+
if (storage === "encrypted") {
|
|
144
|
+
// Encrypted-mode bootstrap from CLI requires SECRETS_MASTER_KEY + the
|
|
145
|
+
// secrets DB. The CLI does NOT spin up the SecretsCrypto/secretsDb
|
|
146
|
+
// here — surface a fail-fast error pointing at the daemon's
|
|
147
|
+
// encrypted-mode path. Operators with encrypted storage must run
|
|
148
|
+
// `comis auth login` from the daemon host (where SECRETS_MASTER_KEY
|
|
149
|
+
// is exported), or switch to file storage.
|
|
150
|
+
error("OAuth storage mode is 'encrypted' but the CLI cannot bootstrap the encrypted store. " +
|
|
151
|
+
"Hint: Either (1) export SECRETS_MASTER_KEY in this shell and rerun, or (2) change " +
|
|
152
|
+
"appConfig.oauth.storage to 'file' for `comis auth login` flows.");
|
|
153
|
+
process.exit(1);
|
|
154
|
+
}
|
|
155
|
+
return selectOAuthCredentialStore({ storage: "file", dataDir });
|
|
156
|
+
}
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
// Internal: build a status string from an absolute expiry timestamp.
|
|
159
|
+
// ---------------------------------------------------------------------------
|
|
160
|
+
function profileStatus(expiresAtMs) {
|
|
161
|
+
return expiresAtMs - Date.now() > ACTIVE_THRESHOLD_MS ? "active" : "expired";
|
|
162
|
+
}
|
|
163
|
+
// ---------------------------------------------------------------------------
|
|
164
|
+
// Public boundary
|
|
165
|
+
// ---------------------------------------------------------------------------
|
|
166
|
+
/**
|
|
167
|
+
* Register the `auth` command group on the program.
|
|
168
|
+
*/
|
|
169
|
+
export function registerAuthCommand(program) {
|
|
170
|
+
const auth = program
|
|
171
|
+
.command("auth")
|
|
172
|
+
.description("OAuth authentication management");
|
|
173
|
+
// -------------------------------------------------------------------------
|
|
174
|
+
// login
|
|
175
|
+
// -------------------------------------------------------------------------
|
|
176
|
+
auth
|
|
177
|
+
.command("login")
|
|
178
|
+
.description("Log in to an OAuth-enabled provider")
|
|
179
|
+
.requiredOption("--provider <id>", "OAuth provider id (must be 'openai-codex')")
|
|
180
|
+
.option("--remote", "Force remote/headless mode (no browser)")
|
|
181
|
+
.option("--local", "Force local/desktop mode (try to open browser)")
|
|
182
|
+
.option("--profile <id>", "Override the auto-derived profile ID (provider portion must match --provider)")
|
|
183
|
+
.option("--method <method>", "Login method: 'browser' (default) or 'device-code' (SSH/no-clipboard)")
|
|
184
|
+
.action(async (opts) => {
|
|
185
|
+
// Provider must be openai-codex.
|
|
186
|
+
if (opts.provider !== PROVIDER_OPENAI_CODEX) {
|
|
187
|
+
error("--provider must be 'openai-codex' (other providers ship later)");
|
|
188
|
+
process.exit(2);
|
|
189
|
+
}
|
|
190
|
+
// Validate --profile override when supplied.
|
|
191
|
+
// The user-supplied id becomes the storage key; the provider portion
|
|
192
|
+
// MUST match --provider (defense against accidentally writing an
|
|
193
|
+
// anthropic profile under an openai-codex login flow).
|
|
194
|
+
if (opts.profile) {
|
|
195
|
+
const validated = validateProfileId(opts.profile);
|
|
196
|
+
if (!validated.ok) {
|
|
197
|
+
error(`Invalid --profile value: ${validated.error.message}. Expected format: <provider>:<identity>.`);
|
|
198
|
+
process.exit(2);
|
|
199
|
+
}
|
|
200
|
+
if (validated.value.provider !== opts.provider) {
|
|
201
|
+
error(`--profile provider portion ("${validated.value.provider}") must match --provider value ("${opts.provider}") — provider mismatch.`);
|
|
202
|
+
process.exit(2);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// Validate --method flag.
|
|
206
|
+
// Defense-in-depth: any value other than "device-code" silently
|
|
207
|
+
// maps to "browser" — the CLI never crashes on an unknown method,
|
|
208
|
+
// it falls back to the safe default.
|
|
209
|
+
const method = opts.method === "device-code" ? "device-code" : "browser";
|
|
210
|
+
if (method === "device-code" && opts.provider !== PROVIDER_OPENAI_CODEX) {
|
|
211
|
+
error("--method device-code is only supported with --provider openai-codex " +
|
|
212
|
+
"(other providers do not support device-code today)");
|
|
213
|
+
process.exit(2);
|
|
214
|
+
}
|
|
215
|
+
try {
|
|
216
|
+
const store = openOAuthStoreFromConfig();
|
|
217
|
+
const isRemote = isRemoteEnvironment({
|
|
218
|
+
env: process.env,
|
|
219
|
+
force: opts.remote ? "remote" : opts.local ? "local" : undefined,
|
|
220
|
+
});
|
|
221
|
+
const prompter = createClackAdapter();
|
|
222
|
+
const result = await loginOpenAICodexOAuth({
|
|
223
|
+
prompter,
|
|
224
|
+
isRemote,
|
|
225
|
+
openUrl: open,
|
|
226
|
+
logger,
|
|
227
|
+
method,
|
|
228
|
+
});
|
|
229
|
+
if (!result.ok) {
|
|
230
|
+
error(result.error.message);
|
|
231
|
+
if (result.error.hint)
|
|
232
|
+
info(result.error.hint);
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
235
|
+
const v = result.value;
|
|
236
|
+
// When --profile is set, override the storage key.
|
|
237
|
+
// email/accountId/displayName remain JWT-derived (preserved on the
|
|
238
|
+
// profile object) so the operator can still identify which upstream
|
|
239
|
+
// account backs the alias.
|
|
240
|
+
const finalProfileId = opts.profile ?? v.profileId;
|
|
241
|
+
const profile = {
|
|
242
|
+
provider: PROVIDER_OPENAI_CODEX,
|
|
243
|
+
profileId: finalProfileId,
|
|
244
|
+
access: v.access,
|
|
245
|
+
refresh: v.refresh,
|
|
246
|
+
expires: v.expires,
|
|
247
|
+
accountId: v.accountId,
|
|
248
|
+
email: v.email,
|
|
249
|
+
displayName: v.displayName,
|
|
250
|
+
version: 1,
|
|
251
|
+
};
|
|
252
|
+
const writeResult = await store.set(finalProfileId, profile);
|
|
253
|
+
if (!writeResult.ok) {
|
|
254
|
+
error(`Failed to persist OAuth profile: ${writeResult.error.message}`);
|
|
255
|
+
process.exit(1);
|
|
256
|
+
}
|
|
257
|
+
// Silent overwrite policy; INFO-log records every login write.
|
|
258
|
+
logger.info({
|
|
259
|
+
provider: PROVIDER_OPENAI_CODEX,
|
|
260
|
+
profileId: finalProfileId,
|
|
261
|
+
identity: redactEmailForLog(v.email) ?? `id-${v.accountId ?? "<unknown>"}`,
|
|
262
|
+
action: "login",
|
|
263
|
+
submodule: "auth-cli",
|
|
264
|
+
}, "OAuth profile written by CLI");
|
|
265
|
+
success(`Logged in as ${v.email ?? v.displayName ?? v.profileId} (profile: ${finalProfileId})`);
|
|
266
|
+
}
|
|
267
|
+
catch (err) {
|
|
268
|
+
// Structured OAuthError values route through `exitOnOAuthError`
|
|
269
|
+
// for the canonical re-login hint; generic errors fall through to
|
|
270
|
+
// the existing pattern.
|
|
271
|
+
if (isOAuthError(err)) {
|
|
272
|
+
exitOnOAuthError(err);
|
|
273
|
+
}
|
|
274
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
275
|
+
error(`Failed to log in: ${msg}`);
|
|
276
|
+
process.exit(1);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
// -------------------------------------------------------------------------
|
|
280
|
+
// list
|
|
281
|
+
// -------------------------------------------------------------------------
|
|
282
|
+
auth
|
|
283
|
+
.command("list")
|
|
284
|
+
.description("List stored OAuth profiles")
|
|
285
|
+
.option("--provider <id>", "Filter to one provider")
|
|
286
|
+
.action(async (opts) => {
|
|
287
|
+
try {
|
|
288
|
+
const store = openOAuthStoreFromConfig();
|
|
289
|
+
const listResult = await store.list();
|
|
290
|
+
if (!listResult.ok) {
|
|
291
|
+
error(`Failed to list OAuth profiles: ${listResult.error.message}`);
|
|
292
|
+
process.exit(1);
|
|
293
|
+
}
|
|
294
|
+
const profiles = listResult.value;
|
|
295
|
+
// Client-side string-match filter; we explicitly opt OUT of
|
|
296
|
+
// validating the provider value against pi-ai's known list (the
|
|
297
|
+
// filter is purely an in-memory display sieve).
|
|
298
|
+
const filtered = opts.provider
|
|
299
|
+
? profiles.filter((p) => p.provider === opts.provider)
|
|
300
|
+
: profiles;
|
|
301
|
+
if (filtered.length === 0) {
|
|
302
|
+
if (opts.provider) {
|
|
303
|
+
info(`No OAuth profiles stored for provider "${opts.provider}".`);
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
info("No OAuth profiles stored.");
|
|
307
|
+
}
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
renderTable(["Provider", "ProfileId", "Identity", "ExpiresIn", "Status"], filtered.map((p) => [
|
|
311
|
+
p.provider,
|
|
312
|
+
p.profileId,
|
|
313
|
+
p.email ?? p.profileId.split(":")[1] ?? "—",
|
|
314
|
+
formatRelativeExpiry(p.expires),
|
|
315
|
+
profileStatus(p.expires),
|
|
316
|
+
]));
|
|
317
|
+
}
|
|
318
|
+
catch (err) {
|
|
319
|
+
// Structured OAuthError gets the re-login hint.
|
|
320
|
+
if (isOAuthError(err)) {
|
|
321
|
+
exitOnOAuthError(err);
|
|
322
|
+
}
|
|
323
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
324
|
+
error(`Failed to list profiles: ${msg}`);
|
|
325
|
+
process.exit(1);
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
// -------------------------------------------------------------------------
|
|
329
|
+
// logout
|
|
330
|
+
// -------------------------------------------------------------------------
|
|
331
|
+
auth
|
|
332
|
+
.command("logout")
|
|
333
|
+
.description("Remove a stored OAuth profile")
|
|
334
|
+
.requiredOption("--profile <id>", "Profile ID to remove (e.g., openai-codex:user@example.com)")
|
|
335
|
+
.action(async (opts) => {
|
|
336
|
+
try {
|
|
337
|
+
const store = openOAuthStoreFromConfig();
|
|
338
|
+
const has = await store.has(opts.profile);
|
|
339
|
+
if (!has.ok) {
|
|
340
|
+
error(`Failed to check profile existence: ${has.error.message}`);
|
|
341
|
+
process.exit(1);
|
|
342
|
+
}
|
|
343
|
+
if (!has.value) {
|
|
344
|
+
error(`profile ${opts.profile} not found`);
|
|
345
|
+
process.exit(1);
|
|
346
|
+
}
|
|
347
|
+
const delResult = await store.delete(opts.profile);
|
|
348
|
+
if (!delResult.ok) {
|
|
349
|
+
error(`Failed to remove profile: ${delResult.error.message}`);
|
|
350
|
+
process.exit(1);
|
|
351
|
+
}
|
|
352
|
+
logger.info({
|
|
353
|
+
profileId: opts.profile,
|
|
354
|
+
action: "logout",
|
|
355
|
+
submodule: "auth-cli",
|
|
356
|
+
}, "OAuth profile removed by CLI");
|
|
357
|
+
success(`Logged out of ${opts.profile}`);
|
|
358
|
+
}
|
|
359
|
+
catch (err) {
|
|
360
|
+
// Structured OAuthError gets the re-login hint.
|
|
361
|
+
if (isOAuthError(err)) {
|
|
362
|
+
exitOnOAuthError(err);
|
|
363
|
+
}
|
|
364
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
365
|
+
error(`Failed to log out: ${msg}`);
|
|
366
|
+
process.exit(1);
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
// -------------------------------------------------------------------------
|
|
370
|
+
// status
|
|
371
|
+
// -------------------------------------------------------------------------
|
|
372
|
+
auth
|
|
373
|
+
.command("status")
|
|
374
|
+
.description("Show per-provider OAuth status")
|
|
375
|
+
.option("--provider <id>", "Filter to one provider")
|
|
376
|
+
.action(async (opts) => {
|
|
377
|
+
try {
|
|
378
|
+
const store = openOAuthStoreFromConfig();
|
|
379
|
+
const listResult = await store.list();
|
|
380
|
+
if (!listResult.ok) {
|
|
381
|
+
error(`Failed to read OAuth status: ${listResult.error.message}`);
|
|
382
|
+
process.exit(1);
|
|
383
|
+
}
|
|
384
|
+
const profiles = listResult.value;
|
|
385
|
+
if (profiles.length === 0) {
|
|
386
|
+
// Empty store — even with --provider filter, the operator's
|
|
387
|
+
// intended diagnostic is the same: nothing here, optionally for
|
|
388
|
+
// the named provider.
|
|
389
|
+
if (opts.provider) {
|
|
390
|
+
info(`No OAuth profiles stored for provider "${opts.provider}".`);
|
|
391
|
+
}
|
|
392
|
+
else {
|
|
393
|
+
info("No OAuth profiles stored.");
|
|
394
|
+
}
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
// Group by provider.
|
|
398
|
+
const byProvider = new Map();
|
|
399
|
+
for (const p of profiles) {
|
|
400
|
+
const arr = byProvider.get(p.provider) ?? [];
|
|
401
|
+
arr.push(p);
|
|
402
|
+
byProvider.set(p.provider, arr);
|
|
403
|
+
}
|
|
404
|
+
// Empty filter case: store has profiles, but none for the requested
|
|
405
|
+
// provider. Print provider-specific empty-state and exit 0 (the
|
|
406
|
+
// standard `return` here, since a missing provider in a populated
|
|
407
|
+
// store is not an error).
|
|
408
|
+
if (opts.provider && !byProvider.has(opts.provider)) {
|
|
409
|
+
info(`No OAuth profiles stored for provider "${opts.provider}".`);
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
for (const [provider, group] of byProvider) {
|
|
413
|
+
// Skip non-matching groups when filter is set.
|
|
414
|
+
if (opts.provider && provider !== opts.provider)
|
|
415
|
+
continue;
|
|
416
|
+
info(`${provider} (${group.length} profile${group.length !== 1 ? "s" : ""})`);
|
|
417
|
+
for (const p of group) {
|
|
418
|
+
const identity = p.email ?? p.profileId.split(":")[1] ?? "—";
|
|
419
|
+
info(` ${p.profileId} — expires in ${formatRelativeExpiry(p.expires)} (${profileStatus(p.expires)}) — identity: ${identity}`);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
catch (err) {
|
|
424
|
+
// Structured OAuthError gets the re-login hint.
|
|
425
|
+
if (isOAuthError(err)) {
|
|
426
|
+
exitOnOAuthError(err);
|
|
427
|
+
}
|
|
428
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
429
|
+
error(`Failed to check OAuth status: ${msg}`);
|
|
430
|
+
process.exit(1);
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
}
|
|
@@ -12,8 +12,11 @@ import type { Command } from "commander";
|
|
|
12
12
|
* Register the `doctor` command on the program.
|
|
13
13
|
*
|
|
14
14
|
* Provides:
|
|
15
|
-
* - `comis doctor` -- run
|
|
15
|
+
* - `comis doctor` -- run 6 health check categories (config, daemon, gateway,
|
|
16
|
+
* channel, workspace, OAuth)
|
|
16
17
|
* - `comis doctor --repair` -- auto-fix repairable issues
|
|
18
|
+
* - `comis doctor --refresh-test` -- opt-in refresh probe per profile.
|
|
19
|
+
* WARNING: rotates the refresh token at OpenAI.
|
|
17
20
|
*
|
|
18
21
|
* @param program - The root Commander program
|
|
19
22
|
*/
|
|
@@ -20,16 +20,18 @@ import { daemonHealthCheck } from "../doctor/checks/daemon-health.js";
|
|
|
20
20
|
import { gatewayHealthCheck } from "../doctor/checks/gateway-health.js";
|
|
21
21
|
import { channelHealthCheck } from "../doctor/checks/channel-health.js";
|
|
22
22
|
import { workspaceHealthCheck } from "../doctor/checks/workspace-health.js";
|
|
23
|
+
import { oauthHealthCheck } from "../doctor/checks/oauth-health.js";
|
|
23
24
|
import { repairConfig } from "../doctor/repairs/repair-config.js";
|
|
24
25
|
import { repairDaemon } from "../doctor/repairs/repair-daemon.js";
|
|
25
26
|
import { repairWorkspace } from "../doctor/repairs/repair-workspace.js";
|
|
26
|
-
/** All doctor checks in execution order (
|
|
27
|
+
/** All doctor checks in execution order (6 categories). */
|
|
27
28
|
const ALL_CHECKS = [
|
|
28
29
|
configHealthCheck,
|
|
29
30
|
daemonHealthCheck,
|
|
30
31
|
gatewayHealthCheck,
|
|
31
32
|
channelHealthCheck,
|
|
32
33
|
workspaceHealthCheck,
|
|
34
|
+
oauthHealthCheck,
|
|
33
35
|
];
|
|
34
36
|
/**
|
|
35
37
|
* Resolve default config paths from COMIS_CONFIG_PATHS env var or standard locations.
|
|
@@ -99,21 +101,30 @@ function buildDoctorContext(configPaths) {
|
|
|
99
101
|
* Register the `doctor` command on the program.
|
|
100
102
|
*
|
|
101
103
|
* Provides:
|
|
102
|
-
* - `comis doctor` -- run
|
|
104
|
+
* - `comis doctor` -- run 6 health check categories (config, daemon, gateway,
|
|
105
|
+
* channel, workspace, OAuth)
|
|
103
106
|
* - `comis doctor --repair` -- auto-fix repairable issues
|
|
107
|
+
* - `comis doctor --refresh-test` -- opt-in refresh probe per profile.
|
|
108
|
+
* WARNING: rotates the refresh token at OpenAI.
|
|
104
109
|
*
|
|
105
110
|
* @param program - The root Commander program
|
|
106
111
|
*/
|
|
107
112
|
export function registerDoctorCommand(program) {
|
|
108
113
|
program
|
|
109
114
|
.command("doctor")
|
|
110
|
-
.description("Diagnose configuration, daemon, gateway, channel, and
|
|
115
|
+
.description("Diagnose configuration, daemon, gateway, channel, workspace, and OAuth health")
|
|
111
116
|
.option("--repair", "Auto-fix repairable issues")
|
|
112
117
|
.option("-c, --config <paths...>", "Config file paths to check")
|
|
113
118
|
.option("--format <format>", 'Output format: "table" or "json"', "table")
|
|
119
|
+
.option("--refresh-test", "Run a real OAuth refresh against the provider per profile. " +
|
|
120
|
+
"WARNING: rotates the refresh token at OpenAI; the stored token will " +
|
|
121
|
+
"be stale after this check. Default: OFF (opt-in).")
|
|
114
122
|
.action(async (options) => {
|
|
115
123
|
const configPaths = options.config ?? resolveDefaultConfigPaths();
|
|
116
|
-
const context =
|
|
124
|
+
const context = {
|
|
125
|
+
...buildDoctorContext(configPaths),
|
|
126
|
+
refreshTest: options.refreshTest,
|
|
127
|
+
};
|
|
117
128
|
const result = await withSpinner("Running diagnostics...", () => runDoctorChecks(ALL_CHECKS, context));
|
|
118
129
|
// Render results
|
|
119
130
|
if (options.format === "json") {
|
|
@@ -156,7 +167,11 @@ export function registerDoctorCommand(program) {
|
|
|
156
167
|
}
|
|
157
168
|
// Re-run diagnostics after repairs
|
|
158
169
|
info("Re-running diagnostics...");
|
|
159
|
-
const
|
|
170
|
+
const rerunContext = {
|
|
171
|
+
...buildDoctorContext(configPaths),
|
|
172
|
+
refreshTest: options.refreshTest,
|
|
173
|
+
};
|
|
174
|
+
const rerunResult = await withSpinner("Verifying repairs...", () => runDoctorChecks(ALL_CHECKS, rerunContext));
|
|
160
175
|
if (options.format === "json") {
|
|
161
176
|
renderDoctorJson(rerunResult);
|
|
162
177
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth health check for `comis doctor`.
|
|
3
|
+
*
|
|
4
|
+
* Per-profile diagnostics: JWT decode → expiry + numeric `secsUntilExpiry`;
|
|
5
|
+
* flag profiles expiring < 7 days as warn, expired as fail; surface
|
|
6
|
+
* schema-version mismatch from the file adapter's hard-fail verbatim
|
|
7
|
+
* (`port.list()` returns `err()` whose message already contains the version
|
|
8
|
+
* + remediation hint). Environmental sub-checks: ca-certificates bundle
|
|
9
|
+
* existence with distro-aware install hint, HTTPS_PROXY env-var heuristic
|
|
10
|
+
* (Node's built-in fetch ignores HTTPS_PROXY by default), TLS preflight
|
|
11
|
+
* against `auth.openai.com` (delegates to `runOAuthTlsPreflight`).
|
|
12
|
+
*
|
|
13
|
+
* Optional `--refresh-test` flag (default OFF): exercises a real OAuth
|
|
14
|
+
* refresh against the provider; rotates the refresh token at OpenAI's end
|
|
15
|
+
* as a side effect (--help warns the operator). Doctor does NOT persist
|
|
16
|
+
* the new credentials; the success suggestion warns the stored token is
|
|
17
|
+
* now stale.
|
|
18
|
+
*
|
|
19
|
+
* Storage mode handling: the CLI process cannot bootstrap the encrypted
|
|
20
|
+
* secrets store without `SECRETS_MASTER_KEY`, so when
|
|
21
|
+
* `appConfig.oauth.storage === "encrypted"` the per-profile sub-check
|
|
22
|
+
* returns a single skip finding pointing the operator at the daemon host.
|
|
23
|
+
*
|
|
24
|
+
* NEVER prints `profile.access` or `profile.refresh` in any DoctorFinding
|
|
25
|
+
* field. Identity labels go through `redactEmailForLog`. The token-leakage
|
|
26
|
+
* test in oauth-health.test.ts asserts no `TEST_LEAK_SENTINEL` substring
|
|
27
|
+
* leakage.
|
|
28
|
+
*
|
|
29
|
+
* @module
|
|
30
|
+
*/
|
|
31
|
+
import type { DoctorCheck } from "../types.js";
|
|
32
|
+
/**
|
|
33
|
+
* Doctor check: OAuth subsystem health.
|
|
34
|
+
*
|
|
35
|
+
* Returns 4 baseline sub-checks (per-profile expiry × N + ca-certificates +
|
|
36
|
+
* HTTPS_PROXY + TLS preflight); +N when `context.refreshTest === true`.
|
|
37
|
+
* Never throws — every failure path returns a finding.
|
|
38
|
+
*/
|
|
39
|
+
export declare const oauthHealthCheck: DoctorCheck;
|