mixdog 1.3.4 → 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/LICENSES/oh-my-pi-MIT.txt +23 -0
- package/NOTICE.md +17 -2
- package/README.md +11 -0
- package/package.json +3 -11
- package/scripts/daemon-stub.mjs +1 -1
- package/scripts/embed-google-oauth-client.mjs +49 -0
- package/scripts/gate-local.mjs +4 -2
- package/scripts/lib/test-spawn-ledger.mjs +46 -1
- 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 +12 -11
- package/src/agents/reviewer/AGENT.md +7 -11
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +25 -1
- package/src/defaults/skills/browser-use/SKILL.md +77 -17
- 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 +29 -2
- package/src/defaults/skills/setup/references/actions.md +117 -28
- package/src/defaults/skills/setup/references/surfaces.md +77 -35
- package/src/defaults/skills/setup-guide/SKILL.md +3 -3
- package/src/defaults/skills/visualize/SKILL.md +2 -1
- package/src/lib/keychain-cjs.cjs +359 -29
- package/src/lib/rules-builder.cjs +10 -8
- package/src/rules/agent/AGENT.md +6 -6
- package/src/rules/agent-mode/AGENT_MODE.md +10 -2
- package/src/rules/agent-mode/MIXY.md +12 -0
- 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/heartbeat-completion.mjs +193 -0
- 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 +34 -0
- 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 +177 -73
- package/src/runtime/agent/orchestrator/mcp/client.mjs +25 -2
- package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +31 -2
- package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +16 -3
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +42 -7
- package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +21 -2
- package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +23 -0
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +11 -1
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +230 -137
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +64 -7
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +18 -5
- 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 +160 -69
- 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-oauth-catalog.mjs +52 -8
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +10 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +22 -6
- package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +15 -4
- package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +17 -2
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +142 -104
- package/src/runtime/agent/orchestrator/providers/cache-warm-admission.mjs +90 -0
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +10 -4
- package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +10 -217
- package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +25 -9
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +22 -6
- package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +409 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-families.mjs +187 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-identity.mjs +342 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-models.mjs +541 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-protobuf.mjs +305 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-request.mjs +558 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-schema.mjs +880 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-session.mjs +190 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-tool-args.mjs +351 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +560 -0
- package/src/runtime/agent/orchestrator/providers/devin.mjs +491 -0
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/gemini-output-limit.mjs +46 -0
- package/src/runtime/agent/orchestrator/providers/gemini-reasoning-relay.mjs +30 -0
- package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +7 -11
- package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +61 -22
- package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -4
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +25 -2
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +96 -5
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +17 -3
- package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +23 -5
- 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 +19 -1
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +39 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +6 -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/opencode-go-gemini.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/provider-availability.mjs +19 -0
- 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 +43 -3
- 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/providers/wire-protobuf-codec.mjs +368 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +12 -7
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
- 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 +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/reaction-tool-defs.mjs +133 -0
- 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-data.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +125 -30
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +23 -5
- package/src/runtime/agent/orchestrator/runtime-core/tool-profile.mjs +35 -10
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +57 -10
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +9 -6
- package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +18 -0
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +0 -3
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +10 -4
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +792 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +148 -25
- 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 +8 -0
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +47 -9
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -4
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +14 -2
- package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +8 -0
- 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 +11 -2
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +51 -3
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +17 -3
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -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 +14 -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 +10 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -10
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +23 -5
- package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +60 -0
- 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-commit.mjs +2 -0
- 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 +14 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -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 +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/session-tool-surface.mjs +13 -0
- 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/message-ids.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/message-reactions.mjs +89 -0
- package/src/runtime/agent/orchestrator/session/message-reactions.test-support.mjs +75 -0
- 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.d.mts +0 -2
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +47 -11
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +20 -2
- 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-header-cache.mjs +85 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +133 -18
- 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/tail-reminder-rules.mjs +11 -5
- 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/tool-batch/state.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +25 -2
- 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/schedule-errors.mjs +51 -0
- package/src/runtime/channels/lib/scheduler.mjs +135 -154
- package/src/runtime/channels/lib/schedules-db.mjs +83 -11
- package/src/runtime/channels/lib/status-snapshot.mjs +1 -1
- package/src/runtime/channels/lib/tool-dispatch.mjs +14 -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 +19 -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/office/com/com-adapter.mjs +17 -1
- package/src/runtime/office/com/office-com-host.ps1 +51 -1
- package/src/runtime/office/pdf/cfb-fixture.mjs +328 -0
- package/src/runtime/office/pdf/cfb-protection.mjs +311 -0
- package/src/runtime/office/pdf/document-preview.mjs +326 -8
- package/src/runtime/office/pdf/ooxml-crypto.mjs +469 -0
- package/src/runtime/office/pdf/ooxml-key-worker.mjs +14 -0
- package/src/runtime/office/portable/portable-soffice.mjs +45 -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/bot-hops.mjs +62 -2
- package/src/runtime/shared/bounded-download.mjs +8 -3
- package/src/runtime/shared/config.mjs +51 -35
- package/src/runtime/shared/connector-accounts.mjs +20 -10
- package/src/runtime/shared/connector-catalog.d.mts +33 -2
- package/src/runtime/shared/connector-catalog.mjs +166 -8
- 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/developer-options.mjs +32 -1
- 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/google-oauth-client.generated.json +4 -0
- package/src/runtime/shared/google-oauth-client.mjs +34 -9
- 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/anthropic-betas.mjs +7 -0
- package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +12 -0
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +1 -0
- package/src/runtime/shared/llm/usage-rollup.mjs +1 -1
- package/src/runtime/shared/llm/well-formed.mjs +66 -0
- 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 +231 -59
- package/src/runtime/shared/provider-api-key.mjs +19 -8
- 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 +52 -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-execution-contract.mjs +2 -0
- package/src/runtime/shared/tool-result-summary.mjs +1 -14
- package/src/runtime/shared/transcript-metadata.mjs +38 -0
- package/src/runtime/shared/user-data-guard.mjs +30 -2
- package/src/runtime/shared/worktrees/activity-gate.mjs +12 -5
- 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 +486 -179
- package/src/session-runtime/agent-room-delivery.mjs +28 -1
- package/src/session-runtime/agent-task-sessions.mjs +561 -199
- package/src/session-runtime/boot/apis.mjs +9 -0
- package/src/session-runtime/boot/begin.mjs +3 -2
- 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 +8 -1
- package/src/session-runtime/bot-chain.mjs +32 -0
- package/src/session-runtime/bot-status.mjs +7 -4
- package/src/session-runtime/channel-config-api.mjs +63 -17
- 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/internal-tool-executor/reaction-tool.mjs +45 -0
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +72 -5
- package/src/session-runtime/internal-tool-executor.mjs +4 -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 +61 -3
- package/src/session-runtime/mcp-oauth-login.mjs +5 -3
- package/src/session-runtime/mixy-heartbeat.mjs +927 -0
- package/src/session-runtime/model-route/route-tuning.mjs +10 -6
- 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 +35 -13
- package/src/session-runtime/prewarm/channel-start.mjs +3 -7
- package/src/session-runtime/provider-auth/login.mjs +7 -0
- package/src/session-runtime/provider-models/row-hydration.mjs +13 -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/routine-home-turn.mjs +33 -6
- package/src/session-runtime/routine-owner.mjs +40 -9
- package/src/session-runtime/schedule-session-run.mjs +7 -3
- package/src/session-runtime/services/agent-tool/close-flow.mjs +3 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +8 -12
- 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 +73 -31
- package/src/session-runtime/services/channel-session-router.mjs +4 -2
- package/src/session-runtime/services/channel-worker.mjs +1 -1
- package/src/session-runtime/services/provider-admin.mjs +128 -25
- package/src/session-runtime/services/schedule-access.mjs +14 -0
- package/src/session-runtime/services/seeds.mjs +0 -28
- package/src/session-runtime/services/usage-dashboard-model.mjs +1 -0
- package/src/session-runtime/session-compaction-sync.mjs +27 -0
- package/src/session-runtime/session-create/session-options.mjs +8 -4
- 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 +28 -1
- package/src/session-runtime/setup-tool/agent-settings-actions.mjs +65 -0
- package/src/session-runtime/setup-tool/executor.mjs +187 -29
- package/src/session-runtime/setup-tool/extended-actions.mjs +33 -2
- package/src/session-runtime/setup-tool/session-route-actions.mjs +152 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +68 -6
- package/src/session-runtime/setup-tool/tool-defs.mjs +92 -6
- package/src/session-runtime/task-session-route.mjs +99 -0
- package/src/session-runtime/tool-policy/agent-profile-fold.mjs +17 -13
- package/src/session-runtime/tool-policy/policy-stage.mjs +21 -4
- package/src/session-runtime/tool-policy/surface-helpers.mjs +2 -3
- package/src/session-runtime/tool-surface.mjs +4 -0
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +98 -21
- package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +4 -0
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -1
- package/src/session-runtime/workspace/transitions.mjs +10 -2
- 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 +161 -157
- package/src/standalone/daemon.mjs +33 -2
- package/src/standalone/session-client.mjs +7 -3
- package/src/standalone/session-protocol.mjs +10 -0
- package/src/standalone/session-service/agent-tree/agent-cancel.mjs +6 -2
- 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-turns.mjs +6 -0
- package/src/standalone/session-service/session-calls/session-views.mjs +8 -0
- package/src/standalone/session-service.mjs +13 -0
- package/src/standalone/session-tool-output.mjs +21 -10
- package/src/tui/app/model-options.mjs +4 -27
- package/src/tui/dist/index.mjs +81 -65
- 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 +23 -1
- package/src/tui/session/queue-helpers.mjs +3 -42
- package/src/tui/session/session-api/integrations.mjs +1 -0
- package/src/tui/session/session-api/lifecycle.mjs +8 -0
- 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 +30 -2
- 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 +36 -3
- package/src/tui/session/turn.mjs +23 -2
- 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
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
// The credential / secret file deny list
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// between bots and agents (session-runtime/handoff-attachments.mjs).
|
|
1
|
+
// The credential / secret file deny list of the runtime's attachment
|
|
2
|
+
// hand-offs between bots and agents (session-runtime/handoff-attachments.mjs):
|
|
3
|
+
// an automatic transfer never carries a secret-bearing file. A paired device
|
|
4
|
+
// is the user's own and gets no such list (it opens what the desktop opens).
|
|
6
5
|
//
|
|
7
6
|
// Matching is on SEGMENTS of a path, lower-cased on every platform, so a
|
|
8
7
|
// denied name cannot hide behind letter case, trailing dots/spaces or an NTFS
|
|
@@ -113,10 +112,6 @@ const CREDENTIAL_FILES = new Set([
|
|
|
113
112
|
* checked in often enough with real values that no name is exempt) and
|
|
114
113
|
* `<stage>.env`. */
|
|
115
114
|
const ENV_FILE = /^(?:\.env.*|[^.]{1,64}(?:\.[^.]{1,64}){0,3}\.env)$/;
|
|
116
|
-
/** The dotenv templates a person may still open on purpose from a paired
|
|
117
|
-
* device (the desktop's remote file lanes, `envTemplates: true`); automatic
|
|
118
|
-
* transfers between bots and agents never get this allowance. */
|
|
119
|
-
const ENV_TEMPLATES = new Set(['.env.example', '.env.sample', '.env.template', '.env.dist']);
|
|
120
115
|
/** Credential JSON a cloud or OAuth client writes or downloads:
|
|
121
116
|
* `credentials.json`, `*credentials*.json`, `service-account*.json`,
|
|
122
117
|
* `client_secret*.json`. */
|
|
@@ -143,10 +138,9 @@ function backupOriginal(name) {
|
|
|
143
138
|
|
|
144
139
|
/** A file whose own name says it holds a secret, wherever it lives: a
|
|
145
140
|
* credential file, a dotenv file, a key or keystore, or a backup of one. */
|
|
146
|
-
function secretFileName(name
|
|
141
|
+
function secretFileName(name) {
|
|
147
142
|
const original = backupOriginal(name);
|
|
148
|
-
if (CREDENTIAL_FILES.has(original) || CREDENTIAL_JSON.test(original)) return true;
|
|
149
|
-
if (ENV_FILE.test(original)) return !(envTemplates && ENV_TEMPLATES.has(original));
|
|
143
|
+
if (CREDENTIAL_FILES.has(original) || CREDENTIAL_JSON.test(original) || ENV_FILE.test(original)) return true;
|
|
150
144
|
const dot = original.lastIndexOf('.');
|
|
151
145
|
if (dot >= 0 && KEY_EXTENSIONS.has(original.slice(dot))) return true;
|
|
152
146
|
return SSH_PRIVATE_KEY.test(original);
|
|
@@ -156,14 +150,7 @@ function secretFileName(name, { envTemplates = false } = {}) {
|
|
|
156
150
|
// (tool results, shell output, media), which stay reachable; only the files
|
|
157
151
|
// and folders that carry provider tokens, API keys, pairing and bridge secrets
|
|
158
152
|
// are denied.
|
|
159
|
-
const MIXDOG_SECRET_DIRECTORIES = new Set([
|
|
160
|
-
'secrets',
|
|
161
|
-
'mcp-oauth',
|
|
162
|
-
'provider-accounts',
|
|
163
|
-
'telegram',
|
|
164
|
-
'relay-data',
|
|
165
|
-
'dev-profile',
|
|
166
|
-
]);
|
|
153
|
+
const MIXDOG_SECRET_DIRECTORIES = new Set(['secrets', 'mcp-oauth', 'provider-accounts', 'relay-data', 'dev-profile']);
|
|
167
154
|
const MIXDOG_SECRET_FILE =
|
|
168
155
|
/^\.?(mixdog-config|provider-accounts|relay-hook-device|auth\.json|[a-z0-9-]+-oauth(-credentials)?\.json|[a-z0-9-]+-bridge\.json)/;
|
|
169
156
|
const MIXDOG_SECRET_EXTENSIONS = new Set(['.dpapi', '.token']);
|
|
@@ -177,7 +164,7 @@ function mixdogSecret(rest) {
|
|
|
177
164
|
|
|
178
165
|
/** The segments of a path as the rules compare them: no extended-path prefix,
|
|
179
166
|
* no NTFS stream suffix, no trailing dots or spaces, lower case. */
|
|
180
|
-
|
|
167
|
+
function sensitivePathSegments(path) {
|
|
181
168
|
return String(path)
|
|
182
169
|
.replace(/^[\\/]{2}[?.][\\/]/, '')
|
|
183
170
|
.split(/[\\/]+/)
|
|
@@ -198,30 +185,21 @@ function hasRun(segments, run) {
|
|
|
198
185
|
}
|
|
199
186
|
|
|
200
187
|
/**
|
|
201
|
-
* Whether `path` is denied under `within`: scopes `{ root: segments
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
* true`, everything but `except`). Pass both the lexical and canonical form.
|
|
205
|
-
* `envTemplates`: a user-initiated remote open may read the dotenv
|
|
206
|
-
* templates; nothing else gets that allowance.
|
|
188
|
+
* Whether `path` is denied under `within`: scopes `{ root: segments }` —
|
|
189
|
+
* Mixdog's home and data folders, where only their secret subset is denied.
|
|
190
|
+
* Pass both the lexical and canonical form.
|
|
207
191
|
*/
|
|
208
|
-
export function matchesSensitivePath(path, within = []
|
|
192
|
+
export function matchesSensitivePath(path, within = []) {
|
|
209
193
|
const segments = sensitivePathSegments(resolve(path));
|
|
210
194
|
const name = segments[segments.length - 1] ?? '';
|
|
211
195
|
if (segments.some((segment) => SECRET_DIRECTORIES.has(segment))) return true;
|
|
212
|
-
if (secretFileName(name
|
|
213
|
-
|
|
214
|
-
({ root }) =>
|
|
196
|
+
if (secretFileName(name) || SECRET_SEQUENCES.some((run) => hasRun(segments, run))) return true;
|
|
197
|
+
return within.some(
|
|
198
|
+
({ root }) =>
|
|
199
|
+
root.length > 0 &&
|
|
200
|
+
root.every((segment, index) => segments[index] === segment) &&
|
|
201
|
+
mixdogSecret(segments.slice(root.length))
|
|
215
202
|
);
|
|
216
|
-
// Mixdog's home and data folders follow Mixdog's own rule even inside a
|
|
217
|
-
// registered private root: a dev or isolated profile keeps them in the app
|
|
218
|
-
// profile, and the tool output and media there stay reachable.
|
|
219
|
-
const own = containing.filter(({ whole }) => !whole);
|
|
220
|
-
if (own.length) return own.some(({ root }) => mixdogSecret(segments.slice(root.length)));
|
|
221
|
-
return containing.some(({ root, except }) => {
|
|
222
|
-
const rest = segments.slice(root.length);
|
|
223
|
-
return rest.length > 0 && !except.includes(rest[0]);
|
|
224
|
-
});
|
|
225
203
|
}
|
|
226
204
|
|
|
227
205
|
function realOrSelf(path) {
|
|
@@ -241,7 +219,7 @@ export function mixdogSensitiveScopes(extraData = []) {
|
|
|
241
219
|
const scopes = [];
|
|
242
220
|
for (const root of roots) {
|
|
243
221
|
for (const form of new Set([resolve(root), realOrSelf(resolve(root))])) {
|
|
244
|
-
scopes.push({ root: sensitivePathSegments(form)
|
|
222
|
+
scopes.push({ root: sensitivePathSegments(form) });
|
|
245
223
|
}
|
|
246
224
|
}
|
|
247
225
|
return scopes;
|
|
@@ -13,7 +13,40 @@ export function onSessionActivityChange(listener) {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export function emitSessionActivityChange(sessionId = '') {
|
|
16
|
-
|
|
16
|
+
emit(listeners, sessionId);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// A turn started on a session: the one point every turn passes through, whoever
|
|
20
|
+
// started it. Unlike the activity pulse it never fires on a settle or a wait.
|
|
21
|
+
const turnStartListeners = new Set();
|
|
22
|
+
|
|
23
|
+
export function onSessionTurnStart(listener) {
|
|
24
|
+
if (typeof listener !== 'function') return () => {};
|
|
25
|
+
turnStartListeners.add(listener);
|
|
26
|
+
return () => turnStartListeners.delete(listener);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function emitSessionTurnStart(sessionId = '') {
|
|
30
|
+
emit(turnStartListeners, sessionId);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// A live session started or stopped showing an approval card waiting on the
|
|
34
|
+
// user (its runtime state's `toolApproval`): the session catalog, which
|
|
35
|
+
// stamps that on each row, listens and re-reads.
|
|
36
|
+
const approvalCardListeners = new Set();
|
|
37
|
+
|
|
38
|
+
export function onSessionApprovalCardChange(listener) {
|
|
39
|
+
if (typeof listener !== 'function') return () => {};
|
|
40
|
+
approvalCardListeners.add(listener);
|
|
41
|
+
return () => approvalCardListeners.delete(listener);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function emitSessionApprovalCardChange(sessionId = '') {
|
|
45
|
+
emit(approvalCardListeners, sessionId);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function emit(targets, sessionId) {
|
|
49
|
+
for (const listener of [...targets]) {
|
|
17
50
|
try {
|
|
18
51
|
listener(String(sessionId || ''));
|
|
19
52
|
} catch {
|
|
@@ -4,7 +4,7 @@ export type SessionSidebarChange =
|
|
|
4
4
|
| { archived: true; cascade: false }
|
|
5
5
|
| { forgotten: true };
|
|
6
6
|
export type SessionSidebarHost = (sessionId: unknown, change: unknown) => unknown;
|
|
7
|
-
export type SessionSidebarState = { archived: Record<string, number> };
|
|
7
|
+
export type SessionSidebarState = { archived: Record<string, number>; favorites?: Record<string, number> };
|
|
8
8
|
export function registerSessionSidebarHost(
|
|
9
9
|
host: SessionSidebarHost,
|
|
10
10
|
options?: { state?: (() => SessionSidebarState | Promise<SessionSidebarState>) | null }
|
|
@@ -41,11 +41,15 @@ export async function applySessionSidebarChange(sessionId, change) {
|
|
|
41
41
|
await active.host(sessionId, change);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
/** The active desktop's flags, `{ archived }` (session id →
|
|
45
|
-
*
|
|
44
|
+
/** The active desktop's flags, `{ archived, favorites? }` (session id →
|
|
45
|
+
* epoch-ms stamp; `favorites` only from a desktop that reports them); null
|
|
46
|
+
* when no desktop (or one without a state reader) is attached. */
|
|
46
47
|
export async function readSessionSidebarState() {
|
|
47
48
|
const active = hosts().at(-1);
|
|
48
49
|
if (!active?.state) return null;
|
|
49
50
|
const state = await active.state();
|
|
50
|
-
return {
|
|
51
|
+
return {
|
|
52
|
+
archived: { ...state?.archived },
|
|
53
|
+
...(state?.favorites && typeof state.favorites === 'object' ? { favorites: { ...state.favorites } } : {}),
|
|
54
|
+
};
|
|
51
55
|
}
|
|
@@ -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
|
+
}
|
|
@@ -195,6 +195,8 @@ const TRANSCRIPT_HIDDEN_CONTROL_TOOL_NAMES = new Set([
|
|
|
195
195
|
'update_goal',
|
|
196
196
|
'load_tool',
|
|
197
197
|
'tool_search',
|
|
198
|
+
// A bot's reaction shows as its emoji under the user's message, not as a card.
|
|
199
|
+
'react',
|
|
198
200
|
]);
|
|
199
201
|
// Skill loads are visible cards EXCEPT for built-in skills: those ride a
|
|
200
202
|
// built-in feature whose own card (Browser Use, Document work, ...) follows
|
|
@@ -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 =
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// These pure helpers keep live rows, persisted messages and restored rows on
|
|
3
3
|
// the same field contract without rewriting older display-only transcripts.
|
|
4
4
|
import { displayModelName } from './model-display.mjs';
|
|
5
|
+
import { botChainOf } from './bot-hops.mjs';
|
|
5
6
|
import { routineTriggerField } from './routine-trigger.mjs';
|
|
6
7
|
|
|
7
8
|
export function transcriptRouteMetadataFields(value) {
|
|
@@ -90,6 +91,11 @@ export function persistedUserTranscriptMetadata(value) {
|
|
|
90
91
|
...transcriptSourceFields(value),
|
|
91
92
|
// Bot-to-bot chain position of a bot's message (session-runtime/bot-hops.mjs).
|
|
92
93
|
...(Number.isInteger(value.hop) && value.hop > 0 ? { hop: value.hop } : {}),
|
|
94
|
+
// The bots that handed this message on, sender last (bot-hops.mjs botChainOf).
|
|
95
|
+
...botChainField(value.botChain),
|
|
96
|
+
// A group-room member turn: the newest user row of the room log its prompt
|
|
97
|
+
// shows (message-reactions.mjs counts a reaction only on that row).
|
|
98
|
+
...(typeof value.roomRow === 'string' && value.roomRow ? { roomRow: value.roomRow } : {}),
|
|
93
99
|
// The turn's change-record key (the outer prompt id), so a restored user
|
|
94
100
|
// row still addresses its turn's Undo/Reapply.
|
|
95
101
|
...(typeof value.checkpointId === 'string' && value.checkpointId ? { checkpointId: value.checkpointId } : {}),
|
|
@@ -104,6 +110,11 @@ export function persistedUserTranscriptMetadata(value) {
|
|
|
104
110
|
};
|
|
105
111
|
}
|
|
106
112
|
|
|
113
|
+
function botChainField(value) {
|
|
114
|
+
const bots = botChainOf(value);
|
|
115
|
+
return bots.length ? { botChain: bots } : {};
|
|
116
|
+
}
|
|
117
|
+
|
|
107
118
|
function submissionIdsField(value) {
|
|
108
119
|
const ids = Array.isArray(value) ? value.filter((id) => typeof id === 'string' && id) : [];
|
|
109
120
|
return ids.length ? { submissionIds: ids } : {};
|
|
@@ -125,6 +136,33 @@ export function transcriptAttachmentFields(value) {
|
|
|
125
136
|
return attachmentsField(value?.attachments);
|
|
126
137
|
}
|
|
127
138
|
|
|
139
|
+
const REACTOR_ID = /^[A-Za-z0-9._-]{1,80}$/;
|
|
140
|
+
const REACTION_EMOJI_MAX_LENGTH = 16;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* The bots' reactions on a user message (`meta.transcript.reactions`):
|
|
144
|
+
* `[{ agentId, emoji, at }]`, one per bot, in the order they were left.
|
|
145
|
+
* Malformed entries and a bot's repeats are dropped.
|
|
146
|
+
*/
|
|
147
|
+
export function normalizeMessageReactions(value) {
|
|
148
|
+
if (!Array.isArray(value)) return [];
|
|
149
|
+
const out = [];
|
|
150
|
+
for (const raw of value) {
|
|
151
|
+
const agentId = typeof raw?.agentId === 'string' ? raw.agentId : '';
|
|
152
|
+
const emoji = typeof raw?.emoji === 'string' ? raw.emoji : '';
|
|
153
|
+
if (!REACTOR_ID.test(agentId) || !emoji || emoji.length > REACTION_EMOJI_MAX_LENGTH) continue;
|
|
154
|
+
if (out.some((entry) => entry.agentId === agentId)) continue;
|
|
155
|
+
out.push({ agentId, emoji, ...(Number.isFinite(raw.at) ? { at: raw.at } : {}) });
|
|
156
|
+
}
|
|
157
|
+
return out;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** The `reactions` field of a transcript row (absent when there are none). */
|
|
161
|
+
export function transcriptReactionsField(value) {
|
|
162
|
+
const reactions = normalizeMessageReactions(value?.reactions);
|
|
163
|
+
return reactions.length ? { reactions } : {};
|
|
164
|
+
}
|
|
165
|
+
|
|
128
166
|
export function persistedAssistantTranscriptMetadata(value, fallbackAt = Date.now()) {
|
|
129
167
|
if (!value || typeof value !== 'object') return null;
|
|
130
168
|
const candidateAt = Number(value.assistantAt);
|
|
@@ -438,13 +438,41 @@ const ensuredDataDirs = new Set();
|
|
|
438
438
|
* data dir per process.
|
|
439
439
|
*/
|
|
440
440
|
export function ensureUserDataInitialized(dataDir) {
|
|
441
|
-
if (!dataDir) return;
|
|
441
|
+
if (!dataDir || skipBackups()) return;
|
|
442
442
|
const key = normalizeDataDir(dataDir);
|
|
443
443
|
if (ensuredDataDirs.has(key)) return;
|
|
444
|
-
|
|
444
|
+
// The marker alone is no proof: a first snapshot whose manifest failed left
|
|
445
|
+
// it behind. Only a published backup of this incarnation counts, so a failed
|
|
446
|
+
// or interrupted one is taken again by the next read or restart.
|
|
447
|
+
if (!hasPublishedBackup(dataDir)) {
|
|
448
|
+
backupUserData(dataDir, 'initial-snapshot');
|
|
449
|
+
if (!hasPublishedBackup(dataDir)) return;
|
|
450
|
+
}
|
|
445
451
|
ensuredDataDirs.add(key);
|
|
446
452
|
}
|
|
447
453
|
|
|
454
|
+
/** Whether this data dir's scope holds a published backup of its current
|
|
455
|
+
* incarnation (marker instanceId). A transient manifest read failure throws. */
|
|
456
|
+
function hasPublishedBackup(dataDir) {
|
|
457
|
+
const instanceId = readInitInstanceId(dataDir);
|
|
458
|
+
if (!instanceId) return false;
|
|
459
|
+
const key = normalizeDataDir(dataDir);
|
|
460
|
+
const scopeDir = scopeDirFor(dataDir);
|
|
461
|
+
return listBackupDirsNewestFirst(scopeDir).some((name) => {
|
|
462
|
+
try {
|
|
463
|
+
const manifest = JSON.parse(readFileSync(manifestPath(scopeDir, name), 'utf8'));
|
|
464
|
+
return (
|
|
465
|
+
typeof manifest?.dataDir === 'string' &&
|
|
466
|
+
normalizeDataDir(manifest.dataDir) === key &&
|
|
467
|
+
manifest.instanceId === instanceId
|
|
468
|
+
);
|
|
469
|
+
} catch (error) {
|
|
470
|
+
if (isAbsentBackupError(error)) return false;
|
|
471
|
+
throw error;
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
|
|
448
476
|
function skipBackups() {
|
|
449
477
|
return process.env.MIXDOG_SKIP_USER_DATA_BACKUP === '1' || process.env.MIXDOG_SKIP_USER_DATA_BACKUP === 'true';
|
|
450
478
|
}
|
|
@@ -15,9 +15,11 @@ const overlaps = (a, b) => isWithin(a, b) || isWithin(b, a);
|
|
|
15
15
|
/**
|
|
16
16
|
* The admission policy's external exception: a linked checkout Mixdog did not
|
|
17
17
|
* create (not a project's main folder, not a registered managed worktree) is
|
|
18
|
-
*
|
|
19
|
-
* admitted whatever is held
|
|
20
|
-
* management action that touches it.
|
|
18
|
+
* not lock-blocked by what is held elsewhere. Management takes no lease on it
|
|
19
|
+
* and its readers are admitted whatever is held outside it; its running
|
|
20
|
+
* readers still refuse a management action that touches it. A management lease
|
|
21
|
+
* published inside the checkout itself (another profile, or a registry
|
|
22
|
+
* recovered empty) still refuses its readers.
|
|
21
23
|
*/
|
|
22
24
|
export function isExternalCheckout(folder) {
|
|
23
25
|
const layout = findGitLayout(folder, { strict: true });
|
|
@@ -291,7 +293,8 @@ function release(commonDir, token) {
|
|
|
291
293
|
|
|
292
294
|
/**
|
|
293
295
|
* Readers share a checkout freely. Null means a management writer currently
|
|
294
|
-
* owns it; a reader in an external checkout is
|
|
296
|
+
* owns it; a reader in an external checkout is admitted whatever is held
|
|
297
|
+
* outside that checkout, but refused by a management lease inside it. Throws
|
|
295
298
|
* `workspace-admission-unreadable` when the ledger cannot be read, was
|
|
296
299
|
* written by a newer build, or the grant could not be made durable in both
|
|
297
300
|
* copies: no work may run unrecorded.
|
|
@@ -304,8 +307,12 @@ export function tryAdmitWorkspaceActivity(sessionId, cwd, { pid = process.pid, k
|
|
|
304
307
|
const path = canonicalPath(cwd);
|
|
305
308
|
const token = randomUUID();
|
|
306
309
|
const lease = { kind, sessionId, pid, token, path };
|
|
310
|
+
// External is this profile's registry view: management another profile (or
|
|
311
|
+
// a registry recovered empty) published inside this very checkout still holds.
|
|
312
|
+
const checkout = canonicalPath(layout.topLevel);
|
|
313
|
+
const held = (other) => (external ? isWithin(checkout, other.path) : overlaps(other.path, path));
|
|
307
314
|
const admitted = mutate(layout.commonDir, (leases) => {
|
|
308
|
-
if (
|
|
315
|
+
if (leases.some((other) => other.kind === 'management' && held(other))) return false;
|
|
309
316
|
leases.push(lease);
|
|
310
317
|
return true;
|
|
311
318
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
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, mkdtempSync, rmSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
4
|
+
import { appendFileSync, chmodSync, cpSync, existsSync, mkdtempSync, rmSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
4
5
|
import { tmpdir } from 'node:os';
|
|
5
6
|
import { dirname, join } from 'node:path';
|
|
6
7
|
|
|
@@ -67,9 +68,13 @@ function repoTemplate(commit) {
|
|
|
67
68
|
if (existing && existsSync(existing)) return existing;
|
|
68
69
|
const dir = tempDir('mixdog-wt-template-');
|
|
69
70
|
git(dir, 'init', '-q', '-b', 'main');
|
|
70
|
-
git
|
|
71
|
-
|
|
72
|
-
git
|
|
71
|
+
// One config write instead of a `git config` process per key. Auto
|
|
72
|
+
// maintenance is off, so no commit (the test's or a merge's) starts a
|
|
73
|
+
// `git maintenance run` child.
|
|
74
|
+
appendFileSync(
|
|
75
|
+
join(dir, '.git', 'config'),
|
|
76
|
+
'[user]\n\tname = Mixdog Test\n\temail = mixdog@example.com\n[core]\n\tautocrlf = false\n[maintenance]\n\tauto = false\n'
|
|
77
|
+
);
|
|
73
78
|
if (commit) commitFile(dir, 'README.md', 'hello\n', 'initial');
|
|
74
79
|
templates.set(commit, dir);
|
|
75
80
|
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
|
}
|
|
@@ -160,7 +170,11 @@ export async function executeVisualizeTool(args, options = {}) {
|
|
|
160
170
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
161
171
|
const timeout = AbortSignal.timeout(validated.action === 'export' ? EXPORT_REQUEST_TIMEOUT_MS : REQUEST_TIMEOUT_MS);
|
|
162
172
|
try {
|
|
163
|
-
result = await requestBridge(
|
|
173
|
+
result = await requestBridge(
|
|
174
|
+
discovery,
|
|
175
|
+
payload,
|
|
176
|
+
options.signal ? AbortSignal.any([timeout, options.signal]) : timeout
|
|
177
|
+
);
|
|
164
178
|
break;
|
|
165
179
|
} catch (error) {
|
|
166
180
|
if (error?.name === 'TimeoutError') return toolError('visualize bridge timed out');
|
|
@@ -175,7 +189,12 @@ export async function executeVisualizeTool(args, options = {}) {
|
|
|
175
189
|
}
|
|
176
190
|
const { body, status } = result;
|
|
177
191
|
if (!body?.ok) {
|
|
178
|
-
return toolError(
|
|
192
|
+
return toolError(
|
|
193
|
+
String(body?.error || `visualize bridge request failed (HTTP ${status})`).replace(/^Error:\s*/, '')
|
|
194
|
+
);
|
|
179
195
|
}
|
|
180
|
-
|
|
196
|
+
// The host ran it for another session's panel: the owner rides as a field
|
|
197
|
+
// (toolMeta, kept with the stored result), never only as prose.
|
|
198
|
+
const toolMeta = visualizeOwnerToolMeta(body.ownerSessionId);
|
|
199
|
+
return { content: [{ type: 'text', text: formatSuccess(body) }], ...(toolMeta ? { toolMeta } : {}) };
|
|
181
200
|
}
|
|
@@ -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;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The structured twin of a `visualize` result (the tool result's `toolMeta`,
|
|
3
|
+
* kept with the stored message and restored onto its transcript item): the
|
|
4
|
+
* desktop host ran the call for another session's work (a sub-agent, a room
|
|
5
|
+
* member) and keeps its tabs in that owner conversation's panel. Chat cards
|
|
6
|
+
* read the owner from here, never from the result text.
|
|
7
|
+
*/
|
|
8
|
+
export const VISUALIZE_OWNER_META_CODE = 'visualize_owner';
|
|
9
|
+
|
|
10
|
+
const SESSION_ID = /^[A-Za-z0-9_.:-]{1,128}$/;
|
|
11
|
+
|
|
12
|
+
/** A session id fit for `toolMeta.ownerSessionId`; '' for anything else. */
|
|
13
|
+
export function visualizeOwnerMetaSessionId(value) {
|
|
14
|
+
return typeof value === 'string' && SESSION_ID.test(value) ? value : '';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** The `toolMeta` of a result run for `ownerSessionId`'s panel; undefined when
|
|
18
|
+
* the id is not a session id. */
|
|
19
|
+
export function visualizeOwnerToolMeta(ownerSessionId) {
|
|
20
|
+
const id = visualizeOwnerMetaSessionId(ownerSessionId);
|
|
21
|
+
return id ? { code: VISUALIZE_OWNER_META_CODE, missing: [], ownerSessionId: id } : undefined;
|
|
22
|
+
}
|
|
@@ -81,7 +81,7 @@ function fetchFailureKind(error) {
|
|
|
81
81
|
|
|
82
82
|
export async function runFetchPipeline(
|
|
83
83
|
url,
|
|
84
|
-
{ http, browser, signal, timeoutMs = 30000, hostPacer = pacer, onAttempt = () => {} } = {}
|
|
84
|
+
{ http, browser, signal, timeoutMs = 30000, hostPacer = pacer, onAttempt = () => {}, sleep: pause = sleep } = {}
|
|
85
85
|
) {
|
|
86
86
|
const budget = Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : 30000;
|
|
87
87
|
const deadline = Date.now() + budget;
|
|
@@ -150,7 +150,7 @@ export async function runFetchPipeline(
|
|
|
150
150
|
if (!transient || retry === 1) break;
|
|
151
151
|
const delay = Math.max(400, error.retryAfterMs || 0);
|
|
152
152
|
if (Date.now() + delay >= deadline) throw error;
|
|
153
|
-
await
|
|
153
|
+
await pause(delay, undefined, { signal: overall });
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
// Rendering does not fix a rate limit or a failing upstream server.
|