mixdog 1.0.11 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE.md +20 -0
- package/README.md +75 -181
- package/package.json +9 -4
- package/scripts/build-shipped-history.mjs +131 -0
- package/scripts/check-changelog-locales.mjs +203 -0
- package/scripts/computer-task-cost-report.mjs +0 -4
- package/scripts/lib/run-node-tests.mjs +235 -13
- package/scripts/lib/test-failure-records.mjs +5 -0
- package/scripts/lib/test-failure-summary.mjs +9 -3
- package/scripts/lib/test-spawn-ledger.mjs +19 -0
- package/scripts/prune-embedding-runtime.mjs +9 -5
- package/scripts/sync-client-version-floors.mjs +100 -0
- package/scripts/test-direct.mjs +16 -1
- package/src/agents/advisor/AGENT.md +38 -0
- package/src/agents/advisor/agent.json +6 -0
- package/src/agents/reviewer/AGENT.md +5 -2
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +381 -0
- package/src/defaults/skills/docx/SKILL.md +7 -5
- package/src/defaults/skills/docx/references/html.md +9 -8
- package/src/defaults/skills/docx/references/native-authoring.md +28 -18
- package/src/defaults/skills/goal-management/SKILL.md +11 -5
- package/src/defaults/skills/local-provider/SKILL.md +2 -1
- package/src/defaults/skills/pdf/SKILL.md +9 -6
- package/src/defaults/skills/pdf/references/html.md +17 -12
- package/src/defaults/skills/pptx/SKILL.md +8 -6
- package/src/defaults/skills/pptx/references/composition.md +4 -4
- package/src/defaults/skills/pptx/references/concepts.md +168 -0
- package/src/defaults/skills/pptx/references/direction.md +5 -4
- package/src/defaults/skills/pptx/references/html.md +6 -29
- package/src/defaults/skills/pptx/references/kit-index.md +11 -3
- package/src/defaults/skills/pptx/references/kit.md +27 -5
- package/src/defaults/skills/pptx/references/review.md +6 -5
- package/src/defaults/skills/setup/SKILL.md +5 -8
- package/src/defaults/skills/setup/references/actions.md +61 -31
- package/src/defaults/skills/setup/references/surfaces.md +12 -10
- package/src/defaults/skills/xlsx/SKILL.md +8 -6
- package/src/defaults/skills/xlsx/references/html.md +8 -4
- package/src/defaults/skills/xlsx/references/model-conventions.md +2 -0
- package/src/defaults/skills/xlsx/references/report-design.md +32 -16
- package/src/help.mjs +1 -1
- package/src/lib/rules-builder.cjs +1 -1
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +3 -1
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +4 -0
- package/src/runtime/agent/orchestrator/config-presets.d.mts +1 -0
- package/src/runtime/agent/orchestrator/config-presets.mjs +44 -0
- package/src/runtime/agent/orchestrator/config-providers-merge.mjs +9 -1
- package/src/runtime/agent/orchestrator/config.mjs +102 -21
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +90 -26
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +44 -14
- package/src/runtime/agent/orchestrator/providers/anthropic-midstream-recovery.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +5 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +79 -8
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +29 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +10 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +11 -2
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +9 -5
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +9 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +30 -22
- package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +28 -10
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +14 -72
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +19 -3
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +20 -10
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-sink.mjs +36 -9
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +11 -17
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +388 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +92 -109
- package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +107 -0
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +138 -30
- package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +32 -15
- package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +39 -5
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +6 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +10 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +5 -1
- package/src/runtime/agent/orchestrator/providers/lib/note-error-usage.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +57 -0
- package/src/runtime/agent/orchestrator/providers/model-cache.mjs +12 -5
- package/src/runtime/agent/orchestrator/providers/npm-cli-version.mjs +20 -15
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +14 -9
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +56 -11
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +28 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +27 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +7 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +12 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +23 -8
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +26 -6
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +34 -15
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +16 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +12 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +0 -6
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +0 -19
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +12 -43
- package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +6 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +39 -9
- package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog.mjs +31 -9
- package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +13 -38
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +40 -9
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +7 -39
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +28 -101
- package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +8 -4
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +3 -6
- package/src/runtime/agent/orchestrator/providers/openai-service-tier.mjs +19 -0
- package/src/runtime/agent/orchestrator/providers/openai-startup-prewarm.mjs +5 -195
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +9 -18
- package/src/runtime/agent/orchestrator/providers/openai-ws-events.mjs +4 -66
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state.mjs +11 -5
- package/src/runtime/agent/orchestrator/providers/openai-ws-send/acquire-attempt.mjs +3 -15
- package/src/runtime/agent/orchestrator/providers/openai-ws-send/attempt-request.mjs +6 -56
- package/src/runtime/agent/orchestrator/providers/openai-ws-send/send-context.mjs +1 -19
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/handshake-failure.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/policy.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/stream-failure-stamps.mjs +0 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/stream-failure.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts.mjs +3 -5
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-outcome.mjs +10 -89
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-span.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-trace.mjs +0 -6
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/terminal-frames.mjs +34 -11
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +0 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +3 -7
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +44 -19
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +40 -12
- package/src/runtime/agent/orchestrator/providers/quota-reading.mjs +70 -0
- package/src/runtime/agent/orchestrator/providers/registry.mjs +38 -3
- package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/retry-midstream.mjs +11 -0
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +31 -41
- package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +5 -0
- package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +0 -17
- package/src/runtime/agent/orchestrator/runtime-core/goal-state.mjs +0 -3
- package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +0 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-text.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-tool-defs.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +1 -2
- package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +18 -4
- package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +8 -1
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +7 -1
- package/src/runtime/agent/orchestrator/runtime-core/session-route-policy.mjs +16 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +6 -2
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +7 -7
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/compact/observation-supersession.mjs +45 -2
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/eager-dispatch/entry.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +6 -13
- package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +114 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +5 -9
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +51 -18
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +7 -4
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +0 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +6 -9
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +63 -3
- package/src/runtime/agent/orchestrator/session/manager/session-owner-liveness.mjs +10 -28
- package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +4 -4
- package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +10 -19
- package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +1 -3
- package/src/runtime/agent/orchestrator/stall-policy.mjs +0 -1
- package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +18 -8
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +19 -20
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +6 -11
- package/src/runtime/agent/orchestrator/tools/builtin/file-version-test-helpers.mjs +11 -0
- package/src/runtime/agent/orchestrator/tools/builtin/file-version.mjs +13 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-single-file-rescue.mjs +8 -5
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +25 -12
- package/src/runtime/agent/orchestrator/tools/builtin/raw-content-publication.mjs +17 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +136 -76
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +15 -17
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +11 -10
- package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +30 -16
- package/src/runtime/agent/orchestrator/tools/builtin/shell-lossless-compact.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/snapshot-helpers.mjs +4 -11
- package/src/runtime/agent/orchestrator/tools/builtin/snapshot-store.mjs +7 -3
- package/src/runtime/agent/orchestrator/tools/builtin/snapshot-validation.mjs +16 -19
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background.mjs +4 -1
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +14 -4
- package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +58 -8
- package/src/runtime/agent/orchestrator/tools/patch/content-guard.mjs +47 -0
- package/src/runtime/agent/orchestrator/tools/patch/delete-quarantine.mjs +155 -0
- package/src/runtime/agent/orchestrator/tools/patch/dispatch/native-proofs.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/patch/dispatch/native-snapshots.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +19 -16
- package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +13 -44
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/patch/post-patch-excerpts.mjs +5 -2
- package/src/runtime/agent/orchestrator/tools/patch/replay-capture.mjs +47 -7
- package/src/runtime/agent/orchestrator/tools/patch/rollback-state.mjs +72 -8
- package/src/runtime/agent/orchestrator/tools/patch/section-coalesce.mjs +3 -2
- package/src/runtime/agent/orchestrator/tools/patch/sequence/run.mjs +9 -1
- package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +9 -1
- package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +6 -6
- package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +16 -4
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +35 -14
- package/src/runtime/agent/orchestrator/tools/patch/wave.mjs +42 -4
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/shell-codepage.mjs +296 -0
- package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +75 -24
- package/src/runtime/browser-bridge/tool-defs.mjs +1 -0
- package/src/runtime/channels/lib/config.mjs +3 -8
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +7 -3
- package/src/{tui → runtime/channels}/lib/voice-setup.mjs +38 -22
- package/src/runtime/channels/lib/webhook/request-handler.mjs +42 -8
- package/src/runtime/computer-bridge/actions.mjs +2 -0
- package/src/runtime/effort-judge/judge-client.mjs +125 -25
- package/src/runtime/effort-judge/judge-input.mjs +96 -0
- package/src/runtime/effort-judge/judge-worker.mjs +52 -20
- package/src/runtime/effort-judge/model-install.mjs +74 -0
- package/src/runtime/effort-judge/model-manifest.json +21 -0
- package/src/runtime/effort-judge/previous-human-request.mjs +162 -0
- package/src/runtime/effort-judge/verified-context-input.mjs +10 -0
- package/src/runtime/github/tool.mjs +214 -14
- package/src/runtime/local-provider/context-settings.mjs +15 -6
- package/src/runtime/local-provider/gguf-header.mjs +13 -5
- package/src/runtime/local-provider/hugging-face.mjs +27 -5
- package/src/runtime/local-provider/install-progress.mjs +7 -0
- package/src/runtime/local-provider/managed-runtime.mjs +2 -1
- package/src/runtime/local-provider/model-maintenance.mjs +15 -6
- package/src/runtime/local-provider/resumable-installations.mjs +40 -1
- package/src/runtime/local-provider/server.mjs +2 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +12 -0
- package/src/runtime/memory/lib/http-router/session-routes.mjs +2 -1
- package/src/runtime/memory/lib/memory-config-flags.mjs +3 -2
- package/src/runtime/memory/lib/memory-embed.mjs +5 -0
- package/src/runtime/memory/lib/pg/process.mjs +57 -5
- package/src/runtime/office/README.md +13 -7
- package/src/runtime/office/authoring/docx-html-build.mjs +4 -4
- package/src/runtime/office/authoring/docx-html-measure.mjs +60 -0
- package/src/runtime/office/authoring/pdf-author-action.mjs +6 -1
- package/src/runtime/office/authoring/pptx-brief.mjs +40 -1
- package/src/runtime/office/authoring/pptx-html-build.mjs +1 -1
- package/src/runtime/office/authoring/pptx-html-measure.mjs +1 -1
- package/src/runtime/office/bench/deck-bench.mjs +1 -1
- package/src/runtime/office/com/office-com-host.ps1 +8 -0
- package/src/runtime/office/core/office-actions-render.mjs +2 -0
- package/src/runtime/office/design/design-art-direction.mjs +10 -2
- package/src/runtime/office/design/design-discipline.mjs +4 -5
- package/src/runtime/office/design/design-tokens.mjs +20 -1
- package/src/runtime/office/design/docx/design-docx/front-matter.mjs +7 -4
- package/src/runtime/office/design/docx/design-docx/section.mjs +3 -1
- package/src/runtime/office/design/docx/design-docx/writer.mjs +1 -0
- package/src/runtime/office/design/docx/design-docx-components.mjs +19 -15
- package/src/runtime/office/design/docx/design-docx.mjs +5 -6
- package/src/runtime/office/design/docx/document-typography.mjs +20 -6
- package/src/runtime/office/design/xlsx/design-xlsx.mjs +9 -2
- package/src/runtime/office/pdf/document-preview.mjs +133 -12
- package/src/runtime/office/pdf/pdf-writer.mjs +56 -22
- package/src/runtime/office/portable/portable-snapshot-docx.mjs +46 -3
- package/src/runtime/office/portable/portable-snapshot-shared.mjs +27 -1
- package/src/runtime/office/quality/assurance-rendered.mjs +21 -5
- package/src/runtime/office/quality/assurance-structure-docx.mjs +41 -9
- package/src/runtime/office/quality/design-aesthetics.mjs +4 -2
- package/src/runtime/office/quality/design-deck-diversity.mjs +15 -3
- package/src/runtime/office/quality/design-review.mjs +13 -5
- package/src/runtime/office/quality/document-brief.mjs +8 -2
- package/src/runtime/office/quality/forced-break-pages.mjs +203 -0
- package/src/runtime/office/quality/pptx-deck-rubric.mjs +21 -3
- package/src/runtime/office/quality/quality-pipeline.mjs +14 -17
- package/src/runtime/session-search/session-search-db.mjs +183 -0
- package/src/runtime/session-search/session-search-ingest.mjs +106 -0
- package/src/runtime/shared/agent-route-config.mjs +50 -2
- package/src/runtime/shared/bounded-file-read.mjs +166 -0
- package/src/runtime/shared/builtin-grandfathering.mjs +37 -0
- package/src/runtime/shared/config.mjs +24 -4
- package/src/runtime/shared/defaults-separation.mjs +263 -0
- package/src/runtime/shared/error-presentation.mjs +8 -1
- package/src/runtime/shared/llm/anthropic-effort.mjs +4 -0
- package/src/runtime/shared/llm/cost.mjs +4 -2
- package/src/runtime/shared/llm/model-catalog-projection.mjs +1 -1
- package/src/runtime/shared/llm/model-catalog.mjs +25 -0
- package/src/runtime/shared/llm/reasoning-usage.mjs +1 -2
- package/src/runtime/shared/llm/usage-accounting.mjs +14 -4
- package/src/runtime/shared/llm/usage-context.mjs +11 -1
- package/src/runtime/shared/llm/usage-ledger-repair.mjs +3 -1
- package/src/runtime/shared/llm/usage-ledger-rollup.mjs +105 -1
- package/src/runtime/shared/llm/usage-ledger-worker.mjs +2 -1
- package/src/runtime/shared/llm/usage-ledger.mjs +72 -5
- package/src/runtime/shared/onnx-runtime-support.mjs +6 -0
- package/src/runtime/shared/orchestration.mjs +14 -6
- package/src/runtime/shared/pristine-execution-contract.json +7 -2
- package/src/runtime/shared/projects.mjs +65 -48
- package/src/runtime/shared/provider-accounts.mjs +47 -6
- package/src/runtime/shared/quota-resume-store.mjs +255 -0
- package/src/runtime/shared/shipped-definitions.mjs +275 -0
- package/src/runtime/shared/tool-card-model/agent-surface.mjs +30 -9
- package/src/runtime/shared/tool-card-model/aggregate-card.mjs +7 -3
- package/src/runtime/shared/tool-card-model/background-task.mjs +17 -1
- package/src/runtime/shared/tool-card-model/card-detail.mjs +10 -4
- package/src/runtime/shared/tool-card-model/card-header.mjs +10 -4
- package/src/runtime/shared/tool-card-model/card-status.mjs +22 -5
- package/src/runtime/shared/tool-card-model/displayed-result.mjs +6 -1
- package/src/runtime/shared/tool-card-model/media-result.mjs +53 -0
- package/src/runtime/shared/tool-card-model/terminal-status.mjs +17 -1
- package/src/runtime/shared/tool-card-model.golden-cases.mjs +1 -1
- package/src/runtime/shared/tool-card-model.golden.json +75 -66
- package/src/runtime/shared/tool-card-model.mjs +1 -0
- package/src/runtime/shared/tool-output-limit.mjs +3 -0
- package/src/runtime/shared/tool-primitives.mjs +24 -18
- package/src/runtime/shared/tool-result-summary.mjs +128 -17
- package/src/runtime/shared/tool-status.mjs +20 -7
- package/src/runtime/shared/tool-surface.mjs +105 -28
- package/src/runtime/shared/tool-work-units.mjs +221 -18
- package/src/runtime/shared/transcript-metadata.mjs +2 -0
- package/src/runtime/shared/turn-review-reply.mjs +2 -0
- package/src/runtime/shared/turn-snapshot.mjs +65 -6
- package/src/runtime/shared/turn-worktree-snapshot.mjs +202 -22
- package/src/runtime/shared/worker-requests.mjs +14 -2
- package/src/runtime/terminal-bridge/client.mjs +311 -0
- package/src/runtime/terminal-bridge/tool-defs.mjs +36 -0
- package/src/runtime/web-search/lib/ssrf-guard.mjs +12 -56
- package/src/runtime/web-search/tool-defs.mjs +2 -0
- package/src/session-runtime/boot/apis.mjs +30 -5
- package/src/session-runtime/boot/config.mjs +4 -0
- package/src/session-runtime/boot/facade.mjs +4 -1
- package/src/session-runtime/boot/infrastructure.mjs +21 -2
- package/src/session-runtime/boot/session.mjs +5 -5
- package/src/session-runtime/boot/tools.mjs +2 -0
- package/src/session-runtime/builtin-features.d.mts +1 -0
- package/src/session-runtime/channel-config-api.mjs +5 -0
- package/src/session-runtime/config-lifecycle/config-writers.mjs +3 -0
- package/src/session-runtime/config-lifecycle.mjs +31 -6
- package/src/session-runtime/goal-facade-api.mjs +4 -0
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +15 -3
- package/src/session-runtime/lifecycle/inheritance.mjs +28 -6
- package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +3 -0
- package/src/session-runtime/lifecycle/session-switch/resume.mjs +7 -1
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +9 -0
- package/src/session-runtime/lifecycle/teardown/session-close.mjs +14 -2
- package/src/session-runtime/lifecycle/teardown.mjs +5 -0
- package/src/session-runtime/local-provider-settings.mjs +10 -0
- package/src/session-runtime/media-api.mjs +32 -22
- package/src/session-runtime/model-recency.mjs +14 -0
- package/src/session-runtime/model-route/route-persist.mjs +17 -2
- package/src/session-runtime/model-route/route-tuning.mjs +16 -5
- package/src/session-runtime/model-route/set-route.mjs +55 -22
- package/src/session-runtime/model-route/web-search-route.mjs +2 -2
- package/src/session-runtime/model-route-api.mjs +2 -1
- package/src/session-runtime/notification-bus.mjs +31 -6
- package/src/session-runtime/provider-auth/login.mjs +6 -0
- package/src/session-runtime/provider-models/catalog-load.mjs +3 -1
- package/src/session-runtime/provider-models/row-hydration.mjs +36 -10
- package/src/session-runtime/quick-model-rows/model-meta.mjs +26 -0
- package/src/session-runtime/quick-model-rows/provider-rows.mjs +40 -14
- package/src/session-runtime/resource-api.mjs +8 -1
- package/src/session-runtime/route-state.mjs +9 -0
- package/src/session-runtime/runtime-core.mjs +4 -0
- package/src/session-runtime/runtime-facade.mjs +20 -1
- package/src/session-runtime/runtime-feature-gates.mjs +2 -0
- package/src/session-runtime/runtime-review-api.mjs +12 -1
- package/src/session-runtime/services/agent-tool/helpers.mjs +14 -1
- package/src/session-runtime/services/agent-tool/index-write-queue.mjs +10 -15
- package/src/session-runtime/services/agent-tool/lead-worker-index/reap-timers.mjs +6 -1
- package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +20 -2
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +14 -6
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +2 -0
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +12 -1
- package/src/session-runtime/services/agent-tool/worker-index.mjs +17 -1
- package/src/session-runtime/services/agent-tool.mjs +1 -0
- package/src/session-runtime/services/channel-admin.mjs +87 -13
- package/src/session-runtime/services/provider-admin.mjs +306 -66
- package/src/session-runtime/services/seeds.mjs +73 -142
- package/src/session-runtime/services/usage-dashboard-model.mjs +29 -0
- package/src/session-runtime/services/usage-dashboard.mjs +7 -0
- package/src/session-runtime/session-address.mjs +125 -0
- package/src/session-runtime/session-create.mjs +57 -2
- package/src/session-runtime/settings-api.mjs +1 -0
- package/src/session-runtime/settings-builtin-tools-api.mjs +15 -10
- package/src/session-runtime/settings-compaction-api.mjs +13 -0
- package/src/session-runtime/setup-tool/executor.mjs +93 -40
- package/src/session-runtime/setup-tool/extended-actions.mjs +64 -5
- package/src/session-runtime/setup-tool/settings-contract.mjs +46 -3
- package/src/session-runtime/setup-tool/tool-defs.mjs +14 -6
- package/src/session-runtime/tool-surface.mjs +16 -9
- package/src/session-runtime/turn/session-ops.mjs +3 -0
- package/src/session-runtime/turn/share-ops.mjs +4 -1
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +6 -0
- package/src/session-runtime/usage-stats-api.mjs +43 -3
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +31 -5
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +6 -2
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +27 -7
- package/src/standalone/daemon-boot-coordinator.mjs +10 -0
- package/src/standalone/daemon-desktop-runtime.mjs +1 -0
- package/src/standalone/daemon-drain-policy.mjs +9 -0
- package/src/standalone/daemon-stored-session-views.mjs +7 -8
- package/src/standalone/daemon.mjs +36 -8
- package/src/standalone/local-session-runtime.mjs +11 -0
- package/src/standalone/session-client.mjs +52 -7
- package/src/standalone/session-protocol.mjs +9 -0
- package/src/standalone/session-service/agent-tree/agent-child.mjs +2 -0
- package/src/standalone/session-service/entries/lifecycle.mjs +2 -0
- package/src/standalone/session-service/entries/session-loads.mjs +9 -0
- package/src/standalone/session-service/projection/revisions.mjs +28 -4
- package/src/standalone/session-service/projection.mjs +1 -0
- package/src/standalone/session-service/quota-resume.mjs +140 -0
- package/src/standalone/session-service/session-calls/session-action.mjs +2 -2
- package/src/standalone/session-service/session-calls.mjs +10 -2
- package/src/standalone/session-service/stored-reader.mjs +26 -1
- package/src/standalone/session-service.mjs +21 -0
- package/src/standalone/session-transport/routes.mjs +2 -0
- package/src/tui/app/doctor.mjs +7 -11
- package/src/tui/app/maintenance-pickers/auto-clear-picker.mjs +3 -5
- package/src/tui/app/model-picker/model-footer.mjs +2 -2
- package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +21 -2
- package/src/tui/app/model-picker/route-selection.mjs +6 -1
- package/src/tui/app/settings-picker/settings-rows.mjs +4 -6
- package/src/tui/app/settings-picker/settings-toggles/store-toggles.mjs +1 -1
- package/src/tui/app/slash-commands.mjs +1 -1
- package/src/tui/app/slash-dispatch/route-commands.mjs +5 -3
- package/src/tui/app/transcript-row-estimate.mjs +17 -5
- package/src/tui/components/ContextPanel.jsx +5 -1
- package/src/tui/components/Spinner.jsx +34 -319
- package/src/tui/components/SpinnerByline.jsx +256 -0
- package/src/tui/components/tool-execution/aggregate-card.jsx +4 -2
- package/src/tui/components/tool-execution/text-format.mjs +1 -0
- package/src/tui/components/use-spinner-progress.mjs +113 -0
- package/src/tui/dist/index.mjs +15896 -14452
- package/src/tui/session/agent-job-feed/execution-delivery.mjs +13 -1
- package/src/tui/session/agent-job-feed/notification-router.mjs +3 -0
- package/src/tui/session/agent-job-feed/pending-resume.mjs +14 -1
- package/src/tui/session/agent-job-feed.mjs +4 -0
- package/src/tui/session/context-state.mjs +13 -1
- package/src/tui/session/initial-state.mjs +6 -0
- package/src/tui/session/quota-resume.mjs +263 -0
- package/src/tui/session/session-api/intake/abort.mjs +39 -35
- package/src/tui/session/session-api/intake/submission.mjs +13 -21
- package/src/tui/session/session-api/intake.mjs +3 -3
- package/src/tui/session/session-api/integrations.mjs +5 -1
- package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
- package/src/tui/session/session-api/lifecycle/inheritance.mjs +2 -2
- package/src/tui/session/session-api/lifecycle/session-reset.mjs +4 -0
- package/src/tui/session/session-api/lifecycle.mjs +71 -2
- package/src/tui/session/session-api/media.mjs +2 -2
- package/src/tui/session/session-api/quota-resume.mjs +21 -0
- package/src/tui/session/session-api/routes.mjs +5 -2
- package/src/tui/session/session-api/settings.mjs +2 -0
- package/src/tui/session/session-api.mjs +2 -0
- package/src/tui/session/session-flow/auto-clear.mjs +14 -6
- package/src/tui/session/session-flow/drain.mjs +52 -5
- package/src/tui/session/session-flow/queue/take-entries.mjs +9 -4
- package/src/tui/session/session-flow/queue.mjs +4 -0
- package/src/tui/session/session-flow/steering.mjs +11 -0
- package/src/tui/session/session-flow.mjs +1 -0
- package/src/tui/session/tool-approval.mjs +7 -2
- package/src/tui/session/transcript-intake.mjs +1 -0
- package/src/tui/session/turn-tool-cards.mjs +4 -6
- package/src/tui/session/turn.mjs +40 -4
- package/src/vendor/statusline/bin/statusline-route.mjs +3 -2
- package/src/vendor/statusline/src/gateway/route-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-warmup.mjs +0 -165
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
// Verifies changelog/<lang>.md against CHANGELOG.md: same releases, same
|
|
2
|
+
// structure, and every machine-checkable token (code, links, issue refs,
|
|
3
|
+
// versions) preserved. Used by the desktop fast-lane test and, with
|
|
4
|
+
// --unreleased, by the Deploy release gate.
|
|
5
|
+
//
|
|
6
|
+
// node scripts/check-changelog-locales.mjs [--unreleased]
|
|
7
|
+
import { readFileSync } from 'node:fs';
|
|
8
|
+
import { dirname, join } from 'node:path';
|
|
9
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
10
|
+
|
|
11
|
+
/** Non-English UI languages (the keys of CATALOGS in the desktop i18n.ts). */
|
|
12
|
+
export const LOCALES = ['de', 'es', 'fr', 'it', 'ja', 'ko', 'pt-BR', 'ru', 'vi', 'zh-CN', 'zh-TW'];
|
|
13
|
+
|
|
14
|
+
const RELEASE_HEADING = /^v\d\S*(?:\s+-\s+\S+)?$/;
|
|
15
|
+
|
|
16
|
+
export function splitChangelog(text) {
|
|
17
|
+
const [intro, ...parts] = text.replace(/\r\n/g, '\n').split(/^## /m);
|
|
18
|
+
const sections = parts.map((part) => {
|
|
19
|
+
const newline = part.indexOf('\n');
|
|
20
|
+
const heading = (newline === -1 ? part : part.slice(0, newline)).trim();
|
|
21
|
+
return { heading, body: newline === -1 ? '' : part.slice(newline + 1) };
|
|
22
|
+
});
|
|
23
|
+
return { intro, sections };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const isUnreleased = (heading) => /^Unreleased\b/.test(heading);
|
|
27
|
+
const keyOf = (heading) => (isUnreleased(heading) ? 'Unreleased' : heading);
|
|
28
|
+
|
|
29
|
+
function selectSections(sections, includeUnreleased) {
|
|
30
|
+
return sections
|
|
31
|
+
.filter(({ heading }) => RELEASE_HEADING.test(heading) || (includeUnreleased && isUnreleased(heading)))
|
|
32
|
+
.map((section) => ({ ...section, key: keyOf(section.heading) }));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function analyze(body) {
|
|
36
|
+
const fences = [];
|
|
37
|
+
const prose = [];
|
|
38
|
+
const skeleton = [];
|
|
39
|
+
const items = [];
|
|
40
|
+
let fence = null;
|
|
41
|
+
let current = null;
|
|
42
|
+
for (const line of body.split('\n')) {
|
|
43
|
+
if (/^\s*(```|~~~)/.test(line)) {
|
|
44
|
+
current = null;
|
|
45
|
+
if (fence) {
|
|
46
|
+
fence.push(line);
|
|
47
|
+
fences.push(fence.join('\n'));
|
|
48
|
+
fence = null;
|
|
49
|
+
} else {
|
|
50
|
+
fence = [line];
|
|
51
|
+
skeleton.push('F');
|
|
52
|
+
}
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (fence) {
|
|
56
|
+
fence.push(line);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
prose.push(line);
|
|
60
|
+
const heading = /^(#{1,6})\s/.exec(line);
|
|
61
|
+
const item = /^(\s*)(?:[-*+]|\d+[.)])\s+(.*)$/.exec(line);
|
|
62
|
+
if (heading) {
|
|
63
|
+
skeleton.push(`H${heading[1].length}`);
|
|
64
|
+
current = null;
|
|
65
|
+
} else if (item) {
|
|
66
|
+
skeleton.push(`L${item[1].length}`);
|
|
67
|
+
current = { top: item[1].length === 0, lines: [item[2].trim()] };
|
|
68
|
+
items.push(current);
|
|
69
|
+
} else if (!line.trim()) {
|
|
70
|
+
current = null;
|
|
71
|
+
} else if (current) {
|
|
72
|
+
current.lines.push(line.trim());
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (fence) fences.push(fence.join('\n'));
|
|
76
|
+
return {
|
|
77
|
+
fences,
|
|
78
|
+
skeleton,
|
|
79
|
+
items: items.map((item) => ({ top: item.top, text: item.lines.join(' ') })),
|
|
80
|
+
prose: prose.join('\n'),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const CODE_SPAN = /(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/g;
|
|
85
|
+
const URL = /https?:\/\/[A-Za-z0-9\-._~:/?#@!$&'*+,;=%]+/g;
|
|
86
|
+
const LINK_TARGET = /\]\(\s*<?([^)\s>]+)/g;
|
|
87
|
+
const ISSUE_REF = /(?<![\w&/])#\d+\b/g;
|
|
88
|
+
const VERSION = /(?<![\w.])v?\d+\.\d+\.\d+(?:-[\w.]+)?(?!\w)/g;
|
|
89
|
+
|
|
90
|
+
function tokens(prose) {
|
|
91
|
+
const code = [...prose.matchAll(CODE_SPAN)].map((match) => match[2].replace(/\s+/g, ' ').trim());
|
|
92
|
+
const bare = prose.replace(CODE_SPAN, ' ');
|
|
93
|
+
const urls = [...bare.matchAll(URL)].map((match) => match[0].replace(/[.,;:!?']+$/, ''));
|
|
94
|
+
const targets = [...bare.matchAll(LINK_TARGET)].map((match) => match[1]);
|
|
95
|
+
const rest = bare.replace(URL, ' ');
|
|
96
|
+
return {
|
|
97
|
+
'inline code': code,
|
|
98
|
+
'link targets': [...urls, ...targets],
|
|
99
|
+
'issue references': rest.match(ISSUE_REF) ?? [],
|
|
100
|
+
'version strings': rest.match(VERSION) ?? [],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function multisetDiff(expected, actual) {
|
|
105
|
+
const counts = new Map();
|
|
106
|
+
for (const value of expected) counts.set(value, (counts.get(value) ?? 0) + 1);
|
|
107
|
+
const extra = [];
|
|
108
|
+
for (const value of actual) {
|
|
109
|
+
const left = counts.get(value) ?? 0;
|
|
110
|
+
if (left > 0) counts.set(value, left - 1);
|
|
111
|
+
else extra.push(value);
|
|
112
|
+
}
|
|
113
|
+
const missing = [...counts].flatMap(([value, left]) => Array(left).fill(value));
|
|
114
|
+
return { missing, extra };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function compareMultiset(label, expected, actual, problems) {
|
|
118
|
+
const { missing, extra } = multisetDiff(expected, actual);
|
|
119
|
+
if (!missing.length && !extra.length) return;
|
|
120
|
+
problems.push(`${label}: differs (missing: ${JSON.stringify(missing)}; unexpected: ${JSON.stringify(extra)})`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const codeOnly = (text) => !/\p{L}/u.test(text.replace(CODE_SPAN, ' '));
|
|
124
|
+
|
|
125
|
+
function checkSection(label, englishBody, localeBody, problems) {
|
|
126
|
+
const english = analyze(englishBody);
|
|
127
|
+
const locale = analyze(localeBody);
|
|
128
|
+
const topCount = (analysis) => analysis.items.filter((item) => item.top).length;
|
|
129
|
+
if (topCount(english) !== topCount(locale)) {
|
|
130
|
+
problems.push(`${label}: ${topCount(locale)} top-level list items, English has ${topCount(english)}`);
|
|
131
|
+
}
|
|
132
|
+
const structureMatches = english.skeleton.join(' ') === locale.skeleton.join(' ');
|
|
133
|
+
if (!structureMatches) {
|
|
134
|
+
problems.push(
|
|
135
|
+
`${label}: structure differs (headings/lists/code blocks): expected [${english.skeleton.join(' ')}], got [${locale.skeleton.join(' ')}]`
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
compareMultiset(`${label}: fenced code blocks`, english.fences, locale.fences, problems);
|
|
139
|
+
const englishTokens = tokens(english.prose);
|
|
140
|
+
const localeTokens = tokens(locale.prose);
|
|
141
|
+
for (const kind of Object.keys(englishTokens)) {
|
|
142
|
+
compareMultiset(`${label}: ${kind}`, englishTokens[kind], localeTokens[kind], problems);
|
|
143
|
+
}
|
|
144
|
+
if (structureMatches) {
|
|
145
|
+
english.items.forEach((item, index) => {
|
|
146
|
+
if (item.text === locale.items[index].text && !codeOnly(item.text)) {
|
|
147
|
+
problems.push(`${label}: list item ${index + 1} is not translated: ${JSON.stringify(item.text.slice(0, 80))}`);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Problems found in one locale file's text against the English changelog text. */
|
|
154
|
+
export function checkLocaleText(englishText, localeText, { includeUnreleased = false } = {}) {
|
|
155
|
+
const problems = [];
|
|
156
|
+
const english = splitChangelog(englishText);
|
|
157
|
+
const locale = splitChangelog(localeText);
|
|
158
|
+
if (english.intro.trim() === locale.intro.trim()) problems.push('intro: not translated (identical to English)');
|
|
159
|
+
const englishSections = selectSections(english.sections, includeUnreleased);
|
|
160
|
+
const localeSections = selectSections(locale.sections, includeUnreleased);
|
|
161
|
+
const englishKeys = englishSections.map((section) => section.key);
|
|
162
|
+
const localeKeys = localeSections.map((section) => section.key);
|
|
163
|
+
const missing = englishKeys.filter((key) => !localeKeys.includes(key));
|
|
164
|
+
const extra = localeKeys.filter((key) => !englishKeys.includes(key));
|
|
165
|
+
for (const key of missing) problems.push(`${key}: section missing`);
|
|
166
|
+
for (const key of extra) problems.push(`${key}: section not in CHANGELOG.md`);
|
|
167
|
+
if (!missing.length && !extra.length && englishKeys.join('\n') !== localeKeys.join('\n')) {
|
|
168
|
+
problems.push(`section order differs: expected [${englishKeys.join(', ')}], got [${localeKeys.join(', ')}]`);
|
|
169
|
+
}
|
|
170
|
+
for (const section of englishSections) {
|
|
171
|
+
const match = localeSections.find((candidate) => candidate.key === section.key);
|
|
172
|
+
if (match) checkSection(section.key, section.body, match.body, problems);
|
|
173
|
+
}
|
|
174
|
+
return problems;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** Problems for every locale file under `<root>/changelog/`, prefixed with the file. */
|
|
178
|
+
export function checkChangelogLocales({
|
|
179
|
+
root = join(dirname(fileURLToPath(import.meta.url)), '..'),
|
|
180
|
+
includeUnreleased = false,
|
|
181
|
+
locales = LOCALES,
|
|
182
|
+
} = {}) {
|
|
183
|
+
const englishText = readFileSync(join(root, 'CHANGELOG.md'), 'utf8');
|
|
184
|
+
return locales.flatMap((language) => {
|
|
185
|
+
const file = `changelog/${language}.md`;
|
|
186
|
+
let text;
|
|
187
|
+
try {
|
|
188
|
+
text = readFileSync(join(root, file), 'utf8');
|
|
189
|
+
} catch {
|
|
190
|
+
return [`${file}: file is missing`];
|
|
191
|
+
}
|
|
192
|
+
return checkLocaleText(englishText, text, { includeUnreleased }).map((problem) => `${file}: ${problem}`);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
197
|
+
const problems = checkChangelogLocales({ includeUnreleased: process.argv.includes('--unreleased') });
|
|
198
|
+
if (problems.length) {
|
|
199
|
+
console.error(problems.join('\n'));
|
|
200
|
+
process.exit(1);
|
|
201
|
+
}
|
|
202
|
+
console.log(`check-changelog-locales: OK (${LOCALES.length} locales)`);
|
|
203
|
+
}
|
|
@@ -29,8 +29,6 @@ const host = load(hostPath);
|
|
|
29
29
|
const sequence = load(sequencePath);
|
|
30
30
|
const rows = Array.isArray(model.rows) ? model.rows : [];
|
|
31
31
|
const totalInputTokens = rows.map((row) => row.usage?.inputTokens);
|
|
32
|
-
const mainInputTokens = rows.map((row) => row.usage?.mainInputTokens);
|
|
33
|
-
const warmupInputTokens = rows.map((row) => row.usage?.warmupInputTokens);
|
|
34
32
|
const cachedTokens = rows.map((row) => row.usage?.cachedTokens);
|
|
35
33
|
const uncachedTokens = rows.map((row) => Number(row.usage?.inputTokens || 0) - Number(row.usage?.cachedTokens || 0));
|
|
36
34
|
const outputTokens = rows.map((row) => row.usage?.outputTokens);
|
|
@@ -60,8 +58,6 @@ const report = {
|
|
|
60
58
|
samples: rows.length,
|
|
61
59
|
first_call_success_rate: model.summary?.first_call_success_rate ?? null,
|
|
62
60
|
total_input_tokens: perToolCallInput,
|
|
63
|
-
main_input_tokens: distribution(mainInputTokens),
|
|
64
|
-
warmup_input_tokens: distribution(warmupInputTokens),
|
|
65
61
|
cached_tokens: distribution(cachedTokens),
|
|
66
62
|
uncached_tokens: distribution(uncachedTokens),
|
|
67
63
|
output_tokens: distribution(outputTokens),
|
|
@@ -2,10 +2,12 @@ import { spawn } from 'node:child_process';
|
|
|
2
2
|
import { appendFile, mkdtemp, readdir, readFile, rm, stat } from 'node:fs/promises';
|
|
3
3
|
import { availableParallelism, tmpdir } from 'node:os';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
|
-
import {
|
|
5
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
6
|
+
import { FAILURE_RECORDS_ENV, spawnLedgerPath } from './test-failure-records.mjs';
|
|
6
7
|
import { classifyRerunOutcomes, formatFailureSummary } from './test-failure-summary.mjs';
|
|
7
8
|
|
|
8
9
|
const SUMMARY_REPORTER = new URL('./test-summary-reporter.mjs', import.meta.url).href;
|
|
10
|
+
const SPAWN_LEDGER = new URL('./test-spawn-ledger.mjs', import.meta.url).href;
|
|
9
11
|
|
|
10
12
|
// A whole-suite run passes ~700 paths to one node process. Windows caps a
|
|
11
13
|
// command line at 32767 characters (CreateProcess) and POSIX caps argv+env at
|
|
@@ -81,17 +83,212 @@ export function testConcurrencyArg(nodeArgs, env = process.env, parallelism = av
|
|
|
81
83
|
return `--test-concurrency=${Math.max(2, Math.floor(parallelism / cap))}`;
|
|
82
84
|
}
|
|
83
85
|
|
|
84
|
-
|
|
86
|
+
// A batch that has not exited by then is killed with its process tree and
|
|
87
|
+
// fails the run; MIXDOG_TEST_BATCH_TIMEOUT_MS overrides the default.
|
|
88
|
+
const DEFAULT_BATCH_TIMEOUT_MS = 60 * 60 * 1000;
|
|
89
|
+
const minutes = (ms) => Number((ms / 60_000).toFixed(2));
|
|
90
|
+
|
|
91
|
+
// Runs a helper command to completion and returns its stdout.
|
|
92
|
+
function capture(command, args) {
|
|
85
93
|
return new Promise((resolve) => {
|
|
86
|
-
const child = spawn(
|
|
94
|
+
const child = spawn(command, args, { stdio: ['ignore', 'pipe', 'ignore'], windowsHide: true });
|
|
95
|
+
let out = '';
|
|
96
|
+
child.stdout.setEncoding('utf8');
|
|
97
|
+
child.stdout.on('data', (chunk) => {
|
|
98
|
+
out += chunk;
|
|
99
|
+
});
|
|
100
|
+
child.on('error', (error) => {
|
|
101
|
+
console.error(`${command} failed: ${error.message}`);
|
|
102
|
+
resolve('');
|
|
103
|
+
});
|
|
104
|
+
child.on('close', () => resolve(out));
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Kills a process and every descendant still linked to it. On POSIX a batch
|
|
109
|
+
// leads its own process group (spawned detached), so the group goes with it.
|
|
110
|
+
async function killTree(pid) {
|
|
111
|
+
if (process.platform === 'win32') {
|
|
112
|
+
await capture('taskkill', ['/T', '/F', '/PID', String(pid)]);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
for (const target of [-pid, pid]) {
|
|
116
|
+
try {
|
|
117
|
+
process.kill(target, 'SIGKILL');
|
|
118
|
+
} catch {
|
|
119
|
+
/* already gone */
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Every live process: { pid, ppid, created (epoch ms), exe ('' when unknown) }.
|
|
125
|
+
// POSIX ps only reports elapsed seconds, so its creation times are ±1 s.
|
|
126
|
+
async function processSnapshot() {
|
|
127
|
+
if (process.platform === 'win32') {
|
|
128
|
+
const out = await capture('powershell', [
|
|
129
|
+
'-NoProfile',
|
|
130
|
+
'-NonInteractive',
|
|
131
|
+
'-Command',
|
|
132
|
+
"Get-CimInstance Win32_Process | Where-Object CreationDate | ForEach-Object { '{0} {1} {2} {3}' -f $_.ProcessId, $_.ParentProcessId, ([DateTimeOffset]$_.CreationDate).ToUnixTimeMilliseconds(), $_.ExecutablePath }",
|
|
133
|
+
]);
|
|
134
|
+
return out
|
|
135
|
+
.split(/\r?\n/)
|
|
136
|
+
.filter(Boolean)
|
|
137
|
+
.map((line) => {
|
|
138
|
+
const [pid, ppid, created, ...exe] = line.split(' ');
|
|
139
|
+
return { pid: Number(pid), ppid: Number(ppid), created: Number(created), exe: exe.join(' ') };
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
const now = Date.now();
|
|
143
|
+
const out = await capture('ps', ['-A', '-o', 'pid=,ppid=,etime=']);
|
|
144
|
+
return out
|
|
145
|
+
.split('\n')
|
|
146
|
+
.map((line) => line.trim().split(/\s+/))
|
|
147
|
+
.filter((fields) => fields.length === 3)
|
|
148
|
+
.map(([pid, ppid, etime]) => {
|
|
149
|
+
// [[dd-]hh:]mm:ss
|
|
150
|
+
const [days, clock] = etime.includes('-') ? etime.split('-') : ['0', etime];
|
|
151
|
+
const seconds = clock.split(':').reduce((total, part) => total * 60 + Number(part), Number(days) * 86_400);
|
|
152
|
+
return { pid: Number(pid), ppid: Number(ppid), created: now - seconds * 1000, exe: '' };
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const CLOCK_SLACK_MS = 2000;
|
|
157
|
+
|
|
158
|
+
// The processes this run owns, out of a snapshot: an anchor (the batch, or a
|
|
159
|
+
// child a test process recorded in its spawn ledger) still alive under its
|
|
160
|
+
// pid, the orphans an exited anchor left (they still name it as their parent;
|
|
161
|
+
// a later process that reuses its pid only has younger children), every
|
|
162
|
+
// descendant of those, and anything executing from the run's scratch root
|
|
163
|
+
// (e.g. the postgres the memory runtime downloads into MIXDOG_DATA_DIR).
|
|
164
|
+
// Command-line text never makes a process the run's: an editor or terminal
|
|
165
|
+
// opened on the scratch root is not.
|
|
166
|
+
export function ownedProcesses(snapshot, anchors, { batchStart, scratchDir, platform = process.platform }) {
|
|
167
|
+
const byPid = new Map(snapshot.map((entry) => [entry.pid, entry]));
|
|
168
|
+
const childrenOf = new Map();
|
|
169
|
+
for (const entry of snapshot) childrenOf.set(entry.ppid, [...(childrenOf.get(entry.ppid) ?? []), entry]);
|
|
170
|
+
const owned = new Map();
|
|
171
|
+
const queue = [];
|
|
172
|
+
const claim = (entry) => {
|
|
173
|
+
if (entry.pid === process.pid || owned.has(entry.pid)) return;
|
|
174
|
+
owned.set(entry.pid, entry);
|
|
175
|
+
queue.push(entry);
|
|
176
|
+
};
|
|
177
|
+
for (const { pid, since } of anchors) {
|
|
178
|
+
const holder = byPid.get(pid);
|
|
179
|
+
if (holder && holder.created >= batchStart - CLOCK_SLACK_MS && holder.created <= since + CLOCK_SLACK_MS) {
|
|
180
|
+
claim(holder);
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
for (const orphan of childrenOf.get(pid) ?? []) {
|
|
184
|
+
if (orphan.created >= since - CLOCK_SLACK_MS && (!holder || orphan.created < holder.created)) claim(orphan);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const fold = (path) => (platform === 'win32' ? path.toLowerCase() : path);
|
|
188
|
+
const scratchPrefix = fold(join(scratchDir, '/'));
|
|
189
|
+
for (const entry of snapshot) if (entry.exe && fold(entry.exe).startsWith(scratchPrefix)) claim(entry);
|
|
190
|
+
while (queue.length > 0) {
|
|
191
|
+
const parent = queue.pop();
|
|
192
|
+
for (const entry of childrenOf.get(parent.pid) ?? []) {
|
|
193
|
+
if (entry.created >= parent.created - CLOCK_SLACK_MS) claim(entry);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return [...owned.values()];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async function readSpawnLedger(path) {
|
|
200
|
+
const text = await readFile(path, 'utf8').catch(() => '');
|
|
201
|
+
return text
|
|
202
|
+
.split('\n')
|
|
203
|
+
.filter(Boolean)
|
|
204
|
+
.map((line) => {
|
|
205
|
+
const [pid, since] = line.split(' ').map(Number);
|
|
206
|
+
return { pid, since };
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// A process a test leaves running must not outlive its batch: it can hold a
|
|
211
|
+
// port, a database, or files in the scratch root the run removes at the end.
|
|
212
|
+
async function reapLeftovers(child, { batchStart, ledger, scratchDir }) {
|
|
213
|
+
// The batch itself has exited: only its process group can remain.
|
|
214
|
+
if (process.platform !== 'win32' && child.pid) {
|
|
215
|
+
try {
|
|
216
|
+
process.kill(-child.pid, 'SIGKILL');
|
|
217
|
+
} catch {
|
|
218
|
+
/* the group is empty */
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
const anchors = [...(child.pid ? [{ pid: child.pid, since: batchStart }] : []), ...(await readSpawnLedger(ledger))];
|
|
222
|
+
const leftovers = ownedProcesses(await processSnapshot(), anchors, { batchStart, scratchDir });
|
|
223
|
+
if (leftovers.length === 0) return;
|
|
224
|
+
const pids = leftovers.map((entry) => entry.pid);
|
|
225
|
+
console.error(`Killing ${pids.length} process(es) a test left running: ${pids.join(' ')}`);
|
|
226
|
+
if (process.platform === 'win32') {
|
|
227
|
+
await capture('taskkill', ['/T', '/F', ...pids.flatMap((pid) => ['/PID', String(pid)])]);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
for (const pid of pids) {
|
|
231
|
+
try {
|
|
232
|
+
process.kill(pid, 'SIGKILL');
|
|
233
|
+
} catch {
|
|
234
|
+
/* already gone */
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Resolves { code, hung } once the batch exited and its leftovers are gone.
|
|
240
|
+
function spawnBatch(args, env, { files, ledger, scratchDir, timeoutMs }) {
|
|
241
|
+
return new Promise((resolve) => {
|
|
242
|
+
const batchStart = Date.now();
|
|
243
|
+
const child = spawn(process.execPath, args, { stdio: 'inherit', env, detached: process.platform !== 'win32' });
|
|
244
|
+
let hung = '';
|
|
245
|
+
const watchdog = setTimeout(() => {
|
|
246
|
+
hung = `hung after ${minutes(timeoutMs)} min: ${files.join(' ') || '(discovered files)'}`;
|
|
247
|
+
console.error(`Test batch ${hung}; killing its process tree`);
|
|
248
|
+
void killTree(child.pid);
|
|
249
|
+
}, timeoutMs);
|
|
250
|
+
// A detached POSIX batch no longer gets the terminal's signals itself.
|
|
251
|
+
const forward = (signal) => {
|
|
252
|
+
try {
|
|
253
|
+
process.kill(-child.pid, signal);
|
|
254
|
+
} catch {
|
|
255
|
+
/* already gone */
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
const signals = process.platform === 'win32' ? [] : ['SIGINT', 'SIGTERM'];
|
|
259
|
+
for (const signal of signals) process.on(signal, forward);
|
|
260
|
+
const settle = async (code) => {
|
|
261
|
+
clearTimeout(watchdog);
|
|
262
|
+
for (const signal of signals) process.off(signal, forward);
|
|
263
|
+
await reapLeftovers(child, { batchStart, ledger, scratchDir });
|
|
264
|
+
resolve({ code: hung ? 1 : code, hung });
|
|
265
|
+
};
|
|
87
266
|
child.on('error', (error) => {
|
|
88
267
|
console.error(error);
|
|
89
|
-
|
|
268
|
+
void settle(1);
|
|
90
269
|
});
|
|
91
|
-
child.on('exit', (code, signal) =>
|
|
270
|
+
child.on('exit', (code, signal) => void settle(code ?? (signal ? 1 : 0)));
|
|
92
271
|
});
|
|
93
272
|
}
|
|
94
273
|
|
|
274
|
+
// rm's own maxRetries re-walks the tree on every nested retry, so one held
|
|
275
|
+
// file a few directories down multiplied its delay into hours. Each pass here
|
|
276
|
+
// is a single bounded walk.
|
|
277
|
+
async function removeScratch(dir) {
|
|
278
|
+
for (let attempt = 1; ; attempt += 1) {
|
|
279
|
+
try {
|
|
280
|
+
await rm(dir, { recursive: true, force: true });
|
|
281
|
+
return;
|
|
282
|
+
} catch (error) {
|
|
283
|
+
if (attempt === 5) {
|
|
284
|
+
console.error(`Test scratch left behind (${error.code}): ${dir}`);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
await delay(200 * attempt);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
95
292
|
// The failure reporter writes one JSON line per failed test; a spawn that
|
|
96
293
|
// died before Node opened its destination leaves no file at all.
|
|
97
294
|
async function readFailureRecords(path) {
|
|
@@ -136,6 +333,8 @@ export async function runNodeTests(
|
|
|
136
333
|
const runArgs = [
|
|
137
334
|
...nodeArgs,
|
|
138
335
|
...(concurrencyArg ? [concurrencyArg] : []),
|
|
336
|
+
// Node's test runner passes --import on to every test file process.
|
|
337
|
+
`--import=${SPAWN_LEDGER}`,
|
|
139
338
|
`--test-reporter=${SUMMARY_REPORTER}`,
|
|
140
339
|
'--test-reporter-destination=stdout',
|
|
141
340
|
'--test-reporter=spec',
|
|
@@ -171,15 +370,25 @@ export async function runNodeTests(
|
|
|
171
370
|
...(coverageDir ? { NODE_V8_COVERAGE: coverageDir } : {}),
|
|
172
371
|
...(nodeOptions ? { NODE_OPTIONS: nodeOptions } : {}),
|
|
173
372
|
});
|
|
373
|
+
const batchOptions = (files, recordsPath) => ({
|
|
374
|
+
files,
|
|
375
|
+
ledger: spawnLedgerPath(recordsPath),
|
|
376
|
+
scratchDir,
|
|
377
|
+
timeoutMs: positiveInt(process.env.MIXDOG_TEST_BATCH_TIMEOUT_MS) ?? DEFAULT_BATCH_TIMEOUT_MS,
|
|
378
|
+
});
|
|
174
379
|
let status = 0;
|
|
175
380
|
const failures = [];
|
|
381
|
+
const hung = [];
|
|
176
382
|
for (const [index, batch] of batches.entries()) {
|
|
177
383
|
const batchLog = batches.length === 1 ? logPath : `${logPath}.${index + 1}`;
|
|
178
384
|
const batchFailures = join(failureDir, `batch-${index + 1}.jsonl`);
|
|
179
|
-
const
|
|
385
|
+
const outcome = await spawnBatch(
|
|
180
386
|
[...runArgs, `--test-reporter-destination=${batchLog}`, ...batch],
|
|
181
|
-
childEnv(batchFailures)
|
|
387
|
+
childEnv(batchFailures),
|
|
388
|
+
batchOptions(batch, batchFailures)
|
|
182
389
|
);
|
|
390
|
+
const { code } = outcome;
|
|
391
|
+
if (outcome.hung) hung.push(outcome.hung);
|
|
183
392
|
if (batchLog !== logPath) {
|
|
184
393
|
await appendFile(logPath, await readFile(batchLog));
|
|
185
394
|
await rm(batchLog, { force: true });
|
|
@@ -196,10 +405,13 @@ export async function runNodeTests(
|
|
|
196
405
|
console.error(`Re-running ${files.length} failed file(s): attempt ${attempt}/${rerunFailed}`);
|
|
197
406
|
const attemptLog = `${logPath}.rerun-${attempt}`;
|
|
198
407
|
const attemptFailures = join(failureDir, `rerun-${attempt}.jsonl`);
|
|
199
|
-
|
|
408
|
+
const outcome = await spawnBatch(
|
|
200
409
|
[...runArgs, `--test-reporter-destination=${attemptLog}`, ...files],
|
|
201
|
-
childEnv(attemptFailures)
|
|
410
|
+
childEnv(attemptFailures),
|
|
411
|
+
batchOptions(files, attemptFailures)
|
|
202
412
|
);
|
|
413
|
+
lastAttemptStatus = outcome.code;
|
|
414
|
+
if (outcome.hung) hung.push(outcome.hung);
|
|
203
415
|
await appendFile(logPath, await readFile(attemptLog));
|
|
204
416
|
await rm(attemptLog, { force: true });
|
|
205
417
|
attempts.push({ files, failures: await readFailureRecords(attemptFailures) });
|
|
@@ -209,17 +421,27 @@ export async function runNodeTests(
|
|
|
209
421
|
// Flaky tolerance applies only to an ordinary test-failure exit that the
|
|
210
422
|
// re-runs fully explained: nothing failed twice and the last re-run itself
|
|
211
423
|
// came back clean.
|
|
212
|
-
|
|
424
|
+
// A hung batch is never explained by re-runs.
|
|
425
|
+
if (
|
|
426
|
+
rerunFailed > 0 &&
|
|
427
|
+
status === 1 &&
|
|
428
|
+
hung.length === 0 &&
|
|
429
|
+
failed.length === 0 &&
|
|
430
|
+
flaky.length > 0 &&
|
|
431
|
+
lastAttemptStatus === 0
|
|
432
|
+
)
|
|
433
|
+
status = 0;
|
|
213
434
|
process.exitCode = status;
|
|
214
435
|
|
|
215
436
|
await rm(failureDir, { recursive: true, force: true });
|
|
216
|
-
//
|
|
217
|
-
|
|
437
|
+
// Leftover processes are already killed; what a process outside the run
|
|
438
|
+
// still holds stays behind.
|
|
439
|
+
await removeScratch(scratchDir);
|
|
218
440
|
if (coverageDir) {
|
|
219
441
|
const { reportCoverage } = await import('./coverage.mjs');
|
|
220
442
|
await reportCoverage(coverageDir);
|
|
221
443
|
await rm(coverageDir, { recursive: true, force: true });
|
|
222
444
|
}
|
|
223
445
|
// Last line of the run, after every reporter and the coverage report.
|
|
224
|
-
process.stdout.write(`\n${formatFailureSummary({ failed, flaky, rerunFailed })}`);
|
|
446
|
+
process.stdout.write(`\n${formatFailureSummary({ failed, flaky, rerunFailed, hung })}`);
|
|
225
447
|
}
|
|
@@ -13,6 +13,11 @@ import { relative } from 'node:path';
|
|
|
13
13
|
|
|
14
14
|
export const FAILURE_RECORDS_ENV = 'MIXDOG_TEST_FAILURE_RECORDS';
|
|
15
15
|
|
|
16
|
+
// Every child process a test process starts is logged beside its spawn's
|
|
17
|
+
// failure records (scripts/lib/test-spawn-ledger.mjs), so the runner can tell
|
|
18
|
+
// a process the run started from one that merely names its directories.
|
|
19
|
+
export const spawnLedgerPath = (recordsPath) => (recordsPath ? `${recordsPath}.spawns` : '');
|
|
20
|
+
|
|
16
21
|
// Ancestor names are tracked per file: node:test runs files concurrently, so
|
|
17
22
|
// one flat stack would mix their nestings.
|
|
18
23
|
export function failureRecord(event, stacks) {
|
|
@@ -43,8 +43,14 @@ export function policyLine(rerunFailed) {
|
|
|
43
43
|
: 'policy: --rerun-failed is off, so every failure fails the run (pass --rerun-failed <n> to classify flaky)';
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
// `hung` holds one "hung after N min: <files>" message per batch the runner's
|
|
47
|
+
// watchdog killed; such a batch fails the run whatever its tests reported.
|
|
48
|
+
export function formatFailureSummary({ failed = [], flaky = [], rerunFailed = 0, hung = [] }) {
|
|
49
|
+
const hungCount = hung.length > 0 ? `, ${hung.length} hung batch(es)` : '';
|
|
50
|
+
const lines = [
|
|
51
|
+
`${SUMMARY_TAG} ${failed.length} failed, ${flaky.length} flaky${hungCount} (every failed test is named below)`,
|
|
52
|
+
];
|
|
53
|
+
for (const message of hung) lines.push(`${SUMMARY_TAG} HUNG ${message}`);
|
|
48
54
|
for (const record of failed) {
|
|
49
55
|
const origin = record.firstSeenOnRerun ? ` (first seen on re-run ${record.firstSeenOnRerun})` : '';
|
|
50
56
|
lines.push(`${SUMMARY_TAG} FAILED ${record.file} > ${record.name}${origin}`);
|
|
@@ -54,6 +60,6 @@ export function formatFailureSummary({ failed = [], flaky = [], rerunFailed = 0
|
|
|
54
60
|
`${SUMMARY_TAG} FLAKY ${record.file} > ${record.name} (failed, then passed on re-run ${record.passedOnAttempt}/${rerunFailed})`
|
|
55
61
|
);
|
|
56
62
|
}
|
|
57
|
-
if (failed.length > 0 || flaky.length > 0) lines.push(`${SUMMARY_TAG} ${policyLine(rerunFailed)}`);
|
|
63
|
+
if (failed.length > 0 || flaky.length > 0 || hung.length > 0) lines.push(`${SUMMARY_TAG} ${policyLine(rerunFailed)}`);
|
|
58
64
|
return `${lines.join('\n')}\n`;
|
|
59
65
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Preloaded (--import) into every test process the runner starts: records
|
|
2
|
+
// "<pid> <spawn time ms>" for each child process, so a process a test leaves
|
|
3
|
+
// running can be traced back to the run after its parent exited
|
|
4
|
+
// (scripts/lib/run-node-tests.mjs). Without the runner's environment it does
|
|
5
|
+
// nothing.
|
|
6
|
+
import { ChildProcess } from 'node:child_process';
|
|
7
|
+
import { appendFileSync } from 'node:fs';
|
|
8
|
+
import { FAILURE_RECORDS_ENV, spawnLedgerPath } from './test-failure-records.mjs';
|
|
9
|
+
|
|
10
|
+
const ledger = spawnLedgerPath(process.env[FAILURE_RECORDS_ENV]);
|
|
11
|
+
if (ledger) {
|
|
12
|
+
// spawn, exec, execFile and fork all start their process here.
|
|
13
|
+
const spawn = ChildProcess.prototype.spawn;
|
|
14
|
+
ChildProcess.prototype.spawn = function recordedSpawn(...args) {
|
|
15
|
+
const result = spawn.apply(this, args);
|
|
16
|
+
if (this.pid) appendFileSync(ledger, `${this.pid} ${Date.now()}\n`);
|
|
17
|
+
return result;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { access, readdir, rm } from 'node:fs/promises';
|
|
4
4
|
import { dirname, join, resolve } from 'node:path';
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
6
|
+
import { onnxRuntimeSupported } from '../src/runtime/shared/onnx-runtime-support.mjs';
|
|
6
7
|
|
|
7
8
|
const SUPPORTED_TARGETS = new Map([
|
|
8
9
|
['win32', new Set(['x64', 'arm64'])],
|
|
@@ -83,8 +84,9 @@ export async function pruneEmbeddingRuntime(packageRoot, options = {}) {
|
|
|
83
84
|
).find(Boolean);
|
|
84
85
|
if (!ortRoot) throw new Error('Embedding runtime is incomplete: onnxruntime-node is unavailable');
|
|
85
86
|
|
|
86
|
-
const
|
|
87
|
-
|
|
87
|
+
const onnx = onnxRuntimeSupported(target.platform, target.arch);
|
|
88
|
+
const targetBinaryDir = onnx ? join(ortRoot, 'bin', 'napi-v6', target.platform, target.arch) : null;
|
|
89
|
+
if (onnx && !(await exists(join(targetBinaryDir, 'onnxruntime_binding.node')))) {
|
|
88
90
|
throw new Error(`Embedding runtime is incomplete: missing ${target.key} ONNX binding`);
|
|
89
91
|
}
|
|
90
92
|
|
|
@@ -100,10 +102,11 @@ export async function pruneEmbeddingRuntime(packageRoot, options = {}) {
|
|
|
100
102
|
// bin/napi-v6/${process.platform}/${process.arch}/onnxruntime_binding.node.
|
|
101
103
|
// Keep one native payload and remove every foreign OS/architecture.
|
|
102
104
|
const napiRoot = join(ortRoot, 'bin', 'napi-v6');
|
|
103
|
-
|
|
104
|
-
await removeChildrenExcept(
|
|
105
|
+
// Targets without an ONNX binding keep no native payload at all.
|
|
106
|
+
await removeChildrenExcept(napiRoot, new Set(onnx ? [target.platform] : []));
|
|
107
|
+
if (onnx) await removeChildrenExcept(join(napiRoot, target.platform), new Set([target.arch]));
|
|
105
108
|
const removedTargetFiles = [];
|
|
106
|
-
if (target.platform === 'win32') {
|
|
109
|
+
if (onnx && target.platform === 'win32') {
|
|
107
110
|
// The fixed production embedding profile uses CPU inference. Keep
|
|
108
111
|
// DirectML.dll for explicit device overrides, but remove the optional DXC
|
|
109
112
|
// shader compiler payload verified unnecessary by packaged-runtime warmup.
|
|
@@ -132,6 +135,7 @@ export async function pruneEmbeddingRuntime(packageRoot, options = {}) {
|
|
|
132
135
|
...target,
|
|
133
136
|
transformerRoot,
|
|
134
137
|
ortRoot,
|
|
138
|
+
onnx,
|
|
135
139
|
targetBinaryDir,
|
|
136
140
|
removedTargetFiles,
|
|
137
141
|
};
|