mixdog 1.2.5 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSES/simple-icons-CC0-1.0.txt +30 -0
- package/NOTICE.md +19 -0
- package/package.json +4 -1
- package/scripts/check-model-recommendations.mjs +89 -0
- package/scripts/gate-local.mjs +7 -0
- package/scripts/lib/gate-scheduler.mjs +2 -2
- package/scripts/lib/isolated-test-env.mjs +16 -0
- package/scripts/lib/run-node-tests.mjs +5 -14
- package/scripts/provider-pingpong-live.mjs +9 -9
- package/src/agents/advisor/AGENT.md +4 -4
- package/src/agents/advisor/agent.json +1 -1
- package/src/agents/reviewer/AGENT.md +5 -4
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +17 -0
- package/src/defaults/skills/browser-use/SKILL.md +7 -1
- package/src/defaults/skills/computer-use/SKILL.md +3 -1
- package/src/defaults/skills/memory-management/SKILL.md +4 -1
- package/src/defaults/skills/setup/references/actions.md +11 -4
- package/src/defaults/skills/setup-guide/SKILL.md +175 -0
- package/src/defaults/skills/setup-guide/model-recommendations.json +333 -0
- package/src/defaults/skills/visualize/SKILL.md +3 -2
- package/src/lib/rules-builder.cjs +56 -7
- package/src/output-styles/common.md +22 -6
- package/src/output-styles/detailed.md +7 -5
- package/src/output-styles/minimal.md +7 -3
- package/src/output-styles/simple.md +2 -3
- package/src/rules/agent/AGENT.md +7 -1
- package/src/rules/agent-mode/AGENT_MODE.md +24 -0
- package/src/rules/agent-mode/MIXY.md +21 -0
- package/src/rules/agent-mode/ROUTINE.md +6 -0
- package/src/rules/lead/LEAD.md +9 -4
- package/src/rules/shared/10-tool-workflow.md +2 -1
- package/src/rules/shared/60-verification.md +4 -5
- package/src/rules/shared/70-delivery.md +3 -0
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -1
- package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +86 -0
- package/src/runtime/agent/orchestrator/config.mjs +6 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +77 -14
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +182 -13
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +5 -3
- package/src/runtime/agent/orchestrator/internal-agents.mjs +10 -0
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +215 -0
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +58 -64
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +10 -1
- package/src/runtime/agent/orchestrator/mcp/client.mjs +122 -15
- package/src/runtime/agent/orchestrator/mcp/oauth-account.mjs +97 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +2 -3
- package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +49 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +59 -9
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +32 -7
- package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +45 -6
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +195 -6
- package/src/runtime/agent/orchestrator/mcp/server-connectors.mjs +17 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +41 -19
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +11 -5
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/catalog-deadline.mjs +163 -0
- package/src/runtime/agent/orchestrator/providers/catalog-failures.mjs +34 -0
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +38 -14
- package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +100 -26
- package/src/runtime/agent/orchestrator/providers/lib/send-callbacks.mjs +24 -0
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +13 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +49 -4
- package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +0 -7
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +17 -12
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +5 -1
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +11 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +45 -16
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-connect.mjs +196 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +74 -9
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +14 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-login.mjs +194 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-tokens.mjs +353 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +293 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +33 -100
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +23 -14
- package/src/runtime/agent/orchestrator/providers/registry.mjs +41 -27
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +98 -4
- package/src/runtime/agent/orchestrator/runtime-core/context-status-shape.mjs +4 -0
- package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +6 -4
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +15 -8
- package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +12 -6
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +32 -5
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +10 -4
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +4 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +50 -20
- package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/agent-home.d.mts +4 -0
- package/src/runtime/agent/orchestrator/session/agent-home.mjs +33 -0
- package/src/runtime/agent/orchestrator/session/agent-mode.mjs +62 -0
- package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +15 -3
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +31 -0
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +241 -0
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +162 -0
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +641 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +74 -13
- package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +102 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +8 -2
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +165 -0
- package/src/runtime/agent/orchestrator/session/human-gate/held-message.mjs +95 -0
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +221 -0
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +195 -0
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +167 -0
- package/src/runtime/agent/orchestrator/session/lifecycle-scan.mjs +9 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +39 -2
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +16 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +82 -33
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +11 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +5 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +13 -3
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +6 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +13 -5
- package/src/runtime/agent/orchestrator/session/manager/pending-lifecycle-epoch.mjs +0 -8
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +10 -7
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +62 -22
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +44 -16
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +22 -5
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +23 -1
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +81 -34
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +39 -4
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +27 -5
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +55 -8
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +58 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/mixy-name.mjs +24 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +32 -5
- package/src/runtime/agent/orchestrator/session/request-fork.mjs +47 -0
- package/src/runtime/agent/orchestrator/session/routine-result.d.mts +70 -0
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +277 -0
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +16 -1
- package/src/runtime/agent/orchestrator/session/side-question.mjs +5 -43
- package/src/runtime/agent/orchestrator/session/store/fs-probe.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +73 -6
- package/src/runtime/agent/orchestrator/session/store/load-session.mjs +40 -0
- package/src/runtime/agent/orchestrator/session/store/save-fault.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-header.mjs +36 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +258 -43
- package/src/runtime/agent/orchestrator/session/store-record-strict-scan.mjs +325 -0
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +84 -21
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -12
- package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +46 -0
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +46 -30
- package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +0 -4
- package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +144 -45
- package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +32 -13
- package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +364 -38
- package/src/runtime/agent/orchestrator/session/store.mjs +9 -2
- package/src/runtime/agent/orchestrator/session/task-wait-control.mjs +43 -12
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +23 -6
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +44 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +12 -6
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +13 -7
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/bashism-rewrite.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/benign-exit.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +40 -7
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +37 -34
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +0 -4
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -0
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +29 -27
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/find-files-tool.mjs +28 -11
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +12 -3
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +203 -101
- package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +90 -41
- package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +17 -1
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-delivery.mjs +199 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +12 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +165 -39
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +25 -13
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +113 -5
- package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +7 -6
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +19 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-line-collector.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +25 -7
- package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-render.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +12 -5
- package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +61 -22
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +32 -8
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +193 -19
- package/src/runtime/agent/orchestrator/tools/builtin/shell-direct-exe.mjs +57 -7
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +123 -32
- package/src/runtime/agent/orchestrator/tools/builtin/shell-lossless-compact.mjs +26 -1
- package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +13 -28
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +90 -11
- package/src/runtime/agent/orchestrator/tools/builtin/wait-budgets.mjs +23 -0
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +54 -10
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +22 -28
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +11 -7
- package/src/runtime/agent/orchestrator/tools/destructive-warning.mjs +126 -9
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +15 -6
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +64 -2
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +10 -2
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promotion-results.mjs +13 -3
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +8 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +104 -55
- package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +7 -2
- package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +39 -23
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
- package/src/runtime/attachments/office-extract.mjs +11 -9
- package/src/runtime/browser-bridge/client.mjs +24 -0
- package/src/runtime/channels/lib/scheduler.mjs +40 -12
- package/src/runtime/channels/lib/schedules-db.mjs +71 -12
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +36 -16
- package/src/runtime/channels/lib/webhook.mjs +0 -1
- package/src/runtime/channels/lib/webhooks-db.mjs +100 -10
- package/src/runtime/channels/lib/worker-main.mjs +17 -20
- package/src/runtime/computer-bridge/client.mjs +28 -1
- package/src/runtime/connectors/gmail-app-password.mjs +690 -0
- package/src/runtime/connectors/google-mcp.mjs +446 -0
- package/src/runtime/memory/lib/core-memory-access.mjs +69 -0
- package/src/runtime/memory/lib/core-memory-file.mjs +16 -8
- package/src/runtime/memory/lib/core-memory-index.mjs +15 -9
- package/src/runtime/memory/lib/core-memory-management.mjs +10 -4
- package/src/runtime/memory/lib/core-memory-store.mjs +53 -30
- package/src/runtime/memory/lib/core-memory-uniqueness.mjs +10 -6
- package/src/runtime/memory/lib/embedding-tokenizer.mjs +32 -18
- package/src/runtime/memory/lib/http-router/session-routes.mjs +3 -2
- package/src/runtime/memory/lib/memory-action-handlers/core-actions.mjs +44 -14
- package/src/runtime/memory/lib/memory-schema/core-and-meta.mjs +11 -0
- package/src/runtime/memory/lib/memory.mjs +7 -1
- package/src/runtime/memory/lib/query-core-recall.mjs +9 -1
- package/src/runtime/memory/lib/query-hybrid-search.mjs +2 -0
- package/src/runtime/memory/lib/runtime-fetcher.mjs +1 -1
- package/src/runtime/memory/lib/tool-call-handler.mjs +9 -5
- package/src/runtime/memory/tool-defs.mjs +5 -0
- package/src/runtime/office/authoring/pptx-script-normalize.mjs +11 -8
- package/src/runtime/office/core/tabular.mjs +1 -1
- package/src/runtime/office/design/library/design-template-inspect.mjs +7 -4
- package/src/runtime/office/portable/docx-formatting.mjs +1 -1
- package/src/runtime/office/portable/docx-runs.mjs +1 -1
- package/src/runtime/office/portable/docx-tracked-edits.mjs +2 -2
- package/src/runtime/office/portable/portable-docx-edits.mjs +11 -10
- package/src/runtime/office/portable/portable-docx-operations.mjs +21 -17
- package/src/runtime/office/portable/portable-docx-parts.mjs +15 -9
- package/src/runtime/office/portable/portable-docx-styles.mjs +4 -1
- package/src/runtime/office/portable/portable-docx-xml.mjs +9 -9
- package/src/runtime/office/portable/portable-opc.mjs +27 -13
- package/src/runtime/office/portable/portable-pivot.mjs +3 -3
- package/src/runtime/office/portable/portable-pptx-chart.mjs +3 -3
- package/src/runtime/office/portable/portable-pptx-charts.mjs +24 -18
- package/src/runtime/office/portable/portable-pptx-core.mjs +5 -5
- package/src/runtime/office/portable/portable-pptx-deck.mjs +8 -4
- package/src/runtime/office/portable/portable-pptx-package.mjs +7 -4
- package/src/runtime/office/portable/portable-pptx-shapes.mjs +18 -9
- package/src/runtime/office/portable/portable-sheet-parts.mjs +9 -3
- package/src/runtime/office/portable/portable-sheet-xml.mjs +5 -5
- package/src/runtime/office/portable/portable-xlsx-charts.mjs +4 -1
- package/src/runtime/office/portable/portable-xlsx-drawings.mjs +10 -6
- package/src/runtime/office/portable/portable-xlsx-operations.mjs +8 -5
- package/src/runtime/office/portable/portable-xlsx-pivot-ops.mjs +1 -1
- package/src/runtime/office/portable/portable-xlsx-reference-shift.mjs +11 -7
- package/src/runtime/office/portable/portable-xlsx-sheet-edits.mjs +6 -3
- package/src/runtime/office/portable/portable-xml.mjs +1 -1
- package/src/runtime/shared/agent-avatar-sprites.mjs +445 -0
- package/src/runtime/shared/agent-avatar.d.mts +64 -0
- package/src/runtime/shared/agent-avatar.mjs +320 -0
- package/src/runtime/shared/agent-route-config.d.mts +3 -0
- package/src/runtime/shared/agent-route-config.mjs +16 -0
- package/src/runtime/shared/atomic-file.mjs +36 -14
- package/src/runtime/shared/background-tasks.mjs +60 -20
- package/src/runtime/shared/child-spawn-gate.mjs +26 -16
- package/src/runtime/shared/config.mjs +8 -11
- package/src/runtime/shared/connector-accounts.mjs +15 -0
- package/src/runtime/shared/connector-catalog.d.mts +52 -0
- package/src/runtime/shared/connector-catalog.mjs +230 -0
- package/src/runtime/shared/connector-triggers.d.mts +3 -0
- package/src/runtime/shared/connector-triggers.mjs +43 -0
- package/src/runtime/shared/file-lock.mjs +7 -1
- package/src/runtime/shared/file-permissions-worker.mjs +38 -0
- package/src/runtime/shared/file-permissions.d.mts +19 -4
- package/src/runtime/shared/file-permissions.mjs +310 -4
- package/src/runtime/shared/git-runner-worker.mjs +6 -78
- package/src/runtime/shared/google-oauth-client.mjs +24 -0
- package/src/runtime/shared/held-request-host.d.mts +12 -0
- package/src/runtime/shared/held-request-host.mjs +71 -0
- package/src/runtime/shared/llm/http-agent.mjs +7 -3
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +10 -0
- package/src/runtime/shared/llm/usage-accounting.mjs +2 -0
- package/src/runtime/shared/llm/usage-ledger-import.mjs +32 -3
- package/src/runtime/shared/llm/usage-ledger-rollup.mjs +12 -5
- package/src/runtime/shared/llm/usage-ledger-worker.mjs +1 -1
- package/src/runtime/shared/llm/usage-ledger.mjs +20 -5
- package/src/runtime/shared/memory-snapshot.mjs +5 -1
- package/src/runtime/shared/notify-trace.mjs +8 -1
- package/src/runtime/shared/plain-preview.d.mts +1 -0
- package/src/runtime/shared/plain-preview.mjs +28 -0
- package/src/runtime/shared/pristine-execution-contract.json +5 -1
- package/src/runtime/shared/process-runner-worker.mjs +7 -0
- package/src/runtime/shared/process-runner.mjs +38 -0
- package/src/runtime/shared/provider-accounts.mjs +2 -1
- package/src/runtime/shared/provider-api-key.mjs +0 -1
- package/src/runtime/shared/read-row-numbers.mjs +1 -1
- package/src/runtime/shared/resource-admission.mjs +60 -18
- package/src/runtime/shared/routine-limits.d.mts +11 -0
- package/src/runtime/shared/routine-limits.mjs +21 -0
- package/src/runtime/shared/routine-trigger.d.mts +10 -0
- package/src/runtime/shared/routine-trigger.mjs +44 -0
- package/src/runtime/shared/run-child.mjs +84 -0
- package/src/runtime/shared/schedule-model-ref.mjs +9 -10
- package/src/runtime/shared/session-activity-signal.mjs +23 -0
- package/src/runtime/shared/shell-output-summary.mjs +23 -0
- package/src/runtime/shared/singleton-owner.mjs +126 -42
- package/src/runtime/shared/slow-span.mjs +4 -12
- package/src/runtime/shared/statusline/statusline-segments.mjs +13 -1
- package/src/runtime/shared/tool-output-limit.mjs +4 -2
- package/src/runtime/shared/tool-output-marker.mjs +58 -0
- package/src/runtime/shared/transcript-metadata.mjs +10 -0
- package/src/runtime/shared/turn-changes.mjs +0 -8
- package/src/runtime/shared/usage-readout-totals.mjs +56 -0
- package/src/runtime/shared/user-data-guard.mjs +131 -34
- package/src/runtime/shared/worktrees/activity-gate.mjs +33 -8
- package/src/runtime/shared/worktrees/git-head.mjs +20 -2
- package/src/runtime/shared/worktrees/lock.mjs +3 -2
- package/src/runtime/terminal-bridge/tool-defs.mjs +1 -1
- package/src/runtime/tidy/runners/biome.mjs +3 -1
- package/src/runtime/tidy/shadow.mjs +2 -1
- package/src/runtime/web-search/index.mjs +5 -7
- package/src/runtime/web-search/lib/formatter.mjs +42 -6
- package/src/runtime/web-search/tool-defs.mjs +6 -1
- package/src/session-runtime/agent-home-delivery.mjs +459 -0
- package/src/session-runtime/agent-profile-changes.mjs +21 -0
- package/src/session-runtime/agent-room-delivery.mjs +92 -0
- package/src/session-runtime/agent-task-sessions.mjs +200 -0
- package/src/session-runtime/boot/apis.mjs +50 -18
- package/src/session-runtime/boot/facade.mjs +5 -8
- package/src/session-runtime/boot/infrastructure.mjs +28 -17
- package/src/session-runtime/boot/tools.mjs +3 -0
- package/src/session-runtime/channel-config-api.mjs +53 -5
- package/src/session-runtime/cwd-plugins/core-memory-context.mjs +36 -20
- package/src/session-runtime/cwd-plugins/plugin-status.mjs +6 -1
- package/src/session-runtime/held-requests.mjs +228 -0
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +121 -0
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +5 -1
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +31 -2
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +31 -2
- package/src/session-runtime/internal-tool-executor.mjs +2 -0
- package/src/session-runtime/lifecycle/session-catalog.mjs +9 -0
- package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +4 -3
- package/src/session-runtime/lifecycle/session-switch/resume.mjs +11 -4
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +3 -3
- package/src/session-runtime/lifecycle/shared.mjs +25 -2
- package/src/session-runtime/lifecycle/teardown/session-close.mjs +2 -0
- package/src/session-runtime/lifecycle/teardown.mjs +5 -2
- package/src/session-runtime/lifecycle-api.mjs +3 -1
- package/src/session-runtime/mcp-glue/server-catalog.mjs +8 -0
- package/src/session-runtime/mcp-glue/server-input.mjs +3 -0
- package/src/session-runtime/mcp-oauth-login.mjs +112 -15
- package/src/session-runtime/model-route/set-route.mjs +14 -3
- package/src/session-runtime/owned-automation-run.mjs +229 -0
- package/src/session-runtime/provider-auth/login.mjs +10 -6
- package/src/session-runtime/provider-auth/setup.mjs +19 -2
- package/src/session-runtime/provider-catalog-cache.mjs +101 -25
- package/src/session-runtime/provider-models/catalog-load.mjs +14 -3
- package/src/session-runtime/provider-models/row-hydration.mjs +4 -0
- package/src/session-runtime/provider-models.mjs +76 -10
- package/src/session-runtime/provider-readiness.mjs +4 -0
- package/src/session-runtime/resource-api.mjs +5 -0
- package/src/session-runtime/resource-mcp-api.mjs +107 -13
- package/src/session-runtime/resource-skills-api.mjs +12 -0
- package/src/session-runtime/room-member-gate.mjs +48 -0
- package/src/session-runtime/routine-home-turn.mjs +156 -0
- package/src/session-runtime/routine-owner.mjs +48 -0
- package/src/session-runtime/schedule-session-run.mjs +30 -64
- package/src/session-runtime/services/agent-tool/close-flow.mjs +2 -1
- package/src/session-runtime/services/agent-tool/helpers.mjs +10 -0
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +10 -2
- package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +13 -4
- package/src/session-runtime/services/agent-tool/notify.mjs +15 -4
- package/src/session-runtime/services/agent-tool/restart-notify.mjs +134 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -1
- package/src/session-runtime/services/agent-tool/spawn-flow/deferred-spawn.mjs +2 -1
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +4 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +19 -4
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +2 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -1
- package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +8 -3
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +4 -0
- package/src/session-runtime/services/agent-tool/worker-index.mjs +44 -10
- package/src/session-runtime/services/agent-tool.mjs +20 -0
- package/src/session-runtime/services/channel-admin.mjs +93 -24
- package/src/session-runtime/services/memory-access.mjs +37 -0
- package/src/session-runtime/services/provider-admin.mjs +166 -59
- package/src/session-runtime/services/schedule-access.mjs +91 -0
- package/src/session-runtime/services/usage-dashboard-model.mjs +2 -2
- package/src/session-runtime/services/usage-dashboard.mjs +27 -69
- package/src/session-runtime/session-create/session-options.mjs +34 -7
- package/src/session-runtime/session-hooks.mjs +16 -8
- package/src/session-runtime/setup-tool/executor.mjs +68 -6
- package/src/session-runtime/setup-tool/extended-actions.mjs +72 -14
- package/src/session-runtime/setup-tool/settings-contract.mjs +8 -6
- package/src/session-runtime/setup-tool/tool-defs.mjs +8 -0
- package/src/session-runtime/skills-api.mjs +16 -1
- package/src/session-runtime/tool-policy-refresh.mjs +238 -29
- package/src/session-runtime/turn/session-ops.mjs +10 -3
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +11 -2
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +3 -0
- package/src/session-runtime/usage-stats-api.mjs +6 -1
- package/src/session-runtime/webhook-session-run.mjs +49 -67
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +239 -0
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +556 -22
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +11 -1
- package/src/session-runtime/workflow-agents-api.mjs +4 -1
- package/src/standalone/channel-transport/http-routes.mjs +10 -9
- package/src/standalone/daemon-agent-control.mjs +1 -8
- package/src/standalone/daemon-desktop-runtime.mjs +20 -7
- package/src/standalone/daemon-owner.mjs +117 -25
- package/src/standalone/daemon-session-control.mjs +11 -2
- package/src/standalone/daemon.mjs +61 -17
- package/src/standalone/session-call-cache.mjs +6 -0
- package/src/standalone/session-protocol.mjs +28 -1
- package/src/standalone/session-service/retention/busy.mjs +7 -2
- package/src/standalone/session-service/session-calls/session-turns.mjs +9 -0
- package/src/standalone/session-service.mjs +19 -0
- package/src/standalone/session-transport/routes.mjs +7 -6
- package/src/tui/app/model-options.mjs +39 -2
- package/src/tui/app/model-picker.mjs +16 -2
- package/src/tui/app/provider-setup-picker.mjs +1 -2
- package/src/tui/app/slash-commands.mjs +20 -0
- package/src/tui/dist/index.mjs +487 -128
- package/src/tui/session/context-state.mjs +6 -1
- package/src/tui/session/notice-surface.mjs +35 -4
- package/src/tui/session/notice-text.mjs +0 -1
- package/src/tui/session/queue-helpers.mjs +2 -1
- package/src/tui/session/session-api/extensions.mjs +4 -0
- package/src/tui/session/session-api/intake/submission.mjs +12 -13
- package/src/tui/session/session-api/integrations.mjs +9 -5
- package/src/tui/session/session-api/lifecycle/session-reset.mjs +13 -3
- package/src/tui/session/session-api/lifecycle.mjs +17 -1
- package/src/tui/session/session-api/routes.mjs +48 -3
- package/src/tui/session/session-flow/drain.mjs +20 -3
- package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -1
- package/src/tui/session/session-flow/queue/take-entries.mjs +3 -2
- package/src/tui/session/session-flow/steering.mjs +104 -24
- package/src/tui/session/session-flow.mjs +2 -0
- package/src/tui/session/tool-approval.mjs +26 -5
- package/src/tui/session/transcript-intake.mjs +6 -2
- package/src/tui/session/transcript-spill.mjs +5 -1
- package/src/tui/session/tui-steering-persist.mjs +65 -42
- package/src/tui/session/turn-live-call.mjs +56 -0
- package/src/tui/session/turn-stream.mjs +33 -0
- package/src/tui/session/turn.mjs +50 -7
- package/src/ui/statusline.mjs +1 -6
- package/src/ui/streaming-markdown-heal.mjs +24 -7
- package/src/vendor/statusline/bin/statusline-route.mjs +0 -1
- package/src/vendor/statusline/src/gateway/route-meta.mjs +0 -1
- package/src/workflows/default/WORKFLOW.md +9 -13
- package/src/session-runtime/automation-agents.mjs +0 -94
- package/src/session-runtime/automation-workflow.mjs +0 -59
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
// The Mixdog mascot: a blocky pixel creature on a 16x12 grid, painted from the
|
|
2
|
+
// string layers in agent-avatar-sprites.mjs (design/mockups/mixy-art). Every
|
|
3
|
+
// look is the same body block; the species (ears, marks, tail, legs), an
|
|
4
|
+
// accessory, the expression and the colour vary. An agent's `agent.json`
|
|
5
|
+
// stores its pick as `avatar: { kind: 'mascot', species, accessory,
|
|
6
|
+
// expression, color }` (an older `variant` reads as its mapped look), or its
|
|
7
|
+
// own images per motion state as `avatar: { kind: 'custom', states: { idle,
|
|
8
|
+
// typing?, message? } }`. An agent without one gets a stable look from its id.
|
|
9
|
+
import { MIXY_AGENT_ID } from '../agent/orchestrator/session/agent-home.mjs';
|
|
10
|
+
import { MASCOT_SPRITES } from './agent-avatar-sprites.mjs';
|
|
11
|
+
|
|
12
|
+
/** The palette an avatar colour is chosen from. */
|
|
13
|
+
export const AGENT_AVATAR_COLORS = Object.freeze([
|
|
14
|
+
'#e6e6e6',
|
|
15
|
+
'#9a9a9a',
|
|
16
|
+
'#f06a5f',
|
|
17
|
+
'#f59a42',
|
|
18
|
+
'#f2c94c',
|
|
19
|
+
'#5cc98a',
|
|
20
|
+
'#3fc1c9',
|
|
21
|
+
'#5b9bff',
|
|
22
|
+
'#9b7bff',
|
|
23
|
+
'#ef6fb0',
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
/** Every species a user can pick: the six dogs. Mixy's own (`mixy`) is not one of them. */
|
|
27
|
+
export const MASCOT_SPECIES = Object.freeze(['labrador', 'shepherd', 'terrier', 'corgi', 'husky', 'shiba']);
|
|
28
|
+
export const MASCOT_ACCESSORIES = Object.freeze(['none', 'collar', 'glasses', 'beanie', 'scarf', 'bow']);
|
|
29
|
+
/** Picks that were removed, read as their nearest remaining option. */
|
|
30
|
+
const RETIRED_SPECIES = { dalmatian: 'labrador', cat: 'labrador', bird: 'labrador', robot: 'labrador' };
|
|
31
|
+
const RETIRED_ACCESSORIES = { headset: 'glasses' };
|
|
32
|
+
export const MASCOT_EXPRESSIONS = Object.freeze(['calm', 'happy', 'wink', 'sleepy']);
|
|
33
|
+
|
|
34
|
+
/** Mixy, the primary assistant: its own silver pup with one ear up and a
|
|
35
|
+
* slate collar with the gold star medal. Never offered in the picker. */
|
|
36
|
+
export const MIXY_AVATAR = Object.freeze({
|
|
37
|
+
kind: 'mascot',
|
|
38
|
+
species: 'mixy',
|
|
39
|
+
accessory: 'none',
|
|
40
|
+
expression: 'calm',
|
|
41
|
+
color: '#e6e6e6',
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
/** The fixed inks a sprite letter names; B, D, L and E depend on the look. */
|
|
45
|
+
export const MASCOT_INKS = Object.freeze({
|
|
46
|
+
K: '#141414',
|
|
47
|
+
G: '#f2c94c',
|
|
48
|
+
R: '#e5534b',
|
|
49
|
+
O: '#f59a42',
|
|
50
|
+
W: '#f4f4f4',
|
|
51
|
+
C: '#3fc1c9',
|
|
52
|
+
M: '#8a8a90',
|
|
53
|
+
S: '#2a2b30',
|
|
54
|
+
P: '#ef8fb4',
|
|
55
|
+
N: '#f06a5f',
|
|
56
|
+
n: '#c4544c',
|
|
57
|
+
r: '#b94039',
|
|
58
|
+
F: '#ef6fb0',
|
|
59
|
+
f: '#b8497f',
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
/** `hex` with every channel scaled by `k`. */
|
|
63
|
+
export function shadeHex(hex, k) {
|
|
64
|
+
const n = Number.parseInt(hex.slice(1), 16);
|
|
65
|
+
const channel = (shift) =>
|
|
66
|
+
Math.round(((n >> shift) & 255) * k)
|
|
67
|
+
.toString(16)
|
|
68
|
+
.padStart(2, '0');
|
|
69
|
+
return `#${channel(16)}${channel(8)}${channel(0)}`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** `hex` mixed `k` of the way to white. */
|
|
73
|
+
function liftHex(hex, k) {
|
|
74
|
+
const n = Number.parseInt(hex.slice(1), 16);
|
|
75
|
+
const channel = (shift) => {
|
|
76
|
+
const value = (n >> shift) & 255;
|
|
77
|
+
return Math.round(value + (255 - value) * k)
|
|
78
|
+
.toString(16)
|
|
79
|
+
.padStart(2, '0');
|
|
80
|
+
};
|
|
81
|
+
return `#${channel(16)}${channel(8)}${channel(0)}`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// The 12 looks before species existed, `<ears>-<expression>-<plain|collar>`:
|
|
85
|
+
// each reads as the species with those ears, the collar as an accessory.
|
|
86
|
+
const LEGACY_EARS = { floppy: 'labrador', perky: 'shepherd', folded: 'terrier' };
|
|
87
|
+
const LEGACY_VARIANTS = Object.keys(LEGACY_EARS).flatMap((ears) =>
|
|
88
|
+
['calm', 'happy'].flatMap((expression) => ['plain', 'collar'].map((extra) => `${ears}-${expression}-${extra}`))
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
/** An older `variant` as its species, accessory and expression; null if unknown. */
|
|
92
|
+
export function mascotFromVariant(variant) {
|
|
93
|
+
if (!LEGACY_VARIANTS.includes(variant)) return null;
|
|
94
|
+
const [ears, expression, extra] = variant.split('-');
|
|
95
|
+
return { species: LEGACY_EARS[ears], accessory: extra === 'collar' ? 'collar' : 'none', expression };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** `species-accessory-expression`: a look's key (data attributes, tests). */
|
|
99
|
+
export const mascotLook = (avatar) => `${avatar.species}-${avatar.accessory}-${avatar.expression}`;
|
|
100
|
+
|
|
101
|
+
function layerCells(rows, color, eye) {
|
|
102
|
+
if (!rows) return [];
|
|
103
|
+
const ink = (key) => {
|
|
104
|
+
if (key === 'B') return color;
|
|
105
|
+
if (key === 'D') return shadeHex(color, 0.7);
|
|
106
|
+
if (key === 'L') return liftHex(color, 0.35);
|
|
107
|
+
return MASCOT_INKS[key === 'E' ? eye : key];
|
|
108
|
+
};
|
|
109
|
+
const cells = [];
|
|
110
|
+
rows.forEach((row, y) => {
|
|
111
|
+
for (let x = 0; x < row.length; x += 1) if (row[x] !== '.') cells.push({ x, y, fill: ink(row[x]) });
|
|
112
|
+
});
|
|
113
|
+
return cells;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** A look's cells by part, in paint order — the groups the renderer draws
|
|
117
|
+
* (tail, legs, then the bobbing body with its ears, marks, eyes and
|
|
118
|
+
* accessory). `blink` is the closed eyes an idle blink shows. Null for an
|
|
119
|
+
* unknown species. */
|
|
120
|
+
export function mascotParts(avatar) {
|
|
121
|
+
const species = MASCOT_SPRITES.species[avatar.species];
|
|
122
|
+
if (!species) return null;
|
|
123
|
+
const paint = (rows) => layerCells(rows, avatar.color, species.eye);
|
|
124
|
+
return {
|
|
125
|
+
tail: paint(species.tail && MASCOT_SPRITES.tails[species.tail]),
|
|
126
|
+
legs: paint(MASCOT_SPRITES.legs[species.legs]),
|
|
127
|
+
body: paint(MASCOT_SPRITES.body),
|
|
128
|
+
ear: paint(species.ears),
|
|
129
|
+
marks: paint(species.marks),
|
|
130
|
+
eyes: paint(MASCOT_SPRITES.eyes[avatar.expression]),
|
|
131
|
+
blink: paint(MASCOT_SPRITES.eyes.sleepy),
|
|
132
|
+
accessory: paint(MASCOT_SPRITES.accessories[avatar.accessory]),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** The look as one still frame: each cell's final fill. [] when unknown. */
|
|
137
|
+
export function mascotCells(avatar) {
|
|
138
|
+
const parts = mascotParts(avatar);
|
|
139
|
+
if (!parts) return [];
|
|
140
|
+
const cells = new Map();
|
|
141
|
+
for (const part of ['tail', 'legs', 'body', 'ear', 'marks', 'eyes', 'accessory']) {
|
|
142
|
+
for (const cell of parts[part]) cells.set(`${cell.y},${cell.x}`, cell);
|
|
143
|
+
}
|
|
144
|
+
return [...cells.values()];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Cells as one SVG path per fill, each row's run one rectangle. */
|
|
148
|
+
export function cellPaths(cells) {
|
|
149
|
+
const byFill = new Map();
|
|
150
|
+
for (const { x, y, fill } of cells) {
|
|
151
|
+
const rows = byFill.get(fill) ?? new Map();
|
|
152
|
+
byFill.set(fill, rows);
|
|
153
|
+
rows.set(y, [...(rows.get(y) ?? []), x]);
|
|
154
|
+
}
|
|
155
|
+
return [...byFill].map(([fill, rows]) => {
|
|
156
|
+
let d = '';
|
|
157
|
+
for (const [y, xs] of [...rows].sort(([a], [b]) => a - b)) {
|
|
158
|
+
const sorted = [...new Set(xs)].sort((a, b) => a - b);
|
|
159
|
+
for (let i = 0; i < sorted.length; ) {
|
|
160
|
+
let j = i;
|
|
161
|
+
while (j + 1 < sorted.length && sorted[j + 1] === sorted[j] + 1) j += 1;
|
|
162
|
+
const run = j - i + 1;
|
|
163
|
+
d += `M${sorted[i]} ${y}h${run}v1h-${run}z`;
|
|
164
|
+
i = j + 1;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return { fill, d };
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** The motion states an avatar shows today, `idle` first (a custom avatar's
|
|
172
|
+
* one required image, and every missing state's fallback). */
|
|
173
|
+
export const AGENT_AVATAR_STATES = Object.freeze(['idle', 'typing', 'message']);
|
|
174
|
+
|
|
175
|
+
/** The single image avatar before per-state images: a PNG beside AGENT.md
|
|
176
|
+
* under a content-hash name. Still read, as a custom avatar's idle image. */
|
|
177
|
+
export const AGENT_AVATAR_IMAGE_FILE = /^avatar-[0-9a-f]{12}\.png$/;
|
|
178
|
+
/** One state's image in `agents/<id>/avatar/`, under a content-hash name (a
|
|
179
|
+
* new upload is a new name, so caches by name never go stale). An animated
|
|
180
|
+
* one keeps its still first frame beside it (avatarPosterFile). */
|
|
181
|
+
export const AGENT_AVATAR_STATE_FILE = /^(idle|typing|message)-[0-9a-f]{12}\.(png|gif|webp)$/;
|
|
182
|
+
export const AGENT_AVATAR_DIR = 'avatar';
|
|
183
|
+
/** The largest image upload accepted, and the largest side of an animation. */
|
|
184
|
+
export const AGENT_AVATAR_IMAGE_MAX_BYTES = 1024 * 1024;
|
|
185
|
+
export const AGENT_AVATAR_IMAGE_MAX_SIDE = 512;
|
|
186
|
+
|
|
187
|
+
/** A state image's path under the agent's folder ('/'-separated). */
|
|
188
|
+
export const agentAvatarStatePath = (file) =>
|
|
189
|
+
AGENT_AVATAR_IMAGE_FILE.test(file) ? file : `${AGENT_AVATAR_DIR}/${file}`;
|
|
190
|
+
/** The still first frame stored beside an animated state image. */
|
|
191
|
+
export const avatarPosterFile = (file) => file.replace(/\.(png|gif|webp)$/, '.poster.png');
|
|
192
|
+
/** The image a custom avatar shows in `state`: its own, else idle's. */
|
|
193
|
+
export const customAvatarStateFile = (avatar, state) => avatar.states[state] ?? avatar.states.idle;
|
|
194
|
+
|
|
195
|
+
const u16le = (bytes, at) => bytes[at] | (bytes[at + 1] << 8);
|
|
196
|
+
const u24le = (bytes, at) => bytes[at] | (bytes[at + 1] << 8) | (bytes[at + 2] << 16);
|
|
197
|
+
const u32be = (bytes, at) => ((bytes[at] << 24) | (bytes[at + 1] << 16) | (bytes[at + 2] << 8) | bytes[at + 3]) >>> 0;
|
|
198
|
+
const ascii = (bytes, at, length) => String.fromCharCode(...bytes.subarray(at, at + length));
|
|
199
|
+
|
|
200
|
+
/** An upload's format and size, read from its header bytes: a PNG (an APNG
|
|
201
|
+
* counts as animated), a GIF (always treated as animated) or a WebP; null
|
|
202
|
+
* for anything else — SVG and every other markup included. */
|
|
203
|
+
export function avatarImageInfo(bytes) {
|
|
204
|
+
if (!(bytes instanceof Uint8Array) || bytes.length < 30) return null;
|
|
205
|
+
if (u32be(bytes, 0) === 0x89504e47 && u32be(bytes, 4) === 0x0d0a1a0a && ascii(bytes, 12, 4) === 'IHDR') {
|
|
206
|
+
let animated = false;
|
|
207
|
+
for (let at = 8; at + 8 <= bytes.length; at += 12 + u32be(bytes, at)) {
|
|
208
|
+
const type = ascii(bytes, at + 4, 4);
|
|
209
|
+
if (type === 'acTL') animated = true;
|
|
210
|
+
if (type === 'IDAT' || type === 'IEND') break;
|
|
211
|
+
}
|
|
212
|
+
return { format: 'png', width: u32be(bytes, 16), height: u32be(bytes, 20), animated };
|
|
213
|
+
}
|
|
214
|
+
if (ascii(bytes, 0, 6) === 'GIF87a' || ascii(bytes, 0, 6) === 'GIF89a') {
|
|
215
|
+
return { format: 'gif', width: u16le(bytes, 6), height: u16le(bytes, 8), animated: true };
|
|
216
|
+
}
|
|
217
|
+
if (ascii(bytes, 0, 4) === 'RIFF' && ascii(bytes, 8, 4) === 'WEBP') {
|
|
218
|
+
const chunk = ascii(bytes, 12, 4);
|
|
219
|
+
if (chunk === 'VP8X') {
|
|
220
|
+
const animated = (bytes[20] & 0x02) !== 0;
|
|
221
|
+
return { format: 'webp', width: u24le(bytes, 24) + 1, height: u24le(bytes, 27) + 1, animated };
|
|
222
|
+
}
|
|
223
|
+
if (chunk === 'VP8 ') {
|
|
224
|
+
return { format: 'webp', width: u16le(bytes, 26) & 0x3fff, height: u16le(bytes, 28) & 0x3fff, animated: false };
|
|
225
|
+
}
|
|
226
|
+
if (chunk === 'VP8L') {
|
|
227
|
+
const bits = (bytes[21] | (bytes[22] << 8) | (bytes[23] << 16) | (bytes[24] << 24)) >>> 0;
|
|
228
|
+
return { format: 'webp', width: (bits & 0x3fff) + 1, height: ((bits >>> 14) & 0x3fff) + 1, animated: false };
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/** Why bytes cannot be a state image ('' when they can): not a PNG, GIF or
|
|
235
|
+
* WebP, over 1 MB, not square, or over 512px. */
|
|
236
|
+
export function agentAvatarImageProblem(bytes) {
|
|
237
|
+
const info = avatarImageInfo(bytes);
|
|
238
|
+
if (!info) return 'must be a PNG, GIF or WebP image';
|
|
239
|
+
if (bytes.length > AGENT_AVATAR_IMAGE_MAX_BYTES) return 'is larger than 1 MB';
|
|
240
|
+
if (!info.width || info.width !== info.height) return 'must be square';
|
|
241
|
+
if (info.width > AGENT_AVATAR_IMAGE_MAX_SIDE) return 'must be 512px or smaller';
|
|
242
|
+
return '';
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function normalizeCustom(states) {
|
|
246
|
+
if (!states || typeof states !== 'object') return null;
|
|
247
|
+
const kept = {};
|
|
248
|
+
for (const state of AGENT_AVATAR_STATES) {
|
|
249
|
+
const file = states[state];
|
|
250
|
+
if (file == null) continue;
|
|
251
|
+
const own = typeof file === 'string' && AGENT_AVATAR_STATE_FILE.test(file) && file.startsWith(`${state}-`);
|
|
252
|
+
const legacy = state === 'idle' && typeof file === 'string' && AGENT_AVATAR_IMAGE_FILE.test(file);
|
|
253
|
+
if (!own && !legacy) return null;
|
|
254
|
+
kept[state] = file;
|
|
255
|
+
}
|
|
256
|
+
return kept.idle ? { kind: 'custom', states: kept } : null;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const pick = (value, list, fallback) => (value == null ? fallback : list.includes(value) ? value : null);
|
|
260
|
+
|
|
261
|
+
/** A stored avatar as the app understands it, or null when it is not one. An
|
|
262
|
+
* older single image reads as a custom avatar with only its idle image; an
|
|
263
|
+
* older mascot `variant` as its mapped species, accessory and expression. */
|
|
264
|
+
export function normalizeAgentAvatar(value) {
|
|
265
|
+
if (!value || typeof value !== 'object') return null;
|
|
266
|
+
if (value.kind === 'image') {
|
|
267
|
+
return typeof value.file === 'string' && AGENT_AVATAR_IMAGE_FILE.test(value.file)
|
|
268
|
+
? { kind: 'custom', states: { idle: value.file } }
|
|
269
|
+
: null;
|
|
270
|
+
}
|
|
271
|
+
if (value.kind === 'custom') return normalizeCustom(value.states);
|
|
272
|
+
if (value.kind !== 'mascot') return null;
|
|
273
|
+
const color = typeof value.color === 'string' ? value.color.toLowerCase() : '';
|
|
274
|
+
if (!AGENT_AVATAR_COLORS.includes(color)) return null;
|
|
275
|
+
const look =
|
|
276
|
+
value.species == null && typeof value.variant === 'string'
|
|
277
|
+
? mascotFromVariant(value.variant)
|
|
278
|
+
: {
|
|
279
|
+
species: pick(
|
|
280
|
+
RETIRED_SPECIES[value.species] ?? value.species,
|
|
281
|
+
[...MASCOT_SPECIES, MIXY_AVATAR.species],
|
|
282
|
+
null
|
|
283
|
+
),
|
|
284
|
+
accessory: pick(RETIRED_ACCESSORIES[value.accessory] ?? value.accessory, MASCOT_ACCESSORIES, 'none'),
|
|
285
|
+
expression: pick(value.expression, MASCOT_EXPRESSIONS, 'calm'),
|
|
286
|
+
};
|
|
287
|
+
if (!look?.species || !look.accessory || !look.expression) return null;
|
|
288
|
+
return { kind: 'mascot', ...look, color };
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// FNV-1a: a small stable string hash, the same on every platform.
|
|
292
|
+
function hashId(id) {
|
|
293
|
+
let hash = 0x811c9dc5;
|
|
294
|
+
for (const char of String(id)) {
|
|
295
|
+
hash ^= char.codePointAt(0);
|
|
296
|
+
hash = Math.imul(hash, 0x01000193) >>> 0;
|
|
297
|
+
}
|
|
298
|
+
return hash;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/** The look of an agent that never picked one: fixed by its id — the
|
|
302
|
+
* species, accessory and colour it had before species existed (its old
|
|
303
|
+
* variant, mapped), with the neutral face every default wears. */
|
|
304
|
+
export function defaultAgentAvatar(id) {
|
|
305
|
+
const hash = hashId(id);
|
|
306
|
+
return {
|
|
307
|
+
kind: 'mascot',
|
|
308
|
+
...mascotFromVariant(LEGACY_VARIANTS[hash % LEGACY_VARIANTS.length]),
|
|
309
|
+
expression: 'calm',
|
|
310
|
+
color: AGENT_AVATAR_COLORS[Math.floor(hash / LEGACY_VARIANTS.length) % AGENT_AVATAR_COLORS.length],
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/** What an agent shows: its own images, else Mixy's fixed look (for Mixy),
|
|
315
|
+
* its own mascot pick, or its id default. */
|
|
316
|
+
export function agentAvatar(id, stored) {
|
|
317
|
+
const own = normalizeAgentAvatar(stored);
|
|
318
|
+
if (id === MIXY_AGENT_ID) return own ?? { ...MIXY_AVATAR };
|
|
319
|
+
return own ?? defaultAgentAvatar(id);
|
|
320
|
+
}
|
|
@@ -16,6 +16,22 @@ export const DEFAULT_DISABLED_AGENT_IDS = Object.freeze([
|
|
|
16
16
|
// runs only once the user turns it on and picks its model.
|
|
17
17
|
export const DEFAULT_DISABLED_AGENT_ROSTER = Object.freeze([...DEFAULT_DISABLED_AGENT_IDS, 'maintainer']);
|
|
18
18
|
|
|
19
|
+
/** The AGENT.md frontmatter `kind` the Workflows page writes when it creates
|
|
20
|
+
* an agent: a workflow delegation role, never a contact (봇). */
|
|
21
|
+
export const WORKFLOW_AGENT_KIND = 'agent';
|
|
22
|
+
|
|
23
|
+
/** A contact agent (a 봇): one the user made — not Mixy ('lead'), not a
|
|
24
|
+
* shipped role (the starter sub-agents Worker, Reviewer, … and the
|
|
25
|
+
* Maintainer), and not marked `kind: agent` (made on the Workflows page).
|
|
26
|
+
* `kind` is the definition's frontmatter `kind`; an unmarked custom agent
|
|
27
|
+
* stays a contact. The one rule for the runtime (delegation, agent catalogs)
|
|
28
|
+
* and the desktop (contacts, agent lists). */
|
|
29
|
+
export function isContactAgentId(value, kind) {
|
|
30
|
+
const id = typeof value === 'string' ? value.trim().toLowerCase() : '';
|
|
31
|
+
const marked = typeof kind === 'string' && kind.trim().toLowerCase() === WORKFLOW_AGENT_KIND;
|
|
32
|
+
return Boolean(id) && id !== 'lead' && !DEFAULT_DISABLED_AGENT_ROSTER.includes(id) && !marked;
|
|
33
|
+
}
|
|
34
|
+
|
|
19
35
|
function record(value) {
|
|
20
36
|
return isPlainObject(value) ? value : {};
|
|
21
37
|
}
|
|
@@ -19,7 +19,8 @@ import {
|
|
|
19
19
|
unlink as unlinkAsync,
|
|
20
20
|
writeFile as writeFileAsync,
|
|
21
21
|
} from 'node:fs/promises';
|
|
22
|
-
import {
|
|
22
|
+
import { tmpdir } from 'node:os';
|
|
23
|
+
import { dirname, basename, join, relative, isAbsolute, resolve } from 'node:path';
|
|
23
24
|
import { randomBytes } from 'node:crypto';
|
|
24
25
|
import { DEFAULT_BACKOFFS_MS, recordLockTiming, withFileLock, withFileLockSync } from './file-lock.mjs';
|
|
25
26
|
import {
|
|
@@ -88,21 +89,30 @@ function nextRenameDelayMs(err, attempt, backoffs) {
|
|
|
88
89
|
return backoffs[attempt] + Math.floor(Math.random() * Math.min(50, Math.max(1, backoffs[attempt])));
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Attempt `attempt` (0-based) of the renameWithRetry schedule: null when the
|
|
94
|
+
* rename landed, else the delay before the next attempt. Throws the rename's
|
|
95
|
+
* own error when that error or the attempt count ends the loop — the same
|
|
96
|
+
* final error renameWithRetrySync throws. A caller that must not block waits
|
|
97
|
+
* the delay asynchronously between attempts.
|
|
98
|
+
*/
|
|
99
|
+
export function renameAttempt(src, dst, attempt, opts = {}) {
|
|
100
|
+
try {
|
|
101
|
+
renameSync(src, dst);
|
|
102
|
+
return null;
|
|
103
|
+
} catch (err) {
|
|
104
|
+
const delayMs = nextRenameDelayMs(err, attempt, renameBackoffs(opts));
|
|
105
|
+
if (delayMs === null) throw err;
|
|
106
|
+
return delayMs;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
91
110
|
export function renameWithRetrySync(src, dst, opts = {}) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
renameSync(src, dst);
|
|
97
|
-
return true;
|
|
98
|
-
} catch (err) {
|
|
99
|
-
lastErr = err;
|
|
100
|
-
const delayMs = nextRenameDelayMs(err, attempt, backoffs);
|
|
101
|
-
if (delayMs === null) break;
|
|
102
|
-
sleepSync(delayMs);
|
|
103
|
-
}
|
|
111
|
+
for (let attempt = 0; ; attempt++) {
|
|
112
|
+
const delayMs = renameAttempt(src, dst, attempt, opts);
|
|
113
|
+
if (delayMs === null) return true;
|
|
114
|
+
sleepSync(delayMs);
|
|
104
115
|
}
|
|
105
|
-
throw lastErr;
|
|
106
116
|
}
|
|
107
117
|
|
|
108
118
|
async function renameWithRetry(src, dst, opts = {}) {
|
|
@@ -155,7 +165,18 @@ async function fsyncPathAsync(path, tolerated) {
|
|
|
155
165
|
}
|
|
156
166
|
}
|
|
157
167
|
|
|
168
|
+
// Node sets NODE_TEST_CONTEXT in every `--test` process. A secret (credential)
|
|
169
|
+
// write from a test must land under the temp dir; anything else is a fixture
|
|
170
|
+
// about to overwrite a real profile, so fail loudly instead.
|
|
171
|
+
function assertTestSecretWriteSafe(filePath, opts) {
|
|
172
|
+
if (opts.secret !== true || !process.env.NODE_TEST_CONTEXT) return;
|
|
173
|
+
const rel = relative(resolve(tmpdir()).toLowerCase(), resolve(filePath).toLowerCase());
|
|
174
|
+
if (rel === '' || (!rel.startsWith('..') && !isAbsolute(rel))) return;
|
|
175
|
+
throw new Error(`refusing to write a secret outside the temp dir under node --test: ${filePath}`);
|
|
176
|
+
}
|
|
177
|
+
|
|
158
178
|
export function writeFileAtomicSync(filePath, data, opts = {}) {
|
|
179
|
+
assertTestSecretWriteSafe(filePath, opts);
|
|
159
180
|
const run = () => {
|
|
160
181
|
const dir = dirname(filePath);
|
|
161
182
|
mkdirSync(dir, { recursive: true });
|
|
@@ -280,6 +301,7 @@ export function updateJsonAtomicSync(filePath, mutator, opts = {}) {
|
|
|
280
301
|
// block the host event loop on read/write/fsync/rename.
|
|
281
302
|
// Async writes retain atomic rename publication; truncate recovery is sync-only.
|
|
282
303
|
export async function writeFileAtomicAsync(filePath, data, opts = {}) {
|
|
304
|
+
assertTestSecretWriteSafe(filePath, opts);
|
|
283
305
|
const run = async () => {
|
|
284
306
|
const dir = dirname(filePath);
|
|
285
307
|
await mkdirAsync(dir, { recursive: true });
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from './tool-execution-contract.mjs';
|
|
8
8
|
import { presentErrorText } from './err-text.mjs';
|
|
9
9
|
import { clean } from './clean.mjs';
|
|
10
|
+
import { emitSessionActivityChange } from './session-activity-signal.mjs';
|
|
10
11
|
import {
|
|
11
12
|
parseTaskNotification,
|
|
12
13
|
renderTaskCompletionEnvelope,
|
|
@@ -104,12 +105,17 @@ function hasScopeCriteria(scope) {
|
|
|
104
105
|
return Boolean(scope?.callerSessionId || scope?.routingSessionId || scope?.clientHostPid);
|
|
105
106
|
}
|
|
106
107
|
|
|
107
|
-
function
|
|
108
|
+
function taskSessionIdOf(task) {
|
|
109
|
+
return task.ownerSessionId || task.notifyContext?.callerSessionId || task.notifyContext?.routingSessionId || null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// `scope` is normalizeTaskScope(options), normalized once per scan by the
|
|
113
|
+
// caller: a scan is O(tasks), and the daemon runs one per session per
|
|
114
|
+
// busy-count, so per-task normalization multiplied into seconds under load.
|
|
115
|
+
function taskMatchesScope(task, scope, { includeUnattributed = true } = {}) {
|
|
108
116
|
if (!task) return false;
|
|
109
|
-
const scope = normalizeTaskScope(options);
|
|
110
117
|
if (!hasScopeCriteria(scope)) return true;
|
|
111
|
-
const taskSessionId =
|
|
112
|
-
task.ownerSessionId || task.notifyContext?.callerSessionId || task.notifyContext?.routingSessionId || null;
|
|
118
|
+
const taskSessionId = taskSessionIdOf(task);
|
|
113
119
|
const taskClientHostPid = task.clientHostPid || task.notifyContext?.clientHostPid || null;
|
|
114
120
|
// Legacy/unattributed tasks remain visible so old async jobs are still recoverable.
|
|
115
121
|
if (!taskSessionId && !taskClientHostPid) return includeUnattributed;
|
|
@@ -127,11 +133,13 @@ function pruneTasks(options = {}) {
|
|
|
127
133
|
const { force = false, surface } = options;
|
|
128
134
|
const now = Date.now();
|
|
129
135
|
const wanted = clean(surface);
|
|
130
|
-
|
|
136
|
+
const scope = normalizeTaskScope(options);
|
|
137
|
+
// Deleting the entry being visited is safe during Map iteration.
|
|
138
|
+
for (const [taskId, task] of tasks) {
|
|
131
139
|
if (wanted && task.surface !== wanted) continue;
|
|
132
|
-
if (!taskMatchesScope(task, options)) continue;
|
|
133
140
|
const finishedAt = task.finishedAtMs || 0;
|
|
134
|
-
if (force
|
|
141
|
+
if (!force && !(finishedAt > 0 && now - finishedAt > TASK_TTL_MS)) continue;
|
|
142
|
+
if (taskMatchesScope(task, scope)) tasks.delete(taskId);
|
|
135
143
|
}
|
|
136
144
|
if (tasks.size <= MAX_TASKS) return;
|
|
137
145
|
const removable = [...tasks.values()]
|
|
@@ -197,6 +205,7 @@ export function registerBackgroundTask({
|
|
|
197
205
|
notifyOnCancel: notifyOnCancel === true,
|
|
198
206
|
};
|
|
199
207
|
tasks.set(id, task);
|
|
208
|
+
emitSessionActivityChange(task.ownerSessionId || '');
|
|
200
209
|
return task;
|
|
201
210
|
}
|
|
202
211
|
|
|
@@ -230,38 +239,64 @@ export function getBackgroundTask(taskId, options = {}) {
|
|
|
230
239
|
if (!task) return null;
|
|
231
240
|
const wanted = clean(options.surface);
|
|
232
241
|
if (wanted && task.surface !== wanted) return null;
|
|
233
|
-
if (!taskMatchesScope(task, options)) return null;
|
|
242
|
+
if (!taskMatchesScope(task, normalizeTaskScope(options))) return null;
|
|
234
243
|
return task;
|
|
235
244
|
}
|
|
236
245
|
|
|
246
|
+
function countsAsActive(task, wanted, awaitedOnly) {
|
|
247
|
+
return task.status === 'running' && !(awaitedOnly && task.detached === true) && (!wanted || task.surface === wanted);
|
|
248
|
+
}
|
|
249
|
+
|
|
237
250
|
/** Lifetime signal: a session-owned background task remains live
|
|
238
|
-
* work even while the interactive turn is idle and every view is detached.
|
|
251
|
+
* work even while the interactive turn is idle and every view is detached.
|
|
252
|
+
* `awaitedOnly` leaves out `detached` tasks: processes a finished command
|
|
253
|
+
* deliberately left running (an app or server it launched), which nothing is
|
|
254
|
+
* waiting on and which may outlive the session's work by days.
|
|
255
|
+
* A read: pruning only ever drops finished tasks, which never count here. */
|
|
239
256
|
export function hasActiveBackgroundTasks(options = {}) {
|
|
240
|
-
pruneTasks(options);
|
|
241
257
|
const wanted = clean(options.surface);
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
258
|
+
const awaitedOnly = options.awaitedOnly === true;
|
|
259
|
+
const scope = normalizeTaskScope(options);
|
|
260
|
+
for (const task of tasks.values()) {
|
|
261
|
+
if (countsAsActive(task, wanted, awaitedOnly) && taskMatchesScope(task, scope, { includeUnattributed: false })) {
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/** Every owner session `hasActiveBackgroundTasks({ callerSessionId, surface,
|
|
269
|
+
* awaitedOnly })` answers true for, from ONE pass over the tasks: a caller
|
|
270
|
+
* asking for every session (busy counts, pool rows) scans once instead of
|
|
271
|
+
* once per session. */
|
|
272
|
+
export function activeBackgroundTaskSessionIds(options = {}) {
|
|
273
|
+
const wanted = clean(options.surface);
|
|
274
|
+
const awaitedOnly = options.awaitedOnly === true;
|
|
275
|
+
const ids = new Set();
|
|
276
|
+
for (const task of tasks.values()) {
|
|
277
|
+
if (!countsAsActive(task, wanted, awaitedOnly)) continue;
|
|
278
|
+
const sessionId = taskSessionIdOf(task);
|
|
279
|
+
if (sessionId) ids.add(sessionId);
|
|
280
|
+
}
|
|
281
|
+
return ids;
|
|
248
282
|
}
|
|
249
283
|
|
|
250
284
|
export function listBackgroundTasks(options = {}) {
|
|
251
285
|
const { surface } = options;
|
|
252
286
|
pruneTasks(options);
|
|
253
287
|
const wanted = clean(surface);
|
|
288
|
+
const scope = normalizeTaskScope(options);
|
|
254
289
|
return [...tasks.values()]
|
|
255
290
|
.filter((task) => !wanted || task.surface === wanted)
|
|
256
|
-
.filter((task) => taskMatchesScope(task,
|
|
291
|
+
.filter((task) => taskMatchesScope(task, scope))
|
|
257
292
|
.map((task) => taskSummary(task));
|
|
258
293
|
}
|
|
259
294
|
|
|
260
295
|
export function cleanupBackgroundTasks(options = {}) {
|
|
261
296
|
const wanted = clean(options.surface);
|
|
297
|
+
const scope = normalizeTaskScope(options);
|
|
262
298
|
const countForSurface = () =>
|
|
263
|
-
[...tasks.values()].filter((task) => (!wanted || task.surface === wanted) && taskMatchesScope(task,
|
|
264
|
-
.length;
|
|
299
|
+
[...tasks.values()].filter((task) => (!wanted || task.surface === wanted) && taskMatchesScope(task, scope)).length;
|
|
265
300
|
const before = countForSurface();
|
|
266
301
|
pruneTasks(options);
|
|
267
302
|
const after = countForSurface();
|
|
@@ -331,6 +366,7 @@ export function cancelBackgroundTasks(options = {}) {
|
|
|
331
366
|
const reason = clean(options.reason) || 'cancelled';
|
|
332
367
|
const wanted = clean(options.surface);
|
|
333
368
|
const executionSessionId = clean(options.executionSessionId);
|
|
369
|
+
const scope = normalizeTaskScope(options);
|
|
334
370
|
let cancelled = 0;
|
|
335
371
|
for (const task of [...tasks.values()]) {
|
|
336
372
|
if (wanted && task.surface !== wanted) continue;
|
|
@@ -341,7 +377,7 @@ export function cancelBackgroundTasks(options = {}) {
|
|
|
341
377
|
// Delegated work executes in its bound session; before binding it still
|
|
342
378
|
// belongs to the registering session. Notification ownership is separate.
|
|
343
379
|
if ((clean(task.meta?.sessionId) || task.ownerSessionId) !== executionSessionId) continue;
|
|
344
|
-
} else if (!taskMatchesScope(task,
|
|
380
|
+
} else if (!taskMatchesScope(task, scope, { includeUnattributed: false })) continue;
|
|
345
381
|
if (TERMINAL_STATUSES.has(task.status)) {
|
|
346
382
|
if (options.notify === false) silenceCancelledNotification(task);
|
|
347
383
|
continue;
|
|
@@ -413,6 +449,7 @@ export function completeBackgroundTask(
|
|
|
413
449
|
if (error != null) task.error = presentErrorText(error, { surface: task.surface });
|
|
414
450
|
if (resultType) task.resultType = resultType;
|
|
415
451
|
if (instruction) task.notificationInstruction = compactText(instruction, 1_000);
|
|
452
|
+
emitSessionActivityChange(task.ownerSessionId || '');
|
|
416
453
|
if (notify) {
|
|
417
454
|
task.meta = sanitizeTaskMeta(task.meta);
|
|
418
455
|
notifyTaskCompletion(task, instruction);
|
|
@@ -522,6 +559,9 @@ export function renderBackgroundTaskNotification(task) {
|
|
|
522
559
|
: resultTextForTask(task);
|
|
523
560
|
if (task.surface === 'shell') {
|
|
524
561
|
const parsed = parseTaskNotification(result);
|
|
562
|
+
// The completion envelope already carries the result (exit code,
|
|
563
|
+
// duration, output or its summary): deliver it as is.
|
|
564
|
+
if (parsed?.result) return result;
|
|
525
565
|
return renderShellCompletionNotice({
|
|
526
566
|
jobId: task.taskId,
|
|
527
567
|
status: task.status,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { availableParallelism } from 'node:os';
|
|
1
|
+
import { availableParallelism, totalmem } from 'node:os';
|
|
2
2
|
import { createOwnerFairGate } from './owner-fair-gate.mjs';
|
|
3
3
|
import { currentToolExecutionOwner } from './tool-execution-owner.mjs';
|
|
4
4
|
import { positiveInt } from './numbers.mjs';
|
|
@@ -9,8 +9,9 @@ import { positiveInt } from './numbers.mjs';
|
|
|
9
9
|
// singleton semaphore CAN bound the number of concurrent child processes (rg,
|
|
10
10
|
// mixdog-graph, …) across ALL agents/workers in this daemon.
|
|
11
11
|
//
|
|
12
|
-
// Default: Windows search
|
|
13
|
-
// code-graph
|
|
12
|
+
// Default: Windows search and code-graph-query scale 2..8 with CPU count;
|
|
13
|
+
// code-graph builds 1..4 with cores and memory. Other platforms bound search
|
|
14
|
+
// only. Windows measurements
|
|
14
15
|
// showed both extremes are poor: cap 1 creates multi-session queue latency,
|
|
15
16
|
// while unbounded multithreaded rg amplifies Defender/process-scan and disk
|
|
16
17
|
// contention. Separate lanes isolate short search from long graph builds.
|
|
@@ -28,7 +29,8 @@ function resolveDefaultChildSpawnLaneMaxInflight(
|
|
|
28
29
|
laneName,
|
|
29
30
|
env = process.env,
|
|
30
31
|
platform = process.platform,
|
|
31
|
-
parallelism = availableParallelism()
|
|
32
|
+
parallelism = availableParallelism(),
|
|
33
|
+
memoryBytes = totalmem()
|
|
32
34
|
) {
|
|
33
35
|
const lane = _laneName(laneName);
|
|
34
36
|
const laneOverride = positiveInt(env[`MIXDOG_CHILD_SPAWN_${_laneEnvKey(lane)}_MAX_INFLIGHT`]);
|
|
@@ -45,13 +47,19 @@ function resolveDefaultChildSpawnLaneMaxInflight(
|
|
|
45
47
|
// Slots are held only across the spawn itself, so a small cap smooths the
|
|
46
48
|
// AV convoy without limiting how many commands run concurrently.
|
|
47
49
|
if (lane === 'process-spawn') return Math.max(2, Math.min(4, Math.floor(cpus / 6) || 2));
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
// Graph builds (Worker thread + native walk/parse) hold a slot for seconds
|
|
51
|
+
// and are memory-heavy: one per 4 cores and per 4 GiB, 1..4. Builds of one
|
|
52
|
+
// repo are already single-flight (build.mjs); distinct repos are independent.
|
|
53
|
+
if (lane === 'code-graph') {
|
|
54
|
+
const memGb = Math.floor((Number(memoryBytes) || 0) / 1024 ** 3);
|
|
55
|
+
return Math.max(1, Math.min(4, Math.floor(cpus / 4), Math.floor(memGb / 4)));
|
|
56
|
+
}
|
|
57
|
+
if (lane !== 'search' && lane !== 'code-graph-query') return 1;
|
|
58
|
+
// Short read-only walks: rg, and the graph binary's `--manifest` that
|
|
59
|
+
// validates a cached graph. Multiple processes beat one under multi-session
|
|
60
|
+
// load, but each is itself threaded and Defender amplifies excess fan-out.
|
|
61
|
+
// Burst stress measured cap-4 starvation (find p50 15s at 8 concurrent
|
|
62
|
+
// sessions), so scale with cores and cap at eight: 4→2, 8→3, 12→4, 18→6, 24+→8.
|
|
55
63
|
return Math.max(2, Math.min(8, Math.ceil(cpus / 3)));
|
|
56
64
|
}
|
|
57
65
|
|
|
@@ -87,11 +95,13 @@ function _laneSetting(name, suffix, fallback) {
|
|
|
87
95
|
// ── Lanes ────────────────────────────────────────────────────────────────
|
|
88
96
|
// Independent optional limits and queues:
|
|
89
97
|
// 'search' — short-lived rg processes.
|
|
90
|
-
// 'code-graph' — long-lived graph workers
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
//
|
|
98
|
+
// 'code-graph' — long-lived graph build workers. A cold build can hold its
|
|
99
|
+
// slot for seconds-to-minutes; a single shared lane would let
|
|
100
|
+
// one build stall every rg spawn behind it. Separate lanes
|
|
101
|
+
// remove that starvation class while keeping each spawn
|
|
102
|
+
// family bounded.
|
|
103
|
+
// 'code-graph-query' — the short read-only manifest walk that validates
|
|
104
|
+
// a cached graph, so queries never wait behind builds.
|
|
95
105
|
function _makeLane(name) {
|
|
96
106
|
const limit = resolveDefaultChildSpawnLaneMaxInflight(name);
|
|
97
107
|
const queueMax = _laneSetting(name, 'MAX_QUEUE', 1024);
|