mixdog 1.2.2 → 1.2.3
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/README.md +18 -0
- package/package.json +2 -1
- package/scripts/provider-pingpong-live.mjs +509 -0
- package/src/agents/advisor/AGENT.md +1 -1
- package/src/agents/advisor/agent.json +1 -1
- package/src/defaults/shipped-history.json +5 -0
- package/src/defaults/skills/setup/SKILL.md +6 -1
- package/src/defaults/skills/setup/references/actions.md +44 -22
- package/src/defaults/skills/setup/references/surfaces.md +10 -8
- package/src/headless-exec.mjs +15 -8
- package/src/lib/keychain-cjs.cjs +7 -4
- package/src/output-styles/common.md +11 -10
- package/src/rules/agent/AGENT.md +5 -5
- package/src/rules/lead/LEAD.md +5 -5
- package/src/runtime/agent/orchestrator/agent-trace-io.mjs +92 -61
- package/src/runtime/agent/orchestrator/cache-mtime.mjs +10 -1
- package/src/runtime/agent/orchestrator/config-providers-merge.mjs +7 -0
- package/src/runtime/agent/orchestrator/config.mjs +5 -0
- package/src/runtime/agent/orchestrator/context/collect.mjs +1 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +26 -7
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +112 -7
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +48 -20
- package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +24 -17
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +7 -6
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +29 -10
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-blocks.mjs +20 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-delta.mjs +15 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +11 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/message-events.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +12 -5
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-outcome.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-state.mjs +14 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +6 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +58 -7
- package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +29 -10
- package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +16 -3
- package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +10 -61
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +12 -6
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +114 -72
- package/src/runtime/agent/orchestrator/providers/compat-request-policy.mjs +78 -2
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +37 -5
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +43 -2
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +64 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +70 -6
- package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +34 -7
- package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +32 -6
- package/src/runtime/agent/orchestrator/providers/deepseek.mjs +67 -0
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +11 -4
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +25 -8
- package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +87 -5
- package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +41 -5
- package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +13 -13
- package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +355 -37
- package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -2
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +93 -47
- package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +55 -10
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +26 -8
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/lib/action-input-contract.mjs +60 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +246 -42
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-server-tool-usage.mjs +18 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-system-blocks.mjs +27 -6
- package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +388 -0
- package/src/runtime/agent/orchestrator/providers/lib/inclusive-usage.mjs +54 -0
- package/src/runtime/agent/orchestrator/providers/lib/origin-bound-fetch.mjs +16 -0
- package/src/runtime/agent/orchestrator/providers/lib/responses-terminal-fields.mjs +11 -0
- package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +48 -22
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +119 -18
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +13 -15
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +1 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +33 -1
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +121 -61
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +35 -14
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +37 -7
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/tool-call-acc.mjs +2 -9
- package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +47 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +47 -25
- package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +5 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +151 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +42 -24
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +63 -25
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2901 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +172 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +53 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +103 -26
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +23 -4
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +11 -6
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +6 -1
- package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +15 -23
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +23 -10
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +25 -4
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +10 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-items.mjs +18 -7
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +5 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/text-relay.mjs +9 -1
- package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +80 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +71 -24
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +323 -0
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +44 -16
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +7 -16
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/refusals.mjs +60 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +51 -35
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state.mjs +30 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +12 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/terminal-frames.mjs +25 -6
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +11 -3
- package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +170 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +75 -70
- package/src/runtime/agent/orchestrator/providers/openrouter.mjs +75 -0
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +147 -8
- package/src/runtime/agent/orchestrator/providers/registry.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +5 -0
- package/src/runtime/agent/orchestrator/providers/transport-scope.d.mts +6 -0
- package/src/runtime/agent/orchestrator/providers/transport-scope.mjs +28 -0
- package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +157 -0
- package/src/runtime/agent/orchestrator/providers/wire-route.mjs +512 -0
- package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +1131 -0
- package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +183 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +100 -0
- package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +21 -0
- package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -0
- package/src/runtime/agent/orchestrator/runtime-core/provider-request-snapshot.mjs +7 -3
- package/src/runtime/agent/orchestrator/runtime-core/session-title.mjs +21 -1
- package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +14 -3
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +526 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +10 -7
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +176 -71
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +62 -10
- package/src/runtime/agent/orchestrator/runtime-core/tool-exposure.mjs +96 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/compact/constants.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +14 -93
- package/src/runtime/agent/orchestrator/session/compact/summary-anchor.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +120 -0
- package/src/runtime/agent/orchestrator/session/context-tool-schema.mjs +17 -2
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -4
- package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +6 -1
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +91 -1
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +56 -0
- package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +18 -8
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +21 -10
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +132 -0
- package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +30 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +63 -20
- package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-call-resolution.mjs +95 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +30 -3
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +150 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +34 -12
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +57 -25
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +208 -14
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +15 -3
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +25 -3
- package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +82 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +19 -2
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/manager.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +96 -0
- package/src/runtime/agent/orchestrator/session/side-question.mjs +192 -0
- package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +17 -3
- package/src/runtime/agent/orchestrator/session/store/live-state.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +58 -2
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +41 -28
- package/src/runtime/agent/orchestrator/session/store/session-observers.mjs +4 -2
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +12 -1
- package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/store-summary-archived-agent.mjs +34 -15
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +10 -1
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +10 -2
- package/src/runtime/agent/orchestrator/session/store.mjs +19 -3
- package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +77 -0
- package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +8 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +14 -10
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +49 -34
- package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +23 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +73 -39
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +18 -1
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -4
- package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +88 -12
- package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +2 -0
- package/src/runtime/computer-bridge/action-schema.mjs +44 -21
- package/src/runtime/github/tool.mjs +92 -2
- package/src/runtime/memory/index.mjs +1 -0
- package/src/runtime/memory/lib/http-router/ingest-routes.mjs +22 -1
- package/src/runtime/memory/lib/ingest/transcript-offsets.mjs +2 -0
- package/src/runtime/memory/lib/pg/adapter.mjs +98 -1
- package/src/runtime/memory/lib/pg/process.mjs +31 -26
- package/src/runtime/memory/lib/pg/run-child.mjs +49 -0
- package/src/runtime/memory/lib/pg/supervisor.mjs +108 -3
- package/src/runtime/memory/lib/runtime-fetcher.mjs +12 -13
- package/src/runtime/memory/lib/transcript-ingest.mjs +14 -0
- package/src/runtime/office/README.md +1 -1
- package/src/runtime/office/authoring/html-document-author.mjs +2 -0
- package/src/runtime/office/authoring/pptx-contact-sheet.mjs +2 -0
- package/src/runtime/office/authoring/pptx-html-measure.mjs +2 -0
- package/src/runtime/office/authoring/pptx-html-runner.mjs +2 -0
- package/src/runtime/office/authoring/xlsx-html-runner.mjs +2 -0
- package/src/runtime/office/core/office-actions-read.mjs +3 -0
- package/src/runtime/office/core/office-render-preview.mjs +2 -0
- package/src/runtime/office/core/office-session-dispatch.mjs +7 -0
- package/src/runtime/office/core/office-sessionless-actions.mjs +8 -0
- package/src/runtime/office/core/office-sessions.mjs +5 -0
- package/src/runtime/office/core/office-transactions.mjs +3 -0
- package/src/runtime/office/core/office-write-ledger.mjs +98 -0
- package/src/runtime/office/design/library/templates/mixdog-executive.mixdog-edit.pptx +0 -0
- package/src/runtime/office/index.mjs +30 -0
- package/src/runtime/office/pdf/pdf-edit-document.mjs +2 -0
- package/src/runtime/office/pdf/pdf-render.mjs +23 -7
- package/src/runtime/office/pdf/pdf-security.mjs +2 -0
- package/src/runtime/office/portable/portable-opc.mjs +4 -1
- package/src/runtime/office/quality/visual-diff.mjs +2 -0
- package/src/runtime/shared/bounded-file-read.mjs +13 -0
- package/src/runtime/shared/bounded-line-diff.mjs +182 -0
- package/src/runtime/shared/buffered-appender.mjs +18 -0
- package/src/runtime/shared/config.mjs +78 -18
- package/src/runtime/shared/err-text.mjs +6 -0
- package/src/runtime/shared/file-permissions.d.mts +6 -1
- package/src/runtime/shared/file-permissions.mjs +54 -6
- package/src/runtime/shared/llm/anthropic-effort.mjs +6 -0
- package/src/runtime/shared/llm/usage-accounting.mjs +5 -2
- package/src/runtime/shared/llm/usage-ledger-rollup.mjs +3 -0
- package/src/runtime/shared/loopback-listener.mjs +9 -0
- package/src/runtime/shared/provider-api-key.mjs +2 -0
- package/src/runtime/shared/review-diff.mjs +52 -0
- package/src/runtime/shared/session-sidebar-host.d.mts +4 -0
- package/src/runtime/shared/session-sidebar-host.mjs +38 -0
- package/src/runtime/shared/slow-span.mjs +114 -0
- package/src/runtime/shared/statusline/statusline-segments.mjs +28 -4
- package/src/runtime/shared/tool-card-model/card-header.mjs +6 -1
- package/src/runtime/shared/tool-card-model/generic-detail.mjs +39 -5
- package/src/runtime/shared/tool-card-model.mjs +5 -2
- package/src/runtime/shared/tool-output-limit.mjs +4 -0
- package/src/runtime/shared/tool-primitives.mjs +13 -0
- package/src/runtime/shared/tool-result-summary.mjs +8 -1
- package/src/runtime/shared/tool-surface.mjs +18 -3
- package/src/runtime/shared/tool-work-units.mjs +40 -4
- package/src/runtime/shared/transcript-writer/purge.mjs +74 -0
- package/src/runtime/shared/transcript-writer.mjs +10 -2
- package/src/runtime/shared/turn-changes.mjs +268 -100
- package/src/runtime/shared/turn-review-reply.mjs +8 -39
- package/src/runtime/shared/turn-snapshot-store.mjs +19 -108
- package/src/runtime/shared/turn-snapshot.mjs +857 -683
- package/src/runtime/shared/turn-worktree-snapshot.mjs +183 -255
- package/src/runtime/shared/user-data-guard.mjs +262 -49
- package/src/runtime/shared/worktrees/carry.mjs +531 -0
- package/src/runtime/shared/worktrees/contract.mjs +34 -0
- package/src/runtime/shared/worktrees/file-recovery.mjs +68 -0
- package/src/runtime/shared/worktrees/git-head.mjs +205 -0
- package/src/runtime/shared/worktrees/git.mjs +8 -3
- package/src/runtime/shared/worktrees/maintenance.mjs +1 -1
- package/src/runtime/shared/worktrees/manager.mjs +156 -8
- package/src/runtime/shared/worktrees/merge.mjs +31 -21
- package/src/runtime/shared/worktrees/paths.d.mts +6 -0
- package/src/runtime/terminal-bridge/client.mjs +44 -11
- package/src/runtime/terminal-bridge/tool-defs.mjs +13 -6
- package/src/runtime/tidy/apply.mjs +47 -2
- package/src/runtime/tidy/run-engines.mjs +11 -5
- package/src/session-runtime/agent-tool-routing.mjs +19 -13
- package/src/session-runtime/boot/apis.mjs +13 -5
- package/src/session-runtime/boot/facade.mjs +1 -0
- package/src/session-runtime/boot/infrastructure.mjs +6 -1
- package/src/session-runtime/boot/session.mjs +0 -1
- package/src/session-runtime/boot/tools.mjs +4 -1
- package/src/session-runtime/cwd-plugins/cwd-apply.mjs +12 -5
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +65 -0
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -1
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +11 -4
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +115 -18
- package/src/session-runtime/internal-tool-executor.mjs +6 -2
- package/src/session-runtime/lifecycle/cold-heir.mjs +188 -0
- package/src/session-runtime/lifecycle/inheritance.mjs +71 -27
- package/src/session-runtime/lifecycle/session-catalog.mjs +12 -3
- package/src/session-runtime/lifecycle/session-switch/resume.mjs +6 -0
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +29 -6
- package/src/session-runtime/lifecycle/teardown.mjs +72 -7
- package/src/session-runtime/lifecycle-api.mjs +1 -0
- package/src/session-runtime/mcp-glue/connect.mjs +17 -5
- package/src/session-runtime/model-route/set-route.mjs +2 -2
- package/src/session-runtime/native-web-search-usage.mjs +51 -0
- package/src/session-runtime/native-web-search.mjs +10 -1
- package/src/session-runtime/new-session-config.mjs +4 -2
- package/src/session-runtime/provider-auth/login.mjs +4 -0
- package/src/session-runtime/resource-scope-decorate.mjs +10 -3
- package/src/session-runtime/runtime-review-api.mjs +8 -2
- package/src/session-runtime/services/agent-tool/index-write-queue.mjs +81 -20
- package/src/session-runtime/services/agent-tool/lead-worker-index/forgotten-leads.mjs +29 -0
- package/src/session-runtime/services/agent-tool/lead-worker-index/index-file.mjs +1 -1
- package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +73 -7
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +15 -1
- package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +10 -1
- package/src/session-runtime/services/agent-tool/worker-index.mjs +46 -7
- package/src/session-runtime/services/agent-tool.mjs +3 -0
- package/src/session-runtime/services/channel-admin.mjs +19 -3
- package/src/session-runtime/services/memory-runtime-proxy/calls.mjs +4 -0
- package/src/session-runtime/services/memory-runtime-proxy.mjs +1 -0
- package/src/session-runtime/services/provider-admin.mjs +81 -15
- package/src/session-runtime/session-transcript-purge.mjs +32 -0
- package/src/session-runtime/session-turn-api.mjs +14 -5
- package/src/session-runtime/settings-builtin-tools-api.mjs +9 -0
- package/src/session-runtime/setup-tool/executor.mjs +36 -6
- package/src/session-runtime/setup-tool/extended-actions.mjs +86 -6
- package/src/session-runtime/setup-tool/settings-contract.mjs +13 -3
- package/src/session-runtime/setup-tool/tool-defs.mjs +13 -4
- package/src/session-runtime/skills-api.mjs +3 -5
- package/src/session-runtime/tool-surface.mjs +5 -1
- package/src/session-runtime/turn/compaction-gate.mjs +25 -0
- package/src/session-runtime/turn/session-ops.mjs +7 -5
- package/src/session-runtime/turn/side-question-ops.mjs +22 -0
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +5 -1
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +8 -3
- package/src/session-runtime/turn/turn-run/turn-settle.mjs +10 -0
- package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
- package/src/session-runtime/turn/turn-run.mjs +25 -9
- package/src/session-runtime/usage-stats-api.mjs +43 -11
- package/src/session-runtime/workspace/project-branches.mjs +7 -5
- package/src/session-runtime/workspace/transition-steps.mjs +129 -31
- package/src/session-runtime/workspace/transitions.mjs +190 -15
- package/src/standalone/daemon-agent-control.mjs +9 -1
- package/src/standalone/daemon-local-session-bridge.mjs +14 -1
- package/src/standalone/daemon-owner.mjs +17 -4
- package/src/standalone/daemon-pg-stop.mjs +51 -0
- package/src/standalone/daemon-stop-budget.d.mts +2 -0
- package/src/standalone/daemon-stop-budget.mjs +18 -0
- package/src/standalone/daemon-stored-session-views.mjs +2 -0
- package/src/standalone/daemon-telemetry.mjs +19 -0
- package/src/standalone/daemon.mjs +61 -1
- package/src/standalone/desktop-service-registry.mjs +5 -0
- package/src/standalone/local-session-runtime.mjs +70 -19
- package/src/standalone/session-client.mjs +42 -0
- package/src/standalone/session-protocol.mjs +7 -0
- package/src/standalone/session-proxy/projection.mjs +41 -4
- package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +15 -1
- package/src/standalone/session-runtime-inline-host.mjs +1 -0
- package/src/standalone/session-service/session-calls/session-action.mjs +18 -3
- package/src/standalone/session-service-api.mjs +6 -1
- package/src/standalone/session-state-patch.d.mts +2 -1
- package/src/standalone/session-state-patch.mjs +41 -1
- package/src/tui/App.jsx +25 -0
- package/src/tui/app/app-view/floating-panel.jsx +26 -1
- package/src/tui/app/btw-controller.mjs +118 -0
- package/src/tui/app/create-app-pickers.mjs +2 -0
- package/src/tui/app/shell-layout/row-budgets.mjs +11 -1
- package/src/tui/app/shell-layout/surfaces.mjs +3 -1
- package/src/tui/app/slash-commands.mjs +13 -3
- package/src/tui/app/slash-dispatch/session-commands.mjs +19 -6
- package/src/tui/app/use-global-key-input/approval-shortcut.mjs +12 -0
- package/src/tui/app/use-global-key-input.mjs +5 -12
- package/src/tui/app/use-prompt-handlers.mjs +11 -0
- package/src/tui/components/BtwPanel.jsx +53 -0
- package/src/tui/components/QuestionPanel.jsx +275 -0
- package/src/tui/components/question-panel-model.mjs +156 -0
- package/src/tui/dist/index.mjs +2413 -1465
- package/src/tui/session/context-state.mjs +4 -2
- package/src/tui/session/session-api/commands.mjs +10 -0
- package/src/tui/session/session-api/controls.mjs +2 -2
- package/src/tui/session/session-api/integrations.mjs +9 -2
- package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
- package/src/tui/session/session-api/lifecycle.mjs +2 -1
- package/src/tui/session/session-api/settings.mjs +6 -0
- package/src/tui/session/session-api.mjs +1 -0
- package/src/tui/session/tool-approval.mjs +10 -7
- package/src/tui/session/transcript-spill.mjs +14 -7
- package/src/tui/session/turn-stream.mjs +174 -31
- package/src/tui/session/turn.mjs +12 -5
- package/src/workflows/default/WORKFLOW.md +3 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { splitBridgeToolArgs } from '../shared/bridge-tool-args.mjs';
|
|
2
2
|
import { hasOwn } from '../shared/object.mjs';
|
|
3
3
|
import { schemaValueError } from '../shared/schema-value-error.mjs';
|
|
4
|
+
import { advertiseActionInputUnion } from '../agent/orchestrator/providers/lib/action-input-contract.mjs';
|
|
4
5
|
import {
|
|
5
6
|
COMPUTER_CORE_ACTION_SCHEMA,
|
|
6
7
|
COMPUTER_DEFAULT_DELIVERY,
|
|
@@ -149,25 +150,11 @@ const captureProperties = {
|
|
|
149
150
|
},
|
|
150
151
|
};
|
|
151
152
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
action: {
|
|
158
|
-
type: 'string',
|
|
159
|
-
enum: ACTIONS,
|
|
160
|
-
description:
|
|
161
|
-
'Use capture to observe, act for simple input actions, and the remaining operations only for their named advanced capability.',
|
|
162
|
-
},
|
|
163
|
-
input: {
|
|
164
|
-
type: 'object',
|
|
165
|
-
description: 'Fields for the selected action.',
|
|
166
|
-
},
|
|
167
|
-
},
|
|
168
|
-
required: ['action'],
|
|
169
|
-
additionalProperties: false,
|
|
170
|
-
oneOf: [
|
|
153
|
+
// The strict per-action contract: which `input` each action accepts. The host
|
|
154
|
+
// validates every call against it (validateComputerToolArgs), and the model-facing
|
|
155
|
+
// schema below derives its `input` from it. It is not part of the advertised
|
|
156
|
+
// root: provider tool schemas must be an object root without anyOf/oneOf/allOf.
|
|
157
|
+
export const COMPUTER_ACTION_CONTRACTS = [
|
|
171
158
|
branch(
|
|
172
159
|
'wait_for_user',
|
|
173
160
|
input({
|
|
@@ -360,11 +347,47 @@ export const COMPUTER_INPUT_SCHEMA = {
|
|
|
360
347
|
['app']
|
|
361
348
|
)
|
|
362
349
|
),
|
|
363
|
-
|
|
350
|
+
];
|
|
351
|
+
|
|
352
|
+
// A JSON Schema 2020-12 object root with no root combinator (Anthropic
|
|
353
|
+
// input_schema rule) whose `input` offers each action's own input as an anyOf
|
|
354
|
+
// alternative titled with that action. The tool advertises its flat projection
|
|
355
|
+
// (flattenActionInputUnion); only provider paths verified to accept the nested
|
|
356
|
+
// alternatives (first-party Anthropic, Claude via Antigravity) send this form
|
|
357
|
+
// (actionInputUnionFor). validateComputerToolArgs enforces the strict
|
|
358
|
+
// per-action contract.
|
|
359
|
+
const COMPUTER_ACTION_INPUT_UNION = {
|
|
360
|
+
type: 'object',
|
|
361
|
+
description:
|
|
362
|
+
'One compact Computer Use operation. Use act.actions to execute 1-6 simple actions and receive one fresh observation.',
|
|
363
|
+
properties: {
|
|
364
|
+
action: {
|
|
365
|
+
type: 'string',
|
|
366
|
+
enum: ACTIONS,
|
|
367
|
+
description:
|
|
368
|
+
'Use capture to observe, act for simple input actions, and the remaining operations only for their named advanced capability.',
|
|
369
|
+
},
|
|
370
|
+
input: {
|
|
371
|
+
type: 'object',
|
|
372
|
+
description: 'Fields for the selected action.',
|
|
373
|
+
anyOf: COMPUTER_ACTION_CONTRACTS.map(({ properties }) => {
|
|
374
|
+
const [action] = properties.action.enum;
|
|
375
|
+
return {
|
|
376
|
+
title: action,
|
|
377
|
+
description: `Input when action="${action}".`,
|
|
378
|
+
...structuredClone(properties.input),
|
|
379
|
+
};
|
|
380
|
+
}),
|
|
381
|
+
},
|
|
382
|
+
},
|
|
383
|
+
required: ['action'],
|
|
384
|
+
additionalProperties: false,
|
|
364
385
|
};
|
|
365
386
|
|
|
387
|
+
export const COMPUTER_INPUT_SCHEMA = advertiseActionInputUnion(COMPUTER_ACTION_INPUT_UNION);
|
|
388
|
+
|
|
366
389
|
const COMPUTER_ACTION_BRANCHES = new Map();
|
|
367
|
-
for (const actionBranch of
|
|
390
|
+
for (const actionBranch of COMPUTER_ACTION_CONTRACTS) {
|
|
368
391
|
for (const action of actionBranch.properties?.action?.enum || []) {
|
|
369
392
|
COMPUTER_ACTION_BRANCHES.set(action, actionBranch);
|
|
370
393
|
}
|
|
@@ -61,6 +61,96 @@ function reduceGithubData(value, key, parentKey) {
|
|
|
61
61
|
return reduced;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
const EXCERPT_MAX = 140;
|
|
65
|
+
const day = (value) => (typeof value === 'string' ? value.slice(0, 10) : undefined);
|
|
66
|
+
const login = (value) => userLogin(value) ?? (typeof value === 'string' ? value : undefined);
|
|
67
|
+
|
|
68
|
+
function excerpt(body) {
|
|
69
|
+
if (typeof body !== 'string') return undefined;
|
|
70
|
+
const text = body.replace(/\s+/g, ' ').trim();
|
|
71
|
+
if (!text) return undefined;
|
|
72
|
+
return text.length > EXCERPT_MAX ? `${text.slice(0, EXCERPT_MAX - 1)}…` : text;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function labelNames(labels) {
|
|
76
|
+
const names = (Array.isArray(labels) ? labels : [])
|
|
77
|
+
.map((label) => (typeof label === 'string' ? label : label?.name))
|
|
78
|
+
.filter(Boolean);
|
|
79
|
+
return names.length ? names : undefined;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Compact per-row projections for *.list actions: only what picks the next item
|
|
83
|
+
// to open. Undefined fields are dropped by JSON.stringify.
|
|
84
|
+
const LIST_PROJECTORS = {
|
|
85
|
+
'issue.list': (item) => ({
|
|
86
|
+
number: item.number,
|
|
87
|
+
title: item.title,
|
|
88
|
+
state: item.state,
|
|
89
|
+
author: login(item.user),
|
|
90
|
+
updated: day(item.updated_at),
|
|
91
|
+
labels: labelNames(item.labels),
|
|
92
|
+
comments: item.comments || undefined,
|
|
93
|
+
excerpt: excerpt(item.body),
|
|
94
|
+
}),
|
|
95
|
+
'pr.list': (item) => ({
|
|
96
|
+
number: item.number,
|
|
97
|
+
title: item.title,
|
|
98
|
+
state: item.merged_at ? 'merged' : item.state,
|
|
99
|
+
draft: item.draft || undefined,
|
|
100
|
+
author: login(item.user),
|
|
101
|
+
updated: day(item.updated_at),
|
|
102
|
+
head: item.head?.ref,
|
|
103
|
+
base: item.base?.ref,
|
|
104
|
+
labels: labelNames(item.labels),
|
|
105
|
+
excerpt: excerpt(item.body),
|
|
106
|
+
}),
|
|
107
|
+
'repo.list': (item) => ({
|
|
108
|
+
name: item.full_name,
|
|
109
|
+
description: excerpt(item.description),
|
|
110
|
+
visibility: item.visibility || (item.private ? 'private' : 'public'),
|
|
111
|
+
language: item.language || undefined,
|
|
112
|
+
fork: item.fork || undefined,
|
|
113
|
+
archived: item.archived || undefined,
|
|
114
|
+
updated: day(item.pushed_at || item.updated_at),
|
|
115
|
+
}),
|
|
116
|
+
'run.list': (item) => ({
|
|
117
|
+
id: item.id,
|
|
118
|
+
name: item.display_title || item.name,
|
|
119
|
+
workflow: item.name,
|
|
120
|
+
status: item.status,
|
|
121
|
+
conclusion: item.conclusion || undefined,
|
|
122
|
+
branch: item.head_branch,
|
|
123
|
+
event: item.event,
|
|
124
|
+
actor: login(item.actor),
|
|
125
|
+
updated: day(item.updated_at),
|
|
126
|
+
}),
|
|
127
|
+
'release.list': (item) => ({
|
|
128
|
+
id: item.id,
|
|
129
|
+
tag: item.tag_name,
|
|
130
|
+
name: item.name || undefined,
|
|
131
|
+
draft: item.draft || undefined,
|
|
132
|
+
prerelease: item.prerelease || undefined,
|
|
133
|
+
author: login(item.author),
|
|
134
|
+
published: day(item.published_at || item.created_at),
|
|
135
|
+
}),
|
|
136
|
+
'notification.list': (item) => ({
|
|
137
|
+
id: item.id,
|
|
138
|
+
unread: item.unread,
|
|
139
|
+
reason: item.reason,
|
|
140
|
+
type: item.subject?.type,
|
|
141
|
+
title: item.subject?.title,
|
|
142
|
+
number: Number(/\/(?:issues|pulls)\/(\d+)$/.exec(item.subject?.url || '')?.[1]) || undefined,
|
|
143
|
+
repo: typeof item.repository === 'string' ? item.repository : item.repository?.full_name,
|
|
144
|
+
updated: day(item.updated_at),
|
|
145
|
+
}),
|
|
146
|
+
'workflow.list': (item) => ({ id: item.id, name: item.name, path: item.path, state: item.state }),
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
function projectList(action, data) {
|
|
150
|
+
const project = LIST_PROJECTORS[action];
|
|
151
|
+
return project && Array.isArray(data) ? data.map(project) : undefined;
|
|
152
|
+
}
|
|
153
|
+
|
|
64
154
|
const fits = (text) => Buffer.byteLength(text, 'utf8') <= GITHUB_OUTPUT_MAX_BYTES;
|
|
65
155
|
|
|
66
156
|
function clampStrings(value, max) {
|
|
@@ -213,7 +303,7 @@ export const GITHUB_TOOL_DEF = {
|
|
|
213
303
|
},
|
|
214
304
|
trigger: 'GitHub repos, issues, PRs, Actions, releases; not local Git history, diffs or staging (git).',
|
|
215
305
|
description:
|
|
216
|
-
'GitHub repositories, issues, PRs and reviews, Actions/logs, releases, and notifications through the signed-in GitHub CLI. Local Git history/diffs/staging belong to git. One action per call; writes are serialized and never retried. Obtain user approval before writes; workflow runs and published releases may deploy. repo is owner/name; omit to resolve the current Project. Lists use page/limit. Review/merge requires the current PR head sha. Install/connect in Extensions → Plugin → Git & GitHub. Results omit API-only URLs and node ids and name users/repos by login/full_name; `raw` is a readable file with the full response, and long results state what is shown.',
|
|
306
|
+
'GitHub repositories, issues, PRs and reviews, Actions/logs, releases, and notifications through the signed-in GitHub CLI. Local Git history/diffs/staging belong to git. One action per call; writes are serialized and never retried. Obtain user approval before writes; workflow runs and published releases may deploy. repo is owner/name; omit to resolve the current Project. Lists use page/limit and return compact rows (issues/PRs: number, title, state, author, updated, labels, 140-char excerpt; other lists: ids and status fields); open a row with its *.view action for bodies and details. Review/merge requires the current PR head sha. Install/connect in Extensions → Plugin → Git & GitHub. Results omit API-only URLs and node ids and name users/repos by login/full_name; `raw` is a readable file with the full response, and long results state what is shown.',
|
|
217
307
|
inputSchema: {
|
|
218
308
|
type: 'object',
|
|
219
309
|
properties: {
|
|
@@ -267,7 +357,7 @@ export const GITHUB_TOOL_DEF = {
|
|
|
267
357
|
export async function executeGithubTool(args, cwd, options = {}) {
|
|
268
358
|
try {
|
|
269
359
|
const result = await executeGithubRequest(args, cwd, options);
|
|
270
|
-
const reduced = { ...result, data: reduceGithubData(result.data) };
|
|
360
|
+
const reduced = { ...result, data: projectList(args.action, result.data) ?? reduceGithubData(result.data) };
|
|
271
361
|
const text = JSON.stringify(reduced);
|
|
272
362
|
if (text === JSON.stringify(result) && fits(text)) return text;
|
|
273
363
|
const raw = persistToolResultArtifactSync({
|
|
@@ -532,6 +532,7 @@ const _httpRouter = createHttpRouter({
|
|
|
532
532
|
_traceDb = v;
|
|
533
533
|
},
|
|
534
534
|
ingestTranscriptFile,
|
|
535
|
+
forgetTranscripts: _transcriptIngest.forgetTranscripts,
|
|
535
536
|
getTranscriptOffset: (fp) => _transcriptIngest.getOffset(fp),
|
|
536
537
|
parseTsToMs,
|
|
537
538
|
refreshCoreMemoryFile: refreshCoreMemorySnapshot,
|
|
@@ -15,7 +15,14 @@ const INSERT_ENTRY = `
|
|
|
15
15
|
RETURNING id
|
|
16
16
|
`;
|
|
17
17
|
|
|
18
|
-
export function createIngestHandler({
|
|
18
|
+
export function createIngestHandler({
|
|
19
|
+
getDb,
|
|
20
|
+
log,
|
|
21
|
+
ingestTranscriptFile,
|
|
22
|
+
forgetTranscripts,
|
|
23
|
+
getTranscriptOffset,
|
|
24
|
+
parseTsToMs,
|
|
25
|
+
}) {
|
|
19
26
|
const entry = async (body, res) => {
|
|
20
27
|
const db = getDb();
|
|
21
28
|
const role = String(body.role ?? 'user');
|
|
@@ -89,9 +96,23 @@ export function createIngestHandler({ getDb, log, ingestTranscriptFile, getTrans
|
|
|
89
96
|
}
|
|
90
97
|
};
|
|
91
98
|
|
|
99
|
+
const forgetTranscript = async (body, res) => {
|
|
100
|
+
const filePaths = body.filePaths;
|
|
101
|
+
if (!Array.isArray(filePaths) || filePaths.some((filePath) => typeof filePath !== 'string' || !filePath)) {
|
|
102
|
+
sendJson(res, { error: 'filePaths required' }, 400);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
sendJson(res, { ok: true, removed: await forgetTranscripts(filePaths) });
|
|
107
|
+
} catch (e) {
|
|
108
|
+
sendJson(res, { error: e.message }, 500);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
92
112
|
const routes = {
|
|
93
113
|
'/entry': entry,
|
|
94
114
|
'/ingest-transcript': ingestTranscript,
|
|
115
|
+
'/transcript/forget': forgetTranscript,
|
|
95
116
|
'/transcript/ingest-sync': ingestSync,
|
|
96
117
|
};
|
|
97
118
|
|
|
@@ -47,6 +47,8 @@ export function createTranscriptOffsets({ loadMeta, persistMeta, log }) {
|
|
|
47
47
|
set: (transcriptPath, position) => {
|
|
48
48
|
offsets.set(transcriptPath, position);
|
|
49
49
|
},
|
|
50
|
+
/** Drop one file's read position; true when an entry existed. */
|
|
51
|
+
forget: (transcriptPath) => offsets.delete(transcriptPath),
|
|
50
52
|
reset: () => {
|
|
51
53
|
offsets = new Map();
|
|
52
54
|
},
|
|
@@ -90,7 +90,9 @@ function installPoolErrorHandler(pool, label, { onConnectionLoss } = {}) {
|
|
|
90
90
|
// db.transaction(async tx => …) → auto BEGIN/COMMIT, ROLLBACK on throw
|
|
91
91
|
|
|
92
92
|
import { resolve } from 'node:path';
|
|
93
|
-
import { ensurePgInstance as supervisorEnsure } from './supervisor.mjs';
|
|
93
|
+
import { ensurePgInstance as supervisorEnsure, stopOwnedPgForShutdown } from './supervisor.mjs';
|
|
94
|
+
|
|
95
|
+
export { installOwnedPgExitStop, pgClusterExists } from './supervisor.mjs';
|
|
94
96
|
|
|
95
97
|
// ---------------------------------------------------------------------------
|
|
96
98
|
// One-shot bootstrap guard — keyed by resolved dataDir (cluster-level, not schema)
|
|
@@ -164,6 +166,52 @@ export async function checkedConnect(pgPool, schema) {
|
|
|
164
166
|
return client;
|
|
165
167
|
}
|
|
166
168
|
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
// Durable-operation tracking — a shutdown lets these settle before PG stops
|
|
171
|
+
// ---------------------------------------------------------------------------
|
|
172
|
+
|
|
173
|
+
/** Schemas holding only data rebuilt from another source of truth: the
|
|
174
|
+
* session-search copy (re-ingested from the session files by its backfill)
|
|
175
|
+
* and trace diagnostics. Every other schema (scheduler, webhooks, memory)
|
|
176
|
+
* holds the only copy, so its in-flight operations are drained first. */
|
|
177
|
+
const DERIVED_SCHEMAS = new Set(['session_search', 'trace']);
|
|
178
|
+
const _durableInFlight = new Set();
|
|
179
|
+
|
|
180
|
+
function trackDurable(schema, run) {
|
|
181
|
+
if (DERIVED_SCHEMAS.has(schema)) return run();
|
|
182
|
+
const op = run();
|
|
183
|
+
_durableInFlight.add(op);
|
|
184
|
+
const settle = () => _durableInFlight.delete(op);
|
|
185
|
+
op.then(settle, settle);
|
|
186
|
+
return op;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** In-flight operations on durable schemas right now. */
|
|
190
|
+
export function pendingDurablePgOps() {
|
|
191
|
+
return _durableInFlight.size;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Wait, bounded, until no durable-schema operation is in flight (including
|
|
196
|
+
* ones issued while waiting). Resolves true when drained, false at the bound.
|
|
197
|
+
*/
|
|
198
|
+
export async function drainDurablePgOps({ timeoutMs = 0 } = {}) {
|
|
199
|
+
const deadline = Date.now() + Math.max(0, Number(timeoutMs) || 0);
|
|
200
|
+
while (_durableInFlight.size > 0) {
|
|
201
|
+
const remaining = deadline - Date.now();
|
|
202
|
+
if (remaining <= 0) return false;
|
|
203
|
+
let timer = null;
|
|
204
|
+
await Promise.race([
|
|
205
|
+
Promise.allSettled([..._durableInFlight]),
|
|
206
|
+
new Promise((resolveBound) => {
|
|
207
|
+
timer = setTimeout(resolveBound, remaining);
|
|
208
|
+
}),
|
|
209
|
+
]);
|
|
210
|
+
clearTimeout(timer);
|
|
211
|
+
}
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
|
|
167
215
|
// ---------------------------------------------------------------------------
|
|
168
216
|
// native PG db shim
|
|
169
217
|
// ---------------------------------------------------------------------------
|
|
@@ -253,6 +301,12 @@ function makeCompatDb(pgPool, schema, dataDir) {
|
|
|
253
301
|
return currentPool();
|
|
254
302
|
},
|
|
255
303
|
};
|
|
304
|
+
// Every statement entry point is tracked, so a shutdown can let durable
|
|
305
|
+
// writes settle before it stops the cluster.
|
|
306
|
+
const { query, exec, transaction } = db;
|
|
307
|
+
db.query = (sql, params) => trackDurable(schema, () => query(sql, params));
|
|
308
|
+
db.exec = (sql) => trackDurable(schema, () => exec(sql));
|
|
309
|
+
db.transaction = (fn) => trackDurable(schema, () => transaction(fn));
|
|
256
310
|
return db;
|
|
257
311
|
}
|
|
258
312
|
|
|
@@ -522,3 +576,46 @@ export async function closePgInstance(dataDir, opts = {}) {
|
|
|
522
576
|
} catch {}
|
|
523
577
|
instances.delete(key);
|
|
524
578
|
}
|
|
579
|
+
|
|
580
|
+
// ---------------------------------------------------------------------------
|
|
581
|
+
// shutdownOwnedPg — process exit: every pool, then the cluster this process owns
|
|
582
|
+
// ---------------------------------------------------------------------------
|
|
583
|
+
|
|
584
|
+
export const POOL_CLOSE_BOUND_MS = 500;
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* For a host whose stores start PostgreSQL (the daemon's schedules/webhooks/
|
|
588
|
+
* session-search): stop the cluster it ensured (supervisor
|
|
589
|
+
* stopOwnedPgForShutdown, `pg_ctl stop -m fast`) while every pool this process
|
|
590
|
+
* opened ends alongside — a pool waiting on a checked-out client never holds
|
|
591
|
+
* the stop back. The stop latches the supervisor first (synchronously), so a
|
|
592
|
+
* pooled client that sees fast shutdown terminate its backend cannot restart
|
|
593
|
+
* PG through connection-loss recovery; the pools are dropped from the cache,
|
|
594
|
+
* and their close is waited on only for a short bound after the stop.
|
|
595
|
+
*/
|
|
596
|
+
export async function shutdownOwnedPg({ timeoutMs, drainMs = 0 } = {}) {
|
|
597
|
+
// Durable writes still in flight (schedule/webhook state) commit first,
|
|
598
|
+
// bounded by `drainMs`; derived writes (session search, trace) are not
|
|
599
|
+
// waited on — their sources rebuild them.
|
|
600
|
+
if (!(await drainDurablePgOps({ timeoutMs: drainMs }))) {
|
|
601
|
+
__mixdogMemoryLog(
|
|
602
|
+
`[pg-adapter] stopping PG with ${_durableInFlight.size} durable operation(s) still in flight after ${drainMs}ms\n`
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
const pools = [...instances.values()].map((inst) => inst.pool);
|
|
606
|
+
instances.clear();
|
|
607
|
+
const stopping = stopOwnedPgForShutdown({ timeoutMs });
|
|
608
|
+
const closing = Promise.allSettled(pools.map((pool) => pool.end()));
|
|
609
|
+
try {
|
|
610
|
+
return await stopping;
|
|
611
|
+
} finally {
|
|
612
|
+
let timer = null;
|
|
613
|
+
await Promise.race([
|
|
614
|
+
closing,
|
|
615
|
+
new Promise((resolveBound) => {
|
|
616
|
+
timer = setTimeout(resolveBound, POOL_CLOSE_BOUND_MS);
|
|
617
|
+
}),
|
|
618
|
+
]);
|
|
619
|
+
clearTimeout(timer);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
@@ -5,8 +5,11 @@ import { sleep as delay } from '../../../shared/sleep.mjs';
|
|
|
5
5
|
//
|
|
6
6
|
// Public API:
|
|
7
7
|
// startPg({ runtimeDir, pgdataDir, port?, logPath? }) → { pid, port }
|
|
8
|
-
// stopPg({ runtimeDir, pgdataDir })
|
|
8
|
+
// stopPg({ runtimeDir, pgdataDir, timeoutMs? }) → void
|
|
9
9
|
// healthcheckPg({ port, host? }) → boolean
|
|
10
|
+
//
|
|
11
|
+
// Every child on the start/stop path (initdb, pg_ctl start/reload/status/stop)
|
|
12
|
+
// runs async; only stopPgSync — a process 'exit' hook — may block.
|
|
10
13
|
|
|
11
14
|
import {
|
|
12
15
|
existsSync,
|
|
@@ -24,6 +27,7 @@ import { join } from 'node:path';
|
|
|
24
27
|
import { execFile, spawn, spawnSync } from 'node:child_process';
|
|
25
28
|
import { createConnection, createServer } from 'node:net';
|
|
26
29
|
import { isPidAlive } from '../../../shared/pid-liveness.mjs';
|
|
30
|
+
import { runChild } from './run-child.mjs';
|
|
27
31
|
|
|
28
32
|
// ---------------------------------------------------------------------------
|
|
29
33
|
// Helpers
|
|
@@ -201,14 +205,12 @@ function ensureConfV2(pgdataDir) {
|
|
|
201
205
|
// callers route through this rather than re-implementing the conf/reload pair.
|
|
202
206
|
// Reload-compatible settings apply immediately; postmaster settings such as
|
|
203
207
|
// max_connections apply on the next normal PG start (never restart live work).
|
|
204
|
-
export function reconcileConfV2(runtimeDir, pgdataDir) {
|
|
208
|
+
export async function reconcileConfV2(runtimeDir, pgdataDir) {
|
|
205
209
|
const applied = ensureConfV2(pgdataDir);
|
|
206
210
|
if (!applied) return { applied: false, reloaded: false };
|
|
207
|
-
const reload =
|
|
211
|
+
const reload = await runChild(pgBin(runtimeDir, 'pg_ctl'), ['reload', '-D', pgdataDir], {
|
|
208
212
|
env: libEnv(runtimeDir),
|
|
209
|
-
|
|
210
|
-
timeout: 5_000,
|
|
211
|
-
windowsHide: true,
|
|
213
|
+
timeoutMs: 5_000,
|
|
212
214
|
});
|
|
213
215
|
const reloaded = reload.status === 0;
|
|
214
216
|
if (reloaded) {
|
|
@@ -238,7 +240,7 @@ async function attachExistingPostmaster({ runtimeDir, pgdataDir, existingWaitMs,
|
|
|
238
240
|
__mixdogMemoryLog(`[pg-process] attaching to existing PG pid=${existing.pid} port=${existing.port}\n`);
|
|
239
241
|
// Route through the single reconcile entry point so v1 → v2 conf
|
|
240
242
|
// upgrades land on already-running instances without restart.
|
|
241
|
-
if (v2Applied) reconcileConfV2(runtimeDir, pgdataDir);
|
|
243
|
+
if (v2Applied) await reconcileConfV2(runtimeDir, pgdataDir);
|
|
242
244
|
return { pid: existing.pid, port: existing.port, attached: true };
|
|
243
245
|
}
|
|
244
246
|
if (existing.state === 'alive-not-ready') {
|
|
@@ -259,6 +261,10 @@ async function attachExistingPostmaster({ runtimeDir, pgdataDir, existingWaitMs,
|
|
|
259
261
|
// default_transaction_isolation: native PG default is read committed.
|
|
260
262
|
// Native PG does not default to serializable; set isolation level explicitly
|
|
261
263
|
// so behaviour is unambiguous across PG major versions.
|
|
264
|
+
// Carries every versioned block ensureConfV2 checks for, so a fresh cluster
|
|
265
|
+
// already holds what later boots expect: none of them rewrites the conf and
|
|
266
|
+
// pg_ctl-reloads it (a postmaster-only setting such as shared_buffers cannot
|
|
267
|
+
// change by reload, and every such reload logged an error).
|
|
262
268
|
function freshClusterConfAppend() {
|
|
263
269
|
return (
|
|
264
270
|
[
|
|
@@ -279,7 +285,8 @@ function freshClusterConfAppend() {
|
|
|
279
285
|
].join('\n') +
|
|
280
286
|
'\n' +
|
|
281
287
|
buildV2Block() +
|
|
282
|
-
buildV3Block()
|
|
288
|
+
buildV3Block() +
|
|
289
|
+
buildV4Block()
|
|
283
290
|
);
|
|
284
291
|
}
|
|
285
292
|
|
|
@@ -290,14 +297,14 @@ function freshClusterConfAppend() {
|
|
|
290
297
|
* user profile). Such a share dir is passed through an ASCII junction under
|
|
291
298
|
* %ProgramData% that is removed afterwards.
|
|
292
299
|
*/
|
|
293
|
-
export function withInitdbShareDir(runtimeDir, run) {
|
|
300
|
+
export async function withInitdbShareDir(runtimeDir, run) {
|
|
294
301
|
const shareDir = join(runtimeDir, 'share');
|
|
295
302
|
if (process.platform !== 'win32' || /^[\x20-\x7e]*$/.test(shareDir)) return run(null);
|
|
296
303
|
const linkRoot = mkdtempSync(join(process.env.ProgramData, 'mixdog-initdb-'));
|
|
297
304
|
const link = join(linkRoot, 'share');
|
|
298
305
|
try {
|
|
299
306
|
symlinkSync(shareDir, link, 'junction');
|
|
300
|
-
return run(link);
|
|
307
|
+
return await run(link);
|
|
301
308
|
} finally {
|
|
302
309
|
// Cleanup must not replace initdb's own result or error. Both removals are
|
|
303
310
|
// non-recursive, so the junction target (the runtime share) is never touched.
|
|
@@ -312,11 +319,11 @@ export function withInitdbShareDir(runtimeDir, run) {
|
|
|
312
319
|
}
|
|
313
320
|
|
|
314
321
|
/** initdb if pgdata is not yet initialised (no PG_VERSION file). */
|
|
315
|
-
function initClusterIfNeeded({ runtimeDir, pgdataDir, env }) {
|
|
322
|
+
async function initClusterIfNeeded({ runtimeDir, pgdataDir, env }) {
|
|
316
323
|
if (existsSync(join(pgdataDir, 'PG_VERSION'))) return;
|
|
317
324
|
__mixdogMemoryLog(`[pg-process] initdb → ${pgdataDir}\n`);
|
|
318
|
-
const r = withInitdbShareDir(runtimeDir, (shareDir) =>
|
|
319
|
-
|
|
325
|
+
const r = await withInitdbShareDir(runtimeDir, (shareDir) =>
|
|
326
|
+
runChild(
|
|
320
327
|
pgBin(runtimeDir, 'initdb'),
|
|
321
328
|
[
|
|
322
329
|
'-D',
|
|
@@ -329,7 +336,7 @@ function initClusterIfNeeded({ runtimeDir, pgdataDir, env }) {
|
|
|
329
336
|
'-U',
|
|
330
337
|
'postgres',
|
|
331
338
|
],
|
|
332
|
-
{ env
|
|
339
|
+
{ env }
|
|
333
340
|
)
|
|
334
341
|
);
|
|
335
342
|
if (r.status !== 0) {
|
|
@@ -435,12 +442,7 @@ async function startAndWaitReady({ pgctl, startArgs, env, pgdataDir, port }) {
|
|
|
435
442
|
*/
|
|
436
443
|
async function attachRaceWinner({ pgdataDir, pgctl, env, existingWaitMs }) {
|
|
437
444
|
__mixdogMemoryLog(`[pg-process] pg_ctl start: "another server might be running" — probing status\n`);
|
|
438
|
-
const statusR =
|
|
439
|
-
env,
|
|
440
|
-
stdio: 'pipe',
|
|
441
|
-
timeout: 3_000,
|
|
442
|
-
windowsHide: true,
|
|
443
|
-
});
|
|
445
|
+
const statusR = await runChild(pgctl, ['status', '-D', pgdataDir], { env, timeoutMs: 3_000 });
|
|
444
446
|
__mixdogMemoryLog(
|
|
445
447
|
`[pg-process] pg_ctl status: ${statusR.stdout?.toString() || statusR.stderr?.toString() || 'no output'}\n`
|
|
446
448
|
);
|
|
@@ -480,7 +482,7 @@ export async function startPg({
|
|
|
480
482
|
if (attached) return attached;
|
|
481
483
|
|
|
482
484
|
const pgctl = pgBin(runtimeDir, 'pg_ctl');
|
|
483
|
-
initClusterIfNeeded({ runtimeDir, pgdataDir, env });
|
|
485
|
+
await initClusterIfNeeded({ runtimeDir, pgdataDir, env });
|
|
484
486
|
// PostgreSQL requires a completely empty target on first init. Creating the
|
|
485
487
|
// Spotlight marker before initdb makes every fresh macOS cluster fail with
|
|
486
488
|
// "directory exists but is not empty"; add it only after initialization.
|
|
@@ -511,15 +513,18 @@ export async function startPg({
|
|
|
511
513
|
// stopPg
|
|
512
514
|
// ---------------------------------------------------------------------------
|
|
513
515
|
|
|
514
|
-
|
|
516
|
+
// Bounded graceful stop. `-m fast` rolls back open transactions and
|
|
517
|
+
// disconnects clients; pg_ctl's own wait (-t, whole seconds) and the child
|
|
518
|
+
// timeout share `timeoutMs`, so a wedged stop rejects instead of holding a
|
|
519
|
+
// shutdown sequence open.
|
|
520
|
+
export async function stopPg({ runtimeDir, pgdataDir, timeoutMs = 15_000 }) {
|
|
515
521
|
const pgctl = pgBin(runtimeDir, 'pg_ctl');
|
|
516
522
|
const env = libEnv(runtimeDir);
|
|
523
|
+
const waitSeconds = Math.max(1, Math.ceil(timeoutMs / 1000));
|
|
517
524
|
|
|
518
|
-
const r =
|
|
525
|
+
const r = await runChild(pgctl, ['stop', '-m', 'fast', '-w', '-t', String(waitSeconds), '-D', pgdataDir], {
|
|
519
526
|
env,
|
|
520
|
-
|
|
521
|
-
timeout: 15_000,
|
|
522
|
-
windowsHide: true,
|
|
527
|
+
timeoutMs: waitSeconds * 1000 + 1_000,
|
|
523
528
|
});
|
|
524
529
|
|
|
525
530
|
if (r.status !== 0) {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Async child run with spawnSync's result shape ({ status, signal, stdout,
|
|
5
|
+
* stderr, error }) so the PG runtime's tar / initdb / pg_ctl steps never block
|
|
6
|
+
* the event loop of the process hosting them (the daemon serves every client
|
|
7
|
+
* from one loop). `timeoutMs` > 0 kills the child and reports ETIMEDOUT, like
|
|
8
|
+
* spawnSync's `timeout`. Never rejects.
|
|
9
|
+
*/
|
|
10
|
+
export function runChild(file, args, { timeoutMs = 0, ...options } = {}) {
|
|
11
|
+
return new Promise((resolve) => {
|
|
12
|
+
const stdout = [];
|
|
13
|
+
const stderr = [];
|
|
14
|
+
let settled = false;
|
|
15
|
+
let timer = null;
|
|
16
|
+
let error = null;
|
|
17
|
+
const finish = (status, signal) => {
|
|
18
|
+
if (settled) return;
|
|
19
|
+
settled = true;
|
|
20
|
+
if (timer) clearTimeout(timer);
|
|
21
|
+
resolve({ status, signal, stdout: Buffer.concat(stdout), stderr: Buffer.concat(stderr), error });
|
|
22
|
+
};
|
|
23
|
+
let child;
|
|
24
|
+
try {
|
|
25
|
+
child = spawn(file, args, { windowsHide: true, ...options, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
26
|
+
} catch (spawnError) {
|
|
27
|
+
error = spawnError;
|
|
28
|
+
finish(null, null);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
child.stdout?.on('data', (chunk) => stdout.push(chunk));
|
|
32
|
+
child.stderr?.on('data', (chunk) => stderr.push(chunk));
|
|
33
|
+
child.once('error', (childError) => {
|
|
34
|
+
error ??= childError;
|
|
35
|
+
finish(null, null);
|
|
36
|
+
});
|
|
37
|
+
// 'close' (not 'exit'): stdio is flushed, so captured output is complete.
|
|
38
|
+
child.once('close', (status, signal) => finish(status, signal));
|
|
39
|
+
if (timeoutMs > 0) {
|
|
40
|
+
timer = setTimeout(() => {
|
|
41
|
+
error = Object.assign(new Error(`${file} timed out after ${timeoutMs}ms`), { code: 'ETIMEDOUT' });
|
|
42
|
+
try {
|
|
43
|
+
child.kill();
|
|
44
|
+
} catch {}
|
|
45
|
+
finish(null, 'SIGTERM');
|
|
46
|
+
}, timeoutMs);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|