mixdog 1.3.1 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -4
- package/package.json +2 -2
- package/scripts/native-release-status.mjs +238 -0
- package/src/defaults/shipped-history.json +5 -1
- package/src/defaults/skills/pptx/scripts/qc-pages.mjs +3 -2
- package/src/defaults/skills/setup/SKILL.md +23 -1
- package/src/defaults/skills/setup/references/actions.md +50 -3
- package/src/defaults/skills/setup/references/surfaces.md +23 -3
- package/src/defaults/skills/setup-guide/SKILL.md +7 -3
- package/src/defaults/skills/visualize/SKILL.md +9 -6
- package/src/defaults/skills/visualize/references/craft.md +8 -1
- package/src/help.mjs +1 -1
- package/src/lib/keychain-cjs.cjs +4 -1
- package/src/lib/rules-builder.cjs +14 -7
- package/src/rules/agent-mode/AGENT_MODE.md +8 -5
- package/src/rules/agent-mode/MIXY.md +6 -8
- package/src/rules/lead/LEAD.md +2 -2
- package/src/rules/shared/10-tool-workflow.md +4 -0
- package/src/rules/shared/20-research.md +2 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +5 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/session-prep.mjs +8 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +6 -1
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +114 -26
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +8 -0
- package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +5 -4
- package/src/runtime/agent/orchestrator/agent-trace.mjs +3 -0
- package/src/runtime/agent/orchestrator/cache-break-trace.mjs +4 -0
- package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
- package/src/runtime/agent/orchestrator/config-storage.mjs +10 -3
- package/src/runtime/agent/orchestrator/config.mjs +11 -0
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +9 -2
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +97 -5
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +6 -10
- package/src/runtime/agent/orchestrator/mcp/client.mjs +7 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +80 -31
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +67 -38
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +27 -8
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +31 -4
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +11 -8
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +16 -0
- package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +13 -0
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -1
- package/src/runtime/agent/orchestrator/providers/mixdog-local.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +5 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +9 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +9 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +30 -3
- package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +61 -8
- package/src/runtime/agent/orchestrator/providers/registry.mjs +9 -0
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +90 -24
- package/src/runtime/agent/orchestrator/runtime-core/fs-utils.mjs +8 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-storage.mjs +68 -22
- package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +4 -6
- package/src/runtime/agent/orchestrator/runtime-core/route-context-state.mjs +81 -0
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +12 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +6 -5
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +7 -6
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow/packs.mjs +8 -4
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/agent-mode.mjs +0 -6
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +1 -1
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +22 -4
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +17 -2
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +133 -38
- package/src/runtime/agent/orchestrator/session/attachment-preflight.mjs +80 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +14 -11
- package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +68 -18
- package/src/runtime/agent/orchestrator/session/compact/summary-mode.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/compact/summary-route.mjs +87 -0
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +41 -10
- package/src/runtime/agent/orchestrator/session/human-gate/delegation.mjs +230 -0
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +136 -32
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +20 -0
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +21 -9
- package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +73 -0
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +55 -27
- package/src/runtime/agent/orchestrator/session/human-gate/unattended-port.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +189 -105
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +5 -5
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +38 -5
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +21 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +13 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +44 -18
- package/src/runtime/agent/orchestrator/session/manager/orchestration-mode-switch-notice.mjs +99 -0
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +42 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +3 -9
- package/src/runtime/agent/orchestrator/session/manager/pending-spool-file.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/pending-spool-shard.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +40 -1
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +20 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +55 -27
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +3 -8
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +12 -1
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +6 -15
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +24 -8
- package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +94 -13
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +42 -10
- package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +21 -3
- package/src/runtime/agent/orchestrator/session/routine-result.d.mts +18 -3
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +120 -9
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/store/canonical-reader.mjs +41 -7
- package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +10 -2
- package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +14 -2
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +15 -1
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +8 -3
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +36 -1
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +40 -5
- package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +47 -2
- package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +125 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +78 -43
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +35 -5
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +42 -2
- package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +35 -13
- package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +25 -5
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +13 -14
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/transport-artifacts.mjs +9 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +19 -14
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +6 -14
- package/src/runtime/agent/orchestrator/tools/builtin/pdf-test-fixtures.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-image.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-media.mjs +47 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +264 -87
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +10 -4
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +34 -21
- package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +8 -4
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +9 -30
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +24 -12
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +3 -2
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/patch/delete-quarantine.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/patch/replay-capture.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/patch/rollback-state.mjs +33 -2
- package/src/runtime/agent/orchestrator/tools/patch-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +3 -1
- package/src/runtime/attachments/attachment-reference.mjs +155 -0
- package/src/runtime/attachments/limits.mjs +5 -1
- package/src/runtime/attachments/office-extract.mjs +3 -6
- package/src/runtime/attachments/pdf-extract.mjs +84 -10
- package/src/runtime/attachments/store.mjs +49 -30
- package/src/runtime/browser-bridge/client.mjs +73 -20
- package/src/runtime/channels/lib/runtime-paths.mjs +1 -1
- package/src/runtime/channels/lib/scheduler.mjs +14 -7
- package/src/runtime/channels/lib/state-file.mjs +15 -15
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +14 -13
- package/src/runtime/channels/lib/webhook/relay-tunnel.mjs +22 -18
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +14 -36
- package/src/runtime/channels/lib/worker-main.mjs +3 -2
- package/src/runtime/effort-judge/compact-tokenizer.mjs +8 -2
- package/src/runtime/effort-judge/judge-client.mjs +5 -2
- package/src/runtime/effort-judge/model-install.mjs +16 -8
- package/src/runtime/local-provider/asset-installer.mjs +10 -4
- package/src/runtime/local-provider/catalog.mjs +5 -2
- package/src/runtime/local-provider/registered-models.mjs +64 -27
- package/src/runtime/local-provider/server.mjs +2 -3
- package/src/runtime/media/adapters/image-api.mjs +89 -0
- package/src/runtime/media/auth.mjs +64 -1
- package/src/runtime/media/catalog.mjs +66 -4
- package/src/runtime/media/jobs.mjs +4 -0
- package/src/runtime/media/lanes.mjs +46 -5
- package/src/runtime/media/media-usage.mjs +17 -0
- package/src/runtime/media/renditions.mjs +15 -15
- package/src/runtime/media/store.mjs +36 -35
- package/src/runtime/media/tool.mjs +8 -1
- package/src/runtime/memory/lib/cycle-scheduler/health-ledger.mjs +8 -2
- package/src/runtime/memory/lib/embedding-model-files.mjs +30 -7
- package/src/runtime/memory/lib/ingest/transcript-tail.mjs +16 -7
- package/src/runtime/memory/lib/pg/process.mjs +8 -4
- package/src/runtime/memory/lib/project-id-resolver.mjs +5 -1
- package/src/runtime/memory/lib/runtime-fetcher.mjs +6 -1
- package/src/runtime/office/core/journal.mjs +7 -14
- package/src/runtime/office/design/library/design-library-core.mjs +4 -16
- package/src/runtime/office/pdf/ocr-engine-worker.mjs +37 -0
- package/src/runtime/office/pdf/ocr-engine.mjs +146 -0
- package/src/runtime/office/pdf/pdf-ocr.mjs +51 -21
- package/src/runtime/office/pdf/pdf-render.mjs +30 -18
- package/src/runtime/office/portable/ooxml-validator.mjs +2 -2
- package/src/runtime/office/portable/portable-soffice.mjs +4 -0
- package/src/runtime/shared/agent-kind-migration.mjs +200 -0
- package/src/runtime/shared/agent-message-envelope.d.mts +6 -0
- package/src/runtime/shared/agent-message-envelope.mjs +44 -0
- package/src/runtime/shared/agent-reap-state.d.mts +4 -0
- package/src/runtime/shared/agent-store.mjs +24 -7
- package/src/runtime/shared/agent-task-starts.mjs +27 -0
- package/src/runtime/shared/atomic-file.d.mts +50 -0
- package/src/runtime/shared/atomic-file.mjs +394 -132
- package/src/runtime/shared/background-tasks.mjs +7 -4
- package/src/runtime/shared/bot-hops.mjs +30 -0
- package/src/runtime/shared/bot-split-migration.mjs +1 -1
- package/src/runtime/shared/bounded-download.mjs +4 -2
- package/src/runtime/shared/config.mjs +39 -9
- package/src/runtime/shared/defaults-separation.mjs +6 -2
- package/src/runtime/shared/delegated-approval-host.mjs +74 -0
- package/src/runtime/shared/err-text.mjs +4 -0
- package/src/runtime/shared/error-presentation.mjs +22 -4
- package/src/runtime/shared/file-has-data.mjs +28 -0
- package/src/runtime/shared/llm/usage-ledger-import.mjs +37 -18
- package/src/runtime/shared/pending-agent-work.mjs +54 -0
- package/src/runtime/shared/process-lifecycle.mjs +8 -12
- package/src/runtime/shared/projects.mjs +50 -41
- package/src/runtime/shared/provider-accounts.mjs +17 -12
- package/src/runtime/shared/routine-trigger.d.mts +6 -1
- package/src/runtime/shared/routine-trigger.mjs +14 -6
- package/src/runtime/shared/run-child.d.mts +3 -0
- package/src/runtime/shared/run-child.mjs +24 -3
- package/src/runtime/shared/session-baseline-store.mjs +8 -2
- package/src/runtime/shared/singleton-owner.mjs +7 -6
- package/src/runtime/shared/skill-tool-dependencies.mjs +4 -10
- package/src/runtime/shared/staged-update.mjs +4 -2
- package/src/runtime/shared/statusline/statusline-segments.mjs +4 -15
- package/src/runtime/shared/tool-execution-contract.mjs +6 -0
- package/src/runtime/shared/transcript-metadata.mjs +28 -3
- package/src/runtime/shared/transcript-writer/session-record.mjs +7 -6
- package/src/runtime/shared/turn-snapshot-store.mjs +5 -4
- package/src/runtime/shared/turn-snapshot.mjs +44 -2
- package/src/runtime/shared/user-cwd.mjs +9 -4
- package/src/runtime/shared/user-data-guard.mjs +41 -42
- package/src/runtime/shared/utf8-cut.mjs +10 -0
- package/src/runtime/shared/worktrees/activity-gate.mjs +269 -61
- package/src/runtime/shared/worktrees/registry.mjs +26 -26
- package/src/runtime/tidy/core-install.mjs +26 -4
- package/src/runtime/tidy/install.mjs +91 -23
- package/src/runtime/web-search/lib/config.mjs +4 -16
- package/src/session-runtime/agent-home-delivery.mjs +555 -199
- package/src/session-runtime/agent-room-delivery.mjs +143 -36
- package/src/session-runtime/agent-task-sessions.mjs +667 -165
- package/src/session-runtime/agent-tool-routing.mjs +1 -0
- package/src/session-runtime/boot/apis.mjs +45 -24
- package/src/session-runtime/boot/config.mjs +1 -0
- package/src/session-runtime/boot/facade.mjs +11 -1
- package/src/session-runtime/boot/infrastructure.mjs +14 -2
- package/src/session-runtime/boot/providers.mjs +2 -2
- package/src/session-runtime/boot/shared.mjs +12 -6
- package/src/session-runtime/boot/tools.mjs +2 -2
- package/src/session-runtime/bot-status.mjs +432 -0
- package/src/session-runtime/config-lifecycle/lead-route-sync.mjs +29 -0
- package/src/session-runtime/config-lifecycle.mjs +60 -55
- package/src/session-runtime/cwd-plugins/core-memory-context.mjs +2 -4
- package/src/session-runtime/held-requests.mjs +36 -33
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +10 -1
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -2
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +19 -4
- package/src/session-runtime/lifecycle/session-catalog.mjs +12 -2
- package/src/session-runtime/lifecycle/teardown.mjs +11 -3
- package/src/session-runtime/mcp-glue/connect.mjs +100 -186
- package/src/session-runtime/mcp-glue/initial-connect-gate.mjs +57 -0
- package/src/session-runtime/mcp-glue/server-connection.mjs +71 -0
- package/src/session-runtime/media-api.mjs +5 -2
- package/src/session-runtime/model-route/route-tuning.mjs +4 -1
- package/src/session-runtime/model-route/set-route.mjs +61 -1
- package/src/session-runtime/owned-automation-run.mjs +8 -1
- package/src/session-runtime/room-member-gate.mjs +16 -3
- package/src/session-runtime/route-resolution.mjs +16 -8
- package/src/session-runtime/route-state.mjs +1 -59
- package/src/session-runtime/routine-home-turn.mjs +5 -3
- package/src/session-runtime/runtime-bootstrap.mjs +5 -3
- package/src/session-runtime/runtime-paths.mjs +11 -5
- package/src/session-runtime/runtime-tunables.mjs +6 -0
- package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +11 -2
- package/src/session-runtime/services/agent-tool/close-flow.mjs +4 -2
- package/src/session-runtime/services/agent-tool/execute-send.mjs +1 -0
- package/src/session-runtime/services/agent-tool/execute-spawn.mjs +1 -0
- package/src/session-runtime/services/agent-tool/restart-notify.mjs +10 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +25 -21
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +4 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +6 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +8 -5
- package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +22 -2
- package/src/session-runtime/services/agent-tool/worker-index.mjs +4 -6
- package/src/session-runtime/services/agent-tool.mjs +6 -0
- package/src/session-runtime/services/daemon-crash-capture/daemon-exit-record.mjs +1 -1
- package/src/session-runtime/services/daemon-crash-capture/retention.mjs +4 -3
- package/src/session-runtime/services/hook-bus/config-loader.mjs +14 -5
- package/src/session-runtime/services/hook-bus/rule-file.mjs +49 -11
- package/src/session-runtime/services/plugin-admin.mjs +26 -26
- package/src/session-runtime/services/provider-admin.mjs +14 -4
- package/src/session-runtime/services/schedule-access.mjs +33 -4
- package/src/session-runtime/services/seeds.mjs +4 -3
- package/src/session-runtime/services/usage-dashboard.mjs +1 -1
- package/src/session-runtime/services/usage-stats-model.mjs +2 -1
- package/src/session-runtime/session-create/materialize.mjs +2 -3
- package/src/session-runtime/session-create/session-options.mjs +15 -2
- package/src/session-runtime/settings-builtin-tools-api.mjs +63 -1
- package/src/session-runtime/settings-compaction-api.mjs +86 -39
- package/src/session-runtime/setup-tool/executor.mjs +8 -2
- package/src/session-runtime/setup-tool/settings-contract.mjs +31 -1
- package/src/session-runtime/setup-tool/tool-defs.mjs +20 -3
- package/src/session-runtime/skills-api.mjs +12 -5
- package/src/session-runtime/tool-policy/agent-profile-fold.mjs +265 -0
- package/src/session-runtime/tool-policy/mode-switch.mjs +54 -0
- package/src/session-runtime/tool-policy/pending-switches.mjs +59 -0
- package/src/session-runtime/tool-policy/policy-stage.mjs +165 -0
- package/src/session-runtime/tool-policy/session-switches.mjs +169 -0
- package/src/session-runtime/tool-policy/surface-helpers.mjs +114 -0
- package/src/session-runtime/tool-policy/workflow-overlay.mjs +145 -0
- package/src/session-runtime/tool-policy-refresh.mjs +47 -369
- package/src/session-runtime/tool-surface.mjs +5 -3
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +95 -88
- package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
- package/src/session-runtime/turn/turn-run.mjs +2 -1
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +54 -7
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +519 -333
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +46 -46
- package/src/session-runtime/workflow-agents-api/shared.mjs +5 -1
- package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +14 -1
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -3
- package/src/session-runtime/workspace/workspace-state.mjs +7 -6
- package/src/standalone/daemon-agent-control.mjs +4 -1
- package/src/standalone/daemon-session-control.mjs +51 -10
- package/src/standalone/daemon.mjs +28 -10
- package/src/standalone/local-session-runtime.mjs +22 -14
- package/src/standalone/session-client.mjs +7 -2
- package/src/standalone/session-protocol.mjs +7 -0
- package/src/standalone/session-service.mjs +11 -0
- package/src/standalone/session-state-projection.mjs +19 -9
- package/src/standalone/session-tool-output.mjs +35 -9
- package/src/tui/app/maintenance-pickers/auto-clear-picker.mjs +19 -13
- package/src/tui/app/settings-picker/settings-rows.mjs +2 -2
- package/src/tui/app/slash-commands.mjs +1 -1
- package/src/tui/app/usage-context-panels/context-model.mjs +8 -2
- package/src/tui/dist/index.mjs +529 -333
- package/src/tui/prompt-history-store.mjs +16 -21
- package/src/tui/session/context-state.mjs +4 -0
- package/src/tui/session/session-api/intake/abort.mjs +19 -1
- package/src/tui/session/session-api/media.mjs +2 -1
- package/src/tui/session/session-api/routes-agent-definitions.mjs +75 -0
- package/src/tui/session/session-api/routes-write.mjs +203 -0
- package/src/tui/session/session-api/routes.mjs +23 -247
- package/src/tui/session/session-api/settings.mjs +14 -1
- package/src/tui/session/session-flow/drain.mjs +28 -3
- package/src/tui/session/session-flow/failed-turn-rewind.mjs +4 -2
- package/src/tui/session/session-flow/queue/take-entries.mjs +8 -0
- package/src/tui/session/session-flow/steering.mjs +8 -3
- package/src/tui/session/tool-approval.mjs +185 -20
- package/src/tui/session/transcript-intake.mjs +2 -0
- package/src/tui/session/turn.mjs +23 -14
- package/src/tui/transcript-tool-failures.mjs +8 -2
- package/src/vendor/statusline/src/gateway/route-meta.mjs +7 -8
- package/src/vendor/statusline/src/gateway/session-routes.mjs +6 -7
- package/src/rules/agent-mode/ROUTINE.md +0 -6
|
@@ -28,6 +28,16 @@ export function restartNotificationId(row) {
|
|
|
28
28
|
return `restart:${clean(row.task_id) || `${clean(row.sessionId)}:${clean(row.finishedAt)}`}`;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/** The agent task id an execution id names: a task's own id, or the task a
|
|
32
|
+
* restart notification (restartNotificationId) reports; null for one keyed
|
|
33
|
+
* by session because its row recorded no task id. */
|
|
34
|
+
export function agentTaskIdOfExecution(executionId) {
|
|
35
|
+
const id = clean(executionId);
|
|
36
|
+
if (!id.startsWith('restart:')) return id || null;
|
|
37
|
+
const rest = id.slice('restart:'.length);
|
|
38
|
+
return rest && !rest.includes(':') ? rest : null;
|
|
39
|
+
}
|
|
40
|
+
|
|
31
41
|
/** `pendingRestartFailures()` lists rows whose owner is not yet told;
|
|
32
42
|
* `markRestartNotified(rows)` stamps them. `mgr` supplies the persisted
|
|
33
43
|
* pending queue (enqueuePendingMessage / markCompletionEntry /
|
|
@@ -17,7 +17,13 @@ import {
|
|
|
17
17
|
} from './job-task-reconcile.mjs';
|
|
18
18
|
import { createTurnReviewCollector } from './turn-review.mjs';
|
|
19
19
|
import { handoffContent } from '../../handoff-attachments.mjs';
|
|
20
|
+
import { rebindDelegation } from '../../../runtime/agent/orchestrator/session/human-gate/delegation.mjs';
|
|
20
21
|
import { settledWorkerStatus } from './worker-index/row-liveness.mjs';
|
|
22
|
+
import { whileTurnDispatched } from '../../../runtime/agent/orchestrator/session/manager/runtime-state.mjs';
|
|
23
|
+
|
|
24
|
+
function workerResultIdentity({ session, tag, sessionId }) {
|
|
25
|
+
return { tag, sessionId, agent: session.agent || null, provider: session.provider, model: session.model };
|
|
26
|
+
}
|
|
21
27
|
|
|
22
28
|
// `send` to an existing worker: resolve the live session, run one follow-up
|
|
23
29
|
// turn under the progress watchdog, and reconcile the job/worker row. Busy
|
|
@@ -42,11 +48,7 @@ export function createSendFlow({ mgr, defaultCwd, sessionSurface, canUseSessionS
|
|
|
42
48
|
return (result) => {
|
|
43
49
|
const abnormalError = abnormalEmptyFinishError(result, session.agent || sendAgent);
|
|
44
50
|
return {
|
|
45
|
-
tag,
|
|
46
|
-
sessionId,
|
|
47
|
-
agent: session.agent || null,
|
|
48
|
-
provider: session.provider,
|
|
49
|
-
model: session.model,
|
|
51
|
+
...workerResultIdentity({ session, tag, sessionId }),
|
|
50
52
|
content: result?.content || '',
|
|
51
53
|
...(sessionSurface?.canonical === true ? { handoffOnly: true } : {}),
|
|
52
54
|
...(abnormalError ? { error: abnormalError } : {}),
|
|
@@ -74,10 +76,12 @@ export function createSendFlow({ mgr, defaultCwd, sessionSurface, canUseSessionS
|
|
|
74
76
|
const cwd = session.cwd || defaultCwd;
|
|
75
77
|
// The caller's forwarded files ride along as attachment parts.
|
|
76
78
|
const prompt = handoffContent(text, args.attachmentParts);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
return whileTurnDispatched(sessionId, () => {
|
|
80
|
+
if (canUseSessionSurface(session)) {
|
|
81
|
+
return sessionSurface.runTurn({ session, prompt, context: args.context || null, cwd, ...turnHooks });
|
|
82
|
+
}
|
|
83
|
+
return mgr.askSession(sessionId, prompt, args.context || null, null, cwd, null, turnHooks);
|
|
84
|
+
});
|
|
81
85
|
}
|
|
82
86
|
|
|
83
87
|
async function runSend(prepared, notifyContext = null, job = null) {
|
|
@@ -110,11 +114,7 @@ export function createSendFlow({ mgr, defaultCwd, sessionSurface, canUseSessionS
|
|
|
110
114
|
const settleCancelled = (error, result = null) => {
|
|
111
115
|
finalStatus = 'cancelled';
|
|
112
116
|
reconcileJobCancelled(job, {
|
|
113
|
-
tag,
|
|
114
|
-
sessionId,
|
|
115
|
-
agent: session.agent || null,
|
|
116
|
-
provider: session.provider,
|
|
117
|
-
model: session.model,
|
|
117
|
+
...workerResultIdentity({ session, tag, sessionId }),
|
|
118
118
|
content: turnPartialHandoff(error, mgr.getSession(sessionId), handoffMsgStart) || result?.content || '',
|
|
119
119
|
});
|
|
120
120
|
};
|
|
@@ -145,11 +145,7 @@ export function createSendFlow({ mgr, defaultCwd, sessionSurface, canUseSessionS
|
|
|
145
145
|
if (partial) {
|
|
146
146
|
finalStatus = 'idle';
|
|
147
147
|
const value = {
|
|
148
|
-
tag,
|
|
149
|
-
sessionId,
|
|
150
|
-
agent: session.agent || null,
|
|
151
|
-
provider: session.provider,
|
|
152
|
-
model: session.model,
|
|
148
|
+
...workerResultIdentity({ session, tag, sessionId }),
|
|
153
149
|
content: watchdogStoppedHandoff(error, partial),
|
|
154
150
|
stallAbort: true,
|
|
155
151
|
};
|
|
@@ -164,7 +160,7 @@ export function createSendFlow({ mgr, defaultCwd, sessionSurface, canUseSessionS
|
|
|
164
160
|
turnReview.complete();
|
|
165
161
|
watchdog?.stop?.();
|
|
166
162
|
registry.upsertWorkerSessionDeferred(session, tag, {
|
|
167
|
-
...settledWorkerStatus(finalStatus, stalled),
|
|
163
|
+
...settledWorkerStatus(finalStatus, stalled, job),
|
|
168
164
|
finishedAt: new Date().toISOString(),
|
|
169
165
|
});
|
|
170
166
|
reconcileJobFinally(job, finalStatus);
|
|
@@ -188,6 +184,14 @@ export function createSendFlow({ mgr, defaultCwd, sessionSurface, canUseSessionS
|
|
|
188
184
|
return { ...prepared, session: mgr.getSession(sessionId) || session };
|
|
189
185
|
}
|
|
190
186
|
|
|
187
|
+
// The calling session hands this worker new work (a `send`, or a spawn of its
|
|
188
|
+
// tag): from now on the worker acts as that caller does, so a run's worker
|
|
189
|
+
// asks when the attended chat reuses it and the other way round. Not for a
|
|
190
|
+
// completion wake, which is the worker's own continuation.
|
|
191
|
+
function adoptCaller({ sessionId }, notifyContext) {
|
|
192
|
+
return rebindDelegation(sessionId, notifyContext?.callerSessionId);
|
|
193
|
+
}
|
|
194
|
+
|
|
191
195
|
// Shared send dispatch for an already-resolved live session. Used by the
|
|
192
196
|
// `send` branch AND by the `spawn` branch when an explicit tag maps to a
|
|
193
197
|
// live session (reuse path). Busy sessions queue the prompt; idle ones run a
|
|
@@ -255,5 +259,5 @@ export function createSendFlow({ mgr, defaultCwd, sessionSurface, canUseSessionS
|
|
|
255
259
|
return true;
|
|
256
260
|
}
|
|
257
261
|
|
|
258
|
-
return { prepareSend, dispatchToExistingSession, wakeIdleWorker };
|
|
262
|
+
return { prepareSend, adoptCaller, dispatchToExistingSession, wakeIdleWorker };
|
|
259
263
|
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* agent work, and status publication at start and after terminal settlement.
|
|
5
5
|
*/
|
|
6
6
|
import { sanitizeTaskMeta, startBackgroundTask } from '../../../../runtime/shared/background-tasks.mjs';
|
|
7
|
+
import { recordAgentTaskStart } from '../../../../runtime/shared/agent-task-starts.mjs';
|
|
7
8
|
import { resourceAdmission } from '../../../../runtime/shared/resource-admission.mjs';
|
|
8
9
|
import { clean, terminalPidForContext } from '../helpers.mjs';
|
|
9
10
|
import { renderResult } from '../render.mjs';
|
|
@@ -82,6 +83,9 @@ export function createJobStarter({ mgr, notifyStatusChange, notifySessionComplet
|
|
|
82
83
|
}
|
|
83
84
|
},
|
|
84
85
|
});
|
|
86
|
+
// The model's tool call that started this job owns it (its result message
|
|
87
|
+
// carries the id: agent-task-starts.mjs).
|
|
88
|
+
recordAgentTaskStart(notifyContext?.toolCallId, task.taskId);
|
|
85
89
|
notifyStatusChange();
|
|
86
90
|
return task;
|
|
87
91
|
};
|
|
@@ -9,6 +9,7 @@ import { resolveAgentWatchdogPolicy } from '../../../../runtime/agent/orchestrat
|
|
|
9
9
|
import { prepareAgentSession } from '../../../../runtime/agent/orchestrator/agent-runtime/session-builder.mjs';
|
|
10
10
|
import { getProvider } from '../../../../runtime/agent/orchestrator/providers/registry.mjs';
|
|
11
11
|
import { resolveRouteContextState } from '../../../route-state.mjs';
|
|
12
|
+
import { contextSelectionFromState } from '../../../../runtime/agent/orchestrator/runtime-core/route-context-state.mjs';
|
|
12
13
|
import { createSpawnPlanner } from './spawn-plan.mjs';
|
|
13
14
|
import { enterWorkerSpawn } from '../../../workspace/admission-gate.mjs';
|
|
14
15
|
|
|
@@ -97,11 +98,13 @@ export function createSpawnPreparer({
|
|
|
97
98
|
|
|
98
99
|
async function createSpawnedSession(plan, spec, prepState) {
|
|
99
100
|
// A sub-100 context share needs the window it selects; a percent alone
|
|
100
|
-
// keeps the full served window.
|
|
101
|
+
// keeps the full served window. A model whose window is not known yet
|
|
102
|
+
// resolves to nothing: the agent's own choice then travels as stored (the
|
|
103
|
+
// session sizes it from the provider's window) instead of being dropped
|
|
104
|
+
// for the model's default.
|
|
101
105
|
const sessionSpec = { ...spec };
|
|
102
106
|
if (plan.preset.contextPercent || plan.preset.contextTokens) {
|
|
103
|
-
|
|
104
|
-
Object.assign(sessionSpec, { contextPercent, selectedContextWindow }, contextTokens ? { contextTokens } : {});
|
|
107
|
+
Object.assign(sessionSpec, contextSelectionFromState(resolveRouteContextState(plan.preset, null), plan.preset));
|
|
105
108
|
}
|
|
106
109
|
if (sessionSurface?.canonical === true && typeof sessionSurface.createChild === 'function') {
|
|
107
110
|
return sessionSurface.createChild({ spec: sessionSpec, prompt: plan.prompt, tag: plan.tag });
|
|
@@ -26,6 +26,7 @@ import { saveSessionAsync } from '../../../../runtime/agent/orchestrator/session
|
|
|
26
26
|
import { presetDescriptor } from './spawn-prep.mjs';
|
|
27
27
|
import { workerStageForStatus } from '../worker-rows.mjs';
|
|
28
28
|
import { handoffContent } from '../../../handoff-attachments.mjs';
|
|
29
|
+
import { whileTurnDispatched } from '../../../../runtime/agent/orchestrator/session/manager/runtime-state.mjs';
|
|
29
30
|
|
|
30
31
|
// Mid-turn worker persistence cadence. The watchdog sweep runs every second;
|
|
31
32
|
// a transcript save is far more expensive than a bookkeeping stamp, so the
|
|
@@ -121,10 +122,12 @@ export function createSpawnRunner({
|
|
|
121
122
|
const { args, session, workerCwd } = prepared;
|
|
122
123
|
// The caller's forwarded files ride along as attachment parts.
|
|
123
124
|
const prompt = handoffContent(prepared.prompt, args.attachmentParts);
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
125
|
+
return whileTurnDispatched(session.id, () => {
|
|
126
|
+
if (typeof sessionSurface?.runTurn === 'function' && sessionSurface.canRun?.(session) !== false) {
|
|
127
|
+
return sessionSurface.runTurn({ session, prompt, context: args.context || null, cwd: workerCwd, ...turnHooks });
|
|
128
|
+
}
|
|
129
|
+
return mgr.askSession(session.id, prompt, args.context || null, null, workerCwd, null, turnHooks);
|
|
130
|
+
});
|
|
128
131
|
}
|
|
129
132
|
|
|
130
133
|
async function runSpawn(prepared, notifyContext = null, job = null) {
|
|
@@ -221,7 +224,7 @@ export function createSpawnRunner({
|
|
|
221
224
|
watchdog?.stop?.();
|
|
222
225
|
upsertWorkerSessionDeferred(session, tag, {
|
|
223
226
|
...presetDescriptor(agent, preset, presetName),
|
|
224
|
-
...settledWorkerStatus(finalStatus, stalled),
|
|
227
|
+
...settledWorkerStatus(finalStatus, stalled, job),
|
|
225
228
|
finishedAt: new Date().toISOString(),
|
|
226
229
|
});
|
|
227
230
|
setImmediate(notifyStatusChange);
|
|
@@ -31,10 +31,30 @@ export const PROCESS_RESTART_FAILURE = 'process-restart';
|
|
|
31
31
|
/** The row's turn was stopped by the progress (stall) watchdog. */
|
|
32
32
|
export const WATCHDOG_STALL_FAILURE = 'stalled';
|
|
33
33
|
|
|
34
|
+
/** A failed row whose turn a process restart ended and whose owner has not
|
|
35
|
+
* been told yet (restart-notify). It is the only record of that owed result,
|
|
36
|
+
* so closing the worker never drops it. */
|
|
37
|
+
export const isUnnotifiedRestartFailure = (row) =>
|
|
38
|
+
row?.status === 'failed' &&
|
|
39
|
+
row.failureReason === PROCESS_RESTART_FAILURE &&
|
|
40
|
+
Boolean(clean(row.ownerSessionId)) &&
|
|
41
|
+
!row.restartNotified;
|
|
42
|
+
|
|
34
43
|
/** A turn's settled row status and failure reason: a watchdog stop is a
|
|
35
44
|
* failure whatever partial output it handed back (`finalStatus` may still
|
|
36
|
-
* read `idle` for the job's sake);
|
|
37
|
-
|
|
45
|
+
* read `idle` for the job's sake); a turn the process exit cut off (its `job`
|
|
46
|
+
* cancelled with terminalReason PROCESS_RESTART_FAILURE, lifecycle/teardown)
|
|
47
|
+
* fails as a restart failure under its task id, which the next process tells
|
|
48
|
+
* its owner; everything else keeps `finalStatus`. */
|
|
49
|
+
export function settledWorkerStatus(finalStatus, stalled, job = null) {
|
|
50
|
+
if (job?.status === 'cancelled' && job.terminalReason === PROCESS_RESTART_FAILURE) {
|
|
51
|
+
return {
|
|
52
|
+
status: 'failed',
|
|
53
|
+
stage: 'failed',
|
|
54
|
+
failureReason: PROCESS_RESTART_FAILURE,
|
|
55
|
+
...(job.taskId ? { task_id: job.taskId } : {}),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
38
58
|
return stalled
|
|
39
59
|
? { status: 'failed', stage: 'failed', failureReason: WATCHDOG_STALL_FAILURE }
|
|
40
60
|
: { status: finalStatus, stage: finalStatus };
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
createRowLiveness,
|
|
23
23
|
isActiveWorkerRow,
|
|
24
24
|
isStaleApprovalWait,
|
|
25
|
+
isUnnotifiedRestartFailure,
|
|
25
26
|
PROCESS_RESTART_FAILURE,
|
|
26
27
|
runtimeDied,
|
|
27
28
|
} from './worker-index/row-liveness.mjs';
|
|
@@ -101,12 +102,15 @@ export function createWorkerIndex({ dataDir, cfgMod, mgr, tags, tagAgents, tagCw
|
|
|
101
102
|
const rowFromSession = (session, fallbackTag = '', extra = {}) =>
|
|
102
103
|
workerRowFromSession(session, fallbackTag, extra, (sessionId) => mgr.getSessionRuntime?.(sessionId));
|
|
103
104
|
|
|
105
|
+
// A row whose owner is still owed its restart failure stays: closing the
|
|
106
|
+
// worker (a process exit closes every one) must not lose that result.
|
|
104
107
|
function removeWorkerRow({ tag = '', sessionId = '' } = {}) {
|
|
105
108
|
const targetTag = clean(tag);
|
|
106
109
|
const targetSessionId = clean(sessionId);
|
|
107
110
|
batch.flush();
|
|
108
111
|
store.write((byKey) => {
|
|
109
112
|
for (const [key, row] of [...byKey.entries()]) {
|
|
113
|
+
if (isUnnotifiedRestartFailure(row)) continue;
|
|
110
114
|
if ((targetSessionId && row.sessionId === targetSessionId) || (targetTag && row.tag === targetTag)) {
|
|
111
115
|
byKey.delete(key);
|
|
112
116
|
}
|
|
@@ -194,12 +198,6 @@ export function createWorkerIndex({ dataDir, cfgMod, mgr, tags, tagAgents, tagCw
|
|
|
194
198
|
return true;
|
|
195
199
|
}
|
|
196
200
|
|
|
197
|
-
const isUnnotifiedRestartFailure = (row) =>
|
|
198
|
-
row.status === 'failed' &&
|
|
199
|
-
row.failureReason === PROCESS_RESTART_FAILURE &&
|
|
200
|
-
Boolean(clean(row.ownerSessionId)) &&
|
|
201
|
-
!row.restartNotified;
|
|
202
|
-
|
|
203
201
|
/** Rows whose turn a process restart ended and whose owner has not been told
|
|
204
202
|
* yet — whoever settled the row (this process at startup, or the
|
|
205
203
|
* predecessor's exit flush). Read-only: the caller enqueues the owner's
|
|
@@ -169,6 +169,12 @@ export function createStandaloneAgent({
|
|
|
169
169
|
},
|
|
170
170
|
getStatus,
|
|
171
171
|
recoverWorkers,
|
|
172
|
+
// Daemon start: settle the rows the previous process left running and
|
|
173
|
+
// queue each owner's failure result; resolves once they are queued.
|
|
174
|
+
settleRestartFailures: () => {
|
|
175
|
+
registry.recoverStaleWorkerRows({ deadOnly: true });
|
|
176
|
+
return notifyRestartFailures();
|
|
177
|
+
},
|
|
172
178
|
upsertLeadSession: registry.upsertLeadSession,
|
|
173
179
|
updateLeadWorkerCwd: registry.updateLeadWorkerCwd,
|
|
174
180
|
forgetLeadSession: registry.forgetLeadSession,
|
|
@@ -165,7 +165,7 @@ export function reconcileLostDaemonCaptures({
|
|
|
165
165
|
for (const name of names) {
|
|
166
166
|
const file = path.join(dir, name);
|
|
167
167
|
const record = readRecord(file);
|
|
168
|
-
if (
|
|
168
|
+
if (record?.kind !== 'mixdog-daemon-crash-capture') continue;
|
|
169
169
|
if (!record.pid || record.pid === selfPid || record.exitedAt || record.daemonExit || record.exitReason) continue;
|
|
170
170
|
if (pidAlive(record.pid)) continue;
|
|
171
171
|
try {
|
|
@@ -21,9 +21,10 @@ import { daemonCrashCaptureDir } from './paths.mjs';
|
|
|
21
21
|
// Prune only files this module creates: `daemon-<yyyymmdd>-<hhmmss>-<pid>-<rand>`.
|
|
22
22
|
const CAPTURE_STEM_RE = /^daemon-\d{8}-\d{6}-\d+-[0-9a-f]{4}$/;
|
|
23
23
|
const CAPTURE_SUFFIXES = ['.err.log', '.json'];
|
|
24
|
-
// Debris from this module's own atomic sidecar writes (
|
|
25
|
-
//
|
|
26
|
-
|
|
24
|
+
// Debris from this module's own atomic sidecar writes (the atomic writer names
|
|
25
|
+
// its temp `<basename>.mixdog-tmp-<hex>`; older builds `.<basename>.<hex>.tmp`),
|
|
26
|
+
// never anyone else's file.
|
|
27
|
+
const CAPTURE_TEMP_RE = /^\.?daemon-\d{8}-\d{6}-(\d+)-[0-9a-f]{4}\.json\.(?:[0-9a-f]+\.tmp|mixdog-tmp-[0-9a-f]+)$/;
|
|
27
28
|
export const CRASH_CAPTURE_KEEP_BOOTS = 8;
|
|
28
29
|
const CRASH_CAPTURE_KEEP_BYTES = 2 * 1024 * 1024;
|
|
29
30
|
const CRASH_CAPTURE_TAIL_BYTES = 256 * 1024;
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
* file-stamp set, standard events merged, legacy rules collected, and the
|
|
5
5
|
* parse errors both reported and recorded on the result.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
8
|
-
import { applyHookRulePatches, hookFileStamp } from './rule-file.mjs';
|
|
7
|
+
import { applyHookRulePatches, hookFileStamp, readHookDocument } from './rule-file.mjs';
|
|
9
8
|
import {
|
|
10
9
|
hookConfigEntries,
|
|
11
10
|
mergeEvents,
|
|
@@ -61,14 +60,24 @@ export function createConfigLoader({ dataDir, rulesPath, emit, pendingPatches })
|
|
|
61
60
|
for (const entry of entries) {
|
|
62
61
|
const filePath = entry.path;
|
|
63
62
|
let parsed = null;
|
|
63
|
+
let damaged = false;
|
|
64
64
|
try {
|
|
65
|
-
|
|
65
|
+
// The rules file is this module's own (written with a `.bak`): a
|
|
66
|
+
// damaged copy is restored from it. Other hooks files are only read.
|
|
67
|
+
parsed = readHookDocument(filePath, {
|
|
68
|
+
restore: filePath === rulesPath,
|
|
69
|
+
onDamaged: (error) => {
|
|
70
|
+
damaged = true;
|
|
71
|
+
errors.push({ file: filePath, error: error?.message || String(error) });
|
|
72
|
+
},
|
|
73
|
+
});
|
|
66
74
|
} catch (error) {
|
|
67
|
-
|
|
68
|
-
if (!(error instanceof SyntaxError)) cacheable = false;
|
|
75
|
+
cacheable = false;
|
|
69
76
|
errors.push({ file: filePath, error: error?.message || String(error) });
|
|
70
77
|
continue;
|
|
71
78
|
}
|
|
79
|
+
// Missing, or damaged without a good copy (reported above): no hooks.
|
|
80
|
+
if (damaged || parsed === null) continue;
|
|
72
81
|
sources.push(filePath);
|
|
73
82
|
sourceEntries.push({
|
|
74
83
|
path: filePath,
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { readFileSync, statSync } from 'node:fs';
|
|
2
2
|
import { isDeepStrictEqual } from 'node:util';
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
holdsNoData,
|
|
5
|
+
parseJsonText,
|
|
6
|
+
readJsonStateSync,
|
|
7
|
+
updateJsonAtomicSync,
|
|
8
|
+
} from '../../../runtime/shared/atomic-file.mjs';
|
|
5
9
|
import { normalizeRules } from './config.mjs';
|
|
6
10
|
|
|
7
11
|
export function hookFileStamp(path) {
|
|
@@ -14,13 +18,41 @@ export function hookFileStamp(path) {
|
|
|
14
18
|
}
|
|
15
19
|
}
|
|
16
20
|
|
|
17
|
-
|
|
21
|
+
// The hooks document at `path`, or null when it is missing or damaged (empty,
|
|
22
|
+
// NUL-filled after a crash, or not JSON). A damaged file must not turn every
|
|
23
|
+
// tool call into a policy-check failure, and must not silently drop the deny
|
|
24
|
+
// rules of a good copy: with `restore` (the rules file this module writes with
|
|
25
|
+
// a `.bak`), a valid `<path>.bak` is restored and read — the damaged bytes are
|
|
26
|
+
// kept aside as `<path>.corrupt-<ts>`. Without a good copy the file stays in
|
|
27
|
+
// place (a hand-edit can still fix it) and `onDamaged(error)` reports it; the
|
|
28
|
+
// caller then has no rules from it. Hooks files the user or a plugin owns are
|
|
29
|
+
// read with `restore: false`: never moved, locked or replaced. Real I/O errors
|
|
30
|
+
// still throw.
|
|
31
|
+
export function readHookDocument(path, { restore = true, onDamaged } = {}) {
|
|
32
|
+
let text;
|
|
18
33
|
try {
|
|
19
|
-
|
|
34
|
+
text = readFileSync(path, 'utf8');
|
|
20
35
|
} catch (error) {
|
|
21
36
|
if (error?.code === 'ENOENT' || error?.code === 'ENOTDIR') return null;
|
|
22
37
|
throw error;
|
|
23
38
|
}
|
|
39
|
+
let damage;
|
|
40
|
+
if (holdsNoData(text)) {
|
|
41
|
+
damage = new SyntaxError('the file holds no data (empty or NUL-filled)');
|
|
42
|
+
} else {
|
|
43
|
+
try {
|
|
44
|
+
return parseJsonText(text);
|
|
45
|
+
} catch (error) {
|
|
46
|
+
if (!(error instanceof SyntaxError)) throw error;
|
|
47
|
+
damage = error;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (restore) {
|
|
51
|
+
const restored = readJsonStateSync(path, { fallback: null, keepWithoutBackup: true });
|
|
52
|
+
if (restored !== null) return restored;
|
|
53
|
+
}
|
|
54
|
+
onDamaged?.(damage);
|
|
55
|
+
return null;
|
|
24
56
|
}
|
|
25
57
|
|
|
26
58
|
function replaceRules(document, rules) {
|
|
@@ -36,13 +68,19 @@ function replaceRules(document, rules) {
|
|
|
36
68
|
}
|
|
37
69
|
|
|
38
70
|
export function updateHookRules(path, update) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
71
|
+
let next;
|
|
72
|
+
// A damaged file is kept aside as <path>.corrupt-<ts> (its last good copy
|
|
73
|
+
// <path>.bak restored) before the update, never overwritten.
|
|
74
|
+
updateJsonAtomicSync(
|
|
75
|
+
path,
|
|
76
|
+
(document) => {
|
|
77
|
+
const rules = normalizeRules(document).filter((rule) => rule && typeof rule === 'object');
|
|
78
|
+
next = update(rules);
|
|
79
|
+
return replaceRules(document, next);
|
|
80
|
+
},
|
|
81
|
+
{ backup: true }
|
|
82
|
+
);
|
|
83
|
+
return { stamp: hookFileStamp(path), rules: next };
|
|
46
84
|
}
|
|
47
85
|
|
|
48
86
|
export function applyHookRulePatches(rules, patches, { strict = true } = {}) {
|
|
@@ -3,12 +3,11 @@ import { existsSync, mkdirSync, readdirSync, renameSync, rmSync } from 'node:fs'
|
|
|
3
3
|
import { basename, dirname, join, resolve } from 'node:path';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
5
|
import { createHash, randomUUID } from 'node:crypto';
|
|
6
|
-
import {
|
|
6
|
+
import { readJsonStateSync, updateJsonAtomicSync, withFileLockSync } from '../../runtime/shared/atomic-file.mjs';
|
|
7
7
|
import { resolvePluginData } from '../../runtime/shared/plugin-paths.mjs';
|
|
8
8
|
import { pluginManifest } from '../../runtime/shared/plugin-manifest.mjs';
|
|
9
9
|
import { pluginMetadata } from '../../runtime/shared/plugin-metadata.mjs';
|
|
10
10
|
import { clean } from '../../runtime/shared/clean.mjs';
|
|
11
|
-
import { readJsonSafe } from '../../runtime/shared/json-file.mjs';
|
|
12
11
|
|
|
13
12
|
const REGISTRY_VERSION = 1;
|
|
14
13
|
|
|
@@ -28,38 +27,39 @@ function installRoot(dataDir = resolvePluginData()) {
|
|
|
28
27
|
return join(pluginBaseDir(dataDir), 'installed');
|
|
29
28
|
}
|
|
30
29
|
|
|
30
|
+
const emptyRegistry = () => ({ version: REGISTRY_VERSION, plugins: [] });
|
|
31
|
+
const hasPluginList = (raw) => Boolean(raw && Array.isArray(raw.plugins));
|
|
32
|
+
|
|
33
|
+
// A damaged registry (empty, NUL-filled after a crash, malformed, or not a
|
|
34
|
+
// plugin list) never blocks the plugin features: its bytes are kept aside as
|
|
35
|
+
// registry.json.corrupt-<ts>, the last good copy registry.json.bak is
|
|
36
|
+
// restored when there is one, else the registry starts empty. I/O errors
|
|
37
|
+
// still throw.
|
|
31
38
|
function loadRegistry(dataDir = resolvePluginData()) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
return readJsonStateSync(registryPath(dataDir), {
|
|
40
|
+
validate(raw) {
|
|
41
|
+
if (!hasPluginList(raw)) throw new Error('plugin registry has no plugin list');
|
|
42
|
+
return raw;
|
|
43
|
+
},
|
|
44
|
+
fallback: emptyRegistry(),
|
|
45
|
+
secret: true,
|
|
46
|
+
});
|
|
37
47
|
}
|
|
38
48
|
|
|
39
49
|
function mutateRegistry(dataDir, mutator) {
|
|
40
50
|
const path = registryPath(dataDir);
|
|
41
51
|
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
{
|
|
50
|
-
version: REGISTRY_VERSION,
|
|
51
|
-
plugins: Array.isArray(registry.plugins) ? registry.plugins : [],
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
lock: false,
|
|
55
|
-
secret: true,
|
|
56
|
-
fsyncDir: true,
|
|
57
|
-
}
|
|
58
|
-
);
|
|
59
|
-
return result;
|
|
52
|
+
let result;
|
|
53
|
+
updateJsonAtomicSync(
|
|
54
|
+
path,
|
|
55
|
+
(raw) => {
|
|
56
|
+
const registry = hasPluginList(raw) ? raw : emptyRegistry();
|
|
57
|
+
result = mutator(registry);
|
|
58
|
+
return { version: REGISTRY_VERSION, plugins: registry.plugins };
|
|
60
59
|
},
|
|
61
|
-
{ secret: true }
|
|
60
|
+
{ secret: true, fsyncDir: true, backup: true }
|
|
62
61
|
);
|
|
62
|
+
return result;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
function displayNameFromUrl(url) {
|
|
@@ -394,7 +394,10 @@ function oauthProviderSetup(p, providers, checkSecrets) {
|
|
|
394
394
|
|
|
395
395
|
const CUSTOM_ID_RE = /^custom-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
396
396
|
const CUSTOM_TEST_TIMEOUT_MS = 20_000;
|
|
397
|
-
|
|
397
|
+
// A catalog host can sit behind a slow gateway: api.nano-gpt.com's /models
|
|
398
|
+
// answered 503 only after ~44 s, so the wait must outlast that to surface the
|
|
399
|
+
// service's own answer instead of a local timeout.
|
|
400
|
+
const CUSTOM_DISCOVERY_TIMEOUT_MS = 60_000;
|
|
398
401
|
|
|
399
402
|
export function isCustomProviderConfig(entry) {
|
|
400
403
|
return Boolean(entry) && typeof entry === 'object' && entry.type === 'custom';
|
|
@@ -949,7 +952,9 @@ async function withTimeout(run, ms, label) {
|
|
|
949
952
|
const timeout = new Promise((_, reject) => {
|
|
950
953
|
timer = setTimeout(() => {
|
|
951
954
|
controller.abort();
|
|
952
|
-
reject(
|
|
955
|
+
reject(
|
|
956
|
+
Object.assign(new Error(`${label} timed out after ${Math.round(ms / 1000)}s`), { code: 'EPROVIDERTIMEOUT' })
|
|
957
|
+
);
|
|
953
958
|
}, ms);
|
|
954
959
|
});
|
|
955
960
|
try {
|
|
@@ -1330,7 +1335,11 @@ export async function discoverCustomProviderModels(cfgMod, rawInput) {
|
|
|
1330
1335
|
try {
|
|
1331
1336
|
const { createCustomProvider } = await loadCustomProviderModule();
|
|
1332
1337
|
const provider = await createCustomProvider(id || 'custom-discovery', { ...config, apiKey });
|
|
1333
|
-
const listed = await withTimeout(
|
|
1338
|
+
const listed = await withTimeout(
|
|
1339
|
+
(signal) => provider.listModels({ signal, timeoutMs: CUSTOM_DISCOVERY_TIMEOUT_MS }),
|
|
1340
|
+
CUSTOM_DISCOVERY_TIMEOUT_MS,
|
|
1341
|
+
'model discovery'
|
|
1342
|
+
);
|
|
1334
1343
|
const models = publicCustomModelRows(listed);
|
|
1335
1344
|
// A failed discovery that still left manual rows reports its error too.
|
|
1336
1345
|
const failure = provider.customDiscoveryError;
|
|
@@ -1343,8 +1352,9 @@ export async function discoverCustomProviderModels(cfgMod, rawInput) {
|
|
|
1343
1352
|
function discoveryErrorView(error, secrets) {
|
|
1344
1353
|
const status = Number.isInteger(error?.status) ? error.status : undefined;
|
|
1345
1354
|
const authKind = status === 401 || status === 403 ? 'authentication' : 'request';
|
|
1355
|
+
const kind = status === 404 || status === 405 ? 'unavailable' : authKind;
|
|
1346
1356
|
return {
|
|
1347
|
-
kind:
|
|
1357
|
+
kind: error?.code === 'EPROVIDERTIMEOUT' ? 'timeout' : kind,
|
|
1348
1358
|
...(status === undefined ? {} : { status }),
|
|
1349
1359
|
message: sanitizeCustomError(error, secrets).message,
|
|
1350
1360
|
};
|
|
@@ -11,17 +11,31 @@
|
|
|
11
11
|
// - a group-room member session is no background run, but it speaks for the
|
|
12
12
|
// room, not for the user: it creates or changes no agent, automation or
|
|
13
13
|
// other setting either.
|
|
14
|
+
// - an unattended run — a routine turn in a bot's home chat (Mixy's too), or
|
|
15
|
+
// work it or a room started (held-requests.mjs unattendedRunOf) — is checked
|
|
16
|
+
// first and only ever narrows: at most its own bot's agent scope
|
|
17
|
+
// (`unattended: true`), which manages that bot's own automations and route
|
|
18
|
+
// and changes no other setting.
|
|
14
19
|
// The app's own panels call channel-admin directly and act for the human.
|
|
15
20
|
import { MIXY_AGENT_ID, agentIdOfHomeSession } from '../../runtime/agent/orchestrator/session/agent-home.mjs';
|
|
16
21
|
import { roomMemberOfSession } from '../../runtime/agent/orchestrator/session/agent-room.mjs';
|
|
17
22
|
import { mixyDisplayName } from '../../runtime/agent/orchestrator/session/mixy-name.mjs';
|
|
18
23
|
import { isAgentOwner } from '../../runtime/agent/orchestrator/agent-owner.mjs';
|
|
24
|
+
import { unattendedRunOf } from '../held-requests.mjs';
|
|
19
25
|
|
|
20
26
|
const INTERACTIVE_SOURCE_TYPES = new Set(['', 'lead', 'cli']);
|
|
27
|
+
// What an unattended run may still change: its own bot's automations (each
|
|
28
|
+
// checked by assertAutomationAccess) and its own route (assertOwnAgentSettings).
|
|
29
|
+
const UNATTENDED_OWN_ACTIONS = new Set([
|
|
30
|
+
'save_automation',
|
|
31
|
+
'set_automation_enabled',
|
|
32
|
+
'delete_automation',
|
|
33
|
+
'run_automation',
|
|
34
|
+
'set_agent_route',
|
|
35
|
+
]);
|
|
21
36
|
|
|
22
|
-
/**
|
|
23
|
-
|
|
24
|
-
const id = String(session?.id || '');
|
|
37
|
+
/** The scope by the session's id and record alone. */
|
|
38
|
+
function provenanceScope(session, id) {
|
|
25
39
|
const member = roomMemberOfSession(id);
|
|
26
40
|
if (member) return { kind: 'room-member', agentId: member.agentId };
|
|
27
41
|
const homeAgent = agentIdOfHomeSession(id);
|
|
@@ -35,6 +49,17 @@ export function scheduleCallerScope(session) {
|
|
|
35
49
|
return headless ? { kind: 'headless' } : { kind: 'human' };
|
|
36
50
|
}
|
|
37
51
|
|
|
52
|
+
/** `{ kind: 'human' | 'agent' | 'room-member' | 'headless', agentId?, unattended? }` of a session record. */
|
|
53
|
+
export function scheduleCallerScope(session) {
|
|
54
|
+
const id = String(session?.id || '');
|
|
55
|
+
const scope = provenanceScope(session, id);
|
|
56
|
+
const run = id ? unattendedRunOf(id) : null;
|
|
57
|
+
if (!run || scope.kind === 'headless' || scope.kind === 'room-member') return scope;
|
|
58
|
+
if (run.kind === 'room') return { kind: 'room-member', agentId: run.agentId };
|
|
59
|
+
if (!run.agentId || (scope.kind === 'agent' && scope.agentId !== run.agentId)) return { kind: 'headless' };
|
|
60
|
+
return { kind: 'agent', agentId: run.agentId, unattended: true };
|
|
61
|
+
}
|
|
62
|
+
|
|
38
63
|
/** Throws unless `scope` may `action` the `kind` ('schedule' | 'webhook')
|
|
39
64
|
* automation `current` (null when creating) with `owner` the requested owner
|
|
40
65
|
* ('' keeps the saved one). `agentIds` are the agents a transfer may name;
|
|
@@ -83,8 +108,12 @@ export function assertOwnAgentSettings(scope, agentId, action) {
|
|
|
83
108
|
}
|
|
84
109
|
}
|
|
85
110
|
|
|
86
|
-
/** Throws when `scope` is a headless run: it reads settings, never changes
|
|
111
|
+
/** Throws when `scope` is a headless run: it reads settings, never changes
|
|
112
|
+
* them; an unattended run changes only its own bot's automations and route. */
|
|
87
113
|
export function assertInteractiveCaller(scope, action) {
|
|
114
|
+
if (scope?.unattended && !UNATTENDED_OWN_ACTIONS.has(action)) {
|
|
115
|
+
throw new Error(`An unattended run cannot change settings (setup ${action})`);
|
|
116
|
+
}
|
|
88
117
|
if (scope?.kind === 'human' || scope?.kind === 'agent') return;
|
|
89
118
|
if (scope?.kind === 'room-member') throw new Error(`A group-room member cannot change settings (setup ${action})`);
|
|
90
119
|
throw new Error(`A background run cannot change settings (setup ${action})`);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
+
import { writeFileAtomicSync } from '../../runtime/shared/atomic-file.mjs';
|
|
3
4
|
import { pluginSkillsRoots } from '../../runtime/shared/plugin-manifest.mjs';
|
|
4
5
|
import {
|
|
5
6
|
EMPTY_HISTORY,
|
|
@@ -43,7 +44,7 @@ export function ensureStandaloneEnvironment({ rootDir, dataDir }) {
|
|
|
43
44
|
retireSeededPackCopies({ rootDir, dataDir, backup, includeHistory });
|
|
44
45
|
if (includeHistory && !backup.failures) {
|
|
45
46
|
try {
|
|
46
|
-
|
|
47
|
+
writeFileAtomicSync(markerFile, `${stamp}\n`);
|
|
47
48
|
} catch {
|
|
48
49
|
/* marker only; the sweep simply repeats */
|
|
49
50
|
}
|
|
@@ -68,7 +69,7 @@ function cleanupRetiredChannelSecrets(dataDir) {
|
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
try {
|
|
71
|
-
|
|
72
|
+
writeFileAtomicSync(marker, `${new Date().toISOString()}\n`);
|
|
72
73
|
} catch {
|
|
73
74
|
/* marker only */
|
|
74
75
|
}
|