mixdog 1.4.0 → 1.4.2
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/package.json +3 -2
- package/scripts/build-shipped-history.mjs +115 -33
- package/scripts/check-voice-runtime-inputs.mjs +25 -0
- package/scripts/gate-local.mjs +183 -63
- package/scripts/latest-guard.mjs +21 -9
- package/scripts/lib/gate-scheduler.mjs +138 -32
- package/scripts/lib/gate-timing-reporter.mjs +16 -0
- package/scripts/lib/isolated-test-env.mjs +10 -5
- package/scripts/lib/run-node-tests.mjs +91 -66
- package/scripts/lib/scoped-temp.d.mts +16 -0
- package/scripts/lib/scoped-temp.mjs +124 -0
- package/scripts/lib/stale-temp.mjs +44 -0
- package/scripts/lib/test-failure-records.mjs +14 -1
- package/scripts/lib/test-failure-summary.mjs +16 -4
- package/scripts/lib/test-spawn-ledger.mjs +12 -3
- package/scripts/post-release-check.mjs +1 -6
- package/scripts/pptx-kit-index.mjs +17 -5
- package/scripts/suite-health.mjs +115 -24
- package/scripts/test-data-dir.mjs +10 -7
- package/scripts/test.mjs +9 -14
- package/src/agents/advisor/AGENT.md +4 -4
- package/src/agents/advisor/agent.json +1 -1
- package/src/agents/explore/AGENT.md +22 -0
- package/src/agents/explore/agent.json +6 -0
- package/src/app.mjs +4 -0
- package/src/cli.mjs +7 -0
- package/src/defaults/agents.json +7 -0
- package/src/defaults/shipped-history.json +23 -2
- package/src/defaults/skills/browser-use/SKILL.md +10 -5
- package/src/defaults/skills/code-tidy/SKILL.md +71 -102
- package/src/defaults/skills/code-tidy/references/agent-cleanup.md +66 -114
- package/src/defaults/skills/code-tidy/references/cleanup-report.md +19 -35
- package/src/defaults/skills/code-tidy/references/dead-code.md +3 -9
- package/src/defaults/skills/code-tidy/references/test-suite-slop.md +16 -27
- package/src/defaults/skills/computer-use/SKILL.md +16 -4
- package/src/defaults/skills/goal-management/SKILL.md +1 -1
- package/src/defaults/skills/setup/references/actions.md +12 -6
- package/src/defaults/skills/setup/references/surfaces.md +2 -2
- package/src/defaults/skills/setup-guide/SKILL.md +5 -2
- package/src/defaults/skills/setup-guide/model-recommendations.json +13 -0
- package/src/defaults/skills/skill-creator/SKILL.md +85 -190
- package/src/defaults/skills/skill-creator/references/design.md +70 -162
- package/src/defaults/skills/skill-creator/references/evaluation.md +33 -92
- package/src/defaults/skills/test-suite/SKILL.md +194 -0
- package/src/defaults/skills/test-suite/references/case-management.md +51 -0
- package/src/defaults/skills/test-suite/references/flaky-policy.md +39 -0
- package/src/defaults/skills/test-suite/references/reliability.md +49 -0
- package/src/defaults/skills/test-suite/references/suite-design.md +78 -0
- package/src/defaults/skills/test-suite/scripts/inventory.mjs +335 -0
- package/src/defaults/skills/visualize/SKILL.md +6 -2
- package/src/lib/rules-builder.cjs +35 -42
- package/src/output-styles/common.md +2 -2
- package/src/output-styles/simple.md +1 -1
- package/src/rules/agent/AGENT.md +5 -4
- package/src/rules/lead/LEAD.md +12 -7
- package/src/rules/shared/10-tool-workflow.md +3 -1
- package/src/rules/shared/20-research.md +3 -6
- package/src/rules/shared/40-editing.md +1 -0
- package/src/rules/shared/45-destructive.md +0 -2
- package/src/rules/shared/50-execution.md +2 -0
- package/src/rules/shared/60-verification.md +10 -9
- package/src/rules/shared/70-delivery.md +8 -9
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/abort-link.mjs +5 -1
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +10 -1
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +156 -24
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +13 -0
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +4 -1
- package/src/runtime/agent/orchestrator/cache-break-trace.mjs +2 -0
- package/src/runtime/agent/orchestrator/config.mjs +12 -7
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +8 -8
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +5 -26
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +3 -1
- package/src/runtime/agent/orchestrator/internal-agents.mjs +3 -14
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +122 -12
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +5 -3
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +13 -2
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +152 -58
- package/src/runtime/agent/orchestrator/mcp/client.mjs +51 -18
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +88 -54
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +42 -26
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +54 -8
- package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +37 -31
- package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +8 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +31 -21
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +14 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +6 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +40 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider-keys.mjs +34 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +14 -7
- package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/devin.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +248 -41
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -11
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +45 -6
- package/src/runtime/agent/orchestrator/providers/lib/first-output-window.mjs +58 -0
- package/src/runtime/agent/orchestrator/providers/lib/listen-on.mjs +14 -0
- package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +0 -18
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +138 -6
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/model-cache.mjs +100 -33
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/oauth-secret-fields.fixtures.mjs +45 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +14 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +4 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +5 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +16 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +13 -3
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +13 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +81 -42
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +160 -31
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +22 -12
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +49 -22
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/registry.mjs +45 -2
- package/src/runtime/agent/orchestrator/providers/vertex-ai-auth.mjs +622 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai-maas.mjs +185 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai-models.mjs +445 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai.mjs +567 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +41 -13
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -6
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +7 -3
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +6 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +14 -5
- package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -0
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -5
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +171 -37
- package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +1 -3
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +102 -12
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -8
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/compact/observation-supersession.mjs +103 -23
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +160 -36
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +164 -23
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +139 -19
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +38 -7
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +100 -22
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -3
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -6
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +33 -3
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +9 -2
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +13 -5
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +23 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +23 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +39 -21
- package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +13 -8
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +50 -28
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +30 -13
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +63 -6
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +35 -13
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +24 -14
- package/src/runtime/agent/orchestrator/session/manager/session-scratch-environment.mjs +70 -0
- package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +0 -3
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +10 -6
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +56 -29
- package/src/runtime/agent/orchestrator/session/manager/turn-reap.mjs +125 -0
- package/src/runtime/agent/orchestrator/session/mixy-name.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +30 -7
- package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +154 -0
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +37 -8
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +252 -39
- package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +163 -64
- package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +164 -4
- package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +142 -18
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +61 -2
- package/src/runtime/agent/orchestrator/stall-policy.mjs +23 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +46 -20
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +67 -31
- package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +25 -13
- package/src/runtime/agent/orchestrator/tools/builtin/lib/scoped-search-flight.mjs +9 -5
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +58 -20
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +23 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +1 -8
- package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +20 -15
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +96 -20
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +59 -10
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/federation.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/lib/isolated-test-env.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +99 -2
- package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +103 -13
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +49 -15
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +45 -27
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +34 -10
- package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +28 -4
- package/src/runtime/agent/orchestrator/tools/lib/wait-until-fixture.mjs +26 -0
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -2
- package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
- package/src/runtime/channels/lib/webhook/signature.mjs +4 -1
- package/src/runtime/channels/lib/whisper-port.mjs +29 -11
- package/src/runtime/channels/lib/whisper-server.mjs +10 -1
- package/src/runtime/computer-bridge/action-schema.mjs +2 -2
- package/src/runtime/computer-bridge/core-actions.mjs +2 -2
- package/src/runtime/computer-bridge/error-recovery.mjs +5 -4
- package/src/runtime/computer-bridge/linux-action-capabilities.mjs +24 -5
- package/src/runtime/computer-bridge/linux-readiness.d.mts +7 -2
- package/src/runtime/connectors/connector-accounts-mcp.mjs +236 -103
- package/src/runtime/connectors/gmail-app-password.mjs +3 -3
- package/src/runtime/explore/explorer.mjs +93 -0
- package/src/runtime/explore/tool-defs.mjs +35 -0
- package/src/runtime/explore/tool.mjs +123 -0
- package/src/runtime/local-provider/server-process.mjs +2 -1
- package/src/runtime/media/adapters/gemini-video.mjs +4 -1
- package/src/runtime/media/adapters/xai-media.mjs +2 -1
- package/src/runtime/memory/index.mjs +4 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +4 -1
- package/src/runtime/memory/lib/embedding-worker.mjs +10 -3
- package/src/runtime/memory/lib/memory-action-handlers/cycle-backfill-action.mjs +1 -7
- package/src/runtime/memory/lib/memory-chunk-quality.mjs +1 -6
- package/src/runtime/office/authoring/pdf-author-action.mjs +1 -6
- package/src/runtime/office/design/design-art-direction.mjs +29 -27
- package/src/runtime/office/pdf/pdf-writer.mjs +6 -1
- package/src/runtime/office/portable/portable-snapshot-docx.mjs +7 -1
- package/src/runtime/office/portable/portable-snapshot-shared.mjs +6 -1
- package/src/runtime/office/quality/assurance-rendered.mjs +9 -2
- package/src/runtime/office/quality/assurance-structure-docx.mjs +4 -2
- package/src/runtime/office/quality/design-review.mjs +1 -5
- package/src/runtime/office/quality/document-brief.mjs +1 -5
- package/src/runtime/office/quality/forced-break-pages.mjs +9 -6
- package/src/runtime/office/quality/quality-pipeline.mjs +1 -1
- package/src/runtime/shared/agent-route-config.mjs +17 -2
- package/src/runtime/shared/atomic-file.mjs +103 -2
- package/src/runtime/shared/background-tasks.mjs +15 -6
- package/src/runtime/shared/bot-owned-work.mjs +56 -0
- package/src/runtime/shared/connector-accounts.mjs +5 -5
- package/src/runtime/shared/connector-catalog.d.mts +11 -4
- package/src/runtime/shared/connector-catalog.mjs +60 -52
- package/src/runtime/shared/custom-provider-keys.mjs +20 -0
- package/src/runtime/shared/defaults-separation.mjs +1 -4
- package/src/runtime/shared/fetch-safe-listen.d.mts +16 -0
- package/src/runtime/shared/fetch-safe-listen.mjs +50 -0
- package/src/runtime/shared/file-has-data.mjs +26 -2
- package/src/runtime/shared/file-lock.mjs +13 -15
- package/src/runtime/shared/git-launch.d.mts +9 -0
- package/src/runtime/shared/git-launch.mjs +213 -0
- package/src/runtime/shared/git-runner-worker.mjs +2 -1
- package/src/runtime/shared/handoff-artifacts.d.mts +2 -1
- package/src/runtime/shared/handoff-artifacts.mjs +18 -8
- package/src/runtime/shared/idle-auto-clear-gate.mjs +29 -7
- package/src/runtime/shared/llm/cost.mjs +11 -2
- package/src/runtime/shared/llm/http-agent.mjs +313 -29
- package/src/runtime/shared/llm/model-catalog-projection.mjs +3 -2
- package/src/runtime/shared/llm/model-catalog.mjs +46 -6
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +3 -0
- package/src/runtime/shared/llm/system-proxy.mjs +452 -0
- package/src/runtime/shared/loopback-listener.mjs +25 -2
- package/src/runtime/shared/model-route-chain.d.mts +7 -2
- package/src/runtime/shared/model-route-chain.mjs +22 -4
- package/src/runtime/shared/open-url.mjs +10 -0
- package/src/runtime/shared/provider-accounts.mjs +52 -2
- package/src/runtime/shared/session-activity-signal.mjs +14 -0
- package/src/runtime/shared/session-scratch.mjs +37 -0
- package/src/runtime/shared/staged-install-worker.mjs +5 -0
- package/src/runtime/shared/staged-update.mjs +47 -2
- package/src/runtime/shared/tool-card-model/agent-surface.mjs +1 -3
- package/src/runtime/shared/tool-card-model/card-status.mjs +15 -2
- package/src/runtime/shared/tool-result-summary.mjs +1 -1
- package/src/runtime/shared/tool-surface.mjs +113 -36
- package/src/runtime/shared/tool-work-units.mjs +6 -0
- package/src/runtime/shared/turn-snapshot-store.mjs +13 -6
- package/src/runtime/shared/turn-worktree-snapshot.mjs +414 -54
- package/src/runtime/shared/worktrees/activity-gate.mjs +215 -318
- package/src/runtime/shared/worktrees/activity-ledger-worker.mjs +56 -0
- package/src/runtime/shared/worktrees/activity-ledger.mjs +391 -0
- package/src/runtime/shared/worktrees/branch-management.mjs +9 -3
- package/src/runtime/shared/worktrees/contract.mjs +4 -1
- package/src/runtime/shared/worktrees/git.mjs +72 -0
- package/src/runtime/shared/worktrees/manager.mjs +285 -168
- package/src/runtime/shared/worktrees/test-support.mjs +6 -10
- package/src/runtime/tidy/install.mjs +95 -15
- package/src/runtime/tidy/languages.mjs +17 -15
- package/src/runtime/tidy/process.mjs +7 -4
- package/src/runtime/tidy/resolve.mjs +19 -16
- package/src/runtime/tidy/runners/biome.mjs +3 -3
- package/src/runtime/tidy/tool.mjs +1 -1
- package/src/runtime/tidy/worktree.mjs +10 -6
- package/src/runtime/visualize-bridge/client.mjs +6 -1
- package/src/runtime/visualize-bridge/tool-defs.mjs +7 -2
- package/src/runtime/web-search/index.mjs +1 -1
- package/src/session-runtime/agent-home-delivery.mjs +41 -0
- package/src/session-runtime/agent-task-sessions.mjs +458 -312
- package/src/session-runtime/agent-tool-routing.mjs +8 -41
- package/src/session-runtime/boot/tools.mjs +7 -1
- package/src/session-runtime/bot-status.mjs +107 -101
- package/src/session-runtime/bot-target.mjs +38 -0
- package/src/session-runtime/channel-config-api.mjs +6 -1
- package/src/session-runtime/connector-merge-migration.mjs +18 -15
- package/src/session-runtime/conversation-import/codex-titles.mjs +88 -0
- package/src/session-runtime/conversation-import/discovery.mjs +401 -36
- package/src/session-runtime/conversation-import/service.mjs +35 -8
- package/src/session-runtime/handoff-attachments.mjs +82 -31
- package/src/session-runtime/held-requests.mjs +3 -1
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +12 -13
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +1 -0
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -0
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +8 -0
- package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +4 -1
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +145 -112
- package/src/session-runtime/lifecycle/cold-heir.mjs +11 -6
- package/src/session-runtime/lifecycle/session-catalog.mjs +9 -1
- package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -1
- package/src/session-runtime/lifecycle/teardown.mjs +1 -1
- package/src/session-runtime/mcp-glue/server-catalog.mjs +16 -10
- package/src/session-runtime/mcp-glue/server-input.mjs +4 -1
- package/src/session-runtime/mixy-heartbeat.mjs +1 -1
- package/src/session-runtime/model-route/set-route.mjs +11 -2
- package/src/session-runtime/provider-auth/login.mjs +2 -2
- package/src/session-runtime/provider-catalog-cache.mjs +82 -36
- package/src/session-runtime/provider-models/catalog-load.mjs +23 -6
- package/src/session-runtime/provider-models.mjs +4 -2
- package/src/session-runtime/resource-mcp-api.mjs +98 -35
- package/src/session-runtime/resource-mcp-connector-accounts.mjs +44 -31
- package/src/session-runtime/resource-mcp-secrets.mjs +28 -11
- package/src/session-runtime/resource-mcp-servers.mjs +5 -4
- package/src/session-runtime/resource-recall-api.mjs +6 -1
- package/src/session-runtime/runtime-feature-gates.mjs +5 -1
- package/src/session-runtime/services/agent-tool/execute.mjs +14 -9
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +20 -4
- package/src/session-runtime/services/agent-tool/model-select.mjs +48 -7
- package/src/session-runtime/services/agent-tool/render.mjs +71 -17
- package/src/session-runtime/services/agent-tool/send-flow.mjs +10 -2
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +8 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +4 -1
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +6 -2
- package/src/session-runtime/services/agent-tool/tool-def.mjs +9 -9
- package/src/session-runtime/services/agent-watchdog-registry.mjs +32 -4
- package/src/session-runtime/services/channel-worker/daemon-spawn.mjs +2 -0
- package/src/session-runtime/services/daemon-candidate.mjs +4 -1
- package/src/session-runtime/services/memory-runtime-proxy/daemon-spawn.mjs +4 -0
- package/src/session-runtime/services/plugin-admin.mjs +10 -6
- package/src/session-runtime/services/provider-admin.mjs +283 -11
- package/src/session-runtime/session-turn-api.mjs +2 -0
- package/src/session-runtime/settings-builtin-tools-api.mjs +4 -1
- package/src/session-runtime/settings-system-api.mjs +1 -1
- package/src/session-runtime/setup-tool/agent-settings-actions.mjs +13 -3
- package/src/session-runtime/setup-tool/connector-widen-approval.mjs +96 -0
- package/src/session-runtime/setup-tool/executor.mjs +6 -2
- package/src/session-runtime/setup-tool/tool-defs.mjs +2 -1
- package/src/session-runtime/tool-policy/policy-stage.mjs +1 -0
- package/src/session-runtime/turn/agent-ops.mjs +23 -0
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +49 -11
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +5 -1
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +25 -5
- package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -3
- package/src/session-runtime/workspace/activity-guards.mjs +176 -0
- package/src/session-runtime/workspace/session-view.mjs +149 -0
- package/src/session-runtime/workspace/side-checkouts.mjs +203 -0
- package/src/session-runtime/workspace/transition-runner.mjs +188 -0
- package/src/session-runtime/workspace/transitions.mjs +108 -1041
- package/src/session-runtime/workspace/workspace-merge.mjs +132 -0
- package/src/session-runtime/workspace/worktree-intents.mjs +242 -0
- package/src/session-runtime/workspace/worktree-maintenance.mjs +80 -0
- package/src/session-runtime/workspace/worktree-setup.mjs +85 -0
- package/src/session-runtime/workspace/worktree-tool.mjs +73 -56
- package/src/standalone/daemon-desktop-runtime.mjs +2 -0
- package/src/standalone/daemon-session-control.mjs +169 -138
- package/src/standalone/daemon.mjs +7 -0
- package/src/standalone/desktop-service-registry.mjs +9 -0
- package/src/standalone/local-session-runtime.mjs +5 -1
- package/src/standalone/session-client/daemon-unavailable.mjs +3 -0
- package/src/standalone/session-client.mjs +5 -1
- package/src/standalone/session-frame-stream.mjs +83 -11
- package/src/standalone/session-protocol.mjs +4 -0
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +16 -12
- package/src/standalone/session-service/agent-tree.mjs +45 -9
- package/src/standalone/session-service/projection/transcript-window.mjs +700 -64
- package/src/standalone/session-service/session-calls/session-action.mjs +10 -3
- package/src/standalone/session-service/session-calls/session-views.mjs +160 -104
- package/src/standalone/session-service/stored-reader.mjs +127 -40
- package/src/standalone/session-transport/client-registry/client-grace.mjs +12 -9
- package/src/tui/App.jsx +154 -164
- package/src/tui/app/app-view/floating-panel.jsx +10 -4
- package/src/tui/app/app-view/text-entry-labels.mjs +1 -0
- package/src/tui/app/clipboard.mjs +21 -10
- package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +1 -3
- package/src/tui/app/model-picker/route-selection.mjs +5 -6
- package/src/tui/app/prompt-handlers/use-prompt-history-nav.mjs +1 -1
- package/src/tui/app/prompt-handlers/use-prompt-interrupt.mjs +3 -0
- package/src/tui/app/prompt-submit/provider-prompts.mjs +3 -1
- package/src/tui/app/provider-setup/api-key-actions.mjs +31 -1
- package/src/tui/app/provider-setup/oauth-actions.mjs +58 -21
- package/src/tui/app/provider-setup/provider-items.mjs +8 -2
- package/src/tui/app/provider-setup-picker.mjs +29 -18
- package/src/tui/app/shell-layout/row-budgets.mjs +12 -10
- package/src/tui/app/slash-commands.mjs +1 -0
- package/src/tui/app/slash-dispatch/session-commands.mjs +46 -0
- package/src/tui/app/slash-dispatch.mjs +1 -1
- package/src/tui/app/use-btw-panel.mjs +29 -0
- package/src/tui/app/use-context-panel-refresh.mjs +31 -0
- package/src/tui/app/use-model-catalog-cache.mjs +13 -10
- package/src/tui/app/use-mouse-input.mjs +11 -0
- package/src/tui/app/use-onboarding-start.mjs +8 -3
- package/src/tui/app/use-panel-transition.mjs +10 -1
- package/src/tui/app/use-pasted-buffers.mjs +28 -20
- package/src/tui/app/use-prompt-draft-flow.mjs +7 -0
- package/src/tui/app/use-prompt-layout-rows.mjs +3 -3
- package/src/tui/app/use-prompt-queue-history.mjs +3 -2
- package/src/tui/app/use-selection-focus.mjs +11 -2
- package/src/tui/app/use-selection-geometry.mjs +18 -9
- package/src/tui/app/use-selection-paint.mjs +4 -4
- package/src/tui/app/use-selection-stitch.mjs +3 -3
- package/src/tui/app/use-slash-palette.mjs +62 -0
- package/src/tui/app/use-terminal-chrome.mjs +2 -2
- package/src/tui/app/use-transcript-activity.mjs +47 -32
- package/src/tui/app/use-transcript-follow.mjs +12 -4
- package/src/tui/app/use-transcript-scroll.mjs +46 -17
- package/src/tui/app/use-transcript-swap-reset.mjs +27 -0
- package/src/tui/app/use-transcript-window/geometry.mjs +19 -5
- package/src/tui/app/use-transcript-window/instance-state.mjs +4 -0
- package/src/tui/app/use-transcript-window/selection-shift.mjs +5 -1
- package/src/tui/app/use-transcript-window.mjs +21 -11
- package/src/tui/app/use-tui-ready.mjs +18 -0
- package/src/tui/app/use-welcome-prompt-hint.mjs +5 -0
- package/src/tui/app/use-workflow-tab-cycle.mjs +5 -3
- package/src/tui/components/Picker.jsx +27 -3
- package/src/tui/components/QuestionPanel.jsx +13 -4
- package/src/tui/components/SignInUrl.jsx +68 -0
- package/src/tui/components/TextEntryPanel.jsx +76 -46
- package/src/tui/components/sign-in-url-layout.mjs +24 -0
- package/src/tui/dist/index.mjs +1963 -1361
- package/src/tui/session/goal-turn-state.mjs +6 -2
- package/src/tui/session/session-api/controls.mjs +4 -0
- package/src/tui/session/session-api/extensions.mjs +8 -0
- package/src/tui/session/session-api/intake/abort.mjs +2 -1
- package/src/tui/session/session-api/intake.mjs +2 -0
- package/src/tui/session/session-api/integrations.mjs +2 -2
- package/src/tui/session/session-api/routes-agent-definitions.mjs +1 -0
- package/src/tui/session/session-api/settings.mjs +2 -2
- package/src/tui/session/session-flow/queue/take-entries.mjs +11 -0
- package/src/tui/session/transcript-spill/spill-writer.mjs +15 -0
- package/src/tui/session/transcript-spill.mjs +92 -4
- package/src/tui/session/transcript-store.mjs +2 -0
- package/src/ui/statusline-agents.mjs +1 -3
- package/src/defaults/skills/skill-creator/references/source-review.md +0 -94
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
// Scoped scratch directories for tests: every directory this module creates is
|
|
2
|
+
// named `mixdog-<prefix>-*` in the system temp dir and is removed whether the
|
|
3
|
+
// test passed or failed. Removal retries a bounded number of times, because on
|
|
4
|
+
// Windows a just-closed file or a just-exited child can hold a path for a
|
|
5
|
+
// moment (EBUSY / EPERM / ENOTEMPTY).
|
|
6
|
+
//
|
|
7
|
+
// Pick the narrowest scope that fits the test:
|
|
8
|
+
// tempDirFor(t, prefix) removed after the node:test context `t`
|
|
9
|
+
// scopedTempDir(prefix) `.path` + dispose; use `await using` on
|
|
10
|
+
// Node 24+, or `try { } finally { await d.remove() }`
|
|
11
|
+
// withTempDir(prefix, fn) removed when `fn` settles
|
|
12
|
+
// makeTempDirSync(prefix) removed by removeTempDirSync, and always swept at
|
|
13
|
+
// process exit (a late write may recreate it)
|
|
14
|
+
// Close anything holding files inside the directory (sqlite handles, servers,
|
|
15
|
+
// child processes) before the removal runs.
|
|
16
|
+
import { mkdtempSync } from 'node:fs';
|
|
17
|
+
import { tmpdir } from 'node:os';
|
|
18
|
+
import { basename, dirname, join, resolve } from 'node:path';
|
|
19
|
+
import { removeTempDirSync as removeDirWithRetrySync } from './stale-temp.mjs';
|
|
20
|
+
|
|
21
|
+
const live = new Set();
|
|
22
|
+
let exitHookInstalled = false;
|
|
23
|
+
|
|
24
|
+
function directoryPrefix(prefix) {
|
|
25
|
+
const bare = String(prefix)
|
|
26
|
+
.replace(/^mixdog-/, '')
|
|
27
|
+
.replace(/-+$/, '');
|
|
28
|
+
return `mixdog-${bare}-`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function removeAllAtExit() {
|
|
32
|
+
for (const dir of live) removeDirWithRetrySync(dir);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function installExitHook() {
|
|
36
|
+
if (exitHookInstalled) return;
|
|
37
|
+
exitHookInstalled = true;
|
|
38
|
+
process.on('exit', removeAllAtExit);
|
|
39
|
+
// A module under test may add its own exit handler (a final flush can
|
|
40
|
+
// recreate its directory), so keep this one the last to run.
|
|
41
|
+
process.on('newListener', (event, listener) => {
|
|
42
|
+
if (event !== 'exit' || listener === removeAllAtExit) return;
|
|
43
|
+
queueMicrotask(() => {
|
|
44
|
+
process.removeListener('exit', removeAllAtExit);
|
|
45
|
+
process.on('exit', removeAllAtExit);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Creates `mixdog-<prefix>-*` in the system temp dir; removed at process exit unless removed sooner. */
|
|
51
|
+
export function makeTempDirSync(prefix) {
|
|
52
|
+
const dir = mkdtempSync(join(tmpdir(), directoryPrefix(prefix)));
|
|
53
|
+
live.add(dir);
|
|
54
|
+
installExitHook();
|
|
55
|
+
return dir;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Registers a directory its creator made as test-owned, so it is swept again
|
|
60
|
+
* as the last exit step (a late write by the code under test can recreate it
|
|
61
|
+
* after the creator's own exit handler ran). Only an exact `mixdog-*` child of
|
|
62
|
+
* the system temp dir is accepted; nothing is ever inferred from an env var.
|
|
63
|
+
*/
|
|
64
|
+
export function registerOwnedTempDir(dir) {
|
|
65
|
+
const resolved = resolve(dir);
|
|
66
|
+
const same = (a, b) => (process.platform === 'win32' ? a.toLowerCase() === b.toLowerCase() : a === b);
|
|
67
|
+
if (!basename(resolved).startsWith('mixdog-') || !same(dirname(resolved), resolve(tmpdir()))) {
|
|
68
|
+
throw new Error(`refusing to own a directory outside the system temp root: ${dir}`);
|
|
69
|
+
}
|
|
70
|
+
live.add(resolved);
|
|
71
|
+
installExitHook();
|
|
72
|
+
return resolved;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* For code under test that makes its own mixdog-* directories in the system
|
|
77
|
+
* temp dir: points TEMP/TMP/TMPDIR at one scoped directory for the rest of the
|
|
78
|
+
* process, so everything created there is removed with it at exit.
|
|
79
|
+
*/
|
|
80
|
+
export function redirectSystemTemp(prefix = 'temp-root') {
|
|
81
|
+
const dir = makeTempDirSync(prefix);
|
|
82
|
+
process.env.TEMP = dir;
|
|
83
|
+
process.env.TMP = dir;
|
|
84
|
+
process.env.TMPDIR = dir;
|
|
85
|
+
return dir;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function removeTempDirSync(dir) {
|
|
89
|
+
if (!removeDirWithRetrySync(dir)) process.stderr.write(`scratch folder ${dir} could not be removed\n`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export async function removeTempDir(dir) {
|
|
93
|
+
removeTempDirSync(dir);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** A directory removed after the node:test context (test or suite) `t` finishes, pass or fail. */
|
|
97
|
+
export function tempDirFor(t, prefix) {
|
|
98
|
+
const dir = makeTempDirSync(prefix);
|
|
99
|
+
t.after(() => removeTempDir(dir));
|
|
100
|
+
return dir;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** A directory with `.path`, `join()` and `remove()`; also `await using` / `using` disposable. */
|
|
104
|
+
export function scopedTempDir(prefix) {
|
|
105
|
+
const path = makeTempDirSync(prefix);
|
|
106
|
+
return {
|
|
107
|
+
path,
|
|
108
|
+
join: (...parts) => join(path, ...parts),
|
|
109
|
+
remove: () => removeTempDir(path),
|
|
110
|
+
removeSync: () => removeTempDirSync(path),
|
|
111
|
+
[Symbol.asyncDispose]: () => removeTempDir(path),
|
|
112
|
+
[Symbol.dispose]: () => removeTempDirSync(path),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Runs `fn(dir)` with a fresh directory and removes it when `fn` settles. */
|
|
117
|
+
export async function withTempDir(prefix, fn) {
|
|
118
|
+
const dir = makeTempDirSync(prefix);
|
|
119
|
+
try {
|
|
120
|
+
return await fn(dir);
|
|
121
|
+
} finally {
|
|
122
|
+
await removeTempDir(dir);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Temp dirs a test run or the local gate owns. A normal exit removes them, but
|
|
2
|
+
// a killed process runs no exit handler, so each run starts by sweeping what an
|
|
3
|
+
// earlier killed run left behind.
|
|
4
|
+
import { lstatSync, readdirSync, rmSync } from 'node:fs';
|
|
5
|
+
import { tmpdir } from 'node:os';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
|
|
8
|
+
// How long a kept test log stays readable; also what counts as a leftover.
|
|
9
|
+
export const STALE_TEMP_MS = 3 * 24 * 60 * 60 * 1000;
|
|
10
|
+
|
|
11
|
+
// rmSync retries the lock errors itself (EBUSY, EPERM, ENOTEMPTY, ...) a
|
|
12
|
+
// bounded number of times per entry before it throws. Returns whether the
|
|
13
|
+
// directory is gone; a held file leaves it for the next start-of-run sweep.
|
|
14
|
+
export function removeTempDirSync(dir) {
|
|
15
|
+
try {
|
|
16
|
+
rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
17
|
+
return true;
|
|
18
|
+
} catch {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Removes every directory in `root` whose name starts with one of `prefixes`
|
|
24
|
+
// and whose mtime is older than `maxAgeMs`.
|
|
25
|
+
export function pruneStaleTempDirs(prefixes, { root = tmpdir(), maxAgeMs = STALE_TEMP_MS, now = Date.now() } = {}) {
|
|
26
|
+
let names = [];
|
|
27
|
+
try {
|
|
28
|
+
names = readdirSync(root);
|
|
29
|
+
} catch {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const cutoff = now - maxAgeMs;
|
|
33
|
+
for (const name of names) {
|
|
34
|
+
if (!prefixes.some((prefix) => name.startsWith(prefix))) continue;
|
|
35
|
+
const path = join(root, name);
|
|
36
|
+
try {
|
|
37
|
+
// lstat: a link or a plain file that merely matches the prefix is not ours to remove.
|
|
38
|
+
const info = lstatSync(path);
|
|
39
|
+
if (info.isDirectory() && info.mtimeMs < cutoff) removeTempDirSync(path);
|
|
40
|
+
} catch {
|
|
41
|
+
/* another run may own or be removing it */
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -36,7 +36,20 @@ export function failureRecord(event, stacks) {
|
|
|
36
36
|
if (event.data.todo) return null;
|
|
37
37
|
if (event.data.details?.error?.failureType === 'subtestsFailed') return null;
|
|
38
38
|
const ancestors = (stacks.get(file) ?? []).slice(0, event.data.nesting);
|
|
39
|
-
|
|
39
|
+
const exit = processExit(event.data.details?.error);
|
|
40
|
+
return { file, name: [...ancestors, event.data.name].join(' > '), ...(exit ? { exit } : {}) };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// A test file whose process ended badly fails with only "test failed"; node
|
|
44
|
+
// keeps how it ended on the error. A Windows NTSTATUS code (e.g. 0xC0000142,
|
|
45
|
+
// the process could not initialise) reads better in hex.
|
|
46
|
+
export function processExit(error) {
|
|
47
|
+
if (error?.failureType !== 'testCodeFailure') return '';
|
|
48
|
+
if (error.signal) return `test process killed by ${error.signal}`;
|
|
49
|
+
const code = error.exitCode;
|
|
50
|
+
if (!Number.isInteger(code) || code === 0) return '';
|
|
51
|
+
const hex = code > 255 || code < 0 ? ` (0x${(code >>> 0).toString(16).toUpperCase().padStart(8, '0')})` : '';
|
|
52
|
+
return `test process exited with code ${code}${hex}`;
|
|
40
53
|
}
|
|
41
54
|
|
|
42
55
|
// The runner sets FAILURE_RECORDS_ENV to a per-spawn JSONL path. Without it
|
|
@@ -46,19 +46,31 @@ export function policyLine(rerunFailed) {
|
|
|
46
46
|
// `hung` holds one "hung after N min: <files>" message per batch the runner's
|
|
47
47
|
// watchdog killed; such a batch fails the run whatever its tests reported.
|
|
48
48
|
// A non-zero `exitCode` with no failed test, flaky test or hung batch behind it
|
|
49
|
-
// (a bad node flag, a crashed runner) is its own failure,
|
|
50
|
-
|
|
49
|
+
// (a bad node flag, a crashed runner, a kill from outside) is its own failure,
|
|
50
|
+
// never "0 failed". `pids` names the node --test processes that exited
|
|
51
|
+
// non-zero, so a kill can be matched to the "Killing ... <pid>" line of
|
|
52
|
+
// whatever killed them.
|
|
53
|
+
export function formatFailureSummary({
|
|
54
|
+
failed = [],
|
|
55
|
+
flaky = [],
|
|
56
|
+
rerunFailed = 0,
|
|
57
|
+
hung = [],
|
|
58
|
+
exitCode = 0,
|
|
59
|
+
pids = [],
|
|
60
|
+
}) {
|
|
51
61
|
const hungCount = hung.length > 0 ? `, ${hung.length} hung batch(es)` : '';
|
|
52
62
|
const unexplained = exitCode !== 0 && failed.length === 0 && hung.length === 0;
|
|
63
|
+
const runner = pids.length > 0 ? `node --test pid ${pids.join(' ')}: ` : '';
|
|
53
64
|
const lines = [
|
|
54
65
|
unexplained
|
|
55
|
-
? `${SUMMARY_TAG} RUN FAILED: exit code ${exitCode} with no failed test recorded (bad argument or
|
|
66
|
+
? `${SUMMARY_TAG} RUN FAILED: exit code ${exitCode} with no failed test recorded (${runner}bad argument, runner error or killed from outside; see output above)`
|
|
56
67
|
: `${SUMMARY_TAG} ${failed.length} failed, ${flaky.length} flaky${hungCount} (every failed test is named below)`,
|
|
57
68
|
];
|
|
58
69
|
for (const message of hung) lines.push(`${SUMMARY_TAG} HUNG ${message}`);
|
|
59
70
|
for (const record of failed) {
|
|
60
71
|
const origin = record.firstSeenOnRerun ? ` (first seen on re-run ${record.firstSeenOnRerun})` : '';
|
|
61
|
-
|
|
72
|
+
const exit = record.exit ? ` (${record.exit})` : '';
|
|
73
|
+
lines.push(`${SUMMARY_TAG} FAILED ${record.file} > ${record.name}${exit}${origin}`);
|
|
62
74
|
}
|
|
63
75
|
for (const record of flaky) {
|
|
64
76
|
lines.push(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Preloaded (--import) into every test process the runner starts: records
|
|
2
|
-
//
|
|
2
|
+
// each child process's pid, spawn time and exit, so a process a test leaves
|
|
3
3
|
// running can be traced back to the run after its parent exited
|
|
4
4
|
// (scripts/lib/run-node-tests.mjs). Without the runner's environment it does
|
|
5
5
|
// nothing.
|
|
@@ -54,11 +54,20 @@ if (
|
|
|
54
54
|
|
|
55
55
|
const ledger = spawnLedgerPath(process.env[FAILURE_RECORDS_ENV]);
|
|
56
56
|
if (ledger) {
|
|
57
|
-
// spawn, exec, execFile and fork all start their process here.
|
|
57
|
+
// spawn, exec, execFile and fork all start their process here. A spawn is
|
|
58
|
+
// "<pid> <before> <since>", the clock just before and just after it; the
|
|
59
|
+
// same line plus "<exited>" follows once its exit is seen. The 'exit' event
|
|
60
|
+
// comes before the child's handle is closed, so the pid is still this
|
|
61
|
+
// child's when the exit is written: from then on another process may hold it.
|
|
58
62
|
const spawn = ChildProcess.prototype.spawn;
|
|
59
63
|
ChildProcess.prototype.spawn = function recordedSpawn(...args) {
|
|
64
|
+
const before = Date.now();
|
|
60
65
|
const result = spawn.apply(this, args);
|
|
61
|
-
if (this.pid)
|
|
66
|
+
if (this.pid) {
|
|
67
|
+
const spawned = `${this.pid} ${before} ${Date.now()}`;
|
|
68
|
+
appendFileSync(ledger, `${spawned}\n`);
|
|
69
|
+
this.once('exit', () => appendFileSync(ledger, `${spawned} ${Date.now()}\n`));
|
|
70
|
+
}
|
|
62
71
|
return result;
|
|
63
72
|
};
|
|
64
73
|
}
|
|
@@ -215,12 +215,7 @@ export function getReleaseByTag(repo, tag, run = gh) {
|
|
|
215
215
|
* rethrown, so an API outage fails the job instead of silently skipping
|
|
216
216
|
* verification of a release that may be public.
|
|
217
217
|
*/
|
|
218
|
-
export async function detectPublished({
|
|
219
|
-
fetchRelease,
|
|
220
|
-
sleep = defaultSleep,
|
|
221
|
-
attempts = 5,
|
|
222
|
-
firstDelayMs = 2000,
|
|
223
|
-
}) {
|
|
218
|
+
export async function detectPublished({ fetchRelease, sleep = defaultSleep, attempts = 5, firstDelayMs = 2000 }) {
|
|
224
219
|
let delay = firstDelayMs;
|
|
225
220
|
for (let attempt = 1; ; attempt++) {
|
|
226
221
|
try {
|
|
@@ -21,8 +21,11 @@ const SOURCES = [
|
|
|
21
21
|
// A statement this short says its whole meaning (a constant, a one-line arrow); a longer one gives its first line.
|
|
22
22
|
const WHOLE_STATEMENT = 240;
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
property.type === 'Property'
|
|
24
|
+
function propertyName(property) {
|
|
25
|
+
if (property.type === 'Property') return String(property.key.name ?? property.key.value ?? '');
|
|
26
|
+
if (property.type === 'SpreadElement') return '…';
|
|
27
|
+
return '';
|
|
28
|
+
}
|
|
26
29
|
|
|
27
30
|
// The keys an object literal offers a script, one level into object-valued keys ("body: { x, y, w, h }"). A table of
|
|
28
31
|
// like entries (STYLES: an id per style, each with the same fields) reads as its ids and the fields each carries.
|
|
@@ -30,7 +33,9 @@ function objectShape(node) {
|
|
|
30
33
|
const properties = node.properties.filter((property) => propertyName(property));
|
|
31
34
|
const nested = properties.filter((property) => property.value?.type === 'ObjectExpression');
|
|
32
35
|
if (properties.length >= 4 && nested.length === properties.length) {
|
|
33
|
-
const fields = [...new Set(nested.flatMap((property) => property.value.properties.map(propertyName)))].filter(
|
|
36
|
+
const fields = [...new Set(nested.flatMap((property) => property.value.properties.map(propertyName)))].filter(
|
|
37
|
+
Boolean
|
|
38
|
+
);
|
|
34
39
|
return `{ ${properties.map(propertyName).join(', ')} } each { ${fields.join(', ')} }`;
|
|
35
40
|
}
|
|
36
41
|
const keys = properties.map((property) =>
|
|
@@ -48,7 +53,8 @@ function returnedShape(fn) {
|
|
|
48
53
|
const visit = (node) => {
|
|
49
54
|
if (!node || typeof node.type !== 'string') return;
|
|
50
55
|
if (node !== fn.body && /Function/.test(node.type)) return;
|
|
51
|
-
if (node.type === 'ReturnStatement' && node.argument?.type === 'ObjectExpression')
|
|
56
|
+
if (node.type === 'ReturnStatement' && node.argument?.type === 'ObjectExpression')
|
|
57
|
+
shapes.push(objectShape(node.argument));
|
|
52
58
|
for (const value of Object.values(node)) {
|
|
53
59
|
if (Array.isArray(value)) value.forEach(visit);
|
|
54
60
|
else if (value && typeof value === 'object' && typeof value.type === 'string') visit(value);
|
|
@@ -116,7 +122,13 @@ function summarizeFile({ file, prose }) {
|
|
|
116
122
|
output.push('```js', summarizeCode(part).trimEnd(), '```');
|
|
117
123
|
return;
|
|
118
124
|
}
|
|
119
|
-
const kept =
|
|
125
|
+
const kept =
|
|
126
|
+
prose === 'all'
|
|
127
|
+
? part.trim()
|
|
128
|
+
: part
|
|
129
|
+
.split('\n')
|
|
130
|
+
.filter((line) => /^#{1,3} /.test(line))
|
|
131
|
+
.join('\n');
|
|
120
132
|
if (kept) output.push(kept.replace(/^# /m, '## '));
|
|
121
133
|
});
|
|
122
134
|
return [`# ${file}`, ...output].join('\n\n');
|
package/scripts/suite-health.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// Weekly opt-out sweep: run every test:*/smoke:* npm script in the repository
|
|
3
|
-
// so no locally-registered suite can rot silently (docs/testing.md, "
|
|
4
|
-
// contract suite runs in CI or it drifts"). New scripts join automatically;
|
|
3
|
+
// so no locally-registered suite can rot silently (docs/testing.md, "CI coverage"). New scripts join automatically;
|
|
5
4
|
// exclusions are explicit, reasoned, and fail closed when they go stale.
|
|
6
5
|
import { readFileSync, writeFileSync } from 'node:fs';
|
|
7
6
|
import { join } from 'node:path';
|
|
@@ -36,13 +35,9 @@ export const WORKSPACES = [
|
|
|
36
35
|
'test:daemon:e2e': 'needs the built daemon; the release gate desktop job owns it',
|
|
37
36
|
'test:spec-advisory': 'advisory by design (MIXDOG_TEST_ADVISORY)',
|
|
38
37
|
'test:browser-host:integration': 'live desktop integration harness',
|
|
39
|
-
'test:browser-login-persistence:integration':
|
|
40
|
-
'live desktop integration harness; launches real Electron, which needs a display the Linux sweep runner lacks',
|
|
41
|
-
'test:browser-login-popup:integration':
|
|
42
|
-
'live desktop integration harness; launches real Electron, which needs a display the Linux sweep runner lacks',
|
|
43
38
|
'test:browser-profile-import:integration': 'live desktop integration harness',
|
|
44
39
|
'test:remote-webrtc-sender:integration':
|
|
45
|
-
'live desktop integration harness; launches real Electron
|
|
40
|
+
'live desktop integration harness; launches real Electron and has never run in the sweep, so it stays out until verified under Xvfb',
|
|
46
41
|
'test:computer-host:integration': 'live desktop integration harness',
|
|
47
42
|
'test:computer-host:scenarios': 'live desktop scenario harness',
|
|
48
43
|
'test:computer-host:repeats': 'live desktop scenario harness',
|
|
@@ -50,6 +45,32 @@ export const WORKSPACES = [
|
|
|
50
45
|
},
|
|
51
46
|
];
|
|
52
47
|
|
|
48
|
+
// Swept scripts that launch a real Electron window. The headless Linux runner
|
|
49
|
+
// has no X server, so they run inside a virtual one (xvfb-run, as
|
|
50
|
+
// linux-desktop-verify.yml does). The runner also has no usable keyring (a
|
|
51
|
+
// keyring daemon there prompts for an unlock on a display it cannot open and
|
|
52
|
+
// stalls the entry), and these entries check Mixdog's own persistence and
|
|
53
|
+
// sign-out logic, not the OS keychain. So on Linux the sweep sets
|
|
54
|
+
// TEST_PLAINTEXT_SAFE_STORAGE_ENV and the test harness alone (never the app)
|
|
55
|
+
// switches Electron's safeStorage to its in-memory-password fallback.
|
|
56
|
+
export const DISPLAY_SUITES = ['test:browser-login-persistence:integration', 'test:browser-login-popup:integration'];
|
|
57
|
+
export const TEST_PLAINTEXT_SAFE_STORAGE_ENV = 'MIXDOG_TEST_PLAINTEXT_SAFE_STORAGE';
|
|
58
|
+
|
|
59
|
+
const runsUnderDisplay = (ws, name, platform) =>
|
|
60
|
+
platform === 'linux' && ws.dir !== '.' && DISPLAY_SUITES.includes(name);
|
|
61
|
+
|
|
62
|
+
export function sweepCommand(ws, name, platform = process.platform) {
|
|
63
|
+
const args = ['run', name, ...(ws.dir === '.' ? [] : ['--prefix', ws.dir])];
|
|
64
|
+
if (runsUnderDisplay(ws, name, platform)) {
|
|
65
|
+
return ['xvfb-run', ['-a', '--server-args=-screen 0 1440x900x24', 'npm', ...args]];
|
|
66
|
+
}
|
|
67
|
+
return [platform === 'win32' ? 'npm.cmd' : 'npm', args];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function sweepEnv(ws, name, platform = process.platform, base = process.env) {
|
|
71
|
+
return runsUnderDisplay(ws, name, platform) ? { ...base, [TEST_PLAINTEXT_SAFE_STORAGE_ENV]: '1' } : base;
|
|
72
|
+
}
|
|
73
|
+
|
|
53
74
|
export function selectSuiteScripts(scripts, exclusions) {
|
|
54
75
|
const names = Object.keys(scripts).filter((name) => /^(test|smoke)(:|$)/.test(name));
|
|
55
76
|
const stale = Object.keys(exclusions).filter((name) => !names.includes(name));
|
|
@@ -59,6 +80,81 @@ export function selectSuiteScripts(scripts, exclusions) {
|
|
|
59
80
|
return names.filter((name) => !(name in exclusions));
|
|
60
81
|
}
|
|
61
82
|
|
|
83
|
+
const TAIL_LINES = 25;
|
|
84
|
+
const lastLines = (text, name) => {
|
|
85
|
+
const lines = String(text || '')
|
|
86
|
+
.trim()
|
|
87
|
+
.split('\n');
|
|
88
|
+
if (lines.length <= TAIL_LINES) return lines.join('\n');
|
|
89
|
+
return [`[${name} truncated: last ${TAIL_LINES} of ${lines.length} lines]`, ...lines.slice(-TAIL_LINES)].join('\n');
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// What a failed entry shows in the report: how it ended, every failure-summary
|
|
93
|
+
// and failed-test line from either stream (a long stderr must not hide them),
|
|
94
|
+
// then each stream's tail.
|
|
95
|
+
export function failureParts({ stdout, stderr, status, signal, error }) {
|
|
96
|
+
const failedLines = `${stdout || ''}\n${stderr || ''}`
|
|
97
|
+
.split('\n')
|
|
98
|
+
.filter((line) => /^\[failure-summary\]|^\s*✖ /.test(line));
|
|
99
|
+
const ended = error
|
|
100
|
+
? `spawn error: ${error.message}`
|
|
101
|
+
: `exit ${status ?? 'none'}${signal ? `, signal ${signal}` : ''}`;
|
|
102
|
+
const tails = [lastLines(stdout, 'stdout'), lastLines(stderr, 'stderr')].filter(Boolean).join('\n');
|
|
103
|
+
return { ended, failedLines, tails };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const failureText = ({ ended, failedLines, tails }) =>
|
|
107
|
+
[ended, failedLines.join('\n'), tails].filter(Boolean).join('\n').trim();
|
|
108
|
+
|
|
109
|
+
export const failureTail = (child) => failureText(failureParts(child));
|
|
110
|
+
|
|
111
|
+
// GitHub rejects an issue body over 65,536 characters (HTTP 422). Past the
|
|
112
|
+
// limit the tails go first, then failure lines from the end; the omission is
|
|
113
|
+
// always stated, and the full diagnostics stay in the workflow log.
|
|
114
|
+
const ISSUE_BODY_LIMIT = 60_000;
|
|
115
|
+
|
|
116
|
+
export function buildReport({ checked, runUrl, reportLines, failures, limit = ISSUE_BODY_LIMIT }) {
|
|
117
|
+
const render = (withTails, keep) => {
|
|
118
|
+
let left = keep;
|
|
119
|
+
let omitted = 0;
|
|
120
|
+
const blocks = failures.map(({ title, parts }) => {
|
|
121
|
+
const shown = parts.failedLines.slice(0, left);
|
|
122
|
+
left -= shown.length;
|
|
123
|
+
omitted += parts.failedLines.length - shown.length;
|
|
124
|
+
const text = failureText({ ...parts, failedLines: shown, tails: withTails ? parts.tails : '' });
|
|
125
|
+
return `${title}\n\n\`\`\`\n${text}\n\`\`\``;
|
|
126
|
+
});
|
|
127
|
+
const notes = [];
|
|
128
|
+
if (!withTails) notes.push('Stdout/stderr tails omitted to fit the issue size limit; see the workflow log.');
|
|
129
|
+
if (omitted) notes.push(`${omitted} more failure lines omitted — see the workflow log: ${runUrl}`);
|
|
130
|
+
return [
|
|
131
|
+
'# Weekly suite health sweep failed',
|
|
132
|
+
'',
|
|
133
|
+
`Checked: ${checked}`,
|
|
134
|
+
`Workflow run: ${runUrl}`,
|
|
135
|
+
'',
|
|
136
|
+
...reportLines,
|
|
137
|
+
'',
|
|
138
|
+
...blocks,
|
|
139
|
+
'',
|
|
140
|
+
...notes,
|
|
141
|
+
]
|
|
142
|
+
.join('\n')
|
|
143
|
+
.trimEnd()
|
|
144
|
+
.concat('\n');
|
|
145
|
+
};
|
|
146
|
+
const total = failures.reduce((sum, { parts }) => sum + parts.failedLines.length, 0);
|
|
147
|
+
if (render(true, total).length <= limit) return render(true, total);
|
|
148
|
+
let low = 0;
|
|
149
|
+
let high = total;
|
|
150
|
+
while (low < high) {
|
|
151
|
+
const mid = Math.ceil((low + high) / 2);
|
|
152
|
+
if (render(false, mid).length <= limit) low = mid;
|
|
153
|
+
else high = mid - 1;
|
|
154
|
+
}
|
|
155
|
+
return render(false, low);
|
|
156
|
+
}
|
|
157
|
+
|
|
62
158
|
function runSweep() {
|
|
63
159
|
const failures = [];
|
|
64
160
|
const reportLines = [];
|
|
@@ -68,8 +164,9 @@ function runSweep() {
|
|
|
68
164
|
for (const name of names) {
|
|
69
165
|
const label = ws.dir === '.' ? name : `${ws.dir} ${name}`;
|
|
70
166
|
const started = Date.now();
|
|
71
|
-
const args =
|
|
72
|
-
const child = spawnSync(
|
|
167
|
+
const [command, args] = sweepCommand(ws, name);
|
|
168
|
+
const child = spawnSync(command, args, {
|
|
169
|
+
env: sweepEnv(ws, name),
|
|
73
170
|
encoding: 'utf8',
|
|
74
171
|
shell: process.platform === 'win32',
|
|
75
172
|
maxBuffer: 64 * 1024 * 1024,
|
|
@@ -79,10 +176,12 @@ function runSweep() {
|
|
|
79
176
|
reportLines.push(`- ${label}: OK (${seconds}s)`);
|
|
80
177
|
console.log(`${label}: OK (${seconds}s)`);
|
|
81
178
|
} else {
|
|
82
|
-
|
|
83
|
-
|
|
179
|
+
// Tail each stream on its own: a long stderr (cargo build chatter) must
|
|
180
|
+
// not push the test failure summary on stdout out of the report.
|
|
181
|
+
const parts = failureParts(child);
|
|
182
|
+
failures.push({ title: `- ${label}: FAILED (${seconds}s)`, parts });
|
|
84
183
|
reportLines.push(`- ${label}: FAILED (${seconds}s)`);
|
|
85
|
-
console.error(`${label}: FAILED (${seconds}s)\n${
|
|
184
|
+
console.error(`${label}: FAILED (${seconds}s)\n${failureText(parts)}`);
|
|
86
185
|
}
|
|
87
186
|
}
|
|
88
187
|
}
|
|
@@ -91,18 +190,10 @@ function runSweep() {
|
|
|
91
190
|
const runUrl = process.env.GITHUB_RUN_ID
|
|
92
191
|
? `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`
|
|
93
192
|
: '(local run)';
|
|
94
|
-
|
|
95
|
-
'
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
`Workflow run: ${runUrl}`,
|
|
99
|
-
'',
|
|
100
|
-
...reportLines,
|
|
101
|
-
'',
|
|
102
|
-
...failures,
|
|
103
|
-
'',
|
|
104
|
-
].join('\n');
|
|
105
|
-
writeFileSync('suite-health-report.md', report);
|
|
193
|
+
writeFileSync(
|
|
194
|
+
'suite-health-report.md',
|
|
195
|
+
buildReport({ checked: new Date().toISOString(), runUrl, reportLines, failures })
|
|
196
|
+
);
|
|
106
197
|
process.exitCode = 1;
|
|
107
198
|
}
|
|
108
199
|
}
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
// Side-effect module: import FIRST in tests that touch the read-snapshot store.
|
|
2
2
|
// Points the Mixdog data dir at a per-run temp dir before snapshot-store.mjs
|
|
3
3
|
// resolves SNAPSHOT_DIR at module load, so tests never write to the real one.
|
|
4
|
-
import { mkdtempSync
|
|
4
|
+
import { mkdtempSync } from 'node:fs';
|
|
5
5
|
import { tmpdir } from 'node:os';
|
|
6
6
|
import { join } from 'node:path';
|
|
7
|
+
import { registerOwnedTempDir } from './lib/scoped-temp.mjs';
|
|
8
|
+
import { pruneStaleTempDirs, removeTempDirSync } from './lib/stale-temp.mjs';
|
|
7
9
|
|
|
8
10
|
if (!process.env.MIXDOG_TEST_DATA_DIR_OWNED) {
|
|
9
|
-
|
|
11
|
+
// The exit handler never runs for a killed process, so each start sweeps
|
|
12
|
+
// what earlier killed processes left.
|
|
13
|
+
const prefix = 'mixdog-test-data-';
|
|
14
|
+
pruneStaleTempDirs([prefix]);
|
|
15
|
+
const dir = mkdtempSync(join(tmpdir(), prefix));
|
|
16
|
+
registerOwnedTempDir(dir);
|
|
10
17
|
process.env.MIXDOG_DATA_DIR = dir;
|
|
11
18
|
process.env.MIXDOG_TEST_DATA_DIR_OWNED = '1';
|
|
12
19
|
process.on('exit', () => {
|
|
13
|
-
|
|
14
|
-
rmSync(dir, { recursive: true, force: true });
|
|
15
|
-
} catch {
|
|
16
|
-
/* best effort */
|
|
17
|
-
}
|
|
20
|
+
removeTempDirSync(dir);
|
|
18
21
|
});
|
|
19
22
|
}
|
package/scripts/test.mjs
CHANGED
|
@@ -40,12 +40,11 @@ export const USAGE = `Usage: node scripts/test.mjs [--lane ${LANES.join('|')}] [
|
|
|
40
40
|
--exclude-lane drop one lane from the selection, repeatable. Electron and
|
|
41
41
|
window-capture tests cannot run twice at once, so a second
|
|
42
42
|
concurrent --lane all run uses --exclude-lane electron.
|
|
43
|
-
--rerun-failed <n> re-run the failed files up to n times
|
|
44
|
-
|
|
45
|
-
overrides the default. A test that
|
|
46
|
-
reported as flaky and does NOT fail the
|
|
47
|
-
fails every re-run still exits 1.
|
|
48
|
-
the run.
|
|
43
|
+
--rerun-failed <n> re-run the failed files up to n times to classify flaky
|
|
44
|
+
tests. Default 0: every failure fails the run;
|
|
45
|
+
MIXDOG_TEST_RERUN_FAILED overrides the default. A test that
|
|
46
|
+
passes on a re-run is reported as flaky and does NOT fail the
|
|
47
|
+
run; a test that fails every re-run still exits 1.
|
|
49
48
|
Per-file timeout: --test-timeout (default 120000 ms for the fast lane, 600000
|
|
50
49
|
ms otherwise); MIXDOG_TEST_TIMEOUT_MS overrides, 0 disables.
|
|
51
50
|
--import forwarded to node (desktop passes its test-env and tsx loaders).
|
|
@@ -88,15 +87,11 @@ function rerunCount(value) {
|
|
|
88
87
|
return Number(value);
|
|
89
88
|
}
|
|
90
89
|
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
// strict policy unless it opts in with --rerun-failed or MIXDOG_TEST_RERUN_FAILED;
|
|
95
|
-
// MIXDOG_TEST_RERUN_FAILED=0 turns the local default off.
|
|
90
|
+
// Every failure fails the run, locally and in CI: a test that passes only on a
|
|
91
|
+
// re-run is a defect to fix, not a pass. Re-runs happen only on an explicit
|
|
92
|
+
// --rerun-failed or MIXDOG_TEST_RERUN_FAILED, to classify a failure as flaky.
|
|
96
93
|
export function defaultRerunFailed(env = process.env) {
|
|
97
|
-
|
|
98
|
-
const ci = String(env.CI ?? '').toLowerCase();
|
|
99
|
-
return ci && ci !== '0' && ci !== 'false' ? 0 : 1;
|
|
94
|
+
return /^\d+$/.test(String(env.MIXDOG_TEST_RERUN_FAILED ?? '')) ? Number(env.MIXDOG_TEST_RERUN_FAILED) : 0;
|
|
100
95
|
}
|
|
101
96
|
|
|
102
97
|
export function parseArgs(argv) {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: Advisor
|
|
3
|
-
description: "Use
|
|
3
|
+
description: "Use as a second mind on hard work: consulting before a risky or complex change is built, hunting a bug whose cause is unclear, errors that recur or results that stop converging, or when the user asks. Never for final verification."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
Independent technical advisor.
|
|
7
7
|
|
|
8
|
-
You are
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
You are a second mind on hard work: consulted before a risky or complex
|
|
9
|
+
change is built, to hunt a bug whose cause is unclear, when errors recur or
|
|
10
|
+
results stop converging, and when the user asks for a second opinion or
|
|
11
11
|
cross-validation. You do not see the Lead's conversation; work from the brief
|
|
12
12
|
and verify its evidence against the source yourself.
|
|
13
13
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "advisor",
|
|
3
3
|
"name": "Advisor",
|
|
4
|
-
"description": "Use
|
|
4
|
+
"description": "Use as a second mind on hard work: consulting before a risky or complex change is built, hunting a bug whose cause is unclear, errors that recur or results that stop converging, or when the user asks. Never for final verification.",
|
|
5
5
|
"entry": "AGENT.md"
|
|
6
6
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Explore
|
|
3
|
+
description: Use when Mixdog runs the explore tool. The tool stays off until a model is picked.
|
|
4
|
+
permission: read
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Read-only explorer for one query of the explore tool. Search and read the
|
|
8
|
+
working directory; never edit, run commands or delegate.
|
|
9
|
+
|
|
10
|
+
Answer the query in the message, then stop:
|
|
11
|
+
|
|
12
|
+
- First a short direct answer.
|
|
13
|
+
- Then the evidence: one `path:line` per finding, copied from tool output,
|
|
14
|
+
with a few words on what is there.
|
|
15
|
+
- Only what you found. If nothing answers the query, say so in one line and
|
|
16
|
+
name what you searched.
|
|
17
|
+
- Nothing else: no locations the query did not ask about, no notes on what
|
|
18
|
+
you did not read.
|
|
19
|
+
|
|
20
|
+
Batch independent patterns and paths in one call. A location a tool returned
|
|
21
|
+
is final: do not re-read or reconfirm it. Stop as soon as the answer is
|
|
22
|
+
supported.
|
package/src/app.mjs
CHANGED
|
@@ -24,6 +24,10 @@ export { parseHeadlessExecCommand };
|
|
|
24
24
|
* running behavior will NOT match the tree, so warn loudly.
|
|
25
25
|
*/
|
|
26
26
|
function warnWhenTuiBundleStale(bundle) {
|
|
27
|
+
// Only a source checkout can drift from its bundle: src/tui/dev is left out
|
|
28
|
+
// of the npm package, and an npm install stamps every file with its own
|
|
29
|
+
// extraction time, so the mtime comparison below would misfire there.
|
|
30
|
+
if (!existsSync(join(__dirname, 'tui', 'dev', 'jit-rebuild.mjs'))) return;
|
|
27
31
|
try {
|
|
28
32
|
const bundleMtime = statSync(bundle).mtimeMs;
|
|
29
33
|
const hotSources = [
|