@adhdev/daemon-core 0.9.82-rc.49 → 0.9.82-rc.490
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/boot/daemon-lifecycle.d.ts +9 -0
- package/dist/boot/process-hardening.d.ts +50 -0
- package/dist/build-info.d.ts +37 -0
- package/dist/chat/source-machine.d.ts +166 -0
- package/dist/chat/source-resolver.d.ts +104 -0
- package/dist/chat/subscription-updates.d.ts +1 -0
- package/dist/cli-adapter-types.d.ts +68 -2
- package/dist/cli-adapters/cli-script-runner.d.ts +117 -0
- package/dist/cli-adapters/cli-state-engine.d.ts +220 -0
- package/dist/cli-adapters/provider-cli-adapter.d.ts +137 -64
- package/dist/cli-adapters/provider-cli-parse.d.ts +5 -0
- package/dist/cli-adapters/provider-cli-runtime.d.ts +34 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +74 -0
- package/dist/cli-adapters/pty-write-chunking.d.ts +34 -0
- package/dist/cli-adapters/raw-terminal-io.d.ts +37 -0
- package/dist/cli-adapters/resolve-executable.d.ts +69 -0
- package/dist/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +6 -3
- package/dist/cli-adapters/terminal-backends/types.d.ts +10 -2
- package/dist/cli-adapters/terminal-screen.d.ts +4 -11
- package/dist/commands/chat-commands-debug-bundle.d.ts +14 -0
- package/dist/commands/chat-commands-read.d.ts +23 -0
- package/dist/commands/chat-commands-scope.d.ts +39 -0
- package/dist/commands/chat-commands-shared.d.ts +33 -0
- package/dist/commands/chat-commands-write.d.ts +14 -0
- package/dist/commands/chat-commands.d.ts +10 -23
- package/dist/commands/cli-manager.d.ts +71 -1
- package/dist/commands/handler.d.ts +125 -0
- package/dist/commands/high-family/index.d.ts +3 -0
- package/dist/commands/high-family/mesh-coordinator-launch.d.ts +2 -0
- package/dist/commands/high-family/mesh-events.d.ts +2 -0
- package/dist/commands/high-family/mesh-status.d.ts +2 -0
- package/dist/commands/high-family/types.d.ts +64 -0
- package/dist/commands/low-family/coordinator-prompt.d.ts +9 -0
- package/dist/commands/low-family/daemon-lifecycle.d.ts +2 -0
- package/dist/commands/low-family/diagnostics.d.ts +2 -0
- package/dist/commands/low-family/index.d.ts +3 -0
- package/dist/commands/low-family/mesh-ledger.d.ts +10 -0
- package/dist/commands/low-family/mesh-node-logs.d.ts +2 -0
- package/dist/commands/low-family/notification.d.ts +2 -0
- package/dist/commands/low-family/refine-config.d.ts +2 -0
- package/dist/commands/low-family/session-host.d.ts +2 -0
- package/dist/commands/low-family/spec-providerdev.d.ts +11 -0
- package/dist/commands/low-family/status-meta.d.ts +2 -0
- package/dist/commands/low-family/types.d.ts +33 -0
- package/dist/commands/med-family/cli-agent.d.ts +2 -0
- package/dist/commands/med-family/fast-forward.d.ts +2 -0
- package/dist/commands/med-family/ide.d.ts +10 -0
- package/dist/commands/med-family/index.d.ts +3 -0
- package/dist/commands/med-family/mesh-crud.d.ts +48 -0
- package/dist/commands/med-family/mesh-host-pairing.d.ts +2 -0
- package/dist/commands/med-family/mesh-queue.d.ts +2 -0
- package/dist/commands/med-family/mesh-restart.d.ts +2 -0
- package/dist/commands/med-family/types.d.ts +152 -0
- package/dist/commands/mesh-coordinator.d.ts +85 -1
- package/dist/commands/router-aggregate-status.d.ts +24 -0
- package/dist/commands/router-mesh-session-owner.d.ts +59 -0
- package/dist/commands/router-refine.d.ts +151 -0
- package/dist/commands/router-worktree-cleanup.d.ts +133 -0
- package/dist/commands/router.d.ts +203 -15
- package/dist/commands/upgrade-helper.d.ts +41 -1
- package/dist/config/chat-history.d.ts +11 -0
- package/dist/config/config.d.ts +19 -0
- package/dist/config/mesh-config.d.ts +65 -0
- package/dist/config/mesh-json-config.d.ts +199 -0
- package/dist/config/registry-resolver.d.ts +54 -0
- package/dist/config/repo-settings.d.ts +77 -0
- package/dist/config/state-store.d.ts +30 -0
- package/dist/daemon/dev-server.d.ts +0 -2
- package/dist/detection/cli-detector.d.ts +17 -0
- package/dist/detection/ide-detector.d.ts +13 -0
- package/dist/detection/win32-ide-version.d.ts +37 -0
- package/dist/git/change-impact-config.d.ts +159 -0
- package/dist/git/git-commands.d.ts +26 -2
- package/dist/git/git-diff.d.ts +6 -0
- package/dist/git/git-executor.d.ts +11 -0
- package/dist/git/git-status.d.ts +80 -0
- package/dist/git/git-types.d.ts +2 -50
- package/dist/git/git-worktree.d.ts +71 -1
- package/dist/git/index.d.ts +3 -1
- package/dist/index.d.ts +70 -17
- package/dist/index.js +53532 -19073
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +53283 -18989
- package/dist/index.mjs.map +1 -1
- package/dist/installer.d.ts +1 -4
- package/dist/ipc/local-ipc-server.d.ts +91 -0
- package/dist/launch.d.ts +1 -1
- package/dist/logging/async-batch-writer.d.ts +10 -0
- package/dist/logging/debug-config.d.ts +16 -0
- package/dist/logging/log-redactor.d.ts +24 -0
- package/dist/logging/log-tail-reader.d.ts +81 -0
- package/dist/logging/logger.d.ts +1 -1
- package/dist/mesh/contracts.d.ts +256 -0
- package/dist/mesh/coordinator-prompt.d.ts +76 -0
- package/dist/mesh/coordinator-registry.d.ts +59 -0
- package/dist/mesh/mesh-active-work.d.ts +203 -0
- package/dist/mesh/mesh-clone-grace.d.ts +8 -0
- package/dist/mesh/mesh-completion-synthesis.d.ts +4 -0
- package/dist/mesh/mesh-coordinator-config.d.ts +21 -0
- package/dist/mesh/mesh-delivery-policy.d.ts +104 -0
- package/dist/mesh/mesh-event-classify.d.ts +7 -0
- package/dist/mesh/mesh-event-forwarding.d.ts +58 -0
- package/dist/mesh/mesh-event-trace.d.ts +21 -0
- package/dist/mesh/mesh-events-coordinator.d.ts +4 -0
- package/dist/mesh/mesh-events-pending.d.ts +258 -0
- package/dist/mesh/mesh-events-stale.d.ts +61 -0
- package/dist/mesh/mesh-events-utils.d.ts +75 -0
- package/dist/mesh/mesh-events.d.ts +6 -49
- package/dist/mesh/mesh-fast-forward.d.ts +81 -0
- package/dist/mesh/mesh-host-ownership.d.ts +21 -1
- package/dist/mesh/mesh-init.d.ts +128 -0
- package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -4
- package/dist/mesh/mesh-ledger.d.ts +139 -1
- package/dist/mesh/mesh-magi-status.d.ts +63 -0
- package/dist/mesh/mesh-missions.d.ts +281 -0
- package/dist/mesh/mesh-node-identity.d.ts +310 -0
- package/dist/mesh/mesh-queue-assignment.d.ts +162 -0
- package/dist/mesh/mesh-reconcile-acked-hold.d.ts +17 -0
- package/dist/mesh/mesh-reconcile-config.d.ts +6 -0
- package/dist/mesh/mesh-reconcile-identity.d.ts +6 -0
- package/dist/mesh/mesh-reconcile-loop.d.ts +84 -0
- package/dist/mesh/mesh-reconcile-v2-backstop.d.ts +16 -0
- package/dist/mesh/mesh-refine-batch.d.ts +68 -0
- package/dist/mesh/mesh-refine-gates.d.ts +457 -0
- package/dist/mesh/mesh-refine-status.d.ts +62 -0
- package/dist/mesh/mesh-remote-event-pull.d.ts +15 -0
- package/dist/mesh/mesh-review-inbox.d.ts +90 -0
- package/dist/mesh/mesh-routing.d.ts +70 -0
- package/dist/mesh/mesh-runtime-store.d.ts +567 -0
- package/dist/mesh/mesh-scheduling-runtime.d.ts +78 -0
- package/dist/mesh/mesh-task-inflight.d.ts +46 -0
- package/dist/mesh/mesh-task-stats.d.ts +49 -0
- package/dist/mesh/mesh-unresolved-forward-outbox.d.ts +34 -0
- package/dist/mesh/mesh-warmup-deadline.d.ts +68 -0
- package/dist/mesh/mesh-work-queue.d.ts +392 -1
- package/dist/mesh/preview-freshness.d.ts +28 -0
- package/dist/mesh/refine-config.d.ts +97 -0
- package/dist/mesh/worktree-bootstrap-config.d.ts +219 -0
- package/dist/providers/acp-provider-instance.d.ts +5 -0
- package/dist/providers/approval-utils.d.ts +46 -0
- package/dist/providers/chat-message-normalization.d.ts +58 -1
- package/dist/providers/cli-provider-effect-format.d.ts +30 -0
- package/dist/providers/cli-provider-history-dedup.d.ts +17 -0
- package/dist/providers/cli-provider-input-prompt.d.ts +12 -0
- package/dist/providers/cli-provider-instance-types.d.ts +45 -0
- package/dist/providers/cli-provider-instance.d.ts +426 -30
- package/dist/providers/cli-provider-status-helpers.d.ts +46 -0
- package/dist/providers/cli-provider-transcript-merge.d.ts +7 -0
- package/dist/providers/contracts.d.ts +196 -6
- package/dist/providers/external-sources.d.ts +71 -0
- package/dist/providers/manual-attendance.d.ts +79 -0
- package/dist/providers/native-history/antigravity-claim-registry.d.ts +39 -0
- package/dist/providers/native-history/antigravity-cli-transcript.d.ts +137 -0
- package/dist/providers/native-history/claude-cli-transcript.d.ts +70 -0
- package/dist/providers/native-history/codex-cli-transcript.d.ts +73 -0
- package/dist/providers/native-history/constants.d.ts +12 -0
- package/dist/providers/native-history/dispatcher.d.ts +44 -0
- package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
- package/dist/providers/native-history/index.d.ts +13 -0
- package/dist/providers/provider-instance-manager.d.ts +30 -0
- package/dist/providers/provider-instance.d.ts +31 -1
- package/dist/providers/provider-loader.d.ts +42 -5
- package/dist/providers/provider-trust.d.ts +31 -0
- package/dist/providers/read-chat-contract.d.ts +29 -0
- package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
- package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +86 -0
- package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
- package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
- package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
- package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
- package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
- package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
- package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
- package/dist/providers/sdk/v1/index.d.ts +30 -0
- package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
- package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
- package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
- package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
- package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
- package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
- package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
- package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
- package/dist/providers/spec/adapter.d.ts +98 -0
- package/dist/providers/spec/cli-adapter.d.ts +223 -0
- package/dist/providers/spec/evaluator.d.ts +45 -0
- package/dist/providers/spec/fsm-driver.d.ts +449 -0
- package/dist/providers/spec/fsm-evaluator.d.ts +93 -0
- package/dist/providers/spec/fsm-loader.d.ts +14 -0
- package/dist/providers/spec/fsm-types.d.ts +202 -0
- package/dist/providers/spec/native-history-executor.d.ts +41 -0
- package/dist/providers/spec/pre-launch-trust.d.ts +16 -0
- package/dist/providers/spec/route.d.ts +4 -0
- package/dist/providers/spec/types.d.ts +244 -0
- package/dist/providers/status-monitor.d.ts +7 -7
- package/dist/providers/transcript-v2.d.ts +176 -0
- package/dist/providers/types/interactive-prompt.d.ts +84 -0
- package/dist/providers/working-dir.d.ts +17 -0
- package/dist/repo-mesh-types.d.ts +616 -12
- package/dist/runtime-defaults.d.ts +2 -0
- package/dist/session-host/managed-host.d.ts +64 -0
- package/dist/session-host/runtime-surface.d.ts +10 -16
- package/dist/sessions/registry.d.ts +26 -0
- package/dist/shared-types-extra.d.ts +2 -4
- package/dist/shared-types.d.ts +110 -55
- package/dist/status/chat-tail-hot-sessions.d.ts +40 -0
- package/dist/status/normalize.d.ts +1 -1
- package/dist/status/normalize.js +1 -0
- package/dist/status/normalize.js.map +1 -1
- package/dist/status/normalize.mjs +1 -0
- package/dist/status/normalize.mjs.map +1 -1
- package/dist/status/reporter.d.ts +2 -0
- package/dist/status/snapshot.d.ts +27 -0
- package/dist/system/hash.d.ts +8 -0
- package/dist/system/load-better-sqlite3.d.ts +21 -0
- package/dist/types.d.ts +20 -6
- package/package.json +11 -4
- package/src/agent-stream/poller.ts +2 -3
- package/src/agent-stream/provider-adapter.ts +1 -1
- package/src/boot/daemon-lifecycle.ts +80 -14
- package/src/boot/process-hardening.ts +89 -0
- package/src/build-info.ts +73 -0
- package/src/chat/source-machine.ts +534 -0
- package/src/chat/source-resolver.ts +0 -0
- package/src/chat/subscription-updates.ts +20 -1
- package/src/cli-adapter-types.d.ts +3 -1
- package/src/cli-adapter-types.ts +68 -2
- package/src/cli-adapters/cli-script-runner.ts +421 -0
- package/src/cli-adapters/cli-state-engine.ts +1282 -0
- package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +1048 -1143
- package/src/cli-adapters/provider-cli-parse.d.ts +2 -0
- package/src/cli-adapters/provider-cli-parse.ts +19 -0
- package/src/cli-adapters/provider-cli-runtime.ts +56 -7
- package/src/cli-adapters/provider-cli-shared.d.ts +4 -0
- package/src/cli-adapters/provider-cli-shared.ts +121 -11
- package/src/cli-adapters/pty-transport.ts +2 -1
- package/src/cli-adapters/pty-write-chunking.ts +106 -0
- package/src/cli-adapters/raw-terminal-io.ts +252 -0
- package/src/cli-adapters/resolve-executable.ts +204 -0
- package/src/cli-adapters/session-host-transport.ts +2 -1
- package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +63 -29
- package/src/cli-adapters/terminal-backends/types.ts +10 -3
- package/src/cli-adapters/terminal-screen.ts +16 -81
- package/src/commands/chat-commands-debug-bundle.ts +398 -0
- package/src/commands/chat-commands-read.ts +2788 -0
- package/src/commands/chat-commands-scope.ts +54 -0
- package/src/commands/chat-commands-shared.ts +114 -0
- package/src/commands/chat-commands-write.ts +891 -0
- package/src/commands/chat-commands.ts +19 -1841
- package/src/commands/cli-manager.d.ts +2 -0
- package/src/commands/cli-manager.ts +724 -27
- package/src/commands/handler.ts +865 -2
- package/src/commands/high-family/index.ts +28 -0
- package/src/commands/high-family/mesh-coordinator-launch.ts +696 -0
- package/src/commands/high-family/mesh-events.ts +102 -0
- package/src/commands/high-family/mesh-status.ts +857 -0
- package/src/commands/high-family/types.ts +80 -0
- package/src/commands/low-family/coordinator-prompt.ts +125 -0
- package/src/commands/low-family/daemon-lifecycle.ts +120 -0
- package/src/commands/low-family/diagnostics.ts +57 -0
- package/src/commands/low-family/index.ts +37 -0
- package/src/commands/low-family/mesh-ledger.ts +62 -0
- package/src/commands/low-family/mesh-node-logs.ts +87 -0
- package/src/commands/low-family/notification.ts +116 -0
- package/src/commands/low-family/refine-config.ts +106 -0
- package/src/commands/low-family/session-host.ts +282 -0
- package/src/commands/low-family/spec-providerdev.ts +217 -0
- package/src/commands/low-family/status-meta.ts +112 -0
- package/src/commands/low-family/types.ts +39 -0
- package/src/commands/med-family/cli-agent.ts +270 -0
- package/src/commands/med-family/fast-forward.ts +230 -0
- package/src/commands/med-family/ide.ts +163 -0
- package/src/commands/med-family/index.ts +37 -0
- package/src/commands/med-family/mesh-crud.ts +1268 -0
- package/src/commands/med-family/mesh-host-pairing.ts +234 -0
- package/src/commands/med-family/mesh-queue.ts +167 -0
- package/src/commands/med-family/mesh-restart.ts +92 -0
- package/src/commands/med-family/types.ts +153 -0
- package/src/commands/mesh-coordinator.ts +334 -124
- package/src/commands/router-aggregate-status.ts +209 -0
- package/src/commands/router-mesh-session-owner.ts +114 -0
- package/src/commands/router-refine.ts +1794 -0
- package/src/commands/router-worktree-cleanup.ts +870 -0
- package/src/commands/router.ts +567 -4149
- package/src/commands/stream-commands.ts +8 -0
- package/src/commands/upgrade-helper.ts +310 -45
- package/src/config/chat-history.ts +517 -24
- package/src/config/config.ts +30 -0
- package/src/config/mesh-config.ts +300 -24
- package/src/config/mesh-json-config.ts +376 -0
- package/src/config/recent-activity.ts +8 -2
- package/src/config/registry-resolver.ts +100 -0
- package/src/config/repo-settings.ts +111 -0
- package/src/config/state-store.ts +55 -0
- package/src/daemon/dev-auto-implement.ts +3 -2
- package/src/daemon/dev-cli-debug.ts +10 -1
- package/src/daemon/dev-server.ts +0 -541
- package/src/detection/cli-detector.ts +94 -9
- package/src/detection/ide-detector.ts +55 -16
- package/src/detection/win32-ide-version.ts +106 -0
- package/src/git/change-impact-config.ts +354 -0
- package/src/git/git-commands.ts +112 -16
- package/src/git/git-diff.ts +81 -11
- package/src/git/git-executor.ts +12 -0
- package/src/git/git-status.ts +822 -48
- package/src/git/git-types.ts +14 -62
- package/src/git/git-worktree.ts +261 -4
- package/src/git/index.ts +17 -0
- package/src/index.ts +190 -13
- package/src/installer.d.ts +1 -1
- package/src/installer.ts +8 -6
- package/src/ipc/local-ipc-server.ts +278 -0
- package/src/launch.d.ts +1 -1
- package/src/launch.ts +37 -28
- package/src/logging/async-batch-writer.ts +55 -0
- package/src/logging/command-log.ts +7 -5
- package/src/logging/debug-config.ts +25 -0
- package/src/logging/debug-trace.ts +7 -2
- package/src/logging/log-redactor.ts +100 -0
- package/src/logging/log-tail-reader.ts +341 -0
- package/src/logging/logger.ts +14 -7
- package/src/mesh/contracts.ts +510 -0
- package/src/mesh/coordinator-prompt.ts +627 -34
- package/src/mesh/coordinator-registry.ts +121 -0
- package/src/mesh/mesh-active-work.ts +706 -0
- package/src/mesh/mesh-clone-grace.ts +68 -0
- package/src/mesh/mesh-completion-synthesis.ts +416 -0
- package/src/mesh/mesh-coordinator-config.ts +97 -0
- package/src/mesh/mesh-delivery-policy.ts +284 -0
- package/src/mesh/mesh-event-classify.ts +78 -0
- package/src/mesh/mesh-event-forwarding.ts +2030 -0
- package/src/mesh/mesh-event-trace.ts +67 -0
- package/src/mesh/mesh-events-coordinator.ts +32 -0
- package/src/mesh/mesh-events-pending.ts +1548 -0
- package/src/mesh/mesh-events-stale.ts +452 -0
- package/src/mesh/mesh-events-utils.ts +443 -0
- package/src/mesh/mesh-events.ts +43 -1035
- package/src/mesh/mesh-fast-forward.ts +856 -0
- package/src/mesh/mesh-host-ownership.ts +41 -3
- package/src/mesh/mesh-init.ts +350 -0
- package/src/mesh/mesh-ledger-reconciliation.ts +12 -7
- package/src/mesh/mesh-ledger.ts +897 -102
- package/src/mesh/mesh-magi-status.ts +223 -0
- package/src/mesh/mesh-missions.ts +695 -0
- package/src/mesh/mesh-node-identity.ts +2065 -0
- package/src/mesh/mesh-queue-assignment.ts +2498 -0
- package/src/mesh/mesh-reconcile-acked-hold.ts +230 -0
- package/src/mesh/mesh-reconcile-config.ts +66 -0
- package/src/mesh/mesh-reconcile-identity.ts +103 -0
- package/src/mesh/mesh-reconcile-loop.ts +1696 -0
- package/src/mesh/mesh-reconcile-v2-backstop.ts +62 -0
- package/src/mesh/mesh-refine-batch.ts +205 -0
- package/src/mesh/mesh-refine-gates.ts +1792 -0
- package/src/mesh/mesh-refine-status.ts +231 -0
- package/src/mesh/mesh-remote-event-pull.ts +279 -0
- package/src/mesh/mesh-review-inbox.ts +308 -0
- package/src/mesh/mesh-routing.ts +291 -0
- package/src/mesh/mesh-runtime-store.ts +2292 -0
- package/src/mesh/mesh-scheduling-runtime.ts +198 -0
- package/src/mesh/mesh-task-inflight.ts +70 -0
- package/src/mesh/mesh-task-stats.ts +161 -0
- package/src/mesh/mesh-unresolved-forward-outbox.ts +215 -0
- package/src/mesh/mesh-warmup-deadline.ts +152 -0
- package/src/mesh/mesh-work-queue.ts +1489 -145
- package/src/mesh/preview-freshness.ts +163 -0
- package/src/mesh/refine-config.ts +129 -12
- package/src/mesh/worktree-bootstrap-config.ts +599 -0
- package/src/providers/acp-provider-instance.ts +43 -10
- package/src/providers/approval-utils.d.ts +5 -0
- package/src/providers/approval-utils.ts +100 -6
- package/src/providers/chat-message-normalization.ts +126 -4
- package/src/providers/cli-provider-effect-format.ts +53 -0
- package/src/providers/cli-provider-history-dedup.ts +75 -0
- package/src/providers/cli-provider-input-prompt.ts +133 -0
- package/src/providers/cli-provider-instance-types.ts +131 -0
- package/src/providers/cli-provider-instance.ts +2771 -499
- package/src/providers/cli-provider-status-helpers.ts +123 -0
- package/src/providers/cli-provider-transcript-merge.ts +114 -0
- package/src/providers/contracts.d.ts +55 -0
- package/src/providers/contracts.ts +207 -6
- package/src/providers/extension-provider-instance.ts +12 -7
- package/src/providers/external-sources.ts +218 -0
- package/src/providers/ide-provider-instance.ts +35 -12
- package/src/providers/manual-attendance.ts +105 -0
- package/src/providers/native-history/antigravity-claim-registry.ts +138 -0
- package/src/providers/native-history/antigravity-cli-transcript.ts +1275 -0
- package/src/providers/native-history/claude-cli-transcript.ts +396 -0
- package/src/providers/native-history/codex-cli-transcript.ts +479 -0
- package/src/providers/native-history/constants.ts +19 -0
- package/src/providers/native-history/dispatcher.ts +617 -0
- package/src/providers/native-history/hermes-cli-transcript.ts +312 -0
- package/src/providers/native-history/index.ts +30 -0
- package/src/providers/provider-instance-manager.ts +71 -0
- package/src/providers/provider-instance.ts +24 -1
- package/src/providers/provider-loader.ts +700 -55
- package/src/providers/provider-schema.ts +93 -14
- package/src/providers/provider-trust.ts +114 -0
- package/src/providers/read-chat-contract.ts +76 -16
- package/src/providers/sdk/README.md +49 -0
- package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
- package/src/providers/sdk/v1/builders/cli/detect-status.ts +313 -0
- package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
- package/src/providers/sdk/v1/builders/cli/parse-approval.ts +261 -0
- package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
- package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
- package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
- package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
- package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
- package/src/providers/sdk/v1/index.ts +152 -0
- package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
- package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
- package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
- package/src/providers/sdk/v1/schemas/cli/provider.schema.json +538 -0
- package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
- package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
- package/src/providers/sdk/v1/types/cli/index.ts +365 -0
- package/src/providers/sdk/v1/types/common/index.ts +229 -0
- package/src/providers/sdk/v1/validators/index.ts +19 -0
- package/src/providers/sdk/v1/validators/manifest.ts +110 -0
- package/src/providers/sdk/v1/validators/taint.ts +309 -0
- package/src/providers/spec/adapter.ts +246 -0
- package/src/providers/spec/cli-adapter.ts +1064 -0
- package/src/providers/spec/evaluator.ts +407 -0
- package/src/providers/spec/fsm-driver.ts +1528 -0
- package/src/providers/spec/fsm-evaluator.ts +290 -0
- package/src/providers/spec/fsm-loader.ts +128 -0
- package/src/providers/spec/fsm-types.ts +301 -0
- package/src/providers/spec/native-history-executor.ts +1241 -0
- package/src/providers/spec/pre-launch-trust.ts +104 -0
- package/src/providers/spec/route.ts +51 -0
- package/src/providers/spec/types.ts +284 -0
- package/src/providers/status-monitor.d.ts +7 -7
- package/src/providers/status-monitor.ts +37 -22
- package/src/providers/transcript-v2.ts +567 -0
- package/src/providers/types/interactive-prompt.ts +536 -0
- package/src/providers/version-archive.ts +64 -24
- package/src/providers/working-dir.ts +23 -0
- package/src/repo-mesh-types.ts +861 -14
- package/src/runtime-defaults.ts +39 -0
- package/src/session-host/managed-host.ts +218 -0
- package/src/session-host/runtime-surface.ts +20 -80
- package/src/sessions/registry.ts +44 -0
- package/src/shared-types-extra.ts +2 -4
- package/src/shared-types.d.ts +8 -0
- package/src/shared-types.ts +148 -55
- package/src/status/builders.ts +69 -6
- package/src/status/chat-tail-hot-sessions.ts +117 -2
- package/src/status/normalize.ts +2 -0
- package/src/status/reporter.ts +19 -1
- package/src/status/snapshot.ts +100 -27
- package/src/system/hash.ts +23 -0
- package/src/system/host-memory.ts +29 -12
- package/src/system/load-better-sqlite3.ts +68 -0
- package/src/types.ts +26 -6
- package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
- package/dist/mesh/mesh-sync.d.ts +0 -53
- package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
- package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
- package/src/mesh/mesh-sync.ts +0 -111
|
@@ -0,0 +1,891 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chat Commands — write side: handleSendChat, handleListChats, handleNewChat,
|
|
3
|
+
* handleSwitchChat, handleSetMode, handleChangeModel, handleSetThoughtLevel,
|
|
4
|
+
* handleResolveAction and the send/mode/model helpers they use.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { CommandResult, CommandHelpers } from './handler.js';
|
|
8
|
+
import type { CliAdapter } from '../cli-adapter-types.js';
|
|
9
|
+
import { normalizeInputEnvelope, type InputEnvelope, type ProviderModule, type ProviderScripts } from '../providers/contracts.js';
|
|
10
|
+
import { assertProviderSupportsDeclaredInput, assertTextOnlyInput } from '../providers/provider-input-support.js';
|
|
11
|
+
import { pickApprovalButton } from '../providers/approval-utils.js';
|
|
12
|
+
import { LOG } from '../logging/logger.js';
|
|
13
|
+
import {
|
|
14
|
+
READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS,
|
|
15
|
+
type RuntimeChatMessageMerger,
|
|
16
|
+
buildSendInputSignature,
|
|
17
|
+
getCurrentManagerKey,
|
|
18
|
+
getCurrentProviderType,
|
|
19
|
+
getTargetTransport,
|
|
20
|
+
getTargetedCliAdapter,
|
|
21
|
+
getTargetInstance,
|
|
22
|
+
isExtensionTransport,
|
|
23
|
+
parseMaybeJson,
|
|
24
|
+
} from './chat-commands-shared.js';
|
|
25
|
+
|
|
26
|
+
type LegacyStringScript = (params?: Record<string, unknown> | string) => string;
|
|
27
|
+
|
|
28
|
+
const RECENT_SEND_WINDOW_MS = 1200;
|
|
29
|
+
const HERMES_CLI_STARTING_SEND_SETTLE_MS = 2_000;
|
|
30
|
+
const recentSendByTarget = new Map<string, number>();
|
|
31
|
+
|
|
32
|
+
function buildRecentSendKey(h: CommandHelpers, args: any, provider: ProviderModule | undefined, signature: string): string {
|
|
33
|
+
const transport = getTargetTransport(h, provider) || 'unknown';
|
|
34
|
+
const target =
|
|
35
|
+
args?.targetSessionId
|
|
36
|
+
|| args?.agentType
|
|
37
|
+
|| h.currentSession?.providerType
|
|
38
|
+
|| h.currentProviderType
|
|
39
|
+
|| h.currentManagerKey
|
|
40
|
+
|| 'unknown';
|
|
41
|
+
return `${transport}:${target}:${signature.trim()}`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function getSendChatInputEnvelope(args: any): InputEnvelope {
|
|
45
|
+
return normalizeInputEnvelope(args?.input ? { input: args.input } : args);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function sleep(ms: number): Promise<void> {
|
|
49
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function waitOnceForFreshHermesCliStart(adapter: CliAdapter, log: (msg: string) => void): Promise<void> {
|
|
53
|
+
if (adapter.cliType !== 'hermes-cli') return;
|
|
54
|
+
const status = typeof adapter.getStatus === 'function' ? adapter.getStatus()?.status : undefined;
|
|
55
|
+
if (status !== 'starting') return;
|
|
56
|
+
|
|
57
|
+
log(`Hermes CLI is still starting; waiting ${HERMES_CLI_STARTING_SEND_SETTLE_MS}ms before first send`);
|
|
58
|
+
await sleep(HERMES_CLI_STARTING_SEND_SETTLE_MS);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function callLegacyTextScript(script: ProviderScripts[keyof ProviderScripts] | undefined, text: string): string | null {
|
|
62
|
+
if (typeof script !== 'function') return null;
|
|
63
|
+
return (script as LegacyStringScript)(text);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function isRecentDuplicateSend(key: string): boolean {
|
|
67
|
+
const now = Date.now();
|
|
68
|
+
for (const [candidate, ts] of recentSendByTarget.entries()) {
|
|
69
|
+
if (now - ts > RECENT_SEND_WINDOW_MS) recentSendByTarget.delete(candidate);
|
|
70
|
+
}
|
|
71
|
+
const previous = recentSendByTarget.get(key);
|
|
72
|
+
if (previous && (now - previous) <= RECENT_SEND_WINDOW_MS) return true;
|
|
73
|
+
recentSendByTarget.set(key, now);
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function didProviderConfirmSend(result: any): boolean {
|
|
78
|
+
const parsed = parseMaybeJson(result);
|
|
79
|
+
if (parsed === true) return true;
|
|
80
|
+
if (typeof parsed === 'string') {
|
|
81
|
+
const normalized = parsed.trim().toLowerCase();
|
|
82
|
+
return normalized === 'ok' || normalized === 'sent' || normalized === 'success' || normalized === 'true';
|
|
83
|
+
}
|
|
84
|
+
if (!parsed || typeof parsed !== 'object') return false;
|
|
85
|
+
|
|
86
|
+
return parsed.sent === true
|
|
87
|
+
|| parsed.success === true
|
|
88
|
+
|| parsed.ok === true
|
|
89
|
+
|| parsed.submitted === true
|
|
90
|
+
|| parsed.dispatched === true;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function readExtensionChatState(h: CommandHelpers): Promise<any | null> {
|
|
94
|
+
try {
|
|
95
|
+
const evalResult = await h.evaluateProviderScript('readChat', undefined, READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS);
|
|
96
|
+
if (!evalResult?.result) return null;
|
|
97
|
+
const parsed = parseMaybeJson(evalResult.result);
|
|
98
|
+
return parsed && typeof parsed === 'object' ? parsed : null;
|
|
99
|
+
} catch {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function getStateMessageCount(state: any): number {
|
|
105
|
+
return Array.isArray(state?.messages) ? state.messages.length : 0;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function getStateLastSignature(state: any): string {
|
|
109
|
+
const messages = Array.isArray(state?.messages) ? state.messages : [];
|
|
110
|
+
const last = messages[messages.length - 1];
|
|
111
|
+
if (!last) return '';
|
|
112
|
+
return `${last.role || ''}:${String(last.content || '').replace(/\s+/g, ' ').trim()}`;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function getStableExtensionBaseline(h: CommandHelpers): Promise<any | null> {
|
|
116
|
+
const first = await readExtensionChatState(h);
|
|
117
|
+
if (getStateMessageCount(first) > 0 || getStateLastSignature(first)) return first;
|
|
118
|
+
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
119
|
+
const second = await readExtensionChatState(h);
|
|
120
|
+
return getStateMessageCount(second) >= getStateMessageCount(first) ? second : first;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function verifyExtensionSendObserved(h: CommandHelpers, before: any): Promise<boolean> {
|
|
124
|
+
const beforeCount = getStateMessageCount(before);
|
|
125
|
+
const beforeSignature = getStateLastSignature(before);
|
|
126
|
+
for (let attempt = 0; attempt < 12; attempt += 1) {
|
|
127
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
128
|
+
const state = await readExtensionChatState(h);
|
|
129
|
+
if (state?.status === 'waiting_approval') return true;
|
|
130
|
+
const afterCount = getStateMessageCount(state);
|
|
131
|
+
const afterSignature = getStateLastSignature(state);
|
|
132
|
+
if (afterCount > beforeCount) return true;
|
|
133
|
+
if (afterSignature && afterSignature !== beforeSignature) return true;
|
|
134
|
+
}
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export async function handleSendChat(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
139
|
+
const input = getSendChatInputEnvelope(args);
|
|
140
|
+
const text = input.textFallback;
|
|
141
|
+
const hasInput = input.parts.length > 0 || (typeof text === 'string' && text.trim().length > 0);
|
|
142
|
+
if (!hasInput) return { success: false, error: 'input required' };
|
|
143
|
+
const _log = (msg: string) => LOG.debug('Command', `[send_chat] ${msg}`);
|
|
144
|
+
const provider = h.getProvider(args?.agentType);
|
|
145
|
+
const transport = getTargetTransport(h, provider);
|
|
146
|
+
const dedupeKey = buildRecentSendKey(h, args, provider, buildSendInputSignature(input));
|
|
147
|
+
|
|
148
|
+
const _logSendSuccess = (method: string, targetAgent?: string) => {
|
|
149
|
+
// Sending and transcript persistence are intentionally decoupled.
|
|
150
|
+
// User turns should reach history through read_chat/runtime transcript sync,
|
|
151
|
+
// not by eagerly appending the outgoing input here.
|
|
152
|
+
return { success: true, sent: true, method, targetAgent };
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
if (isRecentDuplicateSend(dedupeKey)) {
|
|
156
|
+
_log(`Suppressed duplicate send for ${dedupeKey}`);
|
|
157
|
+
return { success: true, sent: false, deduplicated: true };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (transport === 'acp') {
|
|
161
|
+
const target = getTargetInstance(h, args);
|
|
162
|
+
if (!target || target.category !== 'acp') {
|
|
163
|
+
return { success: false, error: `ACP instance not found for ${provider?.type || args?.agentType || 'unknown'}` };
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
assertProviderSupportsDeclaredInput(provider, input);
|
|
167
|
+
target.onEvent('send_message', { input });
|
|
168
|
+
return _logSendSuccess('acp-instance', target.type);
|
|
169
|
+
} catch (e: any) {
|
|
170
|
+
return { success: false, error: `acp send failed: ${e.message}` };
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// PTY transport: route structured input through the provider instance so
|
|
175
|
+
// provider-specific CLI attachment strategies (for example Hermes file-path
|
|
176
|
+
// image prompts) are applied instead of collapsing everything to text.
|
|
177
|
+
if (transport === 'pty') {
|
|
178
|
+
const adapter = getTargetedCliAdapter(h, args, provider?.type);
|
|
179
|
+
if (adapter) {
|
|
180
|
+
_log(`${transport} adapter: ${adapter.cliType}`);
|
|
181
|
+
try {
|
|
182
|
+
const hasStructuredParts = input.parts.some((part) => part.type !== 'text');
|
|
183
|
+
if (hasStructuredParts) {
|
|
184
|
+
const target = getTargetInstance(h, args);
|
|
185
|
+
if (!target || target.category !== 'cli') {
|
|
186
|
+
return { success: false, error: `CLI instance not found for ${provider?.type || args?.agentType || 'unknown'}` };
|
|
187
|
+
}
|
|
188
|
+
assertProviderSupportsDeclaredInput(provider, input);
|
|
189
|
+
await waitOnceForFreshHermesCliStart(adapter, _log);
|
|
190
|
+
target.onEvent('send_message', { input });
|
|
191
|
+
return _logSendSuccess(`${transport}-instance`, target.type);
|
|
192
|
+
}
|
|
193
|
+
assertTextOnlyInput(provider, input);
|
|
194
|
+
if (!text) return { success: false, error: 'text required for PTY send' };
|
|
195
|
+
await waitOnceForFreshHermesCliStart(adapter, _log);
|
|
196
|
+
const forceSend = args?.force === true || args?.forceSend === true;
|
|
197
|
+
if (forceSend && typeof adapter.forceSendMessage === 'function') {
|
|
198
|
+
await adapter.forceSendMessage(text);
|
|
199
|
+
} else if (forceSend) {
|
|
200
|
+
await adapter.sendMessage(text, { force: true });
|
|
201
|
+
} else {
|
|
202
|
+
await adapter.sendMessage(text);
|
|
203
|
+
}
|
|
204
|
+
const target = getTargetInstance(h, args) as RuntimeChatMessageMerger | null;
|
|
205
|
+
if (target?.category === 'cli'
|
|
206
|
+
&& target.type === adapter.cliType
|
|
207
|
+
&& typeof target.recordAcknowledgedUserInput === 'function') {
|
|
208
|
+
target.recordAcknowledgedUserInput(input);
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
..._logSendSuccess(`${transport}-adapter`, adapter.cliType),
|
|
212
|
+
...(forceSend ? { forceSent: true } : {}),
|
|
213
|
+
};
|
|
214
|
+
} catch (e: any) {
|
|
215
|
+
return { success: false, error: `${transport} send failed: ${e.message}` };
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
assertTextOnlyInput(provider, input);
|
|
221
|
+
if (!text) return { success: false, error: 'text required' };
|
|
222
|
+
|
|
223
|
+
// Extension transport: via AgentStreamManager
|
|
224
|
+
if (isExtensionTransport(transport)) {
|
|
225
|
+
_log(`Extension: ${provider?.type || 'unknown_extension'}`);
|
|
226
|
+
// Method 1: provider sendMessage script via evaluateInSession
|
|
227
|
+
try {
|
|
228
|
+
const beforeState = await getStableExtensionBaseline(h);
|
|
229
|
+
const evalResult = await h.evaluateProviderScript('sendMessage', { message: text }, 30000);
|
|
230
|
+
if (evalResult?.result) {
|
|
231
|
+
const parsed = parseMaybeJson(evalResult.result);
|
|
232
|
+
if (didProviderConfirmSend(parsed)) {
|
|
233
|
+
const observed = await verifyExtensionSendObserved(h, beforeState);
|
|
234
|
+
if (observed) {
|
|
235
|
+
_log(`Extension script sent OK`);
|
|
236
|
+
return _logSendSuccess('extension-script');
|
|
237
|
+
}
|
|
238
|
+
_log(`Extension script reported send but no chat-state change was observed`);
|
|
239
|
+
}
|
|
240
|
+
if (parsed?.needsTypeAndSend) {
|
|
241
|
+
_log(`Extension needsTypeAndSend → AgentStreamManager`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
} catch (e: any) {
|
|
245
|
+
_log(`Extension script error: ${e.message}`);
|
|
246
|
+
}
|
|
247
|
+
// Method 2: AgentStreamManager
|
|
248
|
+
const extensionSessionId = h.currentSession?.sessionId;
|
|
249
|
+
if (h.agentStream && h.getCdp() && extensionSessionId) {
|
|
250
|
+
const ok = await h.agentStream.sendToSession(h.getCdp()!, extensionSessionId, text);
|
|
251
|
+
if (ok) {
|
|
252
|
+
_log(`AgentStreamManager sent OK`);
|
|
253
|
+
return _logSendSuccess('agent-stream');
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return { success: false, error: `Extension '${provider?.type || 'unknown_extension'}' send failed` };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// IDE category (default): provider sendMessage script is authoritative when present.
|
|
260
|
+
const targetCdp = h.getCdp();
|
|
261
|
+
if (!targetCdp?.isConnected) {
|
|
262
|
+
const managerKey = getCurrentManagerKey(h);
|
|
263
|
+
_log(`No CDP for ${managerKey}`);
|
|
264
|
+
return { success: false, error: `CDP for ${managerKey || 'unknown'} not connected` };
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
_log(`Targeting IDE: ${getCurrentManagerKey(h)}`);
|
|
268
|
+
const sendScript = h.getProviderScript('sendMessage', { message: text });
|
|
269
|
+
if (sendScript) {
|
|
270
|
+
try {
|
|
271
|
+
const result = await targetCdp.evaluate(sendScript, 30000);
|
|
272
|
+
const parsed: any = parseMaybeJson(result);
|
|
273
|
+
if (didProviderConfirmSend(parsed)) {
|
|
274
|
+
_log(`sendMessage script OK`);
|
|
275
|
+
return _logSendSuccess('script');
|
|
276
|
+
}
|
|
277
|
+
if (parsed?.needsTypeAndSend && parsed?.selector) {
|
|
278
|
+
try {
|
|
279
|
+
const sent = await targetCdp.typeAndSend(parsed.selector, text);
|
|
280
|
+
if (sent) {
|
|
281
|
+
_log(`typeAndSend(script.selector=${parsed.selector}) success`);
|
|
282
|
+
return _logSendSuccess('typeAndSend-script');
|
|
283
|
+
}
|
|
284
|
+
} catch (e: any) {
|
|
285
|
+
_log(`typeAndSend(script.selector) failed: ${e.message}`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (parsed?.needsTypeAndSend && parsed?.clickCoords) {
|
|
289
|
+
try {
|
|
290
|
+
const { x, y } = parsed.clickCoords;
|
|
291
|
+
const sent = await targetCdp.typeAndSendAt(x, y, text);
|
|
292
|
+
if (sent) {
|
|
293
|
+
_log(`typeAndSendAt(${x},${y}) success`);
|
|
294
|
+
return _logSendSuccess('typeAndSendAt-script');
|
|
295
|
+
}
|
|
296
|
+
} catch (e: any) {
|
|
297
|
+
_log(`typeAndSendAt failed: ${e.message}`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
if (parsed?.needsTypeAndSend && provider?.inputMethod === 'cdp-type-and-send' && provider.inputSelector) {
|
|
301
|
+
try {
|
|
302
|
+
const sent = await targetCdp.typeAndSend(provider.inputSelector, text);
|
|
303
|
+
if (sent) {
|
|
304
|
+
_log(`typeAndSend(provider.inputSelector=${provider.inputSelector}) success`);
|
|
305
|
+
return _logSendSuccess('typeAndSend-provider');
|
|
306
|
+
}
|
|
307
|
+
} catch (e: any) {
|
|
308
|
+
_log(`typeAndSend(provider) failed: ${e.message}`);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (parsed?.needsTypeAndSend && provider?.webviewMatchText && provider?.scripts?.webviewSendMessage) {
|
|
312
|
+
try {
|
|
313
|
+
const webviewScript = callLegacyTextScript(provider.scripts.webviewSendMessage, text);
|
|
314
|
+
if (webviewScript && targetCdp.evaluateInWebviewFrame) {
|
|
315
|
+
const matchText = provider.webviewMatchText;
|
|
316
|
+
const matchFn = matchText ? (body: string) => body.includes(matchText) : undefined;
|
|
317
|
+
const wvResult = await targetCdp.evaluateInWebviewFrame(webviewScript, matchFn);
|
|
318
|
+
const wvParsed: any = parseMaybeJson(wvResult);
|
|
319
|
+
if (didProviderConfirmSend(wvParsed)) {
|
|
320
|
+
_log(`webviewSendMessage OK`);
|
|
321
|
+
return _logSendSuccess('webview-script');
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
} catch (e: any) {
|
|
325
|
+
_log(`webviewSendMessage failed: ${e.message}`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return { success: false, error: parsed?.error || 'Provider sendMessage did not confirm send' };
|
|
329
|
+
} catch (e: any) {
|
|
330
|
+
_log(`sendMessage script failed: ${e.message}`);
|
|
331
|
+
return { success: false, error: `Provider sendMessage failed: ${e.message}` };
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (provider?.webviewMatchText && provider?.scripts?.webviewSendMessage) {
|
|
336
|
+
try {
|
|
337
|
+
const webviewScript = callLegacyTextScript(provider.scripts.webviewSendMessage, text);
|
|
338
|
+
if (webviewScript && targetCdp.evaluateInWebviewFrame) {
|
|
339
|
+
const matchText = provider.webviewMatchText;
|
|
340
|
+
const matchFn = matchText ? (body: string) => body.includes(matchText) : undefined;
|
|
341
|
+
const wvResult = await targetCdp.evaluateInWebviewFrame(webviewScript, matchFn);
|
|
342
|
+
const wvParsed: any = parseMaybeJson(wvResult);
|
|
343
|
+
if (didProviderConfirmSend(wvParsed)) {
|
|
344
|
+
_log(`webviewSendMessage OK`);
|
|
345
|
+
return _logSendSuccess('webview-script');
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
} catch (e: any) {
|
|
349
|
+
_log(`webviewSendMessage failed: ${e.message}`);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (provider?.inputMethod === 'cdp-type-and-send' && provider.inputSelector) {
|
|
354
|
+
try {
|
|
355
|
+
const sent = await targetCdp.typeAndSend(provider.inputSelector, text);
|
|
356
|
+
if (sent) {
|
|
357
|
+
_log(`typeAndSend(provider.inputSelector=${provider.inputSelector}) success`);
|
|
358
|
+
return _logSendSuccess('typeAndSend-provider');
|
|
359
|
+
}
|
|
360
|
+
} catch (e: any) {
|
|
361
|
+
_log(`typeAndSend(provider) failed: ${e.message}`);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
_log('All methods failed');
|
|
366
|
+
return { success: false, error: 'No provider method could send the message' };
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
export async function handleListChats(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
370
|
+
const provider = h.getProvider(args?.agentType);
|
|
371
|
+
const transport = getTargetTransport(h, provider);
|
|
372
|
+
|
|
373
|
+
// Extension transport: via AgentStreamManager
|
|
374
|
+
if (isExtensionTransport(transport) && h.agentStream && h.getCdp() && h.currentSession?.sessionId) {
|
|
375
|
+
try {
|
|
376
|
+
const chats = await h.agentStream.listSessionChats(h.getCdp()!, h.currentSession.sessionId);
|
|
377
|
+
LOG.info('Command', `[list_chats] Extension: ${chats.length} chats`);
|
|
378
|
+
return { success: true, chats };
|
|
379
|
+
} catch (e: any) {
|
|
380
|
+
LOG.info('Command', `[list_chats] Extension error: ${e.message}`);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// webview IDE
|
|
385
|
+
try {
|
|
386
|
+
const webviewScript = h.getProviderScript('webviewListSessions') || h.getProviderScript('webview_list_sessions');
|
|
387
|
+
if (webviewScript) {
|
|
388
|
+
const matchText = provider?.webviewMatchText;
|
|
389
|
+
const matchFn = matchText ? (body: string) => body.includes(matchText) : undefined;
|
|
390
|
+
const raw = await h.getCdp()?.evaluateInWebviewFrame?.(webviewScript, matchFn);
|
|
391
|
+
let parsed: any = raw;
|
|
392
|
+
if (typeof parsed === 'string') { try { parsed = JSON.parse(parsed); } catch { } }
|
|
393
|
+
if (parsed?.sessions) {
|
|
394
|
+
LOG.info('Command', `[list_chats] Webview OK: ${parsed.sessions.length} chats`);
|
|
395
|
+
return { success: true, chats: parsed.sessions };
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
} catch (e: any) {
|
|
399
|
+
LOG.info('Command', `[list_chats] Webview error: ${e.message}`);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// IDE/default: evaluateProviderScript
|
|
403
|
+
try {
|
|
404
|
+
const evalResult = await h.evaluateProviderScript('listSessions');
|
|
405
|
+
if (evalResult) {
|
|
406
|
+
let parsed = evalResult.result;
|
|
407
|
+
if (typeof parsed === 'string') { try { parsed = JSON.parse(parsed); } catch { } }
|
|
408
|
+
if (parsed?.sessions && Array.isArray(parsed.sessions)) {
|
|
409
|
+
LOG.info('Command', `[list_chats] OK: ${parsed.sessions.length} chats`);
|
|
410
|
+
return { success: true, chats: parsed.sessions };
|
|
411
|
+
}
|
|
412
|
+
if (parsed?.chats && Array.isArray(parsed.chats)) {
|
|
413
|
+
LOG.info('Command', `[list_chats] OK: ${parsed.chats.length} chats`);
|
|
414
|
+
return { success: true, chats: parsed.chats };
|
|
415
|
+
}
|
|
416
|
+
if (Array.isArray(parsed)) {
|
|
417
|
+
LOG.info('Command', `[list_chats] OK: ${parsed.length} chats`);
|
|
418
|
+
return { success: true, chats: parsed };
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
} catch (e: any) {
|
|
422
|
+
LOG.info('Command', `[list_chats] error: ${e.message}`);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
return { success: false, error: 'listSessions script not available for this provider' };
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
export async function handleNewChat(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
429
|
+
const provider = h.getProvider(args?.agentType);
|
|
430
|
+
const transport = getTargetTransport(h, provider);
|
|
431
|
+
|
|
432
|
+
if (transport === 'pty') {
|
|
433
|
+
const adapter = getTargetedCliAdapter(h, args, provider?.type);
|
|
434
|
+
if (!adapter) return { success: false, error: 'CLI adapter not running' };
|
|
435
|
+
if (typeof adapter.clearHistory === 'function') {
|
|
436
|
+
adapter.clearHistory();
|
|
437
|
+
return { success: true, cleared: true };
|
|
438
|
+
}
|
|
439
|
+
return { success: false, error: 'new_chat not supported by this CLI provider' };
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
if (isExtensionTransport(transport) && h.agentStream && h.getCdp() && h.currentSession?.sessionId) {
|
|
443
|
+
const ok = await h.agentStream.newSession(h.getCdp()!, h.currentSession.sessionId);
|
|
444
|
+
return { success: ok };
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// webview IDE
|
|
448
|
+
try {
|
|
449
|
+
const webviewScript = h.getProviderScript('webviewNewSession') || h.getProviderScript('webview_new_session');
|
|
450
|
+
if (webviewScript) {
|
|
451
|
+
const matchText = provider?.webviewMatchText;
|
|
452
|
+
const matchFn = matchText ? (body: string) => body.includes(matchText) : undefined;
|
|
453
|
+
const raw = await h.getCdp()?.evaluateInWebviewFrame?.(webviewScript, matchFn);
|
|
454
|
+
if (raw) return { success: true, result: raw };
|
|
455
|
+
}
|
|
456
|
+
} catch (e: any) {
|
|
457
|
+
return { success: false, error: `webviewNewSession failed: ${e.message}` };
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
try {
|
|
461
|
+
const evalResult = await h.evaluateProviderScript('newSession');
|
|
462
|
+
if (evalResult) return { success: true };
|
|
463
|
+
} catch (e: any) {
|
|
464
|
+
return { success: false, error: `newSession failed: ${e.message}` };
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
return { success: false, error: 'newSession script not available for this provider' };
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
export async function handleSwitchChat(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
471
|
+
const provider = h.getProvider(args?.agentType);
|
|
472
|
+
const transport = getTargetTransport(h, provider);
|
|
473
|
+
const managerKey = getCurrentManagerKey(h);
|
|
474
|
+
const sessionId = args?.sessionId || args?.id || args?.chatId;
|
|
475
|
+
if (!sessionId) return { success: false, error: 'sessionId required' };
|
|
476
|
+
LOG.info('Command', `[switch_chat] sessionId=${sessionId}, manager=${managerKey}`);
|
|
477
|
+
|
|
478
|
+
if (isExtensionTransport(transport) && h.agentStream && h.getCdp() && h.currentSession?.sessionId) {
|
|
479
|
+
const ok = await h.agentStream.switchConversation(h.getCdp()!, h.currentSession.sessionId, sessionId);
|
|
480
|
+
return { success: ok, result: ok ? 'switched' : 'failed' };
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const cdp = h.getCdp(managerKey);
|
|
484
|
+
if (!cdp?.isConnected) return { success: false, error: 'CDP not connected' };
|
|
485
|
+
|
|
486
|
+
// webview IDE
|
|
487
|
+
try {
|
|
488
|
+
const webviewScript = h.getProviderScript('webviewSwitchSession', { SESSION_ID: JSON.stringify(sessionId) });
|
|
489
|
+
if (webviewScript) {
|
|
490
|
+
const matchText = provider?.webviewMatchText;
|
|
491
|
+
const matchFn = matchText ? (body: string) => body.includes(matchText) : undefined;
|
|
492
|
+
const raw = await cdp.evaluateInWebviewFrame?.(webviewScript, matchFn);
|
|
493
|
+
if (raw) return { success: true, result: raw };
|
|
494
|
+
}
|
|
495
|
+
} catch (e: any) {
|
|
496
|
+
return { success: false, error: `webviewSwitchSession failed: ${e.message}` };
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
const switchParams = {
|
|
500
|
+
sessionId,
|
|
501
|
+
title: sessionId,
|
|
502
|
+
id: sessionId,
|
|
503
|
+
SESSION_ID: JSON.stringify(sessionId),
|
|
504
|
+
};
|
|
505
|
+
const script = h.getProviderScript('switchSession', switchParams)
|
|
506
|
+
|| h.getProviderScript('switch_session', switchParams);
|
|
507
|
+
if (!script) return { success: false, error: 'switch_session script not available' };
|
|
508
|
+
|
|
509
|
+
try {
|
|
510
|
+
const raw = await cdp.evaluate(script, 15000);
|
|
511
|
+
LOG.info('Command', `[switch_chat] result: ${raw}`);
|
|
512
|
+
|
|
513
|
+
let parsed: any = null;
|
|
514
|
+
try { parsed = typeof raw === 'string' ? JSON.parse(raw) : raw; } catch { }
|
|
515
|
+
|
|
516
|
+
if (parsed?.action === 'click' && parsed.clickX && parsed.clickY) {
|
|
517
|
+
const x = Math.round(parsed.clickX);
|
|
518
|
+
const y = Math.round(parsed.clickY);
|
|
519
|
+
LOG.info('Command', `[switch_chat] CDP click at (${x}, ${y}) for "${parsed.title}"`);
|
|
520
|
+
await cdp.send('Input.dispatchMouseEvent', {
|
|
521
|
+
type: 'mousePressed', x, y, button: 'left', clickCount: 1
|
|
522
|
+
});
|
|
523
|
+
await cdp.send('Input.dispatchMouseEvent', {
|
|
524
|
+
type: 'mouseReleased', x, y, button: 'left', clickCount: 1
|
|
525
|
+
});
|
|
526
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
527
|
+
|
|
528
|
+
// Auto-handle workspace selection dialog
|
|
529
|
+
const wsResult = await cdp.evaluate(`
|
|
530
|
+
(() => {
|
|
531
|
+
const inp = Array.from(document.querySelectorAll('input[type="text"]'))
|
|
532
|
+
.find(i => i.offsetWidth > 0 && (i.placeholder || '').includes('Select where'));
|
|
533
|
+
if (!inp) return null;
|
|
534
|
+
const rows = inp.closest('[class*="quickInput"]')?.querySelectorAll('[class*="cursor-pointer"]');
|
|
535
|
+
if (rows && rows.length > 0) {
|
|
536
|
+
const r = rows[0].getBoundingClientRect();
|
|
537
|
+
return JSON.stringify({ x: Math.round(r.left + r.width/2), y: Math.round(r.top + r.height/2) });
|
|
538
|
+
}
|
|
539
|
+
return null;
|
|
540
|
+
})()
|
|
541
|
+
`, 5000);
|
|
542
|
+
if (wsResult) {
|
|
543
|
+
try {
|
|
544
|
+
const ws = JSON.parse(wsResult as string);
|
|
545
|
+
await cdp.send('Input.dispatchMouseEvent', {
|
|
546
|
+
type: 'mousePressed', x: ws.x, y: ws.y, button: 'left', clickCount: 1
|
|
547
|
+
});
|
|
548
|
+
await cdp.send('Input.dispatchMouseEvent', {
|
|
549
|
+
type: 'mouseReleased', x: ws.x, y: ws.y, button: 'left', clickCount: 1
|
|
550
|
+
});
|
|
551
|
+
} catch { }
|
|
552
|
+
}
|
|
553
|
+
return { success: true, result: 'switched' };
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
if (parsed?.error) return { success: false, error: parsed.error };
|
|
557
|
+
return { success: true, result: raw };
|
|
558
|
+
} catch (e: any) {
|
|
559
|
+
LOG.error('Command', `[switch_chat] error: ${e.message}`);
|
|
560
|
+
return { success: false, error: e.message };
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
export async function handleSetMode(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
565
|
+
const provider = h.getProvider(args?.agentType);
|
|
566
|
+
const transport = getTargetTransport(h, provider);
|
|
567
|
+
const mode = args?.mode || 'agent';
|
|
568
|
+
|
|
569
|
+
// ACP transport
|
|
570
|
+
if (transport === 'acp') {
|
|
571
|
+
const adapter = getTargetedCliAdapter(h, args, provider?.type);
|
|
572
|
+
const acpInstance = adapter?._acpInstance;
|
|
573
|
+
if (acpInstance && typeof acpInstance.setMode === 'function') {
|
|
574
|
+
await acpInstance.setMode(mode);
|
|
575
|
+
return { success: true, mode };
|
|
576
|
+
}
|
|
577
|
+
return { success: false, error: 'ACP adapter not found' };
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// 1. webview setMode
|
|
581
|
+
const webviewScript = h.getProviderScript('webviewSetMode', { MODE: JSON.stringify(mode) });
|
|
582
|
+
if (webviewScript) {
|
|
583
|
+
const cdp = h.getCdp();
|
|
584
|
+
if (cdp?.isConnected) {
|
|
585
|
+
try {
|
|
586
|
+
const matchText = provider?.webviewMatchText;
|
|
587
|
+
const matchFn = matchText ? (body: string) => body.includes(matchText) : undefined;
|
|
588
|
+
const raw = await cdp.evaluateInWebviewFrame?.(webviewScript, matchFn);
|
|
589
|
+
let result: any = raw;
|
|
590
|
+
if (typeof raw === 'string') { try { result = JSON.parse(raw); } catch { } }
|
|
591
|
+
if (result?.success) return { success: true, mode, method: 'webview-script' };
|
|
592
|
+
} catch (e: any) {
|
|
593
|
+
LOG.info('Command', `[set_mode] webview script error: ${e.message}`);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// 2. main frame setMode
|
|
599
|
+
const mainScript = h.getProviderScript('setMode', { MODE: JSON.stringify(mode) });
|
|
600
|
+
if (mainScript) {
|
|
601
|
+
try {
|
|
602
|
+
const evalResult = await h.evaluateProviderScript('setMode', { MODE: JSON.stringify(mode) }, 15000);
|
|
603
|
+
if (evalResult?.result) {
|
|
604
|
+
let parsed = evalResult.result;
|
|
605
|
+
if (typeof parsed === 'string') { try { parsed = JSON.parse(parsed); } catch { } }
|
|
606
|
+
if (parsed?.success) return { success: true, mode, method: 'script' };
|
|
607
|
+
}
|
|
608
|
+
} catch (e: any) {
|
|
609
|
+
LOG.info('Command', `[set_mode] script error: ${e.message}`);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
return { success: false, error: `setMode '${mode}' not supported by this provider` };
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
export async function handleChangeModel(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
617
|
+
const provider = h.getProvider(args?.agentType);
|
|
618
|
+
const transport = getTargetTransport(h, provider);
|
|
619
|
+
const model = args?.model;
|
|
620
|
+
|
|
621
|
+
LOG.info('Command', `[change_model] model=${model} provider=${provider?.type} transport=${transport} manager=${getCurrentManagerKey(h)} providerType=${getCurrentProviderType(h)}`);
|
|
622
|
+
|
|
623
|
+
// ACP transport
|
|
624
|
+
if (transport === 'acp') {
|
|
625
|
+
const adapter = getTargetedCliAdapter(h, args, provider?.type);
|
|
626
|
+
LOG.info('Command', `[change_model] ACP adapter found: ${!!adapter}, type=${adapter?.cliType}, hasAcpInstance=${!!adapter?._acpInstance}`);
|
|
627
|
+
const acpInstance = adapter?._acpInstance;
|
|
628
|
+
if (acpInstance && typeof acpInstance.setConfigOption === 'function') {
|
|
629
|
+
await acpInstance.setConfigOption('model', model);
|
|
630
|
+
LOG.info('Command', `[change_model] Updated ACP model to ${model}`);
|
|
631
|
+
return { success: true, model };
|
|
632
|
+
}
|
|
633
|
+
return { success: false, error: 'ACP adapter not found' };
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// 1. webview setModel
|
|
637
|
+
const webviewScript = h.getProviderScript('webviewSetModel', { MODEL: JSON.stringify(model) });
|
|
638
|
+
if (webviewScript) {
|
|
639
|
+
const cdp = h.getCdp();
|
|
640
|
+
if (cdp?.isConnected) {
|
|
641
|
+
try {
|
|
642
|
+
const matchText = provider?.webviewMatchText;
|
|
643
|
+
const matchFn = matchText ? (body: string) => body.includes(matchText) : undefined;
|
|
644
|
+
const raw = await cdp.evaluateInWebviewFrame?.(webviewScript, matchFn);
|
|
645
|
+
let result: any = raw;
|
|
646
|
+
if (typeof raw === 'string') { try { result = JSON.parse(raw); } catch { } }
|
|
647
|
+
if (result?.success) return { success: true, model, method: 'webview-script' };
|
|
648
|
+
} catch (e: any) {
|
|
649
|
+
LOG.info('Command', `[change_model] webview script error: ${e.message}`);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// 2. main frame setModel
|
|
655
|
+
const mainScript = h.getProviderScript('setModel', { MODEL: JSON.stringify(model) });
|
|
656
|
+
if (mainScript) {
|
|
657
|
+
try {
|
|
658
|
+
const evalResult = await h.evaluateProviderScript('setModel', { MODEL: JSON.stringify(model) }, 15000);
|
|
659
|
+
if (evalResult?.result) {
|
|
660
|
+
let parsed = evalResult.result;
|
|
661
|
+
if (typeof parsed === 'string') { try { parsed = JSON.parse(parsed); } catch { } }
|
|
662
|
+
if (parsed?.success) return { success: true, model, method: 'script' };
|
|
663
|
+
}
|
|
664
|
+
} catch (e: any) {
|
|
665
|
+
LOG.info('Command', `[change_model] script error: ${e.message}`);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
return { success: false, error: 'changeModel not supported by this IDE provider' };
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
export async function handleSetThoughtLevel(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
673
|
+
const configId = args?.configId;
|
|
674
|
+
const value = args?.value;
|
|
675
|
+
if (!configId || !value) return { success: false, error: 'configId and value required' };
|
|
676
|
+
|
|
677
|
+
const provider = h.getProvider(args?.agentType);
|
|
678
|
+
const transport = getTargetTransport(h, provider);
|
|
679
|
+
if (transport !== 'acp') {
|
|
680
|
+
return { success: false, error: 'set_thought_level only for ACP providers' };
|
|
681
|
+
}
|
|
682
|
+
const adapter = getTargetedCliAdapter(h, args, provider?.type);
|
|
683
|
+
const acpInstance = adapter?._acpInstance;
|
|
684
|
+
if (!acpInstance) return { success: false, error: 'ACP instance not found' };
|
|
685
|
+
if (typeof acpInstance.setConfigOption !== 'function') {
|
|
686
|
+
return { success: false, error: 'ACP setConfigOption not available' };
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
try {
|
|
690
|
+
await acpInstance.setConfigOption(configId, value);
|
|
691
|
+
LOG.info('Command', `[set_thought_level] ${configId}=${value} for ${provider?.type || 'unknown_acp'}`);
|
|
692
|
+
return { success: true, configId, value };
|
|
693
|
+
} catch (e: any) {
|
|
694
|
+
return { success: false, error: e?.message };
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
export async function handleResolveAction(h: CommandHelpers, args: any): Promise<CommandResult> {
|
|
699
|
+
const provider = h.getProvider(args?.agentType);
|
|
700
|
+
const transport = getTargetTransport(h, provider);
|
|
701
|
+
const action = args?.action || 'approve';
|
|
702
|
+
const button = args?.button || args?.buttonText
|
|
703
|
+
|| (action === 'approve' ? 'Accept' : action === 'reject' ? 'Reject' : 'Accept');
|
|
704
|
+
|
|
705
|
+
LOG.info('Command', `[resolveAction] action=${action} button="${button}" provider=${provider?.type}`);
|
|
706
|
+
|
|
707
|
+
// 0. PTY transport: navigate approval dialog via PTY arrow keys + Enter
|
|
708
|
+
if (transport === 'pty') {
|
|
709
|
+
const adapter = getTargetedCliAdapter(h, args, provider?.type);
|
|
710
|
+
if (!adapter) return { success: false, error: 'CLI adapter not running' };
|
|
711
|
+
|
|
712
|
+
// Handle data-driven resolve actions (like from the dashboard 'Fix' button)
|
|
713
|
+
if (args?.data && typeof adapter.resolveAction === 'function') {
|
|
714
|
+
try {
|
|
715
|
+
await adapter.resolveAction(args.data);
|
|
716
|
+
LOG.info('Command', `[resolveAction] CLI PTY → resolveAction triggered with data payload`);
|
|
717
|
+
return { success: true, method: 'cli-resolve-action' };
|
|
718
|
+
} catch (e: any) {
|
|
719
|
+
return { success: false, error: `CLI resolveAction failed: ${e.message}` };
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
const status = adapter.getStatus();
|
|
724
|
+
const targetInstance = getTargetInstance(h, args);
|
|
725
|
+
const targetState = targetInstance?.getState?.() as { activeChat?: { status?: string; activeModal?: { message?: string; buttons?: string[] } | null } } | undefined;
|
|
726
|
+
const surfacedModal = targetState?.activeChat?.activeModal && Array.isArray(targetState.activeChat.activeModal.buttons)
|
|
727
|
+
&& targetState.activeChat.activeModal.buttons.some((candidate) => typeof candidate === 'string' && candidate.trim())
|
|
728
|
+
? targetState.activeChat.activeModal
|
|
729
|
+
: null;
|
|
730
|
+
const statusModal = status?.activeModal && Array.isArray(status.activeModal.buttons)
|
|
731
|
+
&& status.activeModal.buttons.some((candidate) => typeof candidate === 'string' && candidate.trim())
|
|
732
|
+
? status.activeModal
|
|
733
|
+
: null;
|
|
734
|
+
const parsedStatus = !statusModal && !surfacedModal && typeof adapter.getScriptParsedStatus === 'function'
|
|
735
|
+
? (() => {
|
|
736
|
+
try {
|
|
737
|
+
return parseMaybeJson(adapter.getScriptParsedStatus());
|
|
738
|
+
} catch {
|
|
739
|
+
return null;
|
|
740
|
+
}
|
|
741
|
+
})()
|
|
742
|
+
: null;
|
|
743
|
+
const parsedModal = parsedStatus?.status === 'waiting_approval'
|
|
744
|
+
&& parsedStatus?.activeModal
|
|
745
|
+
&& Array.isArray(parsedStatus.activeModal.buttons)
|
|
746
|
+
&& parsedStatus.activeModal.buttons.some((candidate: unknown) => typeof candidate === 'string' && candidate.trim())
|
|
747
|
+
? parsedStatus.activeModal
|
|
748
|
+
: null;
|
|
749
|
+
const effectiveModal = statusModal || surfacedModal || parsedModal;
|
|
750
|
+
const effectiveStatus = status?.status === 'waiting_approval' || targetState?.activeChat?.status === 'waiting_approval' || parsedStatus?.status === 'waiting_approval'
|
|
751
|
+
? 'waiting_approval'
|
|
752
|
+
: status?.status;
|
|
753
|
+
LOG.info('Command', `[resolveAction] CLI PTY gate target=${String(args?.targetSessionId || '')} rawStatus=${String(status?.status || '')} effectiveStatus=${String(effectiveStatus || '')} statusModal=${statusModal ? 'yes' : 'no'} surfacedModal=${surfacedModal ? 'yes' : 'no'} parsedModal=${parsedModal ? 'yes' : 'no'} instance=${targetInstance ? 'yes' : 'no'}`);
|
|
754
|
+
if (!effectiveModal) {
|
|
755
|
+
// APPROVAL Defect-B (live re-probe race): the modal is gone because the worker
|
|
756
|
+
// already resolved this very approval moments ago (delegated auto-approve fired,
|
|
757
|
+
// or a prior resolveAction landed) and the coordinator's approve raced in just
|
|
758
|
+
// after. That is NOT a caller error — return a SOFT already_resolved result so the
|
|
759
|
+
// coordinator does not hard-fail the task on a benign race. Mirrors the in-modal
|
|
760
|
+
// idempotency guard below (isApprovalRecentlyResolved → stalePrompt). Only a session
|
|
761
|
+
// that never had a recently-resolved approval reports the hard 'Not in approval state'.
|
|
762
|
+
if (typeof adapter.isApprovalRecentlyResolved === 'function' && adapter.isApprovalRecentlyResolved()) {
|
|
763
|
+
LOG.info('Command', `[resolveAction] CLI PTY → already_resolved (modal gone, resolved within cooldown)`);
|
|
764
|
+
return { success: true, alreadyResolved: true, status: 'already_resolved' };
|
|
765
|
+
}
|
|
766
|
+
return { success: false, error: 'Not in approval state' };
|
|
767
|
+
}
|
|
768
|
+
const buttons: string[] = Array.isArray(effectiveModal.buttons) ? effectiveModal.buttons : [];
|
|
769
|
+
// Resolve button index: explicit buttonIndex arg → exact text match → explicit action mapping
|
|
770
|
+
let buttonIndex = typeof args?.buttonIndex === 'number' ? args.buttonIndex : -1;
|
|
771
|
+
if (buttonIndex < 0 && button) {
|
|
772
|
+
const btnLower = button.toLowerCase();
|
|
773
|
+
buttonIndex = buttons.findIndex(b => b.toLowerCase().includes(btnLower));
|
|
774
|
+
}
|
|
775
|
+
if (buttonIndex < 0 && (action === 'reject' || action === 'deny')) {
|
|
776
|
+
buttonIndex = buttons.findIndex(b => /deny|reject|no/i.test(b));
|
|
777
|
+
}
|
|
778
|
+
if (buttonIndex < 0 && (action === 'always' || /always/i.test(button))) {
|
|
779
|
+
buttonIndex = buttons.findIndex(b => /always/i.test(b));
|
|
780
|
+
}
|
|
781
|
+
if (buttonIndex < 0 && (action === 'approve' || action === 'accept')) {
|
|
782
|
+
buttonIndex = pickApprovalButton(buttons, provider).index;
|
|
783
|
+
}
|
|
784
|
+
if (buttonIndex < 0) {
|
|
785
|
+
return { success: false, error: 'Approval action did not match any visible button' };
|
|
786
|
+
}
|
|
787
|
+
// Idempotency: if the adapter already resolved this approval within cooldown, report
|
|
788
|
+
// stale_prompt rather than writing a second key to the PTY.
|
|
789
|
+
if (typeof adapter.isApprovalRecentlyResolved === 'function' && adapter.isApprovalRecentlyResolved()) {
|
|
790
|
+
LOG.info('Command', `[resolveAction] CLI PTY → stale_prompt (already resolved within cooldown)`);
|
|
791
|
+
return { success: true, stalePrompt: true, buttonIndex, button: buttons[buttonIndex] ?? button };
|
|
792
|
+
}
|
|
793
|
+
if (typeof adapter.resolveModal === 'function') {
|
|
794
|
+
adapter.resolveModal(buttonIndex);
|
|
795
|
+
} else {
|
|
796
|
+
const keys = '\x1B[B'.repeat(Math.max(0, buttonIndex)) + '\r';
|
|
797
|
+
adapter.writeRaw?.(keys);
|
|
798
|
+
}
|
|
799
|
+
LOG.info('Command', `[resolveAction] CLI PTY → buttonIndex=${buttonIndex} "${buttons[buttonIndex] ?? '?'}"`);
|
|
800
|
+
getTargetInstance(h, args)?.recordApprovalSelection?.(buttons[buttonIndex] ?? button);
|
|
801
|
+
return { success: true, buttonIndex, button: buttons[buttonIndex] ?? button };
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
// 1. Extension transport: via AgentStreamManager
|
|
805
|
+
if (isExtensionTransport(transport) && h.agentStream && h.getCdp() && h.currentSession?.sessionId) {
|
|
806
|
+
const ok = await h.agentStream.resolveSessionAction(h.getCdp()!, h.currentSession.sessionId, action, button);
|
|
807
|
+
return { success: ok };
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// 1.5 ACP transport: resolve protocol permission request directly
|
|
811
|
+
if (transport === 'acp') {
|
|
812
|
+
const adapter = getTargetedCliAdapter(h, args, provider?.type);
|
|
813
|
+
const acpInstance = adapter?._acpInstance;
|
|
814
|
+
if (!acpInstance) return { success: false, error: 'ACP instance not found' };
|
|
815
|
+
if (typeof acpInstance.resolvePermission !== 'function') {
|
|
816
|
+
return { success: false, error: 'ACP resolvePermission not available' };
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
try {
|
|
820
|
+
await acpInstance.resolvePermission(action === 'approve' || action === 'accept' || action === 'always');
|
|
821
|
+
LOG.info('Command', `[resolveAction] ACP → ${action}`);
|
|
822
|
+
return { success: true, action };
|
|
823
|
+
} catch (e: any) {
|
|
824
|
+
return { success: false, error: e?.message || 'ACP resolve action failed' };
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
// 2. Webview Provider script
|
|
829
|
+
if (provider?.scripts?.webviewResolveAction || provider?.scripts?.webview_resolve_action) {
|
|
830
|
+
const script = h.getProviderScript('webviewResolveAction', { action, button, buttonText: button })
|
|
831
|
+
|| h.getProviderScript('webview_resolve_action', { action, button, buttonText: button });
|
|
832
|
+
if (script) {
|
|
833
|
+
const cdp = h.getCdp();
|
|
834
|
+
if (cdp?.isConnected) {
|
|
835
|
+
try {
|
|
836
|
+
const matchText = provider?.webviewMatchText;
|
|
837
|
+
const matchFn = matchText ? (body: string) => body.includes(matchText) : undefined;
|
|
838
|
+
const raw = await cdp.evaluateInWebviewFrame?.(script, matchFn);
|
|
839
|
+
let result: any = raw;
|
|
840
|
+
if (typeof raw === 'string') { try { result = JSON.parse(raw); } catch { } }
|
|
841
|
+
LOG.info('Command', `[resolveAction] webview script result: ${JSON.stringify(result)}`);
|
|
842
|
+
|
|
843
|
+
if (result?.resolved) return { success: true, clicked: result.clicked };
|
|
844
|
+
if (result?.found && result.x != null && result.y != null) {
|
|
845
|
+
LOG.info('Command', `[resolveAction] Webview coordinate click not fully supported via CDP. Click directly in script.`);
|
|
846
|
+
}
|
|
847
|
+
if (result?.found || result?.resolved) return { success: true };
|
|
848
|
+
} catch (e: any) {
|
|
849
|
+
return { success: false, error: `webviewResolveAction failed: ${e.message}` };
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// 3. Provider script (Main DOM) → returns coords → CDP mouse click
|
|
856
|
+
if (provider?.scripts?.resolveAction) {
|
|
857
|
+
const script = provider.scripts.resolveAction({ action, button, buttonText: button });
|
|
858
|
+
if (script) {
|
|
859
|
+
const cdp = h.getCdp();
|
|
860
|
+
if (!cdp?.isConnected) return { success: false, error: 'CDP not connected' };
|
|
861
|
+
try {
|
|
862
|
+
const raw = await cdp.evaluate(script, 30000);
|
|
863
|
+
let result: any = raw;
|
|
864
|
+
if (typeof raw === 'string') { try { result = JSON.parse(raw); } catch {} }
|
|
865
|
+
LOG.info('Command', `[resolveAction] script result: ${JSON.stringify(result)}`);
|
|
866
|
+
|
|
867
|
+
if (result?.resolved) {
|
|
868
|
+
LOG.info('Command', `[resolveAction] script-click resolved — "${result.clicked}"`);
|
|
869
|
+
return { success: true, clicked: result.clicked };
|
|
870
|
+
}
|
|
871
|
+
if (result?.found && result.x != null && result.y != null) {
|
|
872
|
+
const x = result.x;
|
|
873
|
+
const y = result.y;
|
|
874
|
+
await cdp.send('Input.dispatchMouseEvent', {
|
|
875
|
+
type: 'mousePressed', x, y, button: 'left', clickCount: 1
|
|
876
|
+
});
|
|
877
|
+
await cdp.send('Input.dispatchMouseEvent', {
|
|
878
|
+
type: 'mouseReleased', x, y, button: 'left', clickCount: 1
|
|
879
|
+
});
|
|
880
|
+
LOG.info('Command', `[resolveAction] CDP click at (${x}, ${y}) — "${result.text}"`);
|
|
881
|
+
return { success: true, clicked: result.text };
|
|
882
|
+
}
|
|
883
|
+
return { success: false, error: result?.found === false ? `Button not found: ${button}` : 'No coordinates' };
|
|
884
|
+
} catch (e: any) {
|
|
885
|
+
return { success: false, error: `resolveAction failed: ${e.message}` };
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
return { success: false, error: 'resolveAction script not available for this provider' };
|
|
891
|
+
}
|