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
|
@@ -5,7 +5,7 @@ import { SESSION_CONFIGURE_ACTION_SET, SESSION_READ_ACTION_SET } from '../../ses
|
|
|
5
5
|
import { sanitizeForWire } from '../../session-wire-values.mjs';
|
|
6
6
|
|
|
7
7
|
/** Reads a session without a live runtime answers from disk (readStoredReview). */
|
|
8
|
-
const STORED_REVIEW_ACTIONS = new Set(['getTurnReviewDiff', 'getSessionReviewDiff']);
|
|
8
|
+
const STORED_REVIEW_ACTIONS = new Set(['getTurnReviewDiff', 'getSessionReviewDiff', 'getTurnChanges']);
|
|
9
9
|
|
|
10
10
|
/** One compact description of an action result for the daemon log, never the payload itself. */
|
|
11
11
|
function resultSummary(value) {
|
|
@@ -22,8 +22,16 @@ function requireSessionAction(action, allowed) {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export function createSessionActionCalls(ctx) {
|
|
25
|
-
const {
|
|
26
|
-
|
|
25
|
+
const {
|
|
26
|
+
isClosed,
|
|
27
|
+
log,
|
|
28
|
+
listSessions,
|
|
29
|
+
getRemoteSessionState,
|
|
30
|
+
loadProjectStore,
|
|
31
|
+
advanceForCaller,
|
|
32
|
+
readStoredReview,
|
|
33
|
+
responseSessionId,
|
|
34
|
+
} = ctx;
|
|
27
35
|
const { bodyForClient } = ctx.projection;
|
|
28
36
|
const { retainUnwatched } = ctx.retention;
|
|
29
37
|
const { assertAvailable, hostedEntryForSession, entryForSession } = ctx.entries;
|
|
@@ -93,15 +101,20 @@ export function createSessionActionCalls(ctx) {
|
|
|
93
101
|
if (typeof listSessions !== 'function') {
|
|
94
102
|
throw new Error('session catalog is unavailable');
|
|
95
103
|
}
|
|
96
|
-
const
|
|
104
|
+
const listed = await listSessions({
|
|
97
105
|
...(options || {}),
|
|
98
106
|
// Agent-only records are an internal ancestry/reuse source, never part
|
|
99
107
|
// of the ordinary session catalog returned over the public transport.
|
|
100
108
|
includeAgentOnly: false,
|
|
101
109
|
});
|
|
110
|
+
// A `page: { limit, cursor }` request answers one page: { sessions, nextCursor }.
|
|
111
|
+
const page = listed && !Array.isArray(listed) && Array.isArray(listed.sessions) ? listed : null;
|
|
112
|
+
const sessions = page ? page.sessions : listed;
|
|
102
113
|
const remoteSession = typeof getRemoteSessionState === 'function' ? await getRemoteSessionState() : null;
|
|
114
|
+
const nextCursor = typeof page?.nextCursor === 'string' ? page.nextCursor : null;
|
|
103
115
|
return {
|
|
104
116
|
sessions: sanitizeForWire(Array.isArray(sessions) ? sessions : []),
|
|
117
|
+
...(page ? { nextCursor } : {}),
|
|
105
118
|
remoteSession: sanitizeForWire(remoteSession) ?? null,
|
|
106
119
|
};
|
|
107
120
|
}
|
|
@@ -91,14 +91,27 @@ export function createCallRoute({ handleCall, clients, lanes, callCache, nowMs }
|
|
|
91
91
|
// tell a failed CALL from a dead TRANSPORT (which must re-attach). The
|
|
92
92
|
// machine-readable `code` (ECALLIDCONFLICT / ECALLRESULTDROPPED) travels
|
|
93
93
|
// with it: a client must be able to branch on it, not parse prose.
|
|
94
|
+
// Typed (worktree) failures also carry their plain JSON `details`.
|
|
94
95
|
sendJson(
|
|
95
96
|
res,
|
|
96
97
|
{
|
|
97
98
|
error: err?.message || String(err),
|
|
98
99
|
...(err?.code ? { code: String(err.code) } : {}),
|
|
100
|
+
...jsonDetails(err),
|
|
99
101
|
},
|
|
100
102
|
200
|
|
101
103
|
);
|
|
102
104
|
}
|
|
103
105
|
};
|
|
104
106
|
}
|
|
107
|
+
|
|
108
|
+
/** `{ details }` when the error's details are a JSON-safe object, else {}. */
|
|
109
|
+
function jsonDetails(err) {
|
|
110
|
+
const details = err?.details;
|
|
111
|
+
if (!details || typeof details !== 'object') return {};
|
|
112
|
+
try {
|
|
113
|
+
return { details: JSON.parse(JSON.stringify(details)) };
|
|
114
|
+
} catch {
|
|
115
|
+
return {};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -5,11 +5,44 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { isPidAlive } from '../../../runtime/shared/pid-liveness.mjs';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const LEASE_MIN_MS = 3_000;
|
|
9
|
+
const LEASE_MAX_MS = 600_000;
|
|
10
|
+
const LEASE_DEFAULT_MS = 30_000;
|
|
11
|
+
const REMOTE_CLIENT_GRACE_DEFAULT_MS = 1_800_000;
|
|
12
|
+
|
|
13
|
+
/** A remote client's lease: the requested `leaseMs`, clamped to 3s..10min. */
|
|
14
|
+
export function clampLeaseMs(value) {
|
|
15
|
+
const leaseMs = Number(value);
|
|
16
|
+
if (!Number.isFinite(leaseMs) || leaseMs <= 0) return LEASE_DEFAULT_MS;
|
|
17
|
+
return Math.min(LEASE_MAX_MS, Math.max(LEASE_MIN_MS, leaseMs));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// A remote desktop behind a flaky tunnel needs far longer to come back than a
|
|
21
|
+
// local terminal restarting. Read at arm time so the env can change per run.
|
|
22
|
+
function remoteClientGraceMs() {
|
|
23
|
+
const configured = Number(process.env.MIXDOG_REMOTE_CLIENT_GRACE_MS);
|
|
24
|
+
return Number.isFinite(configured) && configured >= 0 && process.env.MIXDOG_REMOTE_CLIENT_GRACE_MS
|
|
25
|
+
? configured
|
|
26
|
+
: REMOTE_CLIENT_GRACE_DEFAULT_MS;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function createClientGrace({
|
|
30
|
+
clients,
|
|
31
|
+
log,
|
|
32
|
+
clientGraceMs,
|
|
33
|
+
sweepMs,
|
|
34
|
+
nowMs = () => Date.now(),
|
|
35
|
+
onClientsEmpty,
|
|
36
|
+
isClosed,
|
|
37
|
+
dropClient,
|
|
38
|
+
}) {
|
|
9
39
|
let graceTimer = null;
|
|
10
40
|
let sweepTimer = null;
|
|
11
41
|
let everHadLifecycleClient = false;
|
|
12
42
|
let signalled = false;
|
|
43
|
+
// Whether the most recently departed lifecycle client was remote; it picks
|
|
44
|
+
// the empty-clients grace.
|
|
45
|
+
let lastLifecycleWasRemote = false;
|
|
13
46
|
|
|
14
47
|
function lifecycleClientCount() {
|
|
15
48
|
let count = 0;
|
|
@@ -45,10 +78,14 @@ export function createClientGrace({ clients, log, clientGraceMs, sweepMs, onClie
|
|
|
45
78
|
try {
|
|
46
79
|
onClientsEmpty();
|
|
47
80
|
} catch {}
|
|
48
|
-
}, clientGraceMs);
|
|
81
|
+
}, lastLifecycleWasRemote ? remoteClientGraceMs() : clientGraceMs);
|
|
49
82
|
graceTimer.unref?.();
|
|
50
83
|
}
|
|
51
84
|
|
|
85
|
+
function noteLifecycleDropped(client) {
|
|
86
|
+
lastLifecycleWasRemote = client.remote === true;
|
|
87
|
+
}
|
|
88
|
+
|
|
52
89
|
/** A lifecycle client holds the daemon up: remember one ever attached and
|
|
53
90
|
* cancel any pending grace. */
|
|
54
91
|
function noteLifecycleClient() {
|
|
@@ -61,6 +98,11 @@ export function createClientGrace({ clients, log, clientGraceMs, sweepMs, onClie
|
|
|
61
98
|
if (sweepTimer || isClosed()) return;
|
|
62
99
|
sweepTimer = setInterval(() => {
|
|
63
100
|
for (const [token, c] of [...clients]) {
|
|
101
|
+
if (c.remote) {
|
|
102
|
+
// Its owning process is on another machine: liveness is the lease.
|
|
103
|
+
if (nowMs() - c.lastSeen > c.leaseMs) dropClient(token, 'lease expired');
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
64
106
|
// A client whose owning process died can never read its stream again.
|
|
65
107
|
if (c.leadPid && !isPidAlive(c.leadPid)) dropClient(token, 'lead pid gone');
|
|
66
108
|
}
|
|
@@ -77,5 +119,5 @@ export function createClientGrace({ clients, log, clientGraceMs, sweepMs, onClie
|
|
|
77
119
|
}
|
|
78
120
|
}
|
|
79
121
|
|
|
80
|
-
return { lifecycleClientCount, cancel, maybeArm, noteLifecycleClient, startSweep, stopTimers };
|
|
122
|
+
return { lifecycleClientCount, cancel, maybeArm, noteLifecycleClient, noteLifecycleDropped, startSweep, stopTimers };
|
|
81
123
|
}
|
|
@@ -31,6 +31,7 @@ export function createRegistrationReplays({ clients, log }) {
|
|
|
31
31
|
replay.leadPid === identity.leadPid &&
|
|
32
32
|
replay.cwd === identity.cwd &&
|
|
33
33
|
replay.lifecycle === identity.lifecycle &&
|
|
34
|
+
replay.remote === identity.remote &&
|
|
34
35
|
replay.clientKind === identity.clientKind &&
|
|
35
36
|
replay.revision === identity.revision;
|
|
36
37
|
if (sameIdentity && clients.has(replay.token)) {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { randomUUID } from 'node:crypto';
|
|
8
8
|
import { parsePid } from '../../runtime/shared/pid-liveness.mjs';
|
|
9
9
|
import { createRegistrationReplays } from './client-registry/registration-replays.mjs';
|
|
10
|
-
import { createClientGrace } from './client-registry/client-grace.mjs';
|
|
10
|
+
import { createClientGrace, clampLeaseMs } from './client-registry/client-grace.mjs';
|
|
11
11
|
|
|
12
12
|
export function createClientRegistry({
|
|
13
13
|
log,
|
|
@@ -18,7 +18,7 @@ export function createClientRegistry({
|
|
|
18
18
|
onClientRegistered,
|
|
19
19
|
onClientDropped,
|
|
20
20
|
}) {
|
|
21
|
-
// token -> { token, leadPid, cwd, lifecycle, sse, pending, lastSeen }
|
|
21
|
+
// token -> { token, leadPid, cwd, lifecycle, remote, leaseMs, sse, pending, lastSeen }
|
|
22
22
|
const clients = new Map();
|
|
23
23
|
let closed = false;
|
|
24
24
|
const replays = createRegistrationReplays({ clients, log });
|
|
@@ -27,6 +27,7 @@ export function createClientRegistry({
|
|
|
27
27
|
log,
|
|
28
28
|
clientGraceMs,
|
|
29
29
|
sweepMs,
|
|
30
|
+
nowMs,
|
|
30
31
|
onClientsEmpty,
|
|
31
32
|
isClosed: () => closed,
|
|
32
33
|
dropClient: (token, reason) => dropClient(token, reason),
|
|
@@ -35,6 +36,7 @@ export function createClientRegistry({
|
|
|
35
36
|
function removeClientRecord(token) {
|
|
36
37
|
const c = clients.get(token);
|
|
37
38
|
if (!c) return;
|
|
39
|
+
if (c.lifecycle) grace.noteLifecycleDropped(c);
|
|
38
40
|
try {
|
|
39
41
|
c.sse?.end?.();
|
|
40
42
|
} catch {}
|
|
@@ -57,6 +59,14 @@ export function createClientRegistry({
|
|
|
57
59
|
grace.maybeArm(reason);
|
|
58
60
|
}
|
|
59
61
|
|
|
62
|
+
/** Refresh a client's lease clock (heartbeat). False for an unknown token. */
|
|
63
|
+
function touch(token) {
|
|
64
|
+
const c = clients.get(token);
|
|
65
|
+
if (!c) return false;
|
|
66
|
+
c.lastSeen = nowMs();
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
|
|
60
70
|
function register({
|
|
61
71
|
leadPid,
|
|
62
72
|
cwd,
|
|
@@ -64,11 +74,14 @@ export function createClientRegistry({
|
|
|
64
74
|
clientKind = 'session',
|
|
65
75
|
registrationId = null,
|
|
66
76
|
revision = 0,
|
|
77
|
+
remote = false,
|
|
78
|
+
leaseMs,
|
|
67
79
|
} = {}) {
|
|
68
80
|
const identity = {
|
|
69
81
|
leadPid: parsePid(leadPid) || 0,
|
|
70
82
|
cwd: cwd || null,
|
|
71
83
|
lifecycle: lifecycle !== false,
|
|
84
|
+
remote: remote === true,
|
|
72
85
|
clientKind: clientKind === 'desktop' ? 'desktop' : 'session',
|
|
73
86
|
revision: Math.max(0, Number(revision) || 0),
|
|
74
87
|
};
|
|
@@ -79,6 +92,7 @@ export function createClientRegistry({
|
|
|
79
92
|
clients.set(token, {
|
|
80
93
|
token,
|
|
81
94
|
...identity,
|
|
95
|
+
leaseMs: clampLeaseMs(leaseMs),
|
|
82
96
|
sse: null,
|
|
83
97
|
// True while the socket asked us to stop writing (see writeFrame).
|
|
84
98
|
paused: false,
|
|
@@ -92,7 +106,8 @@ export function createClientRegistry({
|
|
|
92
106
|
grace.startSweep();
|
|
93
107
|
log(
|
|
94
108
|
`client registered token=${token} lead=${identity.leadPid} cwd=${identity.cwd || '-'}` +
|
|
95
|
-
` lifecycle=${identity.lifecycle} kind=${identity.clientKind}`
|
|
109
|
+
` lifecycle=${identity.lifecycle} kind=${identity.clientKind}` +
|
|
110
|
+
(identity.remote ? ` remote leaseMs=${clients.get(token).leaseMs}` : '')
|
|
96
111
|
);
|
|
97
112
|
if (typeof onClientRegistered === 'function') {
|
|
98
113
|
try {
|
|
@@ -102,6 +117,7 @@ export function createClientRegistry({
|
|
|
102
117
|
cwd: identity.cwd,
|
|
103
118
|
lifecycle: identity.lifecycle,
|
|
104
119
|
clientKind: identity.clientKind,
|
|
120
|
+
...(identity.remote ? { remote: true } : {}),
|
|
105
121
|
});
|
|
106
122
|
} catch {}
|
|
107
123
|
}
|
|
@@ -124,6 +140,7 @@ export function createClientRegistry({
|
|
|
124
140
|
forgetReplaysFor: replays.forgetFor,
|
|
125
141
|
dropClient,
|
|
126
142
|
register,
|
|
143
|
+
touch,
|
|
127
144
|
close,
|
|
128
145
|
};
|
|
129
146
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* session-transport/routes.mjs — the HTTP front door: /health (identity
|
|
3
3
|
* travels with every probe), the daemon-token gate, client register /
|
|
4
|
-
* deregister, the /events SSE attach, /call, /shutdown and the /upgrade
|
|
4
|
+
* deregister / heartbeat, the /events SSE attach, /call, /shutdown, /stop and the /upgrade
|
|
5
5
|
* handshake a newer build uses to replace this daemon.
|
|
6
6
|
*/
|
|
7
|
+
import { readFileSync } from 'node:fs';
|
|
7
8
|
import { sendJson, sendError } from '../../runtime/memory/lib/http-wire.mjs';
|
|
9
|
+
import { modelProxyClientMode } from '../../runtime/shared/model-proxy-mode.mjs';
|
|
8
10
|
import {
|
|
9
11
|
compareRuntimeVersions,
|
|
10
12
|
SESSION_CAPABILITY_FINGERPRINT,
|
|
@@ -13,6 +15,32 @@ import {
|
|
|
13
15
|
runtimeVersion,
|
|
14
16
|
} from '../session-wire.mjs';
|
|
15
17
|
|
|
18
|
+
let installBuildHash;
|
|
19
|
+
/** Build hash of a desktop-installed server runtime: the `.install-complete`
|
|
20
|
+
* marker the installer writes at the package root. Null for any other
|
|
21
|
+
* install (npm, source checkout, packaged desktop). */
|
|
22
|
+
function remoteInstallBuildHash() {
|
|
23
|
+
if (installBuildHash !== undefined) return installBuildHash;
|
|
24
|
+
try {
|
|
25
|
+
const marker = JSON.parse(readFileSync(new URL('../../../.install-complete', import.meta.url), 'utf8'));
|
|
26
|
+
installBuildHash = typeof marker?.buildHash === 'string' && marker.buildHash ? marker.buildHash : null;
|
|
27
|
+
} catch {
|
|
28
|
+
installBuildHash = null;
|
|
29
|
+
}
|
|
30
|
+
return installBuildHash;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Turns in flight: what makes a daemon too busy to replace without asking. */
|
|
34
|
+
function busySessionCount(status) {
|
|
35
|
+
return Math.max(0, Number(status?.busy) || 0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Leave through the embedder's own graceful SIGTERM path. */
|
|
39
|
+
function requestProcessStop() {
|
|
40
|
+
if (process.listenerCount('SIGTERM') > 0) process.emit('SIGTERM', 'SIGTERM');
|
|
41
|
+
else process.kill(process.pid, 'SIGTERM');
|
|
42
|
+
}
|
|
43
|
+
|
|
16
44
|
export function createTransportRoutes({
|
|
17
45
|
serverToken,
|
|
18
46
|
drain,
|
|
@@ -25,11 +53,23 @@ export function createTransportRoutes({
|
|
|
25
53
|
transportMemory,
|
|
26
54
|
onClientsEmpty,
|
|
27
55
|
onUpgradeRequested,
|
|
56
|
+
admitWork = () => true,
|
|
28
57
|
}) {
|
|
58
|
+
// Checked on every register/call, last right before the work is handed on
|
|
59
|
+
// (after the body is read): a daemon that lost (or cannot re-verify) its
|
|
60
|
+
// owner lease serves nothing.
|
|
61
|
+
const refuseUnadmitted = (res) => {
|
|
62
|
+
if (admitWork()) return false;
|
|
63
|
+
sendError(res, 'daemon owner lease is not held', 503);
|
|
64
|
+
return true;
|
|
65
|
+
};
|
|
66
|
+
|
|
29
67
|
const health = (res) => {
|
|
30
68
|
// Identity travels with EVERY health probe: a view negotiates version
|
|
31
69
|
// skew before it attaches, so an embedder can never forget to publish
|
|
32
70
|
// it and leave clients guessing.
|
|
71
|
+
const status = getStatus();
|
|
72
|
+
const busySessions = busySessionCount(status);
|
|
33
73
|
sendJson(res, {
|
|
34
74
|
status: 'ok',
|
|
35
75
|
pid: process.pid,
|
|
@@ -38,10 +78,15 @@ export function createTransportRoutes({
|
|
|
38
78
|
protocol: SESSION_PROTOCOL,
|
|
39
79
|
revision: SESSION_REVISION,
|
|
40
80
|
capabilityFingerprint: SESSION_CAPABILITY_FINGERPRINT,
|
|
81
|
+
modelProxy: modelProxyClientMode() ? 'client' : null,
|
|
41
82
|
draining: drain.reason || null,
|
|
42
83
|
drainCommitted: drain.committed,
|
|
43
84
|
version: runtimeVersion(),
|
|
44
|
-
|
|
85
|
+
packageVersion: runtimeVersion(),
|
|
86
|
+
buildHash: remoteInstallBuildHash(),
|
|
87
|
+
...status,
|
|
88
|
+
busySessions,
|
|
89
|
+
idle: busySessions === 0,
|
|
45
90
|
activeCalls: lanes.active,
|
|
46
91
|
queuedCalls: lanes.queued,
|
|
47
92
|
queuedUrgentCalls: lanes.queuedUrgent,
|
|
@@ -54,6 +99,7 @@ export function createTransportRoutes({
|
|
|
54
99
|
|
|
55
100
|
const register = async (req, res) => {
|
|
56
101
|
const body = await readBody(req);
|
|
102
|
+
if (refuseUnadmitted(res)) return;
|
|
57
103
|
if (drain.committed) {
|
|
58
104
|
sendError(res, `daemon is draining: ${drain.reason}`, 503);
|
|
59
105
|
return;
|
|
@@ -70,6 +116,8 @@ export function createTransportRoutes({
|
|
|
70
116
|
clientKind: body.clientKind,
|
|
71
117
|
registrationId: body.registrationId,
|
|
72
118
|
revision: body.revision,
|
|
119
|
+
remote: body.remote === true,
|
|
120
|
+
leaseMs: body.leaseMs,
|
|
73
121
|
});
|
|
74
122
|
sendJson(res, {
|
|
75
123
|
token: clientToken,
|
|
@@ -85,6 +133,16 @@ export function createTransportRoutes({
|
|
|
85
133
|
sendJson(res, { ok: true });
|
|
86
134
|
};
|
|
87
135
|
|
|
136
|
+
// Lease keep-alive for remote clients (the daemon token gate already ran).
|
|
137
|
+
const heartbeat = async (req, res) => {
|
|
138
|
+
const body = await readBody(req);
|
|
139
|
+
if (!body.token || !registry.touch(String(body.token))) {
|
|
140
|
+
sendError(res, 'unknown client token', 404);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
sendJson(res, { ok: true });
|
|
144
|
+
};
|
|
145
|
+
|
|
88
146
|
const events = (url, res) => {
|
|
89
147
|
const clientToken = url.searchParams.get('token');
|
|
90
148
|
if (!attachSse(clientToken, res)) sendError(res, 'unknown client token', 404);
|
|
@@ -92,11 +150,15 @@ export function createTransportRoutes({
|
|
|
92
150
|
};
|
|
93
151
|
|
|
94
152
|
const call = async (req, res) => {
|
|
153
|
+
if (refuseUnadmitted(res)) return;
|
|
95
154
|
if (drain.committed) {
|
|
96
155
|
sendError(res, `daemon is draining: ${drain.reason}`, 503);
|
|
97
156
|
return;
|
|
98
157
|
}
|
|
99
158
|
const body = await readBody(req);
|
|
159
|
+
// Again right before dispatch: the lease may have been fenced while the
|
|
160
|
+
// body was still arriving.
|
|
161
|
+
if (refuseUnadmitted(res)) return;
|
|
100
162
|
await callRoute(body, res);
|
|
101
163
|
};
|
|
102
164
|
|
|
@@ -109,6 +171,19 @@ export function createTransportRoutes({
|
|
|
109
171
|
}
|
|
110
172
|
};
|
|
111
173
|
|
|
174
|
+
// Authenticated stop for a desktop replacing this daemon with another
|
|
175
|
+
// build: refused while turns run unless forced (the user confirmed).
|
|
176
|
+
const stop = async (req, res) => {
|
|
177
|
+
const body = await readBody(req);
|
|
178
|
+
const busySessions = busySessionCount(getStatus());
|
|
179
|
+
if (busySessions > 0 && body.force !== true) {
|
|
180
|
+
sendError(res, `daemon is busy: ${busySessions} running session(s)`, 409);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
sendJson(res, { ok: true, pid: process.pid, busySessions });
|
|
184
|
+
setImmediate(requestProcessStop);
|
|
185
|
+
};
|
|
186
|
+
|
|
112
187
|
const upgrade = async (req, res) => {
|
|
113
188
|
const body = await readBody(req);
|
|
114
189
|
const requestedProtocol = Number(body.protocol);
|
|
@@ -150,8 +225,10 @@ export function createTransportRoutes({
|
|
|
150
225
|
const tokenRoutes = {
|
|
151
226
|
'POST /client/register': register,
|
|
152
227
|
'POST /client/deregister': deregister,
|
|
228
|
+
'POST /client/heartbeat': heartbeat,
|
|
153
229
|
'POST /call': call,
|
|
154
230
|
'POST /shutdown': (_req, res) => shutdown(res),
|
|
231
|
+
'POST /stop': stop,
|
|
155
232
|
'POST /upgrade': upgrade,
|
|
156
233
|
};
|
|
157
234
|
|
|
@@ -76,6 +76,7 @@ export function createTransportStack({
|
|
|
76
76
|
onClientDropped,
|
|
77
77
|
onUpgradeRequested,
|
|
78
78
|
getStatus,
|
|
79
|
+
admitWork,
|
|
79
80
|
}) {
|
|
80
81
|
const body = createBodyReader();
|
|
81
82
|
const callCache = createSessionCallCache({
|
|
@@ -125,6 +126,7 @@ export function createTransportStack({
|
|
|
125
126
|
}),
|
|
126
127
|
onClientsEmpty,
|
|
127
128
|
onUpgradeRequested,
|
|
129
|
+
admitWork,
|
|
128
130
|
});
|
|
129
131
|
|
|
130
132
|
return { registry, clients, lanes, callCache, broadcast, handleRequest };
|
|
@@ -32,6 +32,9 @@ export function createSessionTransport({
|
|
|
32
32
|
onClientDropped = null,
|
|
33
33
|
onUpgradeRequested = null,
|
|
34
34
|
getStatus = () => ({}),
|
|
35
|
+
// Asked before every register/call; false answers 503 (the daemon's owner
|
|
36
|
+
// lease is not held — daemon-owner.mjs).
|
|
37
|
+
admitWork = () => true,
|
|
35
38
|
} = {}) {
|
|
36
39
|
if (typeof handleCall !== 'function') throw new Error('handleCall is required');
|
|
37
40
|
|
|
@@ -52,6 +55,7 @@ export function createSessionTransport({
|
|
|
52
55
|
onClientDropped,
|
|
53
56
|
onUpgradeRequested,
|
|
54
57
|
getStatus,
|
|
58
|
+
admitWork,
|
|
55
59
|
});
|
|
56
60
|
|
|
57
61
|
function beginDrain(reason = 'daemon replacement') {
|
|
@@ -69,10 +73,19 @@ export function createSessionTransport({
|
|
|
69
73
|
return true;
|
|
70
74
|
}
|
|
71
75
|
|
|
76
|
+
// MIXDOG_SESSION_PORT pins the port (an SSH forward needs a stable one).
|
|
77
|
+
function configuredPort() {
|
|
78
|
+
const port = Number(process.env.MIXDOG_SESSION_PORT);
|
|
79
|
+
return Number.isInteger(port) && port >= 1 && port <= 65535 ? port : 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
72
82
|
function start() {
|
|
73
83
|
if (closed) return Promise.reject(new Error('session service transport is closed'));
|
|
84
|
+
const fixedPort = configuredPort();
|
|
74
85
|
listener ??= createLoopbackListener({
|
|
75
86
|
server: http.createServer(handleRequest),
|
|
87
|
+
basePort: fixedPort,
|
|
88
|
+
maxPort: fixedPort,
|
|
76
89
|
onListening(port) {
|
|
77
90
|
boundPort = port;
|
|
78
91
|
log(`session service transport listening on 127.0.0.1:${boundPort} pid=${process.pid}`);
|
|
@@ -81,7 +94,17 @@ export function createSessionTransport({
|
|
|
81
94
|
if (!fatal) log(`server error: ${error?.message || error}`);
|
|
82
95
|
},
|
|
83
96
|
});
|
|
84
|
-
return listener.start().then((port) =>
|
|
97
|
+
return listener.start().then(async (port) => {
|
|
98
|
+
// The listener falls back to an OS-chosen port when the range is busy;
|
|
99
|
+
// a pinned port must never silently become a different one.
|
|
100
|
+
if (fixedPort && port !== fixedPort) {
|
|
101
|
+
await listener.stop();
|
|
102
|
+
listener = null;
|
|
103
|
+
boundPort = null;
|
|
104
|
+
throw new Error(`session port ${fixedPort} (MIXDOG_SESSION_PORT) is unavailable`);
|
|
105
|
+
}
|
|
106
|
+
return { port, token: serverToken };
|
|
107
|
+
});
|
|
85
108
|
}
|
|
86
109
|
|
|
87
110
|
async function stop() {
|
package/src/tui/App.jsx
CHANGED
|
@@ -21,6 +21,7 @@ import { useApp, useStdin, useStdout } from 'ink';
|
|
|
21
21
|
import { useSession } from './hooks/useSession.mjs';
|
|
22
22
|
import { pickFolder } from '../standalone/folder-dialog.mjs';
|
|
23
23
|
import { deriveSlashPalette } from './app/slash-palette.mjs';
|
|
24
|
+
import { skillMentionQuery, useSkillMentionSkills } from './app/skill-mention-palette.mjs';
|
|
24
25
|
import { shouldSupersedePanelEpoch, supersedePanelEpoch } from './app/panel-epoch.mjs';
|
|
25
26
|
import { createPanelSurface } from './app/panel-surface.mjs';
|
|
26
27
|
import { resolvePickerState } from './app/picker-index-mode.mjs';
|
|
@@ -215,6 +216,8 @@ export function App({ store, initialStatusLine = '', forceOnboarding = false, on
|
|
|
215
216
|
setPromptDraft,
|
|
216
217
|
promptDraftOverride,
|
|
217
218
|
setPromptDraftOverride,
|
|
219
|
+
promptCaret,
|
|
220
|
+
setPromptCaret,
|
|
218
221
|
promptLayoutValueRef,
|
|
219
222
|
setPromptLayoutRows,
|
|
220
223
|
textEntryLayoutRows,
|
|
@@ -625,7 +628,8 @@ export function App({ store, initialStatusLine = '', forceOnboarding = false, on
|
|
|
625
628
|
pastedTextsRef,
|
|
626
629
|
});
|
|
627
630
|
|
|
628
|
-
const
|
|
631
|
+
const mentionSkills = useSkillMentionSkills(store, skillMentionQuery(promptDraft, promptCaret) !== null);
|
|
632
|
+
const { activeSlashQuery, slashCommands, slashPaletteOpen, paletteKind } = deriveSlashPalette({
|
|
629
633
|
providerPrompt,
|
|
630
634
|
settingsPrompt,
|
|
631
635
|
toolApproval,
|
|
@@ -636,6 +640,8 @@ export function App({ store, initialStatusLine = '', forceOnboarding = false, on
|
|
|
636
640
|
commandBusy: state.commandBusy,
|
|
637
641
|
promptDraft,
|
|
638
642
|
slashDismissedFor,
|
|
643
|
+
skills: mentionSkills,
|
|
644
|
+
promptCaret,
|
|
639
645
|
});
|
|
640
646
|
slashPaletteRef.current = { open: slashPaletteOpen, count: slashCommands.length };
|
|
641
647
|
scrollFocusRef.current = {
|
|
@@ -833,10 +839,12 @@ export function App({ store, initialStatusLine = '', forceOnboarding = false, on
|
|
|
833
839
|
hasUserMessages,
|
|
834
840
|
initialStatusLine,
|
|
835
841
|
onPromptDraftChange,
|
|
842
|
+
onPromptCaretChange: setPromptCaret,
|
|
836
843
|
onSubmit,
|
|
837
844
|
overlayHintAttachItemIndex,
|
|
838
845
|
overlayHintFallbackRow,
|
|
839
846
|
overlayHintOnLastItem,
|
|
847
|
+
paletteKind,
|
|
840
848
|
panelInkMaskEpoch,
|
|
841
849
|
panelTransitionEpoch,
|
|
842
850
|
picker,
|
|
@@ -18,6 +18,12 @@ import { textEntryClearsByEmpty } from '../text-entry-policy.mjs';
|
|
|
18
18
|
import { withPickerEnterLatch } from '../picker-enter-latch.mjs';
|
|
19
19
|
import { providerPromptFields, settingsPromptFields } from './text-entry-labels.mjs';
|
|
20
20
|
|
|
21
|
+
// `$name` skill completion reuses the command palette with its own copy.
|
|
22
|
+
const SKILL_PALETTE_TEXT = {
|
|
23
|
+
description: 'Type to filter · Enter or Tab inserts the highlighted skill.',
|
|
24
|
+
help: '↑/↓ select · Enter insert · Esc cancel',
|
|
25
|
+
};
|
|
26
|
+
|
|
21
27
|
function renderToolApproval({ toolApproval, store, frameColumns, expandedOptionPanel }) {
|
|
22
28
|
const resolve = (approved) => {
|
|
23
29
|
store.resolveToolApproval?.(toolApproval.id, {
|
|
@@ -166,13 +172,15 @@ export function renderFloatingPanel(ctx) {
|
|
|
166
172
|
);
|
|
167
173
|
}
|
|
168
174
|
if (slashPaletteOpen) {
|
|
175
|
+
const skills = ctx.paletteKind === 'skills';
|
|
169
176
|
return (
|
|
170
177
|
<SlashCommandPalette
|
|
171
178
|
commands={slashCommands}
|
|
172
179
|
selectedIndex={slashIndex}
|
|
173
|
-
title=
|
|
180
|
+
title={skills ? 'Skills' : 'Commands'}
|
|
174
181
|
columns={frameColumns}
|
|
175
182
|
query={activeSlashQuery}
|
|
183
|
+
{...(skills ? SKILL_PALETTE_TEXT : {})}
|
|
176
184
|
/>
|
|
177
185
|
);
|
|
178
186
|
}
|
package/src/tui/app/app-view.jsx
CHANGED
|
@@ -52,8 +52,10 @@ export function renderAppView(ctx) {
|
|
|
52
52
|
inputHint,
|
|
53
53
|
inputHintTone,
|
|
54
54
|
liveSpinner,
|
|
55
|
+
onPromptCaretChange,
|
|
55
56
|
onPromptDraftChange,
|
|
56
57
|
onSubmit,
|
|
58
|
+
paletteKind,
|
|
57
59
|
panelTransitionClearRows,
|
|
58
60
|
picker,
|
|
59
61
|
promptBoxRectRef,
|
|
@@ -85,6 +87,7 @@ export function renderAppView(ctx) {
|
|
|
85
87
|
onSubmit={onSubmit}
|
|
86
88
|
disabled={exiting || !!picker || !!contextPanel || !!toolApproval || !tuiReady}
|
|
87
89
|
onDraftChange={onPromptDraftChange}
|
|
90
|
+
onCaretChange={onPromptCaretChange}
|
|
88
91
|
interruptActive={state.busy}
|
|
89
92
|
onInterrupt={handlePromptInterrupt}
|
|
90
93
|
initialValue={promptDraft}
|
|
@@ -108,6 +111,9 @@ export function renderAppView(ctx) {
|
|
|
108
111
|
commandPaletteActive={slashPaletteOpen && slashCommands.length > 0}
|
|
109
112
|
commandPaletteOpen={slashPaletteOpen}
|
|
110
113
|
commandPaletteOptionCount={slashCommands.length}
|
|
114
|
+
// The `$name` skill palette leaves Left/Right to the caret: the
|
|
115
|
+
// mention follows it.
|
|
116
|
+
commandPaletteMovesCaret={paletteKind === 'skills'}
|
|
111
117
|
onCommandPaletteNavigate={(direction) => {
|
|
112
118
|
setSlashIndex((index) => stepPaletteIndex(index, direction, slashCommands.length));
|
|
113
119
|
}}
|