mixdog 1.3.5 → 1.4.1
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/check-voice-runtime-inputs.mjs +25 -0
- package/scripts/daemon-stub.mjs +1 -1
- package/scripts/gate-local.mjs +16 -5
- package/scripts/latest-guard.mjs +21 -9
- package/scripts/lib/isolated-test-env.mjs +10 -5
- package/scripts/lib/run-node-tests.mjs +37 -37
- package/scripts/lib/scoped-temp.d.mts +16 -0
- package/scripts/lib/scoped-temp.mjs +123 -0
- package/scripts/lib/stale-temp.mjs +44 -0
- package/scripts/native-release-status.mjs +2 -2
- package/scripts/post-release-check.mjs +1 -6
- package/scripts/pptx-kit-index.mjs +17 -4
- package/scripts/recall-history-cases.json +1 -1
- package/scripts/suite-health.mjs +20 -2
- package/scripts/test-data-dir.mjs +10 -7
- package/scripts/test.mjs +7 -11
- package/src/agents/reviewer/AGENT.md +7 -11
- package/src/agents/reviewer/agent.json +1 -1
- package/src/app.mjs +4 -0
- package/src/defaults/shipped-history.json +22 -1
- package/src/defaults/skills/browser-use/SKILL.md +62 -12
- 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 +35 -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 +39 -20
- package/src/output-styles/common.md +2 -2
- package/src/output-styles/simple.md +1 -1
- package/src/rules/agent/AGENT.md +11 -10
- package/src/rules/lead/LEAD.md +23 -20
- package/src/rules/shared/05-tool-calls.md +5 -6
- package/src/rules/shared/10-tool-workflow.md +4 -0
- package/src/rules/shared/45-destructive.md +0 -2
- package/src/rules/shared/50-execution.md +2 -0
- package/src/rules/shared/60-verification.md +7 -5
- package/src/rules/shared/70-delivery.md +7 -9
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -6
- 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/cache-break-trace.mjs +2 -0
- 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 +73 -68
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +57 -2
- 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/mcp/oauth-login.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +192 -133
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +42 -6
- package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +7 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +8 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-cache-warm.mjs +165 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -2
- 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-request/initial-status.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +159 -69
- package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +25 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +70 -33
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -2
- 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/command-code-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +25 -9
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +25 -13
- package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/devin.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +210 -20
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -11
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +45 -6
- package/src/runtime/agent/orchestrator/providers/lib/first-output-window.mjs +58 -0
- package/src/runtime/agent/orchestrator/providers/lib/listen-on.mjs +14 -0
- 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/mimo-oauth-login.mjs +1 -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-compat-chat-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +14 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +4 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +5 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +16 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +13 -3
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +13 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +81 -42
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +136 -5
- 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/openai-ws-stream/event-switch.mjs +20 -12
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +48 -22
- 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 +38 -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 +49 -16
- 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/orchestration.mjs +7 -6
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +9 -3
- 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/runtime-core/tool-defs.mjs +3 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +1 -3
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +798 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -8
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/compact/observation-supersession.mjs +103 -23
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +280 -45
- 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/context-utils.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +163 -22
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +132 -17
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +38 -7
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +90 -22
- 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 +51 -25
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +37 -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/pre-dispatch-deny.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +13 -5
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +31 -3
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +20 -3
- 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 +5 -4
- 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 +49 -21
- 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-loop-options.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +3 -1
- 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 +24 -14
- 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 +130 -0
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +27 -9
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +81 -8
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +27 -8
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +12 -5
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +9 -4
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +102 -15
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +21 -5
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +9 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +24 -9
- package/src/runtime/agent/orchestrator/session/prompt-cache-idle-gaps.mjs +113 -0
- package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +150 -0
- package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +154 -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-delete.mjs +7 -0
- 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 +16 -2
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +81 -22
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +92 -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 +79 -3
- 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/stall-policy.mjs +23 -0
- 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/invocation-plan.mjs +2 -2
- 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/spawn-env.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +31 -6
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +110 -26
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +31 -5
- package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +22 -8
- package/src/runtime/agent/orchestrator/tools/builtin/lib/scoped-search-flight.mjs +9 -5
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +23 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +1 -8
- package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/federation.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/lib/isolated-test-env.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +26 -4
- 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/webhook/signature.mjs +4 -1
- package/src/runtime/channels/lib/webhooks-db.mjs +5 -9
- package/src/runtime/channels/lib/whisper-port.mjs +10 -1
- 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 +28 -2
- package/src/runtime/computer-bridge/linux-action-capabilities.mjs +24 -5
- package/src/runtime/computer-bridge/linux-readiness.d.mts +7 -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/local-provider/server-process.mjs +2 -1
- package/src/runtime/media/adapters/gemini-video.mjs +4 -1
- package/src/runtime/media/adapters/xai-media.mjs +2 -1
- package/src/runtime/memory/lib/embedding-worker.mjs +6 -3
- package/src/runtime/memory/lib/memory-action-handlers/cycle-backfill-action.mjs +1 -7
- package/src/runtime/memory/lib/memory-chunk-quality.mjs +1 -6
- 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/office/authoring/pdf-author-action.mjs +1 -6
- package/src/runtime/office/design/design-art-direction.mjs +29 -27
- package/src/runtime/office/pdf/pdf-writer.mjs +6 -1
- package/src/runtime/office/portable/portable-snapshot-docx.mjs +7 -1
- package/src/runtime/office/portable/portable-snapshot-shared.mjs +6 -1
- package/src/runtime/office/quality/assurance-rendered.mjs +9 -2
- package/src/runtime/office/quality/assurance-structure-docx.mjs +3 -1
- package/src/runtime/office/quality/design-review.mjs +1 -5
- package/src/runtime/office/quality/document-brief.mjs +1 -5
- package/src/runtime/office/quality/forced-break-pages.mjs +9 -6
- package/src/runtime/office/quality/quality-pipeline.mjs +1 -1
- 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/bot-owned-work.mjs +56 -0
- 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 -17
- package/src/runtime/shared/delegated-approval-host.mjs +103 -11
- package/src/runtime/shared/err-text.mjs +24 -15
- package/src/runtime/shared/fetch-safe-listen.d.mts +16 -0
- package/src/runtime/shared/fetch-safe-listen.mjs +50 -0
- 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/handoff-artifacts.d.mts +2 -1
- package/src/runtime/shared/handoff-artifacts.mjs +18 -8
- 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 +126 -0
- package/src/runtime/shared/llm/cost.mjs +5 -1
- package/src/runtime/shared/llm/usage-rollup.mjs +1 -1
- package/src/runtime/shared/loopback-listener.mjs +25 -2
- package/src/runtime/shared/mixy-presence.mjs +22 -0
- package/src/runtime/shared/model-route-chain.d.mts +7 -2
- package/src/runtime/shared/model-route-chain.mjs +22 -4
- package/src/runtime/shared/open-url.mjs +10 -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 +48 -1
- package/src/runtime/shared/session-scratch.mjs +37 -0
- 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-card-model/agent-surface.mjs +1 -3
- package/src/runtime/shared/tool-card-model/card-status.mjs +15 -2
- package/src/runtime/shared/tool-result-summary.mjs +2 -15
- package/src/runtime/shared/tool-surface.mjs +3 -0
- package/src/runtime/shared/tool-work-units.mjs +2 -0
- package/src/runtime/shared/turn-snapshot-store.mjs +13 -6
- package/src/runtime/shared/worktrees/contract.mjs +4 -1
- package/src/runtime/shared/worktrees/git.mjs +15 -0
- package/src/runtime/shared/worktrees/manager.mjs +87 -38
- package/src/runtime/shared/worktrees/test-support.mjs +14 -13
- package/src/runtime/terminal-bridge/client.mjs +10 -1
- package/src/runtime/visualize-bridge/client.mjs +29 -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 +489 -185
- package/src/session-runtime/agent-task-sessions.mjs +467 -229
- package/src/session-runtime/agent-tool-routing.mjs +8 -41
- 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 +11 -2
- package/src/session-runtime/bot-status.mjs +12 -6
- package/src/session-runtime/bot-target.mjs +38 -0
- package/src/session-runtime/channel-config-api.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/conversation-import/codex-titles.mjs +88 -0
- package/src/session-runtime/conversation-import/discovery.mjs +271 -25
- package/src/session-runtime/conversation-import/service.mjs +26 -5
- package/src/session-runtime/handoff-attachments.mjs +82 -31
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +144 -41
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -0
- package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +4 -1
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +8 -2
- package/src/session-runtime/lifecycle/cold-heir.mjs +11 -6
- package/src/session-runtime/lifecycle/inheritance.mjs +16 -3
- package/src/session-runtime/lifecycle/session-catalog.mjs +12 -2
- 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/model-route/set-route.mjs +11 -2
- 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/provider-catalog-cache.mjs +82 -36
- package/src/session-runtime/provider-models/catalog-load.mjs +23 -6
- package/src/session-runtime/provider-models.mjs +4 -2
- 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/resource-recall-api.mjs +6 -1
- package/src/session-runtime/routine-owner.mjs +40 -9
- package/src/session-runtime/runtime-feature-gates.mjs +5 -1
- package/src/session-runtime/services/agent-tool/close-flow.mjs +3 -0
- package/src/session-runtime/services/agent-tool/execute.mjs +14 -9
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +20 -4
- package/src/session-runtime/services/agent-tool/model-select.mjs +48 -7
- package/src/session-runtime/services/agent-tool/render.mjs +71 -17
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +13 -4
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +1 -0
- package/src/session-runtime/services/agent-tool/tool-def.mjs +9 -9
- 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/provider-admin.mjs +2 -1
- 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 +17 -2
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +5 -1
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +15 -4
- package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -3
- package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +4 -0
- package/src/session-runtime/workspace/transitions.mjs +25 -0
- package/src/session-runtime/workspace/worktree-tool.mjs +26 -9
- 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 +142 -190
- 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/agent-tree/agent-turns.mjs +16 -12
- 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 +30 -2
- package/src/standalone/session-service/session-calls/session-views.mjs +8 -0
- package/src/standalone/session-tool-output.mjs +15 -7
- package/src/standalone/session-transport/client-registry/client-grace.mjs +12 -9
- package/src/tui/app/app-view/floating-panel.jsx +7 -4
- package/src/tui/app/model-options.mjs +3 -28
- package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +1 -3
- package/src/tui/app/model-picker/route-selection.mjs +5 -6
- package/src/tui/app/provider-setup/oauth-actions.mjs +38 -20
- package/src/tui/app/provider-setup/provider-items.mjs +8 -2
- package/src/tui/app/provider-setup-picker.mjs +9 -5
- package/src/tui/components/QuestionPanel.jsx +13 -4
- package/src/tui/dist/index.mjs +133 -92
- 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 +16 -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/ui/statusline-agents.mjs +1 -3
- 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,18 @@
|
|
|
1
|
+
// What must land in a session's transcript right before its next turn's
|
|
2
|
+
// prompt, whoever starts that turn: the daemon registers one prelude
|
|
3
|
+
// (agent-home-delivery.mjs postBeforeAgentTurn) and the prompt queue's drain
|
|
4
|
+
// (tui/session/session-flow/drain.mjs) awaits it before presenting a batch.
|
|
5
|
+
|
|
6
|
+
let prelude = null;
|
|
7
|
+
|
|
8
|
+
/** Register `fn(sessionId)` (null or a promise per turn); a non-function clears it. */
|
|
9
|
+
export function setSessionTurnPrelude(fn) {
|
|
10
|
+
prelude = typeof fn === 'function' ? fn : null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** The prelude's work before a turn of `sessionId`: a promise, or null when
|
|
14
|
+
* there is none (no await, so a turn with nothing owed starts as before). */
|
|
15
|
+
export function sessionTurnPrelude(sessionId) {
|
|
16
|
+
if (!prelude || !sessionId) return null;
|
|
17
|
+
return prelude(String(sessionId)) || null;
|
|
18
|
+
}
|
|
@@ -38,9 +38,7 @@ function agentNameFromResult(resultText) {
|
|
|
38
38
|
// The agent identity a card shows: the call's own fields, else the result
|
|
39
39
|
// envelope when the call only carried a tag/task id.
|
|
40
40
|
function agentDisplayName(args, resultText = '') {
|
|
41
|
-
return (
|
|
42
|
-
titleizeAgentName(args?.agent || args?.subagent_type || args?.name || '') || agentNameFromResult(resultText)
|
|
43
|
-
);
|
|
41
|
+
return titleizeAgentName(args?.agent || args?.subagent_type || args?.name || '') || agentNameFromResult(resultText);
|
|
44
42
|
}
|
|
45
43
|
|
|
46
44
|
function agentModelLabel(args) {
|
|
@@ -7,13 +7,26 @@ import { backgroundTaskFailureStatusLabel } from '../err-text.mjs';
|
|
|
7
7
|
import { agentTerminalDetail, isAgentTool } from './agent-surface.mjs';
|
|
8
8
|
import { backgroundTaskElapsed, backgroundTaskFailureDetail, isBackgroundTaskTool } from './background-task.mjs';
|
|
9
9
|
import { shellDisplayStatus } from './shell-surface.mjs';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
normalizeTerminalStatus,
|
|
12
|
+
resultControlStatus,
|
|
13
|
+
resultEnvelopeStatus,
|
|
14
|
+
shellResultElapsed,
|
|
15
|
+
} from './terminal-status.mjs';
|
|
11
16
|
import { mediaTerminalStatus } from './media-result.mjs';
|
|
12
17
|
import { gitTerminalStatus } from './git-result.mjs';
|
|
13
18
|
import { isUserControlCancellation } from '../tool-status.mjs';
|
|
14
19
|
|
|
15
20
|
// Tools whose result opens with a task/bridge envelope that reports the call's status.
|
|
16
|
-
const ENVELOPE_STATUS_TOOLS = new Set([
|
|
21
|
+
const ENVELOPE_STATUS_TOOLS = new Set([
|
|
22
|
+
'agent',
|
|
23
|
+
'bridge',
|
|
24
|
+
'task',
|
|
25
|
+
'web_search',
|
|
26
|
+
'search_query',
|
|
27
|
+
'image_query',
|
|
28
|
+
'web_search_call',
|
|
29
|
+
]);
|
|
17
30
|
|
|
18
31
|
function shellFragments(base, display, isShellSurface) {
|
|
19
32
|
if (!isShellSurface) return { shellStatus: '', shellElapsed: '' };
|
|
@@ -526,20 +526,7 @@ function summarizeCodeGraphResult({ text, translate }) {
|
|
|
526
526
|
return null;
|
|
527
527
|
}
|
|
528
528
|
|
|
529
|
-
function summarizeFetchResult({ text
|
|
530
|
-
// Channel `fetch` (Discord message fetch — args carry channel/messageId/limit,
|
|
531
|
-
// never url/uri) is not a WEB fetch: the status/size probes would miss and
|
|
532
|
-
// the result fall to raw JSON, so it takes the generic JSON/text summarizer.
|
|
533
|
-
if (normalized === 'fetch') {
|
|
534
|
-
const a = parseToolArgs(args);
|
|
535
|
-
const isChannelFetch =
|
|
536
|
-
!firstText(a.url, a.uri) && Boolean(firstText(a.channel, a.channelId, a.chatId, a.messageId) || a.limit != null);
|
|
537
|
-
if (isChannelFetch) {
|
|
538
|
-
const n = countNonEmptyLines(text);
|
|
539
|
-
if (trimmed && looksLineOriented(text) && n > 0) return countLabel(translate, n, 'message');
|
|
540
|
-
return summarizeGenericResult(text, translate);
|
|
541
|
-
}
|
|
542
|
-
}
|
|
529
|
+
function summarizeFetchResult({ text }) {
|
|
543
530
|
// Status: require a status-like context (HTTP NNN, "Status: NNN",
|
|
544
531
|
// or "NNN OK"/"NNN Not Found") rather than any bare 3-digit number.
|
|
545
532
|
const status =
|
|
@@ -661,7 +648,7 @@ const summarizeAskUserResult = ({ text, translate }) => {
|
|
|
661
648
|
|
|
662
649
|
const TOOL_RESULT_SUMMARIZERS = new Map(
|
|
663
650
|
[
|
|
664
|
-
[['ask_user'], summarizeAskUserResult],
|
|
651
|
+
[['ask_user', 'handoff_user'], summarizeAskUserResult],
|
|
665
652
|
[['read', 'view_image', 'read_mcp_resource'], summarizeReadResult],
|
|
666
653
|
[['apply_patch'], summarizePatchResult],
|
|
667
654
|
[['grep'], summarizeGrepResult],
|
|
@@ -151,6 +151,7 @@ export function displayToolName(name, args = {}) {
|
|
|
151
151
|
case 'request_user_input':
|
|
152
152
|
return 'Ask User';
|
|
153
153
|
case 'ask_user':
|
|
154
|
+
case 'handoff_user':
|
|
154
155
|
return 'Question';
|
|
155
156
|
case 'update_plan':
|
|
156
157
|
return 'Plan';
|
|
@@ -239,6 +240,8 @@ export function summarizeToolArgs(name, args, { max = DEFAULT_SUMMARY_MAX } = {}
|
|
|
239
240
|
return summarizeGithub(a, max);
|
|
240
241
|
case 'goal':
|
|
241
242
|
return compactParts([String(a.action || ''), truncateToolText(a.objective, max)]);
|
|
243
|
+
case 'handoff_user':
|
|
244
|
+
return '';
|
|
242
245
|
case 'ask_user':
|
|
243
246
|
return truncateToolText(
|
|
244
247
|
(Array.isArray(a.questions) ? a.questions : [])
|
|
@@ -91,6 +91,7 @@ const TOOL_CATEGORY = new Map([
|
|
|
91
91
|
['goal', 'Setup'],
|
|
92
92
|
['request_user_input', 'Setup'],
|
|
93
93
|
['ask_user', 'Setup'],
|
|
94
|
+
['handoff_user', 'Setup'],
|
|
94
95
|
['update_plan', 'Setup'],
|
|
95
96
|
['skill', 'Skill'],
|
|
96
97
|
['skill_execute', 'Skill'],
|
|
@@ -734,6 +735,7 @@ const TOOL_UNITS = new Map([
|
|
|
734
735
|
['code_graph', codeGraphUnit],
|
|
735
736
|
['request_user_input', () => unitDescriptor('Setup', { active: 'Asking', done: 'Asked', noun: 'user' })],
|
|
736
737
|
['ask_user', () => unitDescriptor('Setup', { active: 'Asking', done: 'Asked', noun: 'user' })],
|
|
738
|
+
['handoff_user', () => unitDescriptor('Setup', { active: 'Asking', done: 'Asked', noun: 'user' })],
|
|
737
739
|
['update_plan', () => unitDescriptor('Setup', { active: 'Updating', done: 'Updated', noun: 'plan' })],
|
|
738
740
|
['list_mcp_resources', () => unitDescriptor('Setup', { active: 'Listing', done: 'Listed', noun: 'MCP resource' })],
|
|
739
741
|
[
|
|
@@ -117,16 +117,23 @@ function recordPath(sessionId) {
|
|
|
117
117
|
function chain(sessionId, task) {
|
|
118
118
|
const previous = writeChains.get(sessionId) || Promise.resolve();
|
|
119
119
|
const next = previous.then(task, task);
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
() => undefined,
|
|
124
|
-
() => undefined
|
|
125
|
-
)
|
|
120
|
+
const settled = next.then(
|
|
121
|
+
() => undefined,
|
|
122
|
+
() => undefined
|
|
126
123
|
);
|
|
124
|
+
writeChains.set(sessionId, settled);
|
|
125
|
+
// A settled chain with nothing queued behind it holds no order to keep.
|
|
126
|
+
void settled.then(() => {
|
|
127
|
+
if (writeChains.get(sessionId) === settled) writeChains.delete(sessionId);
|
|
128
|
+
});
|
|
127
129
|
return next;
|
|
128
130
|
}
|
|
129
131
|
|
|
132
|
+
/** Sessions with a write chain still held (tests). */
|
|
133
|
+
export function _turnSnapshotWriteChainCountForTest() {
|
|
134
|
+
return writeChains.size;
|
|
135
|
+
}
|
|
136
|
+
|
|
130
137
|
async function readRecordFile(path) {
|
|
131
138
|
try {
|
|
132
139
|
const parsed = JSON.parse(await readFile(path, 'utf8'));
|
|
@@ -27,6 +27,7 @@ const WORKTREE_ENTRY_STATES = Object.freeze(['creating', 'ready', 'deleting', 'r
|
|
|
27
27
|
export const WORKTREE_ERROR_CODES = Object.freeze({
|
|
28
28
|
WORKTREE_BUSY_JOBS: 'WORKTREE_BUSY_JOBS',
|
|
29
29
|
WORKTREE_BRANCH_OCCUPIED: 'WORKTREE_BRANCH_OCCUPIED',
|
|
30
|
+
WORKTREE_DEFAULT_BRANCH: 'WORKTREE_DEFAULT_BRANCH',
|
|
30
31
|
WORKTREE_DISK_INSUFFICIENT: 'WORKTREE_DISK_INSUFFICIENT',
|
|
31
32
|
WORKTREE_LARGE_REPO_CONFIRM: 'WORKTREE_LARGE_REPO_CONFIRM',
|
|
32
33
|
WORKTREE_DIRTY: 'WORKTREE_DIRTY',
|
|
@@ -54,6 +55,8 @@ export const WORKTREE_ERROR_CODES = Object.freeze({
|
|
|
54
55
|
const DEFAULT_ERROR_MESSAGES = Object.freeze({
|
|
55
56
|
WORKTREE_BUSY_JOBS: 'The session has running jobs; wait for them or stop them before changing its workspace.',
|
|
56
57
|
WORKTREE_BRANCH_OCCUPIED: 'The branch is checked out in another worktree.',
|
|
58
|
+
WORKTREE_DEFAULT_BRANCH:
|
|
59
|
+
"The repository's default branch can't be opened in a worktree: the project folder could not switch to it while the worktree exists. Check it out in the project folder, or create a new branch for the worktree.",
|
|
57
60
|
WORKTREE_DISK_INSUFFICIENT: 'Not enough free disk space to create the worktree.',
|
|
58
61
|
WORKTREE_LARGE_REPO_CONFIRM: 'The repository is large; confirm before creating a worktree.',
|
|
59
62
|
WORKTREE_DIRTY: 'The worktree has uncommitted changes.',
|
|
@@ -193,7 +196,7 @@ function record(value, name) {
|
|
|
193
196
|
* @property {string|null} worktreeId Managed worktree id; null when running in the project folder.
|
|
194
197
|
* @property {string|null} branch Checked-out branch at `cwd`; null when detached or not a repository.
|
|
195
198
|
* @property {string|null} baseCommit Commit the worktree branch was created from.
|
|
196
|
-
* @property {string|null} mergeTarget Branch the worktree merges into (the project folder's branch).
|
|
199
|
+
* @property {string|null} mergeTarget Branch the worktree merges into (the project folder's branch); null for an existing branch until a merge records it.
|
|
197
200
|
* @property {number} revision Monotonic; advances on every committed workspace change.
|
|
198
201
|
* @property {WorkspaceTransition} transition In-flight transition marker.
|
|
199
202
|
*/
|
|
@@ -186,6 +186,21 @@ export async function localBranches(cwd, { signal, prefix = '' } = {}) {
|
|
|
186
186
|
return lines(result.stdout);
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
+
/** The local branch names the repository's remotes declare as their default (`refs/remotes/<remote>/HEAD`). */
|
|
190
|
+
export async function remoteDefaultBranches(cwd) {
|
|
191
|
+
const result = await runGit(cwd, ['for-each-ref', '--format=%(refname) %(symref)', 'refs/remotes'], {
|
|
192
|
+
readOnly: true,
|
|
193
|
+
});
|
|
194
|
+
const names = [];
|
|
195
|
+
for (const line of lines(result.stdout)) {
|
|
196
|
+
const [ref, target] = line.split(' ');
|
|
197
|
+
if (!ref.endsWith('/HEAD') || !target) continue;
|
|
198
|
+
const remote = ref.slice(0, -'HEAD'.length);
|
|
199
|
+
if (target.startsWith(remote)) names.push(target.slice(remote.length));
|
|
200
|
+
}
|
|
201
|
+
return names;
|
|
202
|
+
}
|
|
203
|
+
|
|
189
204
|
export async function validBranchName(cwd, branch) {
|
|
190
205
|
if (typeof branch !== 'string' || !branch.trim() || branch.startsWith('-')) return false;
|
|
191
206
|
const result = await runGit(cwd, ['check-ref-format', '--branch', branch], { allowFailure: true });
|
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
WORKTREE_SNAPSHOT_KIND,
|
|
50
50
|
worktreeBranchName,
|
|
51
51
|
worktreeError,
|
|
52
|
+
worktreeRefusal,
|
|
52
53
|
} from './contract.mjs';
|
|
53
54
|
import {
|
|
54
55
|
assertCarryable,
|
|
@@ -68,6 +69,7 @@ import {
|
|
|
68
69
|
listWorktrees,
|
|
69
70
|
localBranches,
|
|
70
71
|
parseStatusPaths,
|
|
72
|
+
remoteDefaultBranches,
|
|
71
73
|
runGit,
|
|
72
74
|
throwIfAborted,
|
|
73
75
|
validBranchName,
|
|
@@ -757,6 +759,11 @@ export async function resolveBranchWorkspace({
|
|
|
757
759
|
repoCommonDir: repo.repoCommonDir,
|
|
758
760
|
};
|
|
759
761
|
}
|
|
762
|
+
// Checked out in a managed worktree, the branch a remote declares its
|
|
763
|
+
// default would stay locked away from the project folder.
|
|
764
|
+
if (!create && (await remoteDefaultBranches(repo.projectPath)).includes(branch)) {
|
|
765
|
+
throw worktreeError('WORKTREE_DEFAULT_BRANCH', undefined, { branch });
|
|
766
|
+
}
|
|
760
767
|
const entry = await createManagedWorktree({
|
|
761
768
|
projectPath,
|
|
762
769
|
sessionId,
|
|
@@ -770,10 +777,6 @@ export async function resolveBranchWorkspace({
|
|
|
770
777
|
confirmLarge,
|
|
771
778
|
signal,
|
|
772
779
|
});
|
|
773
|
-
const record = await getRecord(entry.id);
|
|
774
|
-
record.mergeTarget = repo.currentBranch;
|
|
775
|
-
await putRecord(record);
|
|
776
|
-
entry.mergeTarget = repo.currentBranch;
|
|
777
780
|
return { path: entry.path, branch, entry, created: true, repoCommonDir: repo.repoCommonDir };
|
|
778
781
|
});
|
|
779
782
|
}
|
|
@@ -1219,7 +1222,10 @@ export async function createManagedWorktree({
|
|
|
1219
1222
|
path: managedWorktreePath(repo.repoCommonDir, slug),
|
|
1220
1223
|
branch,
|
|
1221
1224
|
baseCommit,
|
|
1222
|
-
|
|
1225
|
+
// An existing branch has no base it branched from: it merges where a
|
|
1226
|
+
// merge first takes it (recorded then), and until that its own work is
|
|
1227
|
+
// what it gained here since baseCommit.
|
|
1228
|
+
mergeTarget: existingBranch ? null : mergeTarget,
|
|
1223
1229
|
createdAt: Date.now(),
|
|
1224
1230
|
ownerSessionId: owner.sessionId,
|
|
1225
1231
|
existingBranch,
|
|
@@ -1400,9 +1406,7 @@ export async function removeSessionSnapshots(sessionId, { txIds = null } = {}) {
|
|
|
1400
1406
|
const only = txIds ? new Set(txIds) : null;
|
|
1401
1407
|
const held = Object.values((await readRegistry()).entries).filter(
|
|
1402
1408
|
(record) =>
|
|
1403
|
-
record.kind === WORKTREE_SNAPSHOT_KIND &&
|
|
1404
|
-
record.holderSessionId === sessionId &&
|
|
1405
|
-
(!only || only.has(record.txId))
|
|
1409
|
+
record.kind === WORKTREE_SNAPSHOT_KIND && record.holderSessionId === sessionId && (!only || only.has(record.txId))
|
|
1406
1410
|
);
|
|
1407
1411
|
for (const record of held) {
|
|
1408
1412
|
const row = { id: record.id, txId: record.txId };
|
|
@@ -1854,19 +1858,59 @@ export async function removeManagedWorktree({
|
|
|
1854
1858
|
if (!current && !expected) throw worktreeError('WORKTREE_MISSING', undefined, { entryId });
|
|
1855
1859
|
return skipped;
|
|
1856
1860
|
}
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
+
return removeLocked(current, { force, sessionId, preserveBranch, safeOnly });
|
|
1862
|
+
});
|
|
1863
|
+
}
|
|
1864
|
+
|
|
1865
|
+
/** The removal of `current`, under its repository lock. */
|
|
1866
|
+
async function removeLocked(current, { force, sessionId, preserveBranch = false, safeOnly = false }) {
|
|
1867
|
+
assertNotShared(current, sessionId);
|
|
1868
|
+
if (current.state === 'creating' || current.state === 'recovery') {
|
|
1869
|
+
const rollback = await rollbackCreation(current);
|
|
1870
|
+
return rollback.complete ? { removed: true } : { removed: false, retryable: true, remaining: rollback.remaining };
|
|
1871
|
+
}
|
|
1872
|
+
// Every deletion attempt of a snapshot, a resumed one included, waits
|
|
1873
|
+
// for (refuses on) its consumers.
|
|
1874
|
+
const release = current.kind === WORKTREE_SNAPSHOT_KIND ? holdSnapshotFolder(current) : () => {};
|
|
1875
|
+
try {
|
|
1876
|
+
return await decideAndFinishDeletion(current, { force, preserveBranch, safeOnly });
|
|
1877
|
+
} finally {
|
|
1878
|
+
release();
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
/**
|
|
1883
|
+
* Remove a worktree whose owner is gone, on an explicit request: under the
|
|
1884
|
+
* repository lock its retention is read again right before anything moves,
|
|
1885
|
+
* so an owner that came back (a live session, a running lease holder) or a
|
|
1886
|
+
* session the store still keeps it for refuses (WORKTREE_BUSY_JOBS). Then
|
|
1887
|
+
* the ordinary removal guards apply (dirty or unmerged work needs `force`).
|
|
1888
|
+
* @param {{ entryId: string, force?: boolean, liveSessionIds?: string[], retainedSessionIds?: string[] }} input
|
|
1889
|
+
*/
|
|
1890
|
+
export async function removeOrphanedWorktree({
|
|
1891
|
+
entryId,
|
|
1892
|
+
force = false,
|
|
1893
|
+
liveSessionIds = [],
|
|
1894
|
+
retainedSessionIds = [],
|
|
1895
|
+
} = {}) {
|
|
1896
|
+
const record = await getRecord(entryId);
|
|
1897
|
+
if (!record) throw worktreeError('WORKTREE_MISSING', undefined, { entryId });
|
|
1898
|
+
return withRepoLock(record.repoCommonDir, async () => {
|
|
1899
|
+
const current = await getRecord(entryId);
|
|
1900
|
+
if (!current || current.kind === WORKTREE_SNAPSHOT_KIND) {
|
|
1901
|
+
throw worktreeError('WORKTREE_MISSING', undefined, { entryId });
|
|
1861
1902
|
}
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1903
|
+
const { ownerLive, removable } = await retentionOf(current, new Set(liveSessionIds), new Set(retainedSessionIds));
|
|
1904
|
+
if (ownerLive) throw worktreeRefusal('workspace-lease', { entryId });
|
|
1905
|
+
if (!removable) {
|
|
1906
|
+
// Retained recovery data names itself; otherwise sessions still keep it.
|
|
1907
|
+
await assertRecoveryStoresClear(current);
|
|
1908
|
+
throw worktreeRefusal('workspace-retained', {
|
|
1909
|
+
entryId,
|
|
1910
|
+
sessions: [current.ownerSessionId, ...(current.sharedSessionIds ?? [])].filter(Boolean),
|
|
1911
|
+
});
|
|
1869
1912
|
}
|
|
1913
|
+
return removeLocked(current, { force });
|
|
1870
1914
|
});
|
|
1871
1915
|
}
|
|
1872
1916
|
|
|
@@ -1900,25 +1944,7 @@ export async function listManagedWorktrees({ liveSessionIds = [], retainedSessio
|
|
|
1900
1944
|
const retained = new Set(retainedSessionIds);
|
|
1901
1945
|
const rows = [];
|
|
1902
1946
|
for (const record of Object.values((await readRegistry()).entries)) {
|
|
1903
|
-
const
|
|
1904
|
-
const ownerLive = snapshot
|
|
1905
|
-
? await snapshotHolderLive(record, live)
|
|
1906
|
-
: (!!record.ownerSessionId && live.has(record.ownerSessionId)) ||
|
|
1907
|
-
leaseProcessAlive(await readOwnerLease(record));
|
|
1908
|
-
const isRetained = !!record.ownerSessionId && retained.has(record.ownerSessionId);
|
|
1909
|
-
// A snapshot outlives no holder: the prune removes it, changes and all.
|
|
1910
|
-
let removable = snapshot
|
|
1911
|
-
? !ownerLive
|
|
1912
|
-
: !record.sharedSessionIds?.length &&
|
|
1913
|
-
(record.state !== 'ready' || (!ownerLive && (record.disposable === true || !isRetained)));
|
|
1914
|
-
if (removable) {
|
|
1915
|
-
try {
|
|
1916
|
-
await assertRecoveryStoresClear(record);
|
|
1917
|
-
} catch (error) {
|
|
1918
|
-
if (error?.code !== 'WORKTREE_FILE_RECOVERY') throw error;
|
|
1919
|
-
removable = false;
|
|
1920
|
-
}
|
|
1921
|
-
}
|
|
1947
|
+
const { ownerLive, retained: isRetained, removable } = await retentionOf(record, live, retained);
|
|
1922
1948
|
rows.push({
|
|
1923
1949
|
...entryView(record),
|
|
1924
1950
|
projectPath: record.projectPath,
|
|
@@ -1930,6 +1956,29 @@ export async function listManagedWorktrees({ liveSessionIds = [], retainedSessio
|
|
|
1930
1956
|
return rows;
|
|
1931
1957
|
}
|
|
1932
1958
|
|
|
1959
|
+
/** Who keeps `record` (listManagedWorktrees): `live` and `retained` are session id sets. */
|
|
1960
|
+
async function retentionOf(record, live, retained) {
|
|
1961
|
+
const snapshot = record.kind === WORKTREE_SNAPSHOT_KIND;
|
|
1962
|
+
const ownerLive = snapshot
|
|
1963
|
+
? await snapshotHolderLive(record, live)
|
|
1964
|
+
: (!!record.ownerSessionId && live.has(record.ownerSessionId)) || leaseProcessAlive(await readOwnerLease(record));
|
|
1965
|
+
const isRetained = !!record.ownerSessionId && retained.has(record.ownerSessionId);
|
|
1966
|
+
// A snapshot outlives no holder: the prune removes it, changes and all.
|
|
1967
|
+
let removable = snapshot
|
|
1968
|
+
? !ownerLive
|
|
1969
|
+
: !record.sharedSessionIds?.length &&
|
|
1970
|
+
(record.state !== 'ready' || (!ownerLive && (record.disposable === true || !isRetained)));
|
|
1971
|
+
if (removable) {
|
|
1972
|
+
try {
|
|
1973
|
+
await assertRecoveryStoresClear(record);
|
|
1974
|
+
} catch (error) {
|
|
1975
|
+
if (error?.code !== 'WORKTREE_FILE_RECOVERY') throw error;
|
|
1976
|
+
removable = false;
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
return { ownerLive, retained: isRetained, removable };
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1933
1982
|
/**
|
|
1934
1983
|
* Conservative reconcile (daemon startup, and the manual prune). Always:
|
|
1935
1984
|
* resumes interrupted deletions, rolls back interrupted creations of no
|
|
@@ -1,25 +1,22 @@
|
|
|
1
1
|
// Temporary git repositories and data dirs for the worktree suites.
|
|
2
|
+
import '../git-direct.test-support.mjs';
|
|
2
3
|
import { execFileSync } from 'node:child_process';
|
|
3
|
-
import { chmodSync, cpSync, existsSync,
|
|
4
|
-
import { tmpdir } from 'node:os';
|
|
4
|
+
import { appendFileSync, chmodSync, cpSync, existsSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
5
5
|
import { dirname, join } from 'node:path';
|
|
6
|
+
import { makeTempDirSync, removeTempDirSync } from '../../../../scripts/lib/scoped-temp.mjs';
|
|
6
7
|
|
|
7
8
|
const created = [];
|
|
8
9
|
|
|
10
|
+
// A suite that never calls cleanupTempDirs still has its directories removed
|
|
11
|
+
// when the process exits.
|
|
9
12
|
export function tempDir(prefix = 'mixdog-wt-') {
|
|
10
|
-
const dir =
|
|
13
|
+
const dir = makeTempDirSync(prefix);
|
|
11
14
|
created.push(dir);
|
|
12
15
|
return dir;
|
|
13
16
|
}
|
|
14
17
|
|
|
15
18
|
export function cleanupTempDirs() {
|
|
16
|
-
for (const dir of created.splice(0))
|
|
17
|
-
try {
|
|
18
|
-
rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 50 });
|
|
19
|
-
} catch {
|
|
20
|
-
/* best effort */
|
|
21
|
-
}
|
|
22
|
-
}
|
|
19
|
+
for (const dir of created.splice(0)) removeTempDirSync(dir);
|
|
23
20
|
}
|
|
24
21
|
|
|
25
22
|
const GIT_ENV = { ...process.env, GIT_TERMINAL_PROMPT: '0', GIT_EDITOR: 'true' };
|
|
@@ -67,9 +64,13 @@ function repoTemplate(commit) {
|
|
|
67
64
|
if (existing && existsSync(existing)) return existing;
|
|
68
65
|
const dir = tempDir('mixdog-wt-template-');
|
|
69
66
|
git(dir, 'init', '-q', '-b', 'main');
|
|
70
|
-
git
|
|
71
|
-
|
|
72
|
-
git
|
|
67
|
+
// One config write instead of a `git config` process per key. Auto
|
|
68
|
+
// maintenance is off, so no commit (the test's or a merge's) starts a
|
|
69
|
+
// `git maintenance run` child.
|
|
70
|
+
appendFileSync(
|
|
71
|
+
join(dir, '.git', 'config'),
|
|
72
|
+
'[user]\n\tname = Mixdog Test\n\temail = mixdog@example.com\n[core]\n\tautocrlf = false\n[maintenance]\n\tauto = false\n'
|
|
73
|
+
);
|
|
73
74
|
if (commit) commitFile(dir, 'README.md', 'hello\n', 'initial');
|
|
74
75
|
templates.set(commit, dir);
|
|
75
76
|
return dir;
|
|
@@ -262,10 +262,19 @@ function oldestRowsOverCap(rows) {
|
|
|
262
262
|
function formatRun(value) {
|
|
263
263
|
const cursor = Number.isSafeInteger(value?.cursor) ? value.cursor : 0;
|
|
264
264
|
const tab = value?.tab !== undefined ? ` tab=${value.tab}` : '';
|
|
265
|
+
let where = '';
|
|
266
|
+
if (value?.shown === true) where = 'The terminal is shown in the desktop window.';
|
|
267
|
+
else if (value?.shown === false) {
|
|
268
|
+
where =
|
|
269
|
+
'The terminal is not shown in the desktop window right now (a paired phone may still show it); it keeps running.';
|
|
270
|
+
}
|
|
265
271
|
return [
|
|
266
272
|
`Terminal run: ${value?.id || `tab ${value?.tab}`} · ${tabLabel(value)} · cursor=${cursor}`,
|
|
267
273
|
`Command sent to the side terminal. Read its output with action=read${tab} since=${cursor}.`,
|
|
268
|
-
|
|
274
|
+
where,
|
|
275
|
+
]
|
|
276
|
+
.filter(Boolean)
|
|
277
|
+
.join('\n');
|
|
269
278
|
}
|
|
270
279
|
|
|
271
280
|
async function readJson(response) {
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* Response: { ok:true, text, tabs?, path? } | { ok:false, error }.
|
|
7
7
|
*/
|
|
8
8
|
import { bridgeDiscoveryChanged, readBridgeDiscovery, readBridgeDiscoveryDetail } from '../bridge-discovery.mjs';
|
|
9
|
+
import { visualizeOwnerToolMeta } from './tool-meta.mjs';
|
|
9
10
|
|
|
10
11
|
const DISCOVERY_FILE = 'visualize-bridge.json';
|
|
11
12
|
const REQUEST_TIMEOUT_MS = 30_000;
|
|
@@ -38,12 +39,14 @@ export function validateVisualizeArgs(args) {
|
|
|
38
39
|
if (!args || typeof args !== 'object' || Array.isArray(args)) {
|
|
39
40
|
return { ok: false, error: 'visualize arguments must be an object' };
|
|
40
41
|
}
|
|
41
|
-
if (!ACTIONS.has(args.action))
|
|
42
|
+
if (!ACTIONS.has(args.action))
|
|
43
|
+
return { ok: false, error: 'action must be open, close, annotate, capture, export, check, or inspect' };
|
|
42
44
|
const input = args.input ?? {};
|
|
43
45
|
if (typeof input !== 'object' || Array.isArray(input)) return { ok: false, error: 'input must be an object' };
|
|
44
46
|
if (args.action === 'open' && input.content != null) {
|
|
45
47
|
const content = input.content;
|
|
46
|
-
if (input.targets != null)
|
|
48
|
+
if (input.targets != null)
|
|
49
|
+
return { ok: false, error: 'open takes either input.targets or input.content, not both' };
|
|
47
50
|
if (typeof content !== 'object' || Array.isArray(content)) {
|
|
48
51
|
return { ok: false, error: 'open input.content must be { kind, source, title? }' };
|
|
49
52
|
}
|
|
@@ -79,7 +82,10 @@ export function validateVisualizeArgs(args) {
|
|
|
79
82
|
return { ok: false, error: 'open input.version must be a positive integer (a kept version number)' };
|
|
80
83
|
}
|
|
81
84
|
}
|
|
82
|
-
if (
|
|
85
|
+
if (
|
|
86
|
+
['annotate', 'capture', 'export', 'check', 'inspect'].includes(args.action) &&
|
|
87
|
+
(typeof input.tab !== 'string' || !input.tab)
|
|
88
|
+
) {
|
|
83
89
|
return { ok: false, error: `${args.action} requires input.tab` };
|
|
84
90
|
}
|
|
85
91
|
if (args.action === 'inspect') {
|
|
@@ -92,7 +98,10 @@ export function validateVisualizeArgs(args) {
|
|
|
92
98
|
!sized(viewport.width, 200, 3000) ||
|
|
93
99
|
(viewport.height != null && !sized(viewport.height, 200, 4000))
|
|
94
100
|
) {
|
|
95
|
-
return {
|
|
101
|
+
return {
|
|
102
|
+
ok: false,
|
|
103
|
+
error: 'inspect input.viewport must be { width: 200-3000, height?: 200-4000 } in whole pixels',
|
|
104
|
+
};
|
|
96
105
|
}
|
|
97
106
|
}
|
|
98
107
|
if (selector != null && (typeof selector !== 'string' || !selector.trim() || selector.length > 500)) {
|
|
@@ -103,7 +112,8 @@ export function validateVisualizeArgs(args) {
|
|
|
103
112
|
return { ok: false, error: 'capture requires input.output ending in .png' };
|
|
104
113
|
}
|
|
105
114
|
if (args.action === 'export') {
|
|
106
|
-
if (input.format !== 'png' && input.format !== 'pdf')
|
|
115
|
+
if (input.format !== 'png' && input.format !== 'pdf')
|
|
116
|
+
return { ok: false, error: 'export requires input.format png or pdf' };
|
|
107
117
|
if (typeof input.output !== 'string' || !new RegExp('\\.' + input.format + '$', 'i').test(input.output.trim())) {
|
|
108
118
|
return { ok: false, error: `export requires input.output ending in .${input.format}` };
|
|
109
119
|
}
|
|
@@ -153,6 +163,8 @@ export async function executeVisualizeTool(args, options = {}) {
|
|
|
153
163
|
cwd: options.cwd || process.cwd(),
|
|
154
164
|
action: validated.action,
|
|
155
165
|
input: validated.input,
|
|
166
|
+
// The call's id: the host names it in its turn-end record of opens whose tab is gone.
|
|
167
|
+
...(options.callId ? { callId: String(options.callId) } : {}),
|
|
156
168
|
};
|
|
157
169
|
let discovery = readBridgeDiscovery(DISCOVERY_FILE);
|
|
158
170
|
if (!discovery) return toolError(unavailableMessage());
|
|
@@ -160,7 +172,11 @@ export async function executeVisualizeTool(args, options = {}) {
|
|
|
160
172
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
161
173
|
const timeout = AbortSignal.timeout(validated.action === 'export' ? EXPORT_REQUEST_TIMEOUT_MS : REQUEST_TIMEOUT_MS);
|
|
162
174
|
try {
|
|
163
|
-
result = await requestBridge(
|
|
175
|
+
result = await requestBridge(
|
|
176
|
+
discovery,
|
|
177
|
+
payload,
|
|
178
|
+
options.signal ? AbortSignal.any([timeout, options.signal]) : timeout
|
|
179
|
+
);
|
|
164
180
|
break;
|
|
165
181
|
} catch (error) {
|
|
166
182
|
if (error?.name === 'TimeoutError') return toolError('visualize bridge timed out');
|
|
@@ -175,7 +191,12 @@ export async function executeVisualizeTool(args, options = {}) {
|
|
|
175
191
|
}
|
|
176
192
|
const { body, status } = result;
|
|
177
193
|
if (!body?.ok) {
|
|
178
|
-
return toolError(
|
|
194
|
+
return toolError(
|
|
195
|
+
String(body?.error || `visualize bridge request failed (HTTP ${status})`).replace(/^Error:\s*/, '')
|
|
196
|
+
);
|
|
179
197
|
}
|
|
180
|
-
|
|
198
|
+
// The host ran it for another session's panel: the owner rides as a field
|
|
199
|
+
// (toolMeta, kept with the stored result), never only as prose.
|
|
200
|
+
const toolMeta = visualizeOwnerToolMeta(body.ownerSessionId);
|
|
201
|
+
return { content: [{ type: 'text', text: formatSuccess(body) }], ...(toolMeta ? { toolMeta } : {}) };
|
|
181
202
|
}
|
|
@@ -10,8 +10,8 @@ export const TOOL_DEFS = [
|
|
|
10
10
|
name: 'visualize',
|
|
11
11
|
title: 'Mixdog Visualize',
|
|
12
12
|
description:
|
|
13
|
-
|
|
14
|
-
'open: input.targets (1-3 file paths, 2-3 = side-by-side comparison; or a single http(s) URL alone, never mixed with files or other URLs), optional label, optional version (show that kept version of a file tab read-only; each open/reload that changes the files keeps a version). close: optional tab (omit = all). ' +
|
|
13
|
+
'Show the user any artifact you produced or changed (mockups, docs, decks, sheets, PDFs, images, video, local dev pages) in the desktop side panel beside the chat. Panel tabs auto-reload when a file changes, so re-opening after edits is unnecessary. ' +
|
|
14
|
+
'open: input.targets (1-3 file paths, relative to the working directory or absolute anywhere on this machine; 2-3 = side-by-side comparison; or a single http(s) URL alone, never mixed with files or other URLs), optional label, optional version (show that kept version of a file tab read-only; each open/reload that changes the files keeps a version). close: optional tab (omit = all). ' +
|
|
15
15
|
'annotate: tab + add [{selector,label?}] | remove [selector] | clear; HTML pages only, never edits the file. capture: tab + output (.png path). ' +
|
|
16
16
|
'export: tab + format (png|pdf) + output (project-relative path ending .png/.pdf) + optional version (a kept version of the tab) + optional overwrite (true replaces an existing file, only under design/; otherwise an existing file is refused). Writes a record of the approved page inside the project and returns its project-relative path, size/dimensions and the page problems seen while rendering. A single HTML page (file, or inline html/chart) is rendered whole in a hidden window, so the tab need not be on screen (PDF: HTML pages only; PNG has a pixel cap, over it export pdf or shorten the page); any other tab exports as capture does (the displayed tab, PNG only). Same project containment as capture: links and paths outside the working directory are refused. ' +
|
|
17
17
|
'check: tab; HTML pages only; waits briefly for the page to settle and returns only its runtime problems (uncaught errors, unhandled rejections, CSP violations, console errors/warnings, missing local assets). ' +
|
|
@@ -36,7 +36,8 @@ export const TOOL_DEFS = [
|
|
|
36
36
|
items: { type: 'string' },
|
|
37
37
|
minItems: 1,
|
|
38
38
|
maxItems: 3,
|
|
39
|
-
description:
|
|
39
|
+
description:
|
|
40
|
+
'open: 1-3 file paths (side by side), relative to the working directory or absolute in any folder, or exactly one http(s) URL as the only target.',
|
|
40
41
|
},
|
|
41
42
|
content: {
|
|
42
43
|
type: 'object',
|
|
@@ -57,7 +58,8 @@ export const TOOL_DEFS = [
|
|
|
57
58
|
version: {
|
|
58
59
|
type: 'integer',
|
|
59
60
|
minimum: 1,
|
|
60
|
-
description:
|
|
61
|
+
description:
|
|
62
|
+
'open (file tabs): kept version number to show read-only instead of the live files. export: kept version number to render instead of the live page.',
|
|
61
63
|
},
|
|
62
64
|
tab: { type: 'string', description: 'Tab id from open (close: omit for all).' },
|
|
63
65
|
add: {
|
|
@@ -72,9 +74,16 @@ export const TOOL_DEFS = [
|
|
|
72
74
|
},
|
|
73
75
|
remove: { type: 'array', items: { type: 'string' }, description: 'annotate: selectors to un-outline.' },
|
|
74
76
|
clear: { type: 'boolean', description: 'annotate: remove all outlines.' },
|
|
75
|
-
output: {
|
|
77
|
+
output: {
|
|
78
|
+
type: 'string',
|
|
79
|
+
description:
|
|
80
|
+
'capture: project path ending .png. export: project path ending .png or .pdf (matching format).',
|
|
81
|
+
},
|
|
76
82
|
format: { type: 'string', enum: ['png', 'pdf'], description: 'export: file format.' },
|
|
77
|
-
overwrite: {
|
|
83
|
+
overwrite: {
|
|
84
|
+
type: 'boolean',
|
|
85
|
+
description: 'export: replace an existing output file; honored only for paths under design/.',
|
|
86
|
+
},
|
|
78
87
|
viewport: {
|
|
79
88
|
type: 'object',
|
|
80
89
|
properties: {
|
|
@@ -83,9 +92,14 @@ export const TOOL_DEFS = [
|
|
|
83
92
|
},
|
|
84
93
|
required: ['width'],
|
|
85
94
|
additionalProperties: false,
|
|
86
|
-
description:
|
|
95
|
+
description:
|
|
96
|
+
"inspect: size to lay the page out at (height defaults to 800); omit for the panel's current size.",
|
|
97
|
+
},
|
|
98
|
+
selector: {
|
|
99
|
+
type: 'string',
|
|
100
|
+
maxLength: 500,
|
|
101
|
+
description: 'inspect: CSS selector scoping the read-out to one subtree.',
|
|
87
102
|
},
|
|
88
|
-
selector: { type: 'string', maxLength: 500, description: 'inspect: CSS selector scoping the read-out to one subtree.' },
|
|
89
103
|
},
|
|
90
104
|
additionalProperties: false,
|
|
91
105
|
},
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const VISUALIZE_OWNER_META_CODE: 'visualize_owner';
|
|
2
|
+
export declare function visualizeOwnerMetaSessionId(value: unknown): string;
|
|
3
|
+
export declare function visualizeOwnerToolMeta(
|
|
4
|
+
ownerSessionId: unknown
|
|
5
|
+
): { code: typeof VISUALIZE_OWNER_META_CODE; missing: string[]; ownerSessionId: string } | undefined;
|