mixdog 1.3.5 → 1.4.0
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/NOTICE.md +2 -2
- package/README.md +2 -2
- package/package.json +2 -11
- package/scripts/daemon-stub.mjs +1 -1
- package/scripts/gate-local.mjs +4 -2
- package/scripts/native-release-status.mjs +2 -2
- package/scripts/recall-history-cases.json +1 -1
- package/scripts/suite-health.mjs +10 -1
- package/scripts/test.mjs +7 -11
- package/src/agents/reviewer/AGENT.md +7 -11
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +17 -1
- package/src/defaults/skills/browser-use/SKILL.md +59 -11
- package/src/defaults/skills/code-tidy/SKILL.md +142 -270
- package/src/defaults/skills/code-tidy/references/agent-cleanup.md +4 -4
- package/src/defaults/skills/code-tidy/references/cleanup-report.md +31 -76
- package/src/defaults/skills/code-tidy/references/dead-code.md +6 -12
- package/src/defaults/skills/computer-use/SKILL.md +33 -9
- package/src/defaults/skills/setup/SKILL.md +22 -0
- package/src/defaults/skills/setup/references/actions.md +39 -5
- package/src/defaults/skills/setup/references/surfaces.md +11 -2
- package/src/defaults/skills/visualize/SKILL.md +2 -1
- package/src/lib/rules-builder.cjs +10 -8
- package/src/rules/agent/AGENT.md +6 -6
- package/src/rules/lead/LEAD.md +18 -20
- package/src/rules/shared/05-tool-calls.md +5 -6
- package/src/rules/shared/10-tool-workflow.md +2 -0
- package/src/rules/shared/60-verification.md +7 -5
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -3
- package/src/runtime/agent/orchestrator/agent-runtime/title-completion.mjs +3 -1
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +3 -1
- package/src/runtime/agent/orchestrator/config.mjs +17 -1
- package/src/runtime/agent/orchestrator/context/collect.mjs +3 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +72 -67
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +54 -1
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +3 -3
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +176 -72
- package/src/runtime/agent/orchestrator/mcp/client.mjs +19 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +181 -133
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +42 -6
- package/src/runtime/agent/orchestrator/providers/anthropic-cache-warm.mjs +165 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +14 -14
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +145 -66
- package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +25 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +64 -33
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +135 -87
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +123 -102
- package/src/runtime/agent/orchestrator/providers/cache-warm-admission.mjs +90 -0
- package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +25 -9
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +22 -13
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +17 -3
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +52 -10
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +8 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/npm-cli-version.mjs +11 -3
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -9
- package/src/runtime/agent/orchestrator/providers/openai-ws-send/send-context.mjs +22 -3
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +43 -5
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/handshake-failure.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/stream-failure.mjs +6 -3
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +65 -1
- package/src/runtime/agent/orchestrator/providers/quota-reading.mjs +38 -12
- package/src/runtime/agent/orchestrator/providers/registry.mjs +26 -0
- package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +39 -7
- package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +6 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +12 -7
- package/src/runtime/agent/orchestrator/runtime-core/compaction-config-keys.mjs +62 -0
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +37 -16
- package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +100 -23
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +19 -4
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +125 -30
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +792 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +133 -22
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +475 -58
- package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +42 -17
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +0 -2
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -4
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +18 -22
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +32 -3
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +17 -3
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +7 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/after-hook.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +16 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +16 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -10
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +12 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +19 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +133 -90
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +31 -4
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +30 -18
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +23 -13
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +129 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +20 -2
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +7 -2
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +102 -15
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +18 -5
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +19 -8
- package/src/runtime/agent/orchestrator/session/prompt-cache-idle-gaps.mjs +113 -0
- package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +127 -0
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +36 -9
- package/src/runtime/agent/orchestrator/session/sensitive-projection.mjs +100 -0
- package/src/runtime/agent/orchestrator/session/sensitive-values.mjs +257 -0
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +20 -7
- package/src/runtime/agent/orchestrator/session/side-question.mjs +18 -0
- package/src/runtime/agent/orchestrator/session/skill-update-notice.mjs +60 -0
- package/src/runtime/agent/orchestrator/session/store/live-state.mjs +6 -3
- package/src/runtime/agent/orchestrator/session/store/save-delta.mjs +9 -5
- package/src/runtime/agent/orchestrator/session/store/serialize.mjs +9 -8
- package/src/runtime/agent/orchestrator/session/store/session-persistence-events.mjs +29 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +8 -6
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +12 -2
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -14
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +84 -3
- package/src/runtime/agent/orchestrator/session/stored-attachment-history.mjs +32 -0
- package/src/runtime/agent/orchestrator/session/thinking-binding.mjs +108 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +18 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs +9 -7
- package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-text.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/turn-failure.mjs +5 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +5 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +12 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +240 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/shell-cwd.mjs +38 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +25 -5
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +65 -7
- package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +36 -13
- package/src/runtime/browser-bridge/action-schema.mjs +13 -2
- package/src/runtime/browser-bridge/client.mjs +73 -8
- package/src/runtime/browser-bridge/input-fields.mjs +8 -9
- package/src/runtime/browser-bridge/mail-links.mjs +107 -0
- package/src/runtime/browser-bridge/tool-defs.mjs +1 -1
- package/src/runtime/channels/lib/config.mjs +6 -61
- package/src/runtime/channels/lib/crash-log.mjs +1 -1
- package/src/runtime/channels/lib/event-pipeline.mjs +4 -19
- package/src/runtime/channels/lib/event-queue.mjs +3 -18
- package/src/runtime/channels/lib/owned-runtime/automation-services.mjs +2 -2
- package/src/runtime/channels/lib/owned-runtime/automation-start.mjs +3 -4
- package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +4 -59
- package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +33 -115
- package/src/runtime/channels/lib/owned-runtime/owned-stop.mjs +5 -22
- package/src/runtime/channels/lib/owned-runtime/state.mjs +2 -8
- package/src/runtime/channels/lib/owned-runtime.mjs +6 -23
- package/src/runtime/channels/lib/parent-bridge.mjs +2 -2
- package/src/runtime/channels/lib/runtime-paths.mjs +4 -43
- package/src/runtime/channels/lib/scheduler.mjs +33 -147
- package/src/runtime/channels/lib/schedules-db.mjs +34 -11
- package/src/runtime/channels/lib/status-snapshot.mjs +1 -1
- package/src/runtime/channels/lib/tool-dispatch.mjs +1 -2
- package/src/runtime/channels/lib/webhooks-db.mjs +5 -9
- package/src/runtime/channels/lib/worker-bootstrap.mjs +0 -1
- package/src/runtime/channels/lib/worker-ipc.mjs +0 -1
- package/src/runtime/channels/lib/worker-main.mjs +10 -34
- package/src/runtime/computer-bridge/action-schema.mjs +42 -1
- package/src/runtime/computer-bridge/actions.mjs +9 -1
- package/src/runtime/computer-bridge/client.mjs +180 -8
- package/src/runtime/computer-bridge/core-actions.mjs +2 -2
- package/src/runtime/computer-bridge/error-recovery.mjs +27 -2
- package/src/runtime/computer-bridge/linux-readiness.mjs +65 -23
- package/src/runtime/computer-bridge/pending-continuation.mjs +1 -1
- package/src/runtime/connectors/connector-accounts-mcp.mjs +230 -0
- package/src/runtime/connectors/gmail-app-password.mjs +172 -39
- package/src/runtime/connectors/google-mcp.mjs +10 -12
- package/src/runtime/memory/lib/pg/adapter.mjs +77 -70
- package/src/runtime/memory/lib/pg/supervisor.mjs +24 -12
- package/src/runtime/memory/lib/runtime-fetcher.mjs +23 -5
- package/src/runtime/session-search/session-search-db.mjs +73 -9
- package/src/runtime/session-search/session-search-ingest.mjs +110 -20
- package/src/runtime/shared/abort-race.mjs +89 -0
- package/src/runtime/shared/agent-avatar.d.mts +0 -1
- package/src/runtime/shared/agent-kind.mjs +4 -3
- package/src/runtime/shared/bounded-download.mjs +8 -3
- package/src/runtime/shared/config.mjs +2 -13
- package/src/runtime/shared/connector-accounts.mjs +20 -10
- package/src/runtime/shared/connector-catalog.d.mts +29 -0
- package/src/runtime/shared/connector-catalog.mjs +150 -0
- package/src/runtime/shared/connector-triggers.mjs +22 -19
- package/src/runtime/shared/defaults-separation.mjs +2 -14
- package/src/runtime/shared/delegated-approval-host.mjs +103 -11
- package/src/runtime/shared/err-text.mjs +24 -15
- package/src/runtime/shared/file-permissions.d.mts +0 -8
- package/src/runtime/shared/file-permissions.mjs +0 -11
- package/src/runtime/shared/git-direct.test-support.mjs +19 -0
- package/src/runtime/shared/heartbeat-interval.d.mts +4 -0
- package/src/runtime/shared/heartbeat-interval.mjs +19 -0
- package/src/runtime/shared/idle-auto-clear-gate.mjs +104 -0
- package/src/runtime/shared/llm/usage-rollup.mjs +1 -1
- package/src/runtime/shared/mixy-presence.mjs +22 -0
- package/src/runtime/shared/orchestration.d.mts +2 -0
- package/src/runtime/shared/pg-schema-db.mjs +27 -16
- package/src/runtime/shared/profile-config.cjs +1 -1
- package/src/runtime/shared/prompt-origin.d.mts +4 -0
- package/src/runtime/shared/prompt-origin.mjs +21 -0
- package/src/runtime/shared/provider-accounts.mjs +7 -1
- package/src/runtime/shared/provider-display-name.mjs +29 -0
- package/src/runtime/shared/provider-timeout-phase.mjs +2 -0
- package/src/runtime/shared/routine-trigger.d.mts +2 -0
- package/src/runtime/shared/routine-trigger.mjs +10 -0
- package/src/runtime/shared/sensitive-path-rules.d.mts +2 -10
- package/src/runtime/shared/sensitive-path-rules.mjs +19 -41
- package/src/runtime/shared/session-activity-signal.mjs +34 -1
- package/src/runtime/shared/session-sidebar-host.d.mts +1 -1
- package/src/runtime/shared/session-sidebar-host.mjs +7 -3
- package/src/runtime/shared/session-turn-prelude.mjs +18 -0
- package/src/runtime/shared/tool-result-summary.mjs +1 -14
- package/src/runtime/shared/worktrees/test-support.mjs +9 -4
- package/src/runtime/terminal-bridge/client.mjs +10 -1
- package/src/runtime/visualize-bridge/client.mjs +27 -8
- package/src/runtime/visualize-bridge/tool-defs.mjs +22 -8
- package/src/runtime/visualize-bridge/tool-meta.d.mts +5 -0
- package/src/runtime/visualize-bridge/tool-meta.mjs +22 -0
- package/src/runtime/web-search/lib/fetch-pipeline.mjs +2 -2
- package/src/session-runtime/agent-home-delivery.mjs +448 -185
- package/src/session-runtime/agent-task-sessions.mjs +329 -180
- package/src/session-runtime/boot/apis.mjs +9 -0
- package/src/session-runtime/boot/infrastructure.mjs +4 -0
- package/src/session-runtime/boot/providers.mjs +3 -0
- package/src/session-runtime/boot/tools.mjs +6 -1
- package/src/session-runtime/config-lifecycle.mjs +6 -0
- package/src/session-runtime/connector-merge-migration.mjs +305 -0
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +132 -28
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +2 -0
- package/src/session-runtime/lifecycle/inheritance.mjs +16 -3
- package/src/session-runtime/lifecycle/session-catalog.mjs +3 -1
- package/src/session-runtime/lifecycle/teardown/runtime-stops.mjs +50 -4
- package/src/session-runtime/lifecycle/teardown.mjs +23 -5
- package/src/session-runtime/mcp-glue/server-catalog.mjs +55 -3
- package/src/session-runtime/mcp-oauth-login.mjs +5 -3
- package/src/session-runtime/mixy-heartbeat.mjs +153 -33
- package/src/session-runtime/notification-bus.mjs +31 -117
- package/src/session-runtime/notification-completion-queue.mjs +54 -0
- package/src/session-runtime/notification-listeners.mjs +76 -0
- package/src/session-runtime/owned-automation-run.mjs +2 -1
- package/src/session-runtime/prewarm/channel-start.mjs +3 -7
- package/src/session-runtime/resource-mcp-api.mjs +143 -224
- package/src/session-runtime/resource-mcp-connector-accounts.mjs +163 -0
- package/src/session-runtime/resource-mcp-oauth-api.mjs +217 -0
- package/src/session-runtime/resource-mcp-secrets.mjs +82 -0
- package/src/session-runtime/resource-mcp-servers.mjs +78 -0
- package/src/session-runtime/resource-mcp-store.mjs +49 -0
- package/src/session-runtime/routine-owner.mjs +40 -9
- package/src/session-runtime/services/agent-tool/close-flow.mjs +3 -0
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +7 -2
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +1 -0
- package/src/session-runtime/services/agent-tool/worker-index/awaiting-user-sync.mjs +51 -0
- package/src/session-runtime/services/agent-tool/worker-index/disposal.mjs +55 -0
- package/src/session-runtime/services/agent-tool/worker-index/released-store.mjs +123 -0
- package/src/session-runtime/services/agent-tool/worker-index/restart-settlement.mjs +112 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-reads.mjs +36 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +17 -4
- package/src/session-runtime/services/agent-tool/worker-index/row-writes.mjs +58 -0
- package/src/session-runtime/services/agent-tool/worker-index.mjs +41 -241
- package/src/session-runtime/services/agent-tool/worker-rows.mjs +3 -0
- package/src/session-runtime/services/channel-admin.mjs +7 -13
- package/src/session-runtime/services/channel-session-router.mjs +4 -2
- package/src/session-runtime/services/seeds.mjs +0 -28
- package/src/session-runtime/session-compaction-sync.mjs +27 -0
- package/src/session-runtime/session-create/session-options.mjs +1 -0
- package/src/session-runtime/settings-builtin-tools-api.mjs +11 -0
- package/src/session-runtime/settings-compaction-api.mjs +2 -40
- package/src/session-runtime/settings-system-api.mjs +13 -1
- package/src/session-runtime/setup-tool/agent-settings-actions.mjs +65 -0
- package/src/session-runtime/setup-tool/executor.mjs +145 -22
- package/src/session-runtime/setup-tool/extended-actions.mjs +8 -3
- package/src/session-runtime/setup-tool/session-route-actions.mjs +152 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +4 -3
- package/src/session-runtime/setup-tool/tool-defs.mjs +64 -5
- package/src/session-runtime/tool-policy/agent-profile-fold.mjs +17 -13
- package/src/session-runtime/tool-policy/policy-stage.mjs +16 -2
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
- package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +4 -0
- package/src/standalone/channel-transport/client-registry/client-records.mjs +65 -0
- package/src/standalone/channel-transport/client-registry/client-registration.mjs +118 -0
- package/src/standalone/channel-transport/client-registry.mjs +24 -163
- package/src/standalone/channel-transport.mjs +1 -1
- package/src/standalone/daemon-channels-loader.mjs +10 -8
- package/src/standalone/daemon-session-control/list-page.mjs +72 -0
- package/src/standalone/daemon-session-control/request.mjs +51 -0
- package/src/standalone/daemon-session-control/room-host.mjs +57 -0
- package/src/standalone/daemon-session-control/route-control.mjs +48 -0
- package/src/standalone/daemon-session-control/send-turn.mjs +60 -0
- package/src/standalone/daemon-session-control/worktree-control.mjs +40 -0
- package/src/standalone/daemon-session-control.mjs +124 -188
- package/src/standalone/daemon.mjs +26 -3
- package/src/standalone/session-client.mjs +7 -3
- package/src/standalone/session-protocol.mjs +5 -0
- package/src/standalone/session-service/agent-tree/agent-child.mjs +1 -0
- package/src/standalone/session-service/quota-resume.mjs +3 -0
- package/src/standalone/session-service/retention/busy.mjs +65 -1
- package/src/standalone/session-service/session-calls/session-action.mjs +23 -2
- package/src/standalone/session-service/session-calls/session-views.mjs +8 -0
- package/src/standalone/session-tool-output.mjs +15 -7
- package/src/tui/app/model-options.mjs +3 -28
- package/src/tui/dist/index.mjs +58 -64
- package/src/tui/session/agent-job-feed/model-notification.mjs +3 -0
- package/src/tui/session/initial-state.mjs +3 -0
- package/src/tui/session/notice-surface.mjs +7 -1
- package/src/tui/session/queue-helpers.mjs +3 -42
- package/src/tui/session/session-api/routes-agent-definitions.mjs +14 -2
- package/src/tui/session/session-api/routes-write.mjs +5 -1
- package/src/tui/session/session-api/routes.mjs +1 -0
- package/src/tui/session/session-api/settings.mjs +17 -1
- package/src/tui/session/session-flow/auto-clear.mjs +4 -33
- package/src/tui/session/session-flow/drain-closed-queue.mjs +38 -0
- package/src/tui/session/session-flow/drain-enqueue.mjs +86 -0
- package/src/tui/session/session-flow/drain-retry.mjs +35 -0
- package/src/tui/session/session-flow/drain.mjs +118 -149
- package/src/tui/session/session-flow/queue/entry-shape.mjs +5 -0
- package/src/tui/session/session-flow/queue/take-entries.mjs +5 -2
- package/src/tui/session/tool-approval-delegation.mjs +64 -0
- package/src/tui/session/tool-approval-request.mjs +39 -0
- package/src/tui/session/tool-approval-settle.mjs +62 -0
- package/src/tui/session/tool-approval.mjs +69 -115
- package/src/tui/session/tui-steering-persist.mjs +8 -1
- package/src/tui/session/turn-stream.mjs +19 -2
- package/src/tui/session/turn.mjs +1 -0
- package/src/vendor/statusline/bin/statusline-route.mjs +1 -219
- package/src/vendor/statusline/src/gateway/route-meta.mjs +35 -13
- package/scripts/code-graph-description-contract.mjs +0 -188
- package/src/runtime/channels/lib/owned-runtime/ownership-refresh.mjs +0 -36
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/tui/session/tool-approval-request.mjs — the request record a tool-approval
|
|
3
|
+
* queue (tool-approval.mjs) holds and presents: name, args, reason, and its
|
|
4
|
+
* own wait limit.
|
|
5
|
+
*/
|
|
6
|
+
import { humanRequestFields } from '../../runtime/agent/orchestrator/session/human-gate/requests.mjs';
|
|
7
|
+
|
|
8
|
+
/** The queue's default wait limit from its `timeoutMs` option: a positive
|
|
9
|
+
* number, else null (no limit). */
|
|
10
|
+
export function defaultApprovalTimeoutMs(timeoutMs) {
|
|
11
|
+
return Number.isFinite(Number(timeoutMs)) && Number(timeoutMs) > 0 ? Number(timeoutMs) : null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function normalizeToolApprovalRequest(input, id, defaultTimeoutMs) {
|
|
15
|
+
const now = Date.now();
|
|
16
|
+
// An explicit `timeoutMs: null` means no wait limit (no timer, no expiry);
|
|
17
|
+
// any other missing/invalid value falls back to the session default,
|
|
18
|
+
// which is itself no limit unless the runtime configures one.
|
|
19
|
+
let requestTimeoutMs = defaultTimeoutMs;
|
|
20
|
+
if (input?.timeoutMs === null) requestTimeoutMs = null;
|
|
21
|
+
else if (Number.isFinite(Number(input?.timeoutMs)) && Number(input.timeoutMs) > 0) {
|
|
22
|
+
requestTimeoutMs = Number(input.timeoutMs);
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
id,
|
|
26
|
+
name: String(input?.name || input?.tool_name || 'tool'),
|
|
27
|
+
kind: typeof input?.kind === 'string' ? input.kind : '',
|
|
28
|
+
args: input?.args ?? input?.tool_input ?? null,
|
|
29
|
+
cwd: input?.cwd || null,
|
|
30
|
+
sessionId: input?.sessionId || input?.session_id || null,
|
|
31
|
+
toolCallId: input?.toolCallId || input?.tool_use_id || null,
|
|
32
|
+
reason: String(input?.reason || input?.message || 'approval requested by hook').trim(),
|
|
33
|
+
requestedAt: now,
|
|
34
|
+
timeoutMs: requestTimeoutMs,
|
|
35
|
+
expiresAt: requestTimeoutMs === null ? null : now + requestTimeoutMs,
|
|
36
|
+
// outbound / secret / takeover / permission fields (human-gate/requests.mjs).
|
|
37
|
+
...humanRequestFields(input),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/tui/session/tool-approval-settle.mjs — how one tool-approval entry ends:
|
|
3
|
+
* the answer its waiter gets, the forwarded answer of a copy, and the outcome
|
|
4
|
+
* record published on the state (`toolApprovalResult`).
|
|
5
|
+
*/
|
|
6
|
+
import { normalizeHumanResponse } from '../../runtime/agent/orchestrator/session/human-gate/requests.mjs';
|
|
7
|
+
import { withdrawDelegatedApproval } from '../../runtime/shared/delegated-approval-host.mjs';
|
|
8
|
+
|
|
9
|
+
// Settle one entry: drop its timeout, then hand the waiter its answer. The
|
|
10
|
+
// resolve stays guarded — a waiter whose caller already went away must never
|
|
11
|
+
// take the rest of the queue down with it.
|
|
12
|
+
export function settleToolApproval(entry, approved, reason, answers, reply, extra, device = '') {
|
|
13
|
+
if (entry?.timer) clearTimeout(entry.timer);
|
|
14
|
+
const result = { approved, reason };
|
|
15
|
+
if (answers !== undefined) result.answers = answers;
|
|
16
|
+
if (reply !== undefined) result.reply = reply;
|
|
17
|
+
// A human-kind request answers with its canonical response (never a value).
|
|
18
|
+
if (entry?.request?.remember) {
|
|
19
|
+
Object.assign(result, normalizeHumanResponse(entry.request, approved, extra));
|
|
20
|
+
if (device) result.device = device;
|
|
21
|
+
}
|
|
22
|
+
if (extra?.timedOut === true) result.timedOut = true;
|
|
23
|
+
// Settled here: its copy in the top-level chat goes away.
|
|
24
|
+
if (entry?.delegated) {
|
|
25
|
+
withdrawDelegatedApproval(entry.id, { approved, device, ...(extra?.timedOut === true ? { expired: true } : {}) });
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
entry.resolve(result);
|
|
29
|
+
} catch {
|
|
30
|
+
// The requester's resolver must not break settling the queue.
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Hand a copy's answer to the queue that owns the request; false when the
|
|
35
|
+
* owner had already settled it. */
|
|
36
|
+
export function forwardToOwner(entry, approved, reason, device, answers, reply, extra) {
|
|
37
|
+
try {
|
|
38
|
+
return entry.mirror.answer(approved, reason, device, answers, reply, extra) === true;
|
|
39
|
+
} catch {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** How the shown entry ended, from its own finish: only an answer from a known
|
|
45
|
+
* device is attributed; a real timeout says `expired`; any other unattributed
|
|
46
|
+
* end names nobody (null). */
|
|
47
|
+
export function finishedOutcome(id, approved, device, extra) {
|
|
48
|
+
if (device) return { id, approved: approved === true, device: String(device), at: Date.now() };
|
|
49
|
+
if (extra?.timedOut === true) return { id, approved: false, device: '', expired: true, at: Date.now() };
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** How a copy ended, from the owner's settle: answered from a known device
|
|
54
|
+
* (who), a real timeout (`expired`), or taken away with no answer
|
|
55
|
+
* (`withdrawn`: the owner's turn ended, the hand-off copy was removed). */
|
|
56
|
+
export function copyOutcome(id, result) {
|
|
57
|
+
const device = String(result?.device || '');
|
|
58
|
+
const at = Date.now();
|
|
59
|
+
if (device) return { id, approved: result.approved === true, device, at };
|
|
60
|
+
if (result?.expired === true) return { id, approved: false, device: '', expired: true, at };
|
|
61
|
+
return { id, approved: false, device: '', withdrawn: true, at };
|
|
62
|
+
}
|
|
@@ -13,20 +13,14 @@
|
|
|
13
13
|
* that session's own turn ending, and its answer is forwarded to the owning
|
|
14
14
|
* queue, so either place settles the one request once.
|
|
15
15
|
*/
|
|
16
|
-
import {
|
|
17
|
-
humanRequestFields,
|
|
18
|
-
normalizeHumanResponse,
|
|
19
|
-
} from '../../runtime/agent/orchestrator/session/human-gate/requests.mjs';
|
|
20
16
|
import {
|
|
21
17
|
delegateApproval,
|
|
22
18
|
delegatedApprovalsFor,
|
|
23
19
|
registerApprovalQueue,
|
|
24
|
-
withdrawDelegatedApproval,
|
|
25
20
|
} from '../../runtime/shared/delegated-approval-host.mjs';
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const DELEGATED_KINDS = new Set(['', 'approval', 'outbound', 'permission']);
|
|
21
|
+
import { defaultApprovalTimeoutMs, normalizeToolApprovalRequest } from './tool-approval-request.mjs';
|
|
22
|
+
import { copyOutcome, finishedOutcome, forwardToOwner, settleToolApproval } from './tool-approval-settle.mjs';
|
|
23
|
+
import { createApprovalDelegation } from './tool-approval-delegation.mjs';
|
|
30
24
|
|
|
31
25
|
/** The wait limit an approval has when its request names none, from
|
|
32
26
|
* MIXDOG_TOOL_APPROVAL_TIMEOUT_MS (milliseconds, one second at least): null —
|
|
@@ -39,10 +33,18 @@ export function resolveToolApprovalTimeoutMs(env = process.env) {
|
|
|
39
33
|
}
|
|
40
34
|
|
|
41
35
|
export function createToolApproval({ getState, set, nextId, getDisposed, timeoutMs = null, surfaceOf = null }) {
|
|
42
|
-
const defaultTimeoutMs =
|
|
36
|
+
const defaultTimeoutMs = defaultApprovalTimeoutMs(timeoutMs);
|
|
43
37
|
const toolApprovalQueue = [];
|
|
44
38
|
let activeToolApproval = null;
|
|
39
|
+
// Copies of the ask_user questions of sessions this chat handed work to
|
|
40
|
+
// (`{ id, request, mirror }`): published as `handoffQuestions`, each shown
|
|
41
|
+
// at its hand-off line for the user alone (no transcript row), outside the
|
|
42
|
+
// queue so they never hold this chat's own requests back and several show
|
|
43
|
+
// at once. Answered here, the answer goes to the asking session's queue.
|
|
44
|
+
const handoffQuestions = [];
|
|
45
|
+
const publishHandoffQuestions = () => set({ handoffQuestions: handoffQuestions.map((entry) => entry.request) });
|
|
45
46
|
const ownSessionId = () => String(getState()?.sessionId || '');
|
|
47
|
+
const { delegationSurface, handsOff, offerToHandoffs } = createApprovalDelegation({ surfaceOf, ownSessionId });
|
|
46
48
|
const unregister =
|
|
47
49
|
typeof surfaceOf === 'function'
|
|
48
50
|
? registerApprovalQueue({
|
|
@@ -53,33 +55,6 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
|
|
|
53
55
|
})
|
|
54
56
|
: () => {};
|
|
55
57
|
|
|
56
|
-
function normalizeToolApprovalRequest(input = {}, id = nextId()) {
|
|
57
|
-
const now = Date.now();
|
|
58
|
-
// An explicit `timeoutMs: null` means no wait limit (no timer, no expiry);
|
|
59
|
-
// any other missing/invalid value falls back to the session default,
|
|
60
|
-
// which is itself no limit unless the runtime configures one.
|
|
61
|
-
const requestTimeoutMs =
|
|
62
|
-
input?.timeoutMs === null
|
|
63
|
-
? null
|
|
64
|
-
: Number.isFinite(Number(input?.timeoutMs)) && Number(input.timeoutMs) > 0
|
|
65
|
-
? Number(input.timeoutMs)
|
|
66
|
-
: defaultTimeoutMs;
|
|
67
|
-
return {
|
|
68
|
-
id,
|
|
69
|
-
name: String(input?.name || input?.tool_name || 'tool'),
|
|
70
|
-
kind: typeof input?.kind === 'string' ? input.kind : '',
|
|
71
|
-
args: input?.args ?? input?.tool_input ?? null,
|
|
72
|
-
cwd: input?.cwd || null,
|
|
73
|
-
sessionId: input?.sessionId || input?.session_id || null,
|
|
74
|
-
toolCallId: input?.toolCallId || input?.tool_use_id || null,
|
|
75
|
-
reason: String(input?.reason || input?.message || 'approval requested by hook').trim(),
|
|
76
|
-
requestedAt: now,
|
|
77
|
-
timeoutMs: requestTimeoutMs,
|
|
78
|
-
expiresAt: requestTimeoutMs === null ? null : now + requestTimeoutMs,
|
|
79
|
-
// outbound / secret / takeover / permission fields (human-gate/requests.mjs).
|
|
80
|
-
...humanRequestFields(input),
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
58
|
// A request that has a limit expires from ITS OWN requestedAt, queued or
|
|
84
59
|
// active. Arming the timer only on presentation let a queued request sit past
|
|
85
60
|
// expiresAt (retaining its promise and surfacing an obsolete approval later).
|
|
@@ -93,54 +68,35 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
|
|
|
93
68
|
}, remainingMs);
|
|
94
69
|
entry.timer.unref?.();
|
|
95
70
|
}
|
|
96
|
-
// Settle one entry: drop its timeout, then hand the waiter its answer. The
|
|
97
|
-
// resolve stays guarded — a waiter whose caller already went away must never
|
|
98
|
-
// take the rest of the queue down with it.
|
|
99
|
-
function settleToolApproval(entry, approved, reason, answers, reply, extra, device = '') {
|
|
100
|
-
if (entry?.timer) clearTimeout(entry.timer);
|
|
101
|
-
const result = { approved, reason };
|
|
102
|
-
if (answers !== undefined) result.answers = answers;
|
|
103
|
-
if (reply !== undefined) result.reply = reply;
|
|
104
|
-
// A human-kind request answers with its canonical response (never a value).
|
|
105
|
-
if (entry?.request?.remember) {
|
|
106
|
-
Object.assign(result, normalizeHumanResponse(entry.request, approved, extra));
|
|
107
|
-
if (device) result.device = device;
|
|
108
|
-
}
|
|
109
|
-
if (extra?.timedOut === true) result.timedOut = true;
|
|
110
|
-
// Settled here: its copy in the top-level chat goes away.
|
|
111
|
-
if (entry?.delegated) withdrawDelegatedApproval(entry.id, { approved, device });
|
|
112
|
-
try {
|
|
113
|
-
entry.resolve(result);
|
|
114
|
-
} catch {}
|
|
115
|
-
}
|
|
116
|
-
/** Hand a copy's answer to the queue that owns the request; false when the
|
|
117
|
-
* owner had already settled it. */
|
|
118
|
-
function forwardToOwner(entry, approved, reason, device, answers, reply, extra) {
|
|
119
|
-
try {
|
|
120
|
-
return entry.mirror.answer(approved, reason, device, answers, reply, extra) === true;
|
|
121
|
-
} catch {
|
|
122
|
-
return false;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
71
|
function offerDelegatedApproval(delegated) {
|
|
126
72
|
if (getDisposed() || delegated.sessionId !== ownSessionId()) return;
|
|
73
|
+
if (delegated.request?.kind === 'question') {
|
|
74
|
+
if (handoffQuestions.some((entry) => entry.id === delegated.id)) return;
|
|
75
|
+
handoffQuestions.push({ id: delegated.id, request: delegated.request, mirror: delegated });
|
|
76
|
+
publishHandoffQuestions();
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
127
79
|
if (activeToolApproval?.id === delegated.id || toolApprovalQueue.some((entry) => entry.id === delegated.id)) return;
|
|
128
80
|
toolApprovalQueue.push({ id: delegated.id, request: delegated.request, mirror: delegated, timer: null });
|
|
129
81
|
presentNextToolApproval();
|
|
130
82
|
}
|
|
131
83
|
function withdrawDelegatedCopy(id, result) {
|
|
84
|
+
const question = handoffQuestions.findIndex((entry) => entry.id === id);
|
|
85
|
+
if (question >= 0) {
|
|
86
|
+
handoffQuestions.splice(question, 1);
|
|
87
|
+
if (!getDisposed()) publishHandoffQuestions();
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
132
90
|
if (activeToolApproval?.mirror && activeToolApproval.id === id) {
|
|
133
91
|
activeToolApproval = null;
|
|
134
|
-
|
|
135
|
-
set({
|
|
136
|
-
toolApproval: null,
|
|
137
|
-
toolApprovalResult: device ? { id, approved: result.approved === true, device, at: Date.now() } : null,
|
|
138
|
-
});
|
|
92
|
+
set({ toolApproval: null, toolApprovalResult: copyOutcome(id, result) });
|
|
139
93
|
presentNextToolApproval();
|
|
140
94
|
return;
|
|
141
95
|
}
|
|
142
96
|
const index = toolApprovalQueue.findIndex((entry) => entry.mirror && entry.id === id);
|
|
143
|
-
if (index
|
|
97
|
+
if (index < 0) return;
|
|
98
|
+
toolApprovalQueue.splice(index, 1);
|
|
99
|
+
presentNextToolApproval();
|
|
144
100
|
}
|
|
145
101
|
/** Show the delegated approvals waiting for this session (it loaded, or its
|
|
146
102
|
* session id became the top-level one after the request was made). */
|
|
@@ -149,16 +105,23 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
|
|
|
149
105
|
if (!sessionId || typeof surfaceOf !== 'function') return;
|
|
150
106
|
for (const delegated of delegatedApprovalsFor(sessionId)) offerDelegatedApproval(delegated);
|
|
151
107
|
}
|
|
108
|
+
/** Show the next request when none is shown, and publish how many wait
|
|
109
|
+
* behind the shown one (`toolApprovalsWaiting`: the dock's "1/N"). */
|
|
152
110
|
function presentNextToolApproval() {
|
|
153
|
-
if (
|
|
154
|
-
const
|
|
155
|
-
if (!
|
|
156
|
-
|
|
157
|
-
|
|
111
|
+
if (getDisposed()) return;
|
|
112
|
+
const patch = {};
|
|
113
|
+
if (!activeToolApproval) {
|
|
114
|
+
const entry = toolApprovalQueue.shift();
|
|
115
|
+
if (entry) {
|
|
116
|
+
activeToolApproval = entry;
|
|
117
|
+
armToolApprovalTimeout(entry);
|
|
118
|
+
patch.toolApproval = entry.request;
|
|
119
|
+
} else if (getState().toolApproval) patch.toolApproval = null;
|
|
120
|
+
}
|
|
121
|
+
if ((getState().toolApprovalsWaiting ?? 0) !== toolApprovalQueue.length) {
|
|
122
|
+
patch.toolApprovalsWaiting = toolApprovalQueue.length;
|
|
158
123
|
}
|
|
159
|
-
|
|
160
|
-
armToolApprovalTimeout(entry);
|
|
161
|
-
set({ toolApproval: entry.request });
|
|
124
|
+
if (Object.keys(patch).length > 0) set(patch);
|
|
162
125
|
}
|
|
163
126
|
function finishToolApproval(
|
|
164
127
|
id,
|
|
@@ -173,12 +136,7 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
|
|
|
173
136
|
if (activeToolApproval && activeToolApproval.id === targetId) {
|
|
174
137
|
const entry = activeToolApproval;
|
|
175
138
|
activeToolApproval = null;
|
|
176
|
-
|
|
177
|
-
// interrupt names nobody.
|
|
178
|
-
const toolApprovalResult = device
|
|
179
|
-
? { id: targetId, approved: approved === true, device: String(device), at: Date.now() }
|
|
180
|
-
: null;
|
|
181
|
-
set({ toolApproval: null, toolApprovalResult });
|
|
139
|
+
set({ toolApproval: null, toolApprovalResult: finishedOutcome(targetId, approved, device, extra) });
|
|
182
140
|
let accepted = true;
|
|
183
141
|
if (entry.mirror) {
|
|
184
142
|
accepted = forwardToOwner(entry, approved, reason, device, answers, reply, extra);
|
|
@@ -191,10 +149,17 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
|
|
|
191
149
|
const index = toolApprovalQueue.findIndex((entry) => entry.id === targetId);
|
|
192
150
|
if (index >= 0) {
|
|
193
151
|
const [entry] = toolApprovalQueue.splice(index, 1);
|
|
152
|
+
presentNextToolApproval();
|
|
194
153
|
if (entry.mirror) return forwardToOwner(entry, approved, reason, device, answers, reply, extra);
|
|
195
154
|
settleToolApproval(entry, approved === true, String(reason || ''), answers, reply, extra, String(device || ''));
|
|
196
155
|
return true;
|
|
197
156
|
}
|
|
157
|
+
const question = handoffQuestions.findIndex((entry) => entry.id === targetId);
|
|
158
|
+
if (question >= 0) {
|
|
159
|
+
const [entry] = handoffQuestions.splice(question, 1);
|
|
160
|
+
publishHandoffQuestions();
|
|
161
|
+
return forwardToOwner(entry, approved, reason, device, answers, reply, extra);
|
|
162
|
+
}
|
|
198
163
|
return false;
|
|
199
164
|
}
|
|
200
165
|
/** Deny this session's own requests. A copy of a sub-agent's request stays
|
|
@@ -202,11 +167,19 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
|
|
|
202
167
|
* unanswered: the next runtime of this session adopts it again. */
|
|
203
168
|
function denyAllToolApprovals(reason = 'approval cancelled') {
|
|
204
169
|
const closing = getDisposed();
|
|
205
|
-
if (closing)
|
|
170
|
+
if (closing) {
|
|
171
|
+
unregister();
|
|
172
|
+
// Dropped unanswered with this runtime: the next one adopts them again.
|
|
173
|
+
handoffQuestions.length = 0;
|
|
174
|
+
}
|
|
206
175
|
if (activeToolApproval && !(activeToolApproval.mirror && !closing)) {
|
|
207
176
|
const entry = activeToolApproval;
|
|
208
177
|
activeToolApproval = null;
|
|
209
|
-
if (!entry.mirror)
|
|
178
|
+
if (!entry.mirror) {
|
|
179
|
+
settleToolApproval(entry, false, reason);
|
|
180
|
+
// Stop/turn abort ended it: not a timeout, nobody answered.
|
|
181
|
+
set({ toolApprovalResult: { id: entry.id, approved: false, device: '', interrupted: true, at: Date.now() } });
|
|
182
|
+
}
|
|
210
183
|
}
|
|
211
184
|
const kept = [];
|
|
212
185
|
while (toolApprovalQueue.length > 0) {
|
|
@@ -215,7 +188,7 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
|
|
|
215
188
|
else if (!closing) kept.push(entry);
|
|
216
189
|
}
|
|
217
190
|
toolApprovalQueue.push(...kept);
|
|
218
|
-
if (activeToolApproval) return;
|
|
191
|
+
if (activeToolApproval) return presentNextToolApproval();
|
|
219
192
|
if (getState().toolApproval) set({ toolApproval: null });
|
|
220
193
|
presentNextToolApproval();
|
|
221
194
|
}
|
|
@@ -223,43 +196,24 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
|
|
|
223
196
|
if (getDisposed()) return Promise.resolve({ approved: false, reason: 'runtime disposed' });
|
|
224
197
|
return new Promise((resolve) => {
|
|
225
198
|
const id = nextId();
|
|
226
|
-
const full = normalizeToolApprovalRequest(input, id);
|
|
199
|
+
const full = normalizeToolApprovalRequest(input, id, defaultTimeoutMs);
|
|
227
200
|
const surface = delegationSurface(full);
|
|
228
201
|
if (surface) {
|
|
229
202
|
// Who asks, from the top-level chat down ("사무관 › Worker"), and where the copy is.
|
|
230
203
|
full.chain = surface.chain;
|
|
231
204
|
full.surfaceSessionId = surface.sessionId;
|
|
232
205
|
}
|
|
233
|
-
const
|
|
206
|
+
const handoffs = !surface && handsOff(full);
|
|
207
|
+
const entry = { id, request: full, resolve, timer: null, delegated: Boolean(surface || handoffs) };
|
|
234
208
|
toolApprovalQueue.push(entry);
|
|
235
209
|
armToolApprovalTimeout(entry);
|
|
236
210
|
presentNextToolApproval();
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
request: full,
|
|
242
|
-
answer: (approved, reason, device, answers, reply, extra) =>
|
|
243
|
-
finishToolApproval(id, approved, reason, device, answers, reply, extra),
|
|
244
|
-
});
|
|
245
|
-
}
|
|
211
|
+
const answer = (approved, reason, device, answers, reply, extra) =>
|
|
212
|
+
finishToolApproval(id, approved, reason, device, answers, reply, extra);
|
|
213
|
+
if (surface) delegateApproval({ id, sessionId: surface.sessionId, request: full, answer });
|
|
214
|
+
if (handoffs) offerToHandoffs(id, full, answer);
|
|
246
215
|
});
|
|
247
216
|
}
|
|
248
|
-
/** `{ sessionId, chain }` of the top-level chat a sub-agent's request also
|
|
249
|
-
* shows in, or null (no delegation, another kind, or this is the top). */
|
|
250
|
-
function delegationSurface(request) {
|
|
251
|
-
if (typeof surfaceOf !== 'function' || !DELEGATED_KINDS.has(request.kind)) return null;
|
|
252
|
-
const own = String(request.sessionId || ownSessionId());
|
|
253
|
-
let surface = null;
|
|
254
|
-
try {
|
|
255
|
-
surface = surfaceOf(own);
|
|
256
|
-
} catch {
|
|
257
|
-
return null;
|
|
258
|
-
}
|
|
259
|
-
const sessionId = String(surface?.sessionId || '');
|
|
260
|
-
if (!sessionId || sessionId === own || sessionId === ownSessionId()) return null;
|
|
261
|
-
return { sessionId, chain: Array.isArray(surface.chain) ? surface.chain.map(String) : [] };
|
|
262
|
-
}
|
|
263
217
|
|
|
264
218
|
return {
|
|
265
219
|
presentNextToolApproval,
|
|
@@ -70,10 +70,17 @@ function persistedQueuePayload(entry) {
|
|
|
70
70
|
const value = entry[field];
|
|
71
71
|
if (value && typeof value === 'object' && !Array.isArray(value)) out[field] = value;
|
|
72
72
|
}
|
|
73
|
-
for (const field of ['mode', 'priority', 'context']) {
|
|
73
|
+
for (const field of ['mode', 'priority', 'context', 'origin']) {
|
|
74
74
|
if (typeof entry[field] === 'string' && entry[field]) out[field] = entry[field];
|
|
75
75
|
}
|
|
76
76
|
if (entry.skipSlashCommands === true) out.skipSlashCommands = true;
|
|
77
|
+
// Retry of a failed turn: the drain rewinds the failed prompt by these.
|
|
78
|
+
if (typeof entry.skillSelection === 'string') out.skillSelection = entry.skillSelection;
|
|
79
|
+
if (entry.suppressDisplay === true) out.suppressDisplay = true;
|
|
80
|
+
if (entry.retryFailedTurn === true) out.retryFailedTurn = true;
|
|
81
|
+
for (const field of ['retryTurnId', 'retryAttemptId']) {
|
|
82
|
+
if (typeof entry[field] === 'string' && entry[field]) out[field] = entry[field];
|
|
83
|
+
}
|
|
77
84
|
return out;
|
|
78
85
|
}
|
|
79
86
|
|
|
@@ -588,6 +588,12 @@ function stopReconnectCountdown(stream) {
|
|
|
588
588
|
stream.reconnectTimer = null;
|
|
589
589
|
}
|
|
590
590
|
|
|
591
|
+
// The spinner's wait fields for a reconnect stage (see applyStageChange).
|
|
592
|
+
function reconnectWait(detail, now = Date.now()) {
|
|
593
|
+
const retryAt = Number(detail?.retryAt) || 0;
|
|
594
|
+
return { retryAt, retryInMs: retryAt > 0 ? Math.max(0, retryAt - now) : 0 };
|
|
595
|
+
}
|
|
596
|
+
|
|
591
597
|
// Re-renders the reconnect verb once a second until the wait ends, the stage
|
|
592
598
|
// moves on, or the turn is gone. The desktop reads the same spinner state.
|
|
593
599
|
function startReconnectCountdown(stream, detail) {
|
|
@@ -599,7 +605,7 @@ function startReconnectCountdown(stream, detail) {
|
|
|
599
605
|
stopReconnectCountdown(stream);
|
|
600
606
|
return;
|
|
601
607
|
}
|
|
602
|
-
stream.set({ spinner: { ...spinner, verb: reconnectVerb(detail) } });
|
|
608
|
+
stream.set({ spinner: { ...spinner, verb: reconnectVerb(detail), ...reconnectWait(detail) } });
|
|
603
609
|
}, 1_000);
|
|
604
610
|
stream.reconnectTimer.unref?.();
|
|
605
611
|
}
|
|
@@ -635,7 +641,18 @@ export async function applyStageChange(stream, stage, detail = null) {
|
|
|
635
641
|
}
|
|
636
642
|
if (value === 'reconnecting') {
|
|
637
643
|
stream.compactingActive = false;
|
|
638
|
-
|
|
644
|
+
// The wait rides on the spinner so a surface that repaints on its own
|
|
645
|
+
// clock (the desktop status line) counts it down itself: `retryInMs` is
|
|
646
|
+
// the remaining wait at publish (relative, so a remote client's clock skew
|
|
647
|
+
// cannot distort it) and `retryAt` only identifies this retry.
|
|
648
|
+
set({
|
|
649
|
+
spinner: {
|
|
650
|
+
...getState().spinner,
|
|
651
|
+
mode: 'reconnecting',
|
|
652
|
+
verb: reconnectVerb(detail),
|
|
653
|
+
...reconnectWait(detail),
|
|
654
|
+
},
|
|
655
|
+
});
|
|
639
656
|
startReconnectCountdown(stream, detail);
|
|
640
657
|
await yieldToRenderer();
|
|
641
658
|
return;
|
package/src/tui/session/turn.mjs
CHANGED
|
@@ -777,6 +777,7 @@ export function createRunTurn(bag) {
|
|
|
777
777
|
submissionIds: turn.submittedIds,
|
|
778
778
|
submittedAt: options.submittedAt,
|
|
779
779
|
promptSource: options.promptSource,
|
|
780
|
+
...(options.promptOrigin ? { promptOrigin: options.promptOrigin } : {}),
|
|
780
781
|
retryFailedTurn: options.retryFailedTurn === true,
|
|
781
782
|
retryTurnId: options.retryTurnId,
|
|
782
783
|
retryAttemptId: options.retryAttemptId,
|