mixdog 1.1.2 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -5
- package/package.json +2 -1
- package/scripts/lib/run-node-tests.mjs +9 -0
- package/scripts/prune-desktop-runtime.mjs +3 -0
- package/scripts/test-direct.mjs +4 -2
- package/src/defaults/shipped-history.json +10 -0
- package/src/defaults/skills/pptx/SKILL.md +6 -6
- package/src/defaults/skills/pptx/references/review.md +6 -4
- package/src/defaults/skills/pptx/scripts/source-extract.mjs +1 -1
- package/src/defaults/skills/setup/references/actions.md +18 -5
- package/src/defaults/skills/visualize/SKILL.md +160 -0
- package/src/defaults/skills/visualize/references/craft.md +88 -0
- package/src/headless-command.mjs +56 -3
- package/src/headless-exec.mjs +17 -1
- package/src/help.mjs +2 -0
- package/src/rules/shared/60-verification.md +3 -1
- package/src/rules/shared/70-delivery.md +4 -2
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +1 -0
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +2 -0
- package/src/runtime/agent/orchestrator/cache-mtime.mjs +26 -5
- package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
- package/src/runtime/agent/orchestrator/config-providers-merge.mjs +17 -11
- package/src/runtime/agent/orchestrator/config-storage.mjs +1 -0
- package/src/runtime/agent/orchestrator/config.mjs +19 -5
- package/src/runtime/agent/orchestrator/context/collect.mjs +2 -1
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +11 -5
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +74 -21
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +133 -15
- package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +55 -8
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +86 -8
- package/src/runtime/agent/orchestrator/mcp/client.mjs +474 -164
- package/src/runtime/agent/orchestrator/mcp/lazy-output-validator.mjs +25 -0
- package/src/runtime/agent/orchestrator/mcp/plugin-placeholders.mjs +54 -0
- package/src/runtime/agent/orchestrator/mcp/reconnect-singleflight.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +108 -17
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +15 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +32 -12
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +337 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-tokens.mjs +159 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +444 -0
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -4
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +21 -6
- package/src/runtime/agent/orchestrator/providers/effort-rejection.mjs +244 -0
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +41 -28
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/lib/gemini-model-catalog.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +8 -40
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-tokens.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +51 -12
- package/src/runtime/agent/orchestrator/providers/model-cache.mjs +37 -2
- package/src/runtime/agent/orchestrator/providers/model-proxy-bridge.mjs +1080 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +82 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +556 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +251 -0
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth-tokens.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +69 -102
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +15 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +6 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +11 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +15 -4
- package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog-store.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/registry.mjs +47 -7
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +10 -0
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +36 -3
- package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -11
- package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +15 -55
- package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +15 -2
- package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +16 -1
- package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +278 -84
- package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +4 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +21 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +54 -3
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +10 -3
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.mjs +9 -5
- package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +18 -8
- package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +284 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +268 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/sqlite-gate.mjs +27 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +628 -0
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +10 -3
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +24 -13
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +13 -5
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +362 -0
- package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +253 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +184 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +136 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +128 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +127 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +101 -0
- package/src/runtime/agent/orchestrator/session/explicit-skills.mjs +83 -5
- package/src/runtime/agent/orchestrator/session/imported-message.mjs +11 -0
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/continuation.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/diagnostic.mjs +1 -7
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/refusal.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +7 -4
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +21 -10
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +15 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +22 -12
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +9 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +9 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +37 -16
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +17 -4
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +90 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +22 -12
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +32 -3
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +27 -0
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -1
- package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +0 -1
- package/src/runtime/agent/orchestrator/session/message-ids.mjs +123 -0
- package/src/runtime/agent/orchestrator/session/message-ids.test-support.mjs +29 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +33 -22
- package/src/runtime/agent/orchestrator/session/store/listing.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +10 -3
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +11 -0
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +817 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +36 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +23 -12
- package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +158 -0
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +202 -374
- package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +20 -3
- package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +48 -9
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +161 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +17 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -0
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +52 -2
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +32 -22
- package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +10 -3
- package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +6 -6
- package/src/runtime/agent/orchestrator/tools/builtin/read-cache-policy.mjs +8 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +203 -33
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-fast-paths.mjs +32 -35
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +8 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +11 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +9 -6
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +83 -68
- package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +8 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +20 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +16 -7
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +137 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +11 -10
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +21 -11
- package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +12 -1
- package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +13 -10
- package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +17 -12
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +56 -13
- package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +58 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/trusted-roots.mjs +25 -1
- package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/patch/apply-patch/route.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/read-redirects.mjs +34 -30
- package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +7 -7
- package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +78 -5
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -0
- package/src/runtime/attachments/store.d.mts +3 -0
- package/src/runtime/attachments/store.mjs +38 -0
- package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +1 -1
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +16 -4
- package/src/runtime/channels/lib/worker-main.mjs +17 -14
- package/src/runtime/computer-bridge/linux-readiness.mjs +0 -2
- package/src/runtime/effort-judge/judge-client.mjs +56 -18
- package/src/runtime/memory/lib/memory.mjs +1 -1
- package/src/runtime/memory/lib/session-ingest.mjs +2 -2
- package/src/runtime/shared/atomic-file.mjs +33 -6
- package/src/runtime/shared/best-effort-stderr.mjs +8 -0
- package/src/runtime/shared/code-graph-state.mjs +12 -0
- package/src/runtime/shared/defaults-separation.mjs +2 -0
- package/src/runtime/shared/extension-scopes.mjs +5 -3
- package/src/runtime/shared/file-lock.mjs +37 -11
- package/src/runtime/shared/git-runner-worker.mjs +3 -2
- package/src/runtime/shared/git-runner.mjs +4 -3
- package/src/runtime/shared/llm/anthropic-effort.mjs +14 -0
- package/src/runtime/shared/llm/default-context-window.mjs +6 -0
- package/src/runtime/shared/llm/model-catalog-projection.mjs +5 -4
- package/src/runtime/shared/llm/model-catalog.mjs +240 -130
- package/src/runtime/shared/llm/provider-catalog-cache.mjs +36 -28
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +162 -0
- package/src/runtime/shared/llm/provider-seed-rosters.mjs +130 -0
- package/src/runtime/shared/model-proxy-mode.d.mts +3 -0
- package/src/runtime/shared/model-proxy-mode.mjs +19 -0
- package/src/runtime/shared/plugin-manifest.mjs +18 -9
- package/src/runtime/shared/pristine-execution-contract.json +9 -2
- package/src/runtime/shared/pristine-execution.mjs +28 -4
- package/src/runtime/shared/provider-accounts.mjs +125 -21
- package/src/runtime/shared/provider-api-key.mjs +33 -1
- package/src/runtime/shared/schedule-model-ref.mjs +11 -2
- package/src/runtime/shared/session-usage-totals.mjs +19 -0
- package/src/runtime/shared/sharp-electron-linux.mjs +25 -0
- package/src/runtime/shared/shell-display.mjs +9 -3
- package/src/runtime/shared/singleton-owner.mjs +36 -6
- package/src/runtime/shared/skill-mentions.d.mts +10 -0
- package/src/runtime/shared/skill-mentions.mjs +133 -0
- package/src/runtime/shared/skill-script-runtime.mjs +264 -0
- package/src/runtime/shared/statusline/statusline-segments.mjs +68 -14
- package/src/runtime/shared/tool-primitives.mjs +35 -2
- package/src/runtime/shared/tool-surface.mjs +7 -0
- package/src/runtime/shared/tool-work-units.mjs +14 -0
- package/src/runtime/shared/transcript-metadata.mjs +17 -1
- package/src/runtime/shared/turn-changes.mjs +791 -0
- package/src/runtime/shared/turn-snapshot-store.mjs +346 -12
- package/src/runtime/shared/turn-snapshot.mjs +690 -81
- package/src/runtime/shared/turn-worktree-snapshot.mjs +185 -15
- package/src/runtime/shared/worker-requests.mjs +15 -2
- package/src/runtime/shared/worktrees/cache-cleanups.mjs +52 -0
- package/src/runtime/shared/worktrees/contract.mjs +551 -0
- package/src/runtime/shared/worktrees/disk.mjs +57 -0
- package/src/runtime/shared/worktrees/git.mjs +247 -0
- package/src/runtime/shared/worktrees/include.mjs +480 -0
- package/src/runtime/shared/worktrees/lock.mjs +46 -0
- package/src/runtime/shared/worktrees/maintenance.mjs +96 -0
- package/src/runtime/shared/worktrees/manager.mjs +1215 -0
- package/src/runtime/shared/worktrees/merge.mjs +182 -0
- package/src/runtime/shared/worktrees/owner.mjs +46 -0
- package/src/runtime/shared/worktrees/paths.mjs +62 -0
- package/src/runtime/shared/worktrees/registry.mjs +110 -0
- package/src/runtime/shared/worktrees/settings.mjs +84 -0
- package/src/runtime/shared/worktrees/slug.mjs +62 -0
- package/src/runtime/shared/worktrees/test-support.mjs +96 -0
- package/src/runtime/visualize-bridge/client.mjs +181 -0
- package/src/runtime/visualize-bridge/tool-defs.mjs +97 -0
- package/src/session-runtime/automation-agents.mjs +8 -2
- package/src/session-runtime/boot/apis.mjs +90 -0
- package/src/session-runtime/boot/config.mjs +7 -2
- package/src/session-runtime/boot/facade.mjs +21 -0
- package/src/session-runtime/boot/infrastructure.mjs +30 -18
- package/src/session-runtime/boot/session.mjs +1 -0
- package/src/session-runtime/boot/tools.mjs +4 -0
- package/src/session-runtime/config-lifecycle.mjs +10 -1
- package/src/session-runtime/conversation-import/discovery.mjs +698 -0
- package/src/session-runtime/conversation-import/service.mjs +369 -0
- package/src/session-runtime/cwd-plugins/cwd-apply.mjs +21 -6
- package/src/session-runtime/cwd-plugins/plugin-status.mjs +47 -42
- package/src/session-runtime/global-extensions.mjs +2 -2
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +27 -2
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +32 -1
- package/src/session-runtime/internal-tool-executor.mjs +9 -1
- package/src/session-runtime/lifecycle/session-catalog.mjs +8 -1
- package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +5 -0
- package/src/session-runtime/lifecycle/session-switch/resume.mjs +21 -3
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +16 -0
- package/src/session-runtime/mcp-glue/connect.mjs +68 -16
- package/src/session-runtime/mcp-glue/plugin-servers.mjs +499 -0
- package/src/session-runtime/mcp-glue/server-catalog.mjs +122 -33
- package/src/session-runtime/mcp-glue/server-input.mjs +29 -0
- package/src/session-runtime/mcp-glue.mjs +22 -2
- package/src/session-runtime/model-route/route-persist.mjs +3 -0
- package/src/session-runtime/model-route/set-route.mjs +15 -2
- package/src/session-runtime/new-session-config.mjs +3 -2
- package/src/session-runtime/notification-bus.mjs +18 -3
- package/src/session-runtime/provider-auth/accounts.mjs +33 -15
- package/src/session-runtime/provider-models/row-hydration.mjs +2 -0
- package/src/session-runtime/provider-models/web-search-catalog.mjs +5 -1
- package/src/session-runtime/provider-readiness.mjs +16 -10
- package/src/session-runtime/resource-extension-sync.mjs +45 -7
- package/src/session-runtime/resource-mcp-api.mjs +121 -84
- package/src/session-runtime/resource-plugins-api.mjs +29 -41
- package/src/session-runtime/resource-scope-decorate.mjs +6 -8
- package/src/session-runtime/resource-skills-api.mjs +23 -2
- package/src/session-runtime/route-resolution.mjs +10 -1
- package/src/session-runtime/route-state.mjs +16 -2
- package/src/session-runtime/runtime-core.mjs +5 -0
- package/src/session-runtime/runtime-facade.mjs +8 -0
- package/src/session-runtime/runtime-review-api.mjs +9 -0
- package/src/session-runtime/schedule-session-run.mjs +1 -1
- package/src/session-runtime/services/agent-tool/helpers.mjs +5 -0
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +3 -0
- package/src/session-runtime/services/agent-tool/job-views/job-lookup.mjs +1 -0
- package/src/session-runtime/services/agent-tool/job-views/spawn-meta.mjs +1 -0
- package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +15 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +1 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +10 -2
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -7
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +2 -1
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -0
- package/src/session-runtime/services/agent-tool/worker-rows.mjs +1 -0
- package/src/session-runtime/services/agent-tool.mjs +1 -0
- package/src/session-runtime/services/channel-session-router.mjs +4 -1
- package/src/session-runtime/services/daemon-candidate.mjs +3 -2
- package/src/session-runtime/services/daemon-crash-capture/spawn-capture.mjs +55 -0
- package/src/session-runtime/services/hook-bus/command-handler.mjs +4 -1
- package/src/session-runtime/services/hook-bus/handlers.mjs +7 -3
- package/src/session-runtime/services/provider-admin.mjs +64 -18
- package/src/session-runtime/services/usage-dashboard-model.mjs +3 -0
- package/src/session-runtime/session-create/session-options.mjs +10 -1
- package/src/session-runtime/session-turn-api.mjs +1 -0
- package/src/session-runtime/settings-api.mjs +4 -2
- package/src/session-runtime/settings-builtin-tools-api.mjs +9 -2
- package/src/session-runtime/settings-worktree-api.mjs +17 -0
- package/src/session-runtime/setup-tool/executor.mjs +23 -5
- package/src/session-runtime/setup-tool/extended-actions.mjs +1 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +4 -1
- package/src/session-runtime/setup-tool/tool-defs.mjs +38 -4
- package/src/session-runtime/skills-api.mjs +7 -3
- package/src/session-runtime/turn/agent-ops.mjs +12 -1
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +14 -3
- package/src/session-runtime/turn/turn-run/snapshot-tracker.mjs +20 -15
- package/src/session-runtime/turn/turn-run/turn-open.mjs +4 -5
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +29 -1
- package/src/session-runtime/turn/turn-run/turn-settle.mjs +6 -1
- package/src/session-runtime/turn/turn-run.mjs +6 -7
- package/src/session-runtime/webhook-session-run.mjs +16 -4
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +15 -3
- package/src/session-runtime/workspace/admission-gate.mjs +197 -0
- package/src/session-runtime/workspace/project-branches.mjs +136 -0
- package/src/session-runtime/workspace/transition-steps.mjs +364 -0
- package/src/session-runtime/workspace/transitions.mjs +651 -0
- package/src/session-runtime/workspace/workspace-state.mjs +112 -0
- package/src/skill-script-entry.mjs +36 -0
- package/src/standalone/channel-transport/http-routes.mjs +17 -0
- package/src/standalone/channel-transport.mjs +13 -1
- package/src/standalone/daemon-desktop-runtime.mjs +1 -0
- package/src/standalone/daemon-owner.mjs +372 -0
- package/src/standalone/daemon-stored-session-views.mjs +15 -4
- package/src/standalone/daemon.mjs +179 -8
- package/src/standalone/desktop-service-registry.mjs +20 -0
- package/src/standalone/local-session-runtime.mjs +11 -0
- package/src/standalone/session-client/attachment-calls.mjs +3 -1
- package/src/standalone/session-client/daemon-unavailable.mjs +62 -0
- package/src/standalone/session-client/lease-heartbeat.mjs +47 -0
- package/src/standalone/session-client.mjs +104 -13
- package/src/standalone/session-protocol.mjs +21 -0
- package/src/standalone/session-proxy.mjs +3 -0
- package/src/standalone/session-service/agent-tree/agent-child.mjs +4 -0
- package/src/standalone/session-service/agent-tree/agent-rehydrate.mjs +1 -0
- package/src/standalone/session-service/entries/lifecycle.mjs +6 -0
- package/src/standalone/session-service/projection/revisions.mjs +2 -0
- package/src/standalone/session-service/projection/transcript-window.mjs +149 -19
- package/src/standalone/session-service/projection/workspace.mjs +14 -0
- package/src/standalone/session-service/session-calls/session-action.mjs +17 -4
- package/src/standalone/session-transport/call-route.mjs +13 -0
- package/src/standalone/session-transport/client-registry/client-grace.mjs +45 -3
- package/src/standalone/session-transport/client-registry/registration-replays.mjs +1 -0
- package/src/standalone/session-transport/client-registry.mjs +20 -3
- package/src/standalone/session-transport/routes.mjs +79 -2
- package/src/standalone/session-transport/stack.mjs +2 -0
- package/src/standalone/session-transport.mjs +24 -1
- package/src/tui/App.jsx +9 -1
- package/src/tui/app/app-view/floating-panel.jsx +9 -1
- package/src/tui/app/app-view.jsx +6 -0
- package/src/tui/app/extension-pickers/plugins-pickers.mjs +35 -16
- package/src/tui/app/message-selector.mjs +2 -1
- package/src/tui/app/model-options.mjs +37 -5
- package/src/tui/app/model-picker/provider-models-list.mjs +2 -2
- package/src/tui/app/model-picker.mjs +4 -2
- package/src/tui/app/skill-mention-palette.mjs +88 -0
- package/src/tui/app/slash-palette.mjs +23 -7
- package/src/tui/app/transcript-row-estimate.mjs +11 -3
- package/src/tui/app/use-prompt-draft-flow.mjs +7 -2
- package/src/tui/app/use-prompt-state.mjs +5 -0
- package/src/tui/components/Message.jsx +22 -1
- package/src/tui/components/PromptInput.jsx +21 -3
- package/src/tui/components/SlashCommandPalette.jsx +12 -3
- package/src/tui/components/TranscriptItem.jsx +9 -1
- package/src/tui/components/prompt-input/key-handler.mjs +21 -8
- package/src/tui/components/user-message-skills.mjs +38 -0
- package/src/tui/dist/index.mjs +839 -207
- package/src/tui/index.jsx +10 -2
- package/src/tui/session/compaction-view.mjs +147 -0
- package/src/tui/session/context-state.mjs +6 -0
- package/src/tui/session/initial-state.mjs +3 -0
- package/src/tui/session/queue-helpers.mjs +7 -2
- package/src/tui/session/quota-resume.mjs +2 -1
- package/src/tui/session/session-api/commands.mjs +10 -2
- package/src/tui/session/session-api/controls.mjs +4 -0
- package/src/tui/session/session-api/extensions.mjs +4 -2
- package/src/tui/session/session-api/intake/rewind.mjs +2 -1
- package/src/tui/session/session-api/integrations.mjs +17 -0
- package/src/tui/session/session-api/lifecycle/dispose.mjs +6 -1
- package/src/tui/session/session-api/lifecycle/inheritance.mjs +2 -0
- package/src/tui/session/session-api/lifecycle/resume.mjs +3 -0
- package/src/tui/session/session-api/routes.mjs +10 -1
- package/src/tui/session/session-api/settings.mjs +9 -0
- package/src/tui/session/session-api/worktree.mjs +60 -0
- package/src/tui/session/session-api.mjs +2 -0
- package/src/tui/session/session-flow/auto-clear.mjs +31 -12
- package/src/tui/session/session-flow/drain.mjs +27 -3
- package/src/tui/session/session-flow/session-reset.mjs +4 -3
- package/src/tui/session/session-flow.mjs +2 -0
- package/src/tui/session/transcript-intake.mjs +14 -5
- package/src/tui/session/tui-steering-persist.mjs +25 -9
- package/src/tui/session/turn-stream.mjs +32 -4
- package/src/tui/session/turn-tool-cards.mjs +10 -2
- package/src/tui/session/turn.mjs +56 -10
- package/src/runtime/effort-judge/previous-human-request.mjs +0 -162
- package/src/runtime/effort-judge/verified-context-input.mjs +0 -10
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
// The interpreter a built-in skill's bundled scripts run on.
|
|
2
|
+
//
|
|
3
|
+
// `${MIXDOG_SKILL_DIR}` is a real directory every process can read, but the
|
|
4
|
+
// pptx scripts import the runtime by relative path (../../../../runtime/...)
|
|
5
|
+
// and its native dependencies (sharp, @napi-rs/canvas, pdf.js). A packaged
|
|
6
|
+
// desktop keeps those only inside runtime.asar, which plain Node cannot open,
|
|
7
|
+
// so `node "<dir>/scripts/x.mjs"` works from an npm install and fails there.
|
|
8
|
+
//
|
|
9
|
+
// So the daemon that runs the model's shells hands them its OWN runtime: a
|
|
10
|
+
// per-installation directory, first on every model shell's PATH, holds
|
|
11
|
+
// `mixdog-skill-node` launchers that run this process's executable (Electron
|
|
12
|
+
// in node mode, or node) on src/skill-script-entry.mjs, which maps the script
|
|
13
|
+
// back into the archive before importing it. Each daemon builds its own shell
|
|
14
|
+
// env, so an SSH-remote or mobile session gets its execution host's runtime.
|
|
15
|
+
// Launchers carry two paths and nothing else: no credentials, no daemon
|
|
16
|
+
// identity.
|
|
17
|
+
import { createHash } from 'node:crypto';
|
|
18
|
+
import { existsSync, mkdirSync, readFileSync, realpathSync } from 'node:fs';
|
|
19
|
+
import path from 'node:path';
|
|
20
|
+
import { fileURLToPath } from 'node:url';
|
|
21
|
+
import { writeFileAtomicSync } from './atomic-file.mjs';
|
|
22
|
+
import { resolvePluginData } from './plugin-paths.mjs';
|
|
23
|
+
|
|
24
|
+
/** This module's package root (src/runtime/shared → the package). */
|
|
25
|
+
export const SKILL_SCRIPT_PACKAGE_ROOT = path.resolve(fileURLToPath(new URL('.', import.meta.url)), '..', '..', '..');
|
|
26
|
+
|
|
27
|
+
function pathApi(platform) {
|
|
28
|
+
return platform === 'win32' ? path.win32 : path.posix;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** The `…/runtime.asar` prefix of a location inside the runtime archive, or null. */
|
|
32
|
+
export function archiveRootOf(location, platform = process.platform) {
|
|
33
|
+
const sep = platform === 'win32' ? '[\\\\/]' : '/';
|
|
34
|
+
const match = new RegExp(`^(.*?${sep}runtime\\.asar)(?=${sep}|$)`).exec(String(location || ''));
|
|
35
|
+
return match ? pathApi(platform).normalize(match[1]) : null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The path a script must be imported from. A built-in skill's directory is
|
|
40
|
+
* handed out under `runtime.asar.unpacked` (skillExecutionDir), but its
|
|
41
|
+
* relative imports only resolve from the archive, so a script under the
|
|
42
|
+
* sidecar of the archive that holds this package maps back into it. Source
|
|
43
|
+
* trees and npm installs keep the real path (symlinks resolved, as the ESM
|
|
44
|
+
* loader resolves them for import.meta.url).
|
|
45
|
+
*/
|
|
46
|
+
export function canonicalSkillScriptPath(
|
|
47
|
+
target,
|
|
48
|
+
{
|
|
49
|
+
packageRoot = SKILL_SCRIPT_PACKAGE_ROOT,
|
|
50
|
+
platform = process.platform,
|
|
51
|
+
cwd = process.cwd(),
|
|
52
|
+
realpath = realpathSync,
|
|
53
|
+
} = {}
|
|
54
|
+
) {
|
|
55
|
+
const api = pathApi(platform);
|
|
56
|
+
let location = api.resolve(cwd, String(target));
|
|
57
|
+
try {
|
|
58
|
+
location = realpath(location);
|
|
59
|
+
} catch {
|
|
60
|
+
// A missing script fails at import with its own path in the message.
|
|
61
|
+
}
|
|
62
|
+
const archive = archiveRootOf(packageRoot, platform);
|
|
63
|
+
if (!archive) return location;
|
|
64
|
+
const sidecar = `${archive}.unpacked${api.sep}`;
|
|
65
|
+
const fold = (value) => (platform === 'win32' ? value.replaceAll('/', '\\').toLowerCase() : value);
|
|
66
|
+
if (!fold(location).startsWith(fold(sidecar))) return location;
|
|
67
|
+
return `${archive}${api.sep}${location.slice(sidecar.length)}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** The runtime this process would hand a skill script to. */
|
|
71
|
+
export function skillScriptRuntime({
|
|
72
|
+
execPath = process.execPath,
|
|
73
|
+
versions = process.versions,
|
|
74
|
+
packageRoot = SKILL_SCRIPT_PACKAGE_ROOT,
|
|
75
|
+
platform = process.platform,
|
|
76
|
+
} = {}) {
|
|
77
|
+
return {
|
|
78
|
+
platform,
|
|
79
|
+
interpreter: execPath,
|
|
80
|
+
// Electron's own version marker, not ELECTRON_RUN_AS_NODE: model shells
|
|
81
|
+
// scrub that variable, and a daemon may have inherited it without being
|
|
82
|
+
// Electron at all.
|
|
83
|
+
electron: Boolean(versions?.electron),
|
|
84
|
+
packageRoot,
|
|
85
|
+
entry: pathApi(platform).join(packageRoot, 'src', 'skill-script-entry.mjs'),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function batchQuote(value) {
|
|
90
|
+
return `"${String(value).replaceAll('%', '%%')}"`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function posixQuote(value) {
|
|
94
|
+
return `'${String(value).replaceAll("'", "'\\''")}'`;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The command `${MIXDOG_SKILL_NODE}` renders to. It is the same word in every
|
|
99
|
+
* shell: model shells find it on PATH (withSkillLauncherPath), as the
|
|
100
|
+
* extensionless sh launcher (bash, sh, zsh, Git Bash) or as the .cmd beside
|
|
101
|
+
* it (cmd through PATHEXT on Windows). PowerShell model commands define a
|
|
102
|
+
* function of the same name first (renderPowerShellSkillFunction), which
|
|
103
|
+
* takes precedence over both.
|
|
104
|
+
*/
|
|
105
|
+
export const SKILL_LAUNCHER_COMMAND = 'mixdog-skill-node';
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* sh launcher text. Electron node mode is set only inside the launcher, for
|
|
109
|
+
* the one child it execs; every argument and the exit code pass through.
|
|
110
|
+
*/
|
|
111
|
+
export function renderPosixSkillLauncher({ interpreter, entry, electron }) {
|
|
112
|
+
return `${[
|
|
113
|
+
'#!/bin/sh',
|
|
114
|
+
'# Mixdog skill-script launcher, generated for one installation. Do not edit.',
|
|
115
|
+
...(electron ? ['ELECTRON_RUN_AS_NODE=1', 'export ELECTRON_RUN_AS_NODE'] : []),
|
|
116
|
+
`exec ${posixQuote(interpreter)} ${posixQuote(entry)} "$@"`,
|
|
117
|
+
].join('\n')}\n`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** .cmd launcher text, same contract as the sh launcher. */
|
|
121
|
+
export function renderWindowsSkillLauncher({ interpreter, entry, electron }) {
|
|
122
|
+
// cmd decodes a batch file in the console code page line by line, so a
|
|
123
|
+
// non-ASCII path needs UTF-8 for the lines after chcp; the caller's code
|
|
124
|
+
// page is restored before exit.
|
|
125
|
+
const unicode = /\P{ASCII}/u.test(`${interpreter}${entry}`);
|
|
126
|
+
return `${[
|
|
127
|
+
'@echo off',
|
|
128
|
+
'rem Mixdog skill-script launcher, generated for one installation. Do not edit.',
|
|
129
|
+
'setlocal EnableExtensions DisableDelayedExpansion',
|
|
130
|
+
...(unicode
|
|
131
|
+
? ['for /f "tokens=2 delims=:." %%C in (\'chcp\') do set "MIXDOG_SKILL_CP=%%C"', 'chcp 65001 >nul']
|
|
132
|
+
: []),
|
|
133
|
+
...(electron ? ['set "ELECTRON_RUN_AS_NODE=1"'] : []),
|
|
134
|
+
`${batchQuote(interpreter)} ${batchQuote(entry)} %*`,
|
|
135
|
+
'set "MIXDOG_SKILL_EXIT=%ERRORLEVEL%"',
|
|
136
|
+
...(unicode ? ['if defined MIXDOG_SKILL_CP chcp %MIXDOG_SKILL_CP% >nul'] : []),
|
|
137
|
+
'exit /b %MIXDOG_SKILL_EXIT%',
|
|
138
|
+
].join('\r\n')}\r\n`;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Environment variable carrying a PowerShell caller's arguments to the entry. */
|
|
142
|
+
export const SKILL_ARGV_ENV = 'MIXDOG_SKILL_ARGV';
|
|
143
|
+
const SKILL_ARGV_TAG = 'mixdog1';
|
|
144
|
+
|
|
145
|
+
function psQuote(value) {
|
|
146
|
+
// PowerShell also treats the typographic single quotes as quote characters.
|
|
147
|
+
return `'${String(value).replace(/['\u2018\u2019\u201a\u201b]/g, '$&$&')}'`;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* One-line PowerShell definition of `mixdog-skill-node`, prepended to every
|
|
152
|
+
* PowerShell model command. Through PATH, PowerShell would reach the .cmd via
|
|
153
|
+
* `cmd.exe /c` with arguments it does not quote, so `'a&b'` ran `b`. The
|
|
154
|
+
* function runs this daemon's executable on the entry as a plain native
|
|
155
|
+
* command, so PowerShell's own native-command handling provides streaming,
|
|
156
|
+
* ordering, backpressure, line endings, `2>&1`/`2>$null`/`2>file`,
|
|
157
|
+
* `$LASTEXITCODE`, Ctrl-C and early stop. The caller's arguments never reach
|
|
158
|
+
* that command line: they travel in SKILL_ARGV_ENV (UTF-8 base64), because
|
|
159
|
+
* Windows PowerShell 5.1 drops empty native arguments and does not escape
|
|
160
|
+
* embedded double quotes. A failing script ends the command with its exit
|
|
161
|
+
* code (`exit`), because a PowerShell function cannot fail `$?` or the
|
|
162
|
+
* -Command exit code.
|
|
163
|
+
*
|
|
164
|
+
* SKILL_ARGV_ENV and (Electron daemons only) ELECTRON_RUN_AS_NODE are set on
|
|
165
|
+
* $env just for the call and restored in `finally`; the bootstrap deletes
|
|
166
|
+
* both before importing the script. Accepted tradeoff: while the call runs,
|
|
167
|
+
* a process a concurrent downstream pipeline stage starts can see them.
|
|
168
|
+
*/
|
|
169
|
+
export function renderPowerShellSkillFunction({ interpreter, entry, electron }) {
|
|
170
|
+
const names = [SKILL_ARGV_ENV, ...(electron ? ['ELECTRON_RUN_AS_NODE'] : [])];
|
|
171
|
+
const values = ['$__mxa', ...(electron ? ["'1'"] : [])];
|
|
172
|
+
const body = [
|
|
173
|
+
`$__mxa = '${SKILL_ARGV_TAG}'`,
|
|
174
|
+
"foreach ($__mxv in $args) { foreach ($__mxe in @($__mxv)) { if ($null -ne $__mxe) { $__mxa += ',' + [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes([string]$__mxe)) } } }",
|
|
175
|
+
names.map((name, i) => `$__mxo${i} = $env:${name}`).join('; '),
|
|
176
|
+
[
|
|
177
|
+
'try {',
|
|
178
|
+
...names.map((name, i) => `$env:${name} = ${values[i]};`),
|
|
179
|
+
`& ${psQuote(interpreter)} ${psQuote(entry)}`,
|
|
180
|
+
'} finally {',
|
|
181
|
+
names.map((name, i) => `$env:${name} = $__mxo${i}`).join('; '),
|
|
182
|
+
'}',
|
|
183
|
+
].join(' '),
|
|
184
|
+
'if ($LASTEXITCODE) { exit $LASTEXITCODE }',
|
|
185
|
+
];
|
|
186
|
+
return `function ${SKILL_LAUNCHER_COMMAND} { ${body.join('; ')} }`;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** The arguments a PowerShell caller sent through SKILL_ARGV_ENV, or null. */
|
|
190
|
+
export function decodeSkillArgv(value) {
|
|
191
|
+
const text = typeof value === 'string' ? value : '';
|
|
192
|
+
if (!text.startsWith(SKILL_ARGV_TAG)) return null;
|
|
193
|
+
const rest = text.slice(SKILL_ARGV_TAG.length);
|
|
194
|
+
if (!rest) return [];
|
|
195
|
+
return rest
|
|
196
|
+
.slice(1)
|
|
197
|
+
.split(',')
|
|
198
|
+
.map((item) => Buffer.from(item, 'base64').toString('utf8'));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** Launcher files of `runtime`: the sh script everywhere, plus the .cmd on Windows. */
|
|
202
|
+
export function skillLauncherFiles(runtime) {
|
|
203
|
+
return [
|
|
204
|
+
{ name: SKILL_LAUNCHER_COMMAND, content: renderPosixSkillLauncher(runtime) },
|
|
205
|
+
...(runtime.platform === 'win32'
|
|
206
|
+
? [{ name: `${SKILL_LAUNCHER_COMMAND}.cmd`, content: renderWindowsSkillLauncher(runtime) }]
|
|
207
|
+
: []),
|
|
208
|
+
];
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** Private per-installation launcher directory under the data dir. */
|
|
212
|
+
export function skillLauncherDir(runtime, dataDir = resolvePluginData()) {
|
|
213
|
+
const digest = createHash('sha256')
|
|
214
|
+
.update(JSON.stringify([runtime.platform, runtime.interpreter, runtime.entry, runtime.electron]))
|
|
215
|
+
.digest('hex')
|
|
216
|
+
.slice(0, 16);
|
|
217
|
+
return pathApi(runtime.platform).join(dataDir, 'skill-launchers', digest);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const ensuredDirs = new Set();
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Write (atomically) or refresh the launchers for `runtime`; returns their
|
|
224
|
+
* directory. A directory already verified by this process is only checked for
|
|
225
|
+
* presence, so the per-command shell env build stays a couple of stats.
|
|
226
|
+
*/
|
|
227
|
+
export function ensureSkillLauncherDir(runtime = skillScriptRuntime(), dataDir = resolvePluginData()) {
|
|
228
|
+
const dir = skillLauncherDir(runtime, dataDir);
|
|
229
|
+
const api = pathApi(runtime.platform);
|
|
230
|
+
const files = skillLauncherFiles(runtime);
|
|
231
|
+
if (ensuredDirs.has(dir) && files.every(({ name }) => existsSync(api.join(dir, name)))) return dir;
|
|
232
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
233
|
+
for (const { name, content } of files) {
|
|
234
|
+
const file = api.join(dir, name);
|
|
235
|
+
let current = null;
|
|
236
|
+
try {
|
|
237
|
+
current = readFileSync(file, 'utf8');
|
|
238
|
+
} catch {
|
|
239
|
+
// Not written yet.
|
|
240
|
+
}
|
|
241
|
+
if (current !== content) writeFileAtomicSync(file, content, { mode: 0o700 });
|
|
242
|
+
}
|
|
243
|
+
ensuredDirs.add(dir);
|
|
244
|
+
return dir;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* `env` with this installation's launcher directory first on PATH. Only model
|
|
249
|
+
* shell environments call this; the daemon's own env, hooks and internal
|
|
250
|
+
* workers keep their PATH. The directory holds nothing but the launchers, so
|
|
251
|
+
* no existing command is shadowed.
|
|
252
|
+
*/
|
|
253
|
+
export function withSkillLauncherPath(env, { runtime = skillScriptRuntime(), dataDir = resolvePluginData() } = {}) {
|
|
254
|
+
const dir = ensureSkillLauncherDir(runtime, dataDir);
|
|
255
|
+
const delimiter = runtime.platform === 'win32' ? ';' : ':';
|
|
256
|
+
// Windows env keys are case-insensitive and usually spelled `Path`.
|
|
257
|
+
const key =
|
|
258
|
+
(runtime.platform === 'win32' ? Object.keys(env).find((name) => name.toUpperCase() === 'PATH') : null) || 'PATH';
|
|
259
|
+
const entries = String(env[key] || '')
|
|
260
|
+
.split(delimiter)
|
|
261
|
+
.filter((entry) => entry && entry !== dir);
|
|
262
|
+
env[key] = [dir, ...entries].join(delimiter);
|
|
263
|
+
return env;
|
|
264
|
+
}
|
|
@@ -23,7 +23,13 @@ const SHELL_JOBS_SEGMENT_CACHE_MS = 1000;
|
|
|
23
23
|
// Session buckets ride along with the owner-wide totals: one host process can
|
|
24
24
|
// own many sessions (the desktop pools every pane's engine), so a pane must be
|
|
25
25
|
// able to ask for ITS OWN jobs instead of the process aggregate.
|
|
26
|
-
const
|
|
26
|
+
const FINISHED_SHELL_JOB_TTL_MS = 30 * 60 * 1000;
|
|
27
|
+
const EMPTY_SHELL_JOBS_SESSION = Object.freeze({
|
|
28
|
+
count: 0,
|
|
29
|
+
elapsedLabel: '',
|
|
30
|
+
jobs: Object.freeze([]),
|
|
31
|
+
finished: Object.freeze([]),
|
|
32
|
+
});
|
|
27
33
|
const EMPTY_SHELL_JOBS = Object.freeze({
|
|
28
34
|
count: 0,
|
|
29
35
|
elapsedLabel: '',
|
|
@@ -31,8 +37,20 @@ const EMPTY_SHELL_JOBS = Object.freeze({
|
|
|
31
37
|
sessions: Object.freeze({}),
|
|
32
38
|
});
|
|
33
39
|
|
|
34
|
-
|
|
35
|
-
|
|
40
|
+
// One entry per owner pid: a desktop host polls under whichever session frame
|
|
41
|
+
// arrived last, so the owner can alternate between processes. A single shared
|
|
42
|
+
// slot answered every switch with "no jobs" and made the job list flicker.
|
|
43
|
+
const _shellJobsSegmentCache = new Map();
|
|
44
|
+
const _shellJobsRefreshInFlight = new Set();
|
|
45
|
+
const SHELL_JOBS_OWNER_CACHE_TTL_MS = 60_000;
|
|
46
|
+
|
|
47
|
+
function rememberShellJobs(ownerPid, value) {
|
|
48
|
+
const at = Date.now();
|
|
49
|
+
for (const [pid, entry] of _shellJobsSegmentCache) {
|
|
50
|
+
if (at - entry.at > SHELL_JOBS_OWNER_CACHE_TTL_MS) _shellJobsSegmentCache.delete(pid);
|
|
51
|
+
}
|
|
52
|
+
_shellJobsSegmentCache.set(ownerPid, { at, value });
|
|
53
|
+
}
|
|
36
54
|
|
|
37
55
|
function dataDir() {
|
|
38
56
|
return process.env.MIXDOG_DATA_DIR || DEFAULT_STANDALONE_DATA_DIR;
|
|
@@ -50,15 +68,15 @@ export function shellJobsStatus({ clientHostPid, sessionId } = {}) {
|
|
|
50
68
|
const scope = String(sessionId ?? '').trim();
|
|
51
69
|
if (!ownerPid) return scoped ? EMPTY_SHELL_JOBS_SESSION : EMPTY_SHELL_JOBS;
|
|
52
70
|
const now = Date.now();
|
|
53
|
-
const
|
|
54
|
-
const fresh =
|
|
55
|
-
if (!fresh && !_shellJobsRefreshInFlight) {
|
|
56
|
-
_shellJobsRefreshInFlight
|
|
71
|
+
const cached = _shellJobsSegmentCache.get(ownerPid);
|
|
72
|
+
const fresh = cached && now - cached.at < SHELL_JOBS_SEGMENT_CACHE_MS;
|
|
73
|
+
if (!fresh && !_shellJobsRefreshInFlight.has(ownerPid)) {
|
|
74
|
+
_shellJobsRefreshInFlight.add(ownerPid);
|
|
57
75
|
refreshShellJobsStatus(ownerPid).finally(() => {
|
|
58
|
-
_shellJobsRefreshInFlight
|
|
76
|
+
_shellJobsRefreshInFlight.delete(ownerPid);
|
|
59
77
|
});
|
|
60
78
|
}
|
|
61
|
-
const value =
|
|
79
|
+
const value = cached?.value || EMPTY_SHELL_JOBS;
|
|
62
80
|
if (!scoped) return value;
|
|
63
81
|
return (scope && value.sessions?.[scope]) || EMPTY_SHELL_JOBS_SESSION;
|
|
64
82
|
}
|
|
@@ -123,10 +141,10 @@ async function refreshShellJobsStatus(ownerPid) {
|
|
|
123
141
|
try {
|
|
124
142
|
names = await readdir(dir);
|
|
125
143
|
} catch {
|
|
126
|
-
|
|
144
|
+
rememberShellJobs(ownerPid, value);
|
|
127
145
|
return;
|
|
128
146
|
}
|
|
129
|
-
const { ids, ownerByJob } = listOpenShellJobs(names);
|
|
147
|
+
const { ids, ownerByJob, doneIds } = listOpenShellJobs(names);
|
|
130
148
|
let count = 0;
|
|
131
149
|
let oldestMs = Infinity;
|
|
132
150
|
const jobs = [];
|
|
@@ -143,6 +161,10 @@ async function refreshShellJobsStatus(ownerPid) {
|
|
|
143
161
|
continue;
|
|
144
162
|
}
|
|
145
163
|
if (!(await isShellJobAlive(detail, p, dir, id))) continue;
|
|
164
|
+
// A foreground command is awaited in its own tool card; listing it here
|
|
165
|
+
// made every short command flash in and out of the shell list. Only
|
|
166
|
+
// backgrounded jobs (including promoted ones) are background work.
|
|
167
|
+
if (detail?.foreground === true) continue;
|
|
146
168
|
// Owner-wide totals stay this process's own; session buckets take every
|
|
147
169
|
// live job regardless of which host published it.
|
|
148
170
|
const ownedByThisHost = ownerByJob.get(id) === ownerPid;
|
|
@@ -162,12 +184,39 @@ async function refreshShellJobsStatus(ownerPid) {
|
|
|
162
184
|
};
|
|
163
185
|
if (ownedByThisHost) jobs.push(job);
|
|
164
186
|
if (!owner) continue;
|
|
165
|
-
const bucket = bySession.get(owner) || { count: 0, oldestMs: Infinity, jobs: [] };
|
|
187
|
+
const bucket = bySession.get(owner) || { count: 0, oldestMs: Infinity, jobs: [], finished: [] };
|
|
166
188
|
bucket.count += 1;
|
|
167
189
|
if (jobMs < bucket.oldestMs) bucket.oldestMs = jobMs;
|
|
168
190
|
bucket.jobs.push(job);
|
|
169
191
|
bySession.set(owner, bucket);
|
|
170
192
|
}
|
|
193
|
+
// Recently finished background jobs ride in their session bucket only;
|
|
194
|
+
// they never touch the running counts.
|
|
195
|
+
const finishedCutoff = Date.now() - FINISHED_SHELL_JOB_TTL_MS;
|
|
196
|
+
for (const id of doneIds) {
|
|
197
|
+
let detail;
|
|
198
|
+
try {
|
|
199
|
+
detail = JSON.parse(await readFile(join(dir, `${id}.json`), 'utf-8'));
|
|
200
|
+
} catch {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (detail?.foreground === true) continue;
|
|
204
|
+
const owner = String(detail?.ownerSessionId ?? '').trim();
|
|
205
|
+
if (!owner) continue;
|
|
206
|
+
const finishedMs = Date.parse(detail?.finishedAt || detail?.recordedAt || '');
|
|
207
|
+
if (Number.isFinite(finishedMs) && finishedMs < finishedCutoff) continue;
|
|
208
|
+
const bucket = bySession.get(owner) || { count: 0, oldestMs: Infinity, jobs: [], finished: [] };
|
|
209
|
+
bucket.finished.push({
|
|
210
|
+
taskId: id,
|
|
211
|
+
command: String(detail?.command || '').trim(),
|
|
212
|
+
cwd: String(detail?.cwd || '').trim(),
|
|
213
|
+
startedAt: detail?.startedAt || null,
|
|
214
|
+
status: String(detail?.status || ''),
|
|
215
|
+
exitCode: Number.isInteger(detail?.exitCode) ? detail.exitCode : null,
|
|
216
|
+
finishedAt: detail?.finishedAt || detail?.recordedAt || null,
|
|
217
|
+
});
|
|
218
|
+
bySession.set(owner, bucket);
|
|
219
|
+
}
|
|
171
220
|
// A desktop pane's job lands in a session bucket while the owner-wide
|
|
172
221
|
// count stays 0 (its publisher is a shard, not this host), so an empty
|
|
173
222
|
// aggregate must NOT discard the session buckets.
|
|
@@ -175,7 +224,7 @@ async function refreshShellJobsStatus(ownerPid) {
|
|
|
175
224
|
} catch {
|
|
176
225
|
value = EMPTY_SHELL_JOBS;
|
|
177
226
|
}
|
|
178
|
-
|
|
227
|
+
rememberShellJobs(ownerPid, value);
|
|
179
228
|
}
|
|
180
229
|
|
|
181
230
|
// Newest-first, capped ids of job records with no `.done` marker, plus the
|
|
@@ -209,7 +258,11 @@ function listOpenShellJobs(names) {
|
|
|
209
258
|
// the per-refresh cap doubles with it; a live (non-.done) record set is
|
|
210
259
|
// a handful in practice and terminal ones age out on their own.
|
|
211
260
|
.slice(0, 60);
|
|
212
|
-
|
|
261
|
+
const doneIds = [...done]
|
|
262
|
+
.filter((id) => names.includes(`${id}.json`))
|
|
263
|
+
.sort((a, b) => jobStampMs(b) - jobStampMs(a))
|
|
264
|
+
.slice(0, 30);
|
|
265
|
+
return { ids, ownerByJob, doneIds };
|
|
213
266
|
}
|
|
214
267
|
|
|
215
268
|
function summarizeShellJobs({ count, oldestMs, jobs, bySession }) {
|
|
@@ -221,6 +274,7 @@ function summarizeShellJobs({ count, oldestMs, jobs, bySession }) {
|
|
|
221
274
|
count: bucket.count,
|
|
222
275
|
elapsedLabel: Number.isFinite(bucket.oldestMs) ? formatElapsed(now - bucket.oldestMs) : '',
|
|
223
276
|
jobs: bucket.jobs,
|
|
277
|
+
finished: bucket.finished,
|
|
224
278
|
};
|
|
225
279
|
}
|
|
226
280
|
return { count, elapsedLabel, jobs, sessions };
|
|
@@ -22,8 +22,39 @@ function rawToolName(name) {
|
|
|
22
22
|
return String(name || 'tool').replace(/^functions\./, '');
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
// Tool names shortened to fit provider limits -> their real server and tool,
|
|
26
|
+
// recorded when the name is built so name-only callers in this process
|
|
27
|
+
// resolve them. Bounded; the oldest entries go first.
|
|
28
|
+
const MCP_TOOL_IDENTITY_MAX = 4096;
|
|
29
|
+
const mcpToolIdentities = new Map();
|
|
30
|
+
|
|
31
|
+
export function rememberMcpToolIdentity(name, server, tool) {
|
|
32
|
+
const key = String(name || '');
|
|
33
|
+
if (!key) return;
|
|
34
|
+
mcpToolIdentities.delete(key);
|
|
35
|
+
mcpToolIdentities.set(key, { server: String(server || ''), tool: String(tool || '') });
|
|
36
|
+
if (mcpToolIdentities.size > MCP_TOOL_IDENTITY_MAX) mcpToolIdentities.delete(mcpToolIdentities.keys().next().value);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Server and tool of a shortened MCP tool name, when this process built it. */
|
|
40
|
+
export function knownMcpToolIdentity(name) {
|
|
41
|
+
const known = mcpToolIdentities.get(rawToolName(name));
|
|
42
|
+
return known ? { ...known } : null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** `{ server, tool }` of an MCP tool, or null. Takes a tool definition (its
|
|
46
|
+
* `mcpServerName`/`mcpToolName` metadata wins) or a name (a recorded
|
|
47
|
+
* shortened name first, else the `mcp__<server>__<tool>` form). */
|
|
48
|
+
export function parseMcpToolName(nameOrTool) {
|
|
49
|
+
if (nameOrTool && typeof nameOrTool === 'object') {
|
|
50
|
+
const server = String(nameOrTool.mcpServerName || '').trim();
|
|
51
|
+
const parsed = parseMcpToolName(nameOrTool.name);
|
|
52
|
+
if (!server) return parsed;
|
|
53
|
+
return { server, tool: String(nameOrTool.mcpToolName || '') || parsed?.tool || '' };
|
|
54
|
+
}
|
|
55
|
+
const text = rawToolName(nameOrTool);
|
|
56
|
+
const known = mcpToolIdentities.get(text);
|
|
57
|
+
if (known) return { ...known };
|
|
27
58
|
const match = /^mcp__(.+?)__(.+)$/.exec(text);
|
|
28
59
|
if (!match) return null;
|
|
29
60
|
return { server: match[1], tool: match[2] };
|
|
@@ -169,6 +200,8 @@ export function toolSearchDisplayLabel(args = {}) {
|
|
|
169
200
|
export function displayToolSearchTarget(value) {
|
|
170
201
|
const text = String(value || '').trim();
|
|
171
202
|
if (/^skill:/i.test(text)) return text.slice('skill:'.length);
|
|
203
|
+
const known = knownMcpToolIdentity(text);
|
|
204
|
+
if (known) return `${known.server}.${known.tool}`;
|
|
172
205
|
const mcp = /^mcp__(.*?)__(.+)$/.exec(text);
|
|
173
206
|
if (mcp) return `${mcp[1]}.${mcp[2]}`;
|
|
174
207
|
return stripToolPrefix(text);
|
|
@@ -140,6 +140,8 @@ export function displayToolName(name, args = {}) {
|
|
|
140
140
|
return 'Media';
|
|
141
141
|
case 'tidy':
|
|
142
142
|
return 'Tidy';
|
|
143
|
+
case 'visualize':
|
|
144
|
+
return 'Visualize';
|
|
143
145
|
case 'list_mcp_resources':
|
|
144
146
|
case 'list_mcp_resource_templates':
|
|
145
147
|
case 'cwd':
|
|
@@ -310,6 +312,11 @@ export function summarizeToolArgs(name, args, { max = DEFAULT_SUMMARY_MAX } = {}
|
|
|
310
312
|
}
|
|
311
313
|
case 'terminal':
|
|
312
314
|
return compactParts([String(a.action || ''), a.tab ? `tab ${a.tab}` : '']);
|
|
315
|
+
case 'visualize': {
|
|
316
|
+
const input = a.input && typeof a.input === 'object' ? a.input : {};
|
|
317
|
+
const targets = Array.isArray(input.targets) ? input.targets.map(String).join(', ') : '';
|
|
318
|
+
return compactParts([String(a.action || ''), targets || String(input.tab || '')]);
|
|
319
|
+
}
|
|
313
320
|
case 'office':
|
|
314
321
|
return compactParts([String(a.action || ''), pathOrId(a.path, a.session, max)]);
|
|
315
322
|
case 'media':
|
|
@@ -82,6 +82,7 @@ const TOOL_CATEGORY = new Map([
|
|
|
82
82
|
['office', 'Office'],
|
|
83
83
|
['media', 'Media'],
|
|
84
84
|
['tidy', 'Tidy'],
|
|
85
|
+
['visualize', 'Visualize'],
|
|
85
86
|
['list_mcp_resources', 'Setup'],
|
|
86
87
|
['list_mcp_resource_templates', 'Setup'],
|
|
87
88
|
['cwd', 'Setup'],
|
|
@@ -124,6 +125,7 @@ const CATEGORY_COPY = new Map([
|
|
|
124
125
|
['Office', { active: 'Editing', done: 'Edited', noun: 'document action' }],
|
|
125
126
|
['Media', { active: 'Generating', done: 'Generated', noun: 'media action' }],
|
|
126
127
|
['Tidy', { active: 'Tidying', done: 'Tidied', noun: 'cleanup pass' }],
|
|
128
|
+
['Visualize', { active: 'Showing', done: 'Showed', noun: 'artifact' }],
|
|
127
129
|
['Other', { active: 'Calling', done: 'Called', noun: 'tool' }],
|
|
128
130
|
]);
|
|
129
131
|
|
|
@@ -338,6 +340,17 @@ function officeUnit(a) {
|
|
|
338
340
|
return unitDescriptor('Office', { count: 1, active, done, noun: 'document action', effect: true });
|
|
339
341
|
}
|
|
340
342
|
|
|
343
|
+
function visualizeUnit(a) {
|
|
344
|
+
const action = String(a.action || '').toLowerCase();
|
|
345
|
+
if (action === 'capture') return unitDescriptor('Visualize', { count: 1, active: 'Capturing', done: 'Captured', noun: 'screenshot' });
|
|
346
|
+
if (action === 'export') return unitDescriptor('Visualize', { count: 1, active: 'Exporting', done: 'Exported', noun: 'file' });
|
|
347
|
+
if (action === 'annotate') return unitDescriptor('Visualize', { count: 1, active: 'Marking', done: 'Marked', noun: 'annotation' });
|
|
348
|
+
if (action === 'check') return unitDescriptor('Visualize', { count: 1, active: 'Checking', done: 'Checked', noun: 'page' });
|
|
349
|
+
if (action === 'inspect') return unitDescriptor('Visualize', { count: 1, active: 'Inspecting', done: 'Inspected', noun: 'page' });
|
|
350
|
+
if (action === 'close') return unitDescriptor('Visualize', { count: 1, active: 'Closing', done: 'Closed', noun: 'tab' });
|
|
351
|
+
return unitDescriptor('Visualize', { count: 1, active: 'Showing', done: 'Showed', noun: 'artifact' });
|
|
352
|
+
}
|
|
353
|
+
|
|
341
354
|
function terminalUnit(a) {
|
|
342
355
|
return String(a.action || '').toLowerCase() === 'list'
|
|
343
356
|
? unitDescriptor('Terminal', { count: 1, active: 'Listing', done: 'Listed', noun: 'terminal tab' })
|
|
@@ -642,6 +655,7 @@ const TOOL_UNITS = new Map([
|
|
|
642
655
|
['setup', setupUnit],
|
|
643
656
|
['media', mediaUnit],
|
|
644
657
|
['tidy', tidyUnit],
|
|
658
|
+
['visualize', visualizeUnit],
|
|
645
659
|
['fetch', fetchUnit],
|
|
646
660
|
['recall', memoryReadUnit],
|
|
647
661
|
['recall_memory', memoryReadUnit],
|
|
@@ -21,14 +21,29 @@ export function createTranscriptRouteMetadata(session, route = {}, at = Date.now
|
|
|
21
21
|
return { at, ...transcriptRouteMetadataFields({ modelId, model, provider, agent }) };
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/** A new stable message id (`meta.transcript.messageId`). */
|
|
25
|
+
export function newTranscriptMessageId() {
|
|
26
|
+
return `msg_${globalThis.crypto.randomUUID().replaceAll('-', '')}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const stableMessageId = (value) => (typeof value === 'string' && value ? value : newTranscriptMessageId());
|
|
30
|
+
|
|
31
|
+
// Every persisted prompt/reply carries a stable `messageId` from creation on.
|
|
32
|
+
// Compaction rewrites copy `meta`, so the id survives them; the display-only
|
|
33
|
+
// compaction archive and a live view tell dropped rows from rewritten ones
|
|
34
|
+
// by it. A surface that drew the row first passes its id in.
|
|
24
35
|
export function persistedUserTranscriptMetadata(value) {
|
|
25
36
|
if (!value || typeof value !== 'object') return null;
|
|
26
37
|
return {
|
|
38
|
+
messageId: stableMessageId(value.messageId),
|
|
27
39
|
...(Number.isFinite(Number(value.at)) ? { at: Number(value.at) } : {}),
|
|
28
40
|
...transcriptRouteMetadataFields(value),
|
|
29
41
|
...(typeof value.sender === 'string' && value.sender ? { sender: value.sender } : {}),
|
|
30
42
|
// The device that submitted the prompt (host-stamped display name).
|
|
31
43
|
...(typeof value.device === 'string' && value.device ? { device: value.device } : {}),
|
|
44
|
+
// The turn's change-record key (the outer prompt id), so a restored user
|
|
45
|
+
// row still addresses its turn's Undo/Reapply.
|
|
46
|
+
...(typeof value.checkpointId === 'string' && value.checkpointId ? { checkpointId: value.checkpointId } : {}),
|
|
32
47
|
};
|
|
33
48
|
}
|
|
34
49
|
|
|
@@ -37,5 +52,6 @@ export function persistedAssistantTranscriptMetadata(value, fallbackAt = Date.no
|
|
|
37
52
|
const candidateAt = Number(value.assistantAt);
|
|
38
53
|
const assistantAt = Number.isFinite(candidateAt) && candidateAt > 0 ? candidateAt : fallbackAt;
|
|
39
54
|
value.assistantAt = assistantAt;
|
|
40
|
-
|
|
55
|
+
value.assistantMessageId = stableMessageId(value.assistantMessageId);
|
|
56
|
+
return { messageId: value.assistantMessageId, at: assistantAt, ...transcriptRouteMetadataFields(value) };
|
|
41
57
|
}
|