mixdog 0.9.2 → 0.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +8 -3
- package/scripts/anthropic-maxtokens-test.mjs +119 -0
- package/scripts/bench/lead-review-tasks-r3.json +20 -0
- package/scripts/bench/lead-review-tasks.json +20 -0
- package/scripts/bench/r4-mixed-tasks.json +20 -0
- package/scripts/bench/review-tasks.json +20 -0
- package/scripts/bench/round-codex.json +114 -0
- package/scripts/bench/round-mixdog-lead-r3.json +269 -0
- package/scripts/bench/round-mixdog-lead.json +269 -0
- package/scripts/bench/round-mixdog.json +126 -0
- package/scripts/bench/round-r10-bigsample.json +679 -0
- package/scripts/bench/round-r11-codexalign.json +257 -0
- package/scripts/bench/round-r4-codex.json +114 -0
- package/scripts/bench/round-r4-mixed.json +225 -0
- package/scripts/bench/round-r5-gpt-lead.json +259 -0
- package/scripts/bench/round-r6-codex.json +114 -0
- package/scripts/bench/round-r6-solo.json +257 -0
- package/scripts/bench/round-r7-full.json +254 -0
- package/scripts/bench/round-r8-fulldefault.json +255 -0
- package/scripts/bench-run.mjs +215 -29
- package/scripts/build-tui.mjs +13 -1
- package/scripts/explore-bench.mjs +124 -0
- package/scripts/freevar-smoke.mjs +95 -0
- package/scripts/hook-bus-test.mjs +191 -0
- package/scripts/internal-comms-bench.mjs +1 -0
- package/scripts/internal-comms-smoke.mjs +10 -9
- package/scripts/mouse-probe.mjs +45 -0
- package/scripts/output-style-bench.mjs +13 -6
- package/scripts/output-style-smoke.mjs +4 -4
- package/scripts/path-suffix-test.mjs +57 -0
- package/scripts/provider-toolcall-test.mjs +7 -3
- package/scripts/recall-bench.mjs +207 -0
- package/scripts/recall-usecase-cases.json +18 -0
- package/scripts/recall-usecase-probe.json +6 -0
- package/scripts/session-bench.mjs +152 -6
- package/scripts/tool-smoke.mjs +30 -67
- package/scripts/tui-render-smoke.mjs +90 -0
- package/scripts/webhook-smoke.mjs +208 -0
- package/src/agents/debugger/AGENT.md +5 -2
- package/src/agents/heavy-worker/AGENT.md +21 -11
- package/src/agents/maintainer/AGENT.md +4 -0
- package/src/agents/reviewer/AGENT.md +3 -2
- package/src/agents/worker/AGENT.md +21 -11
- package/src/lib/rules-builder.cjs +4 -0
- package/src/mixdog-session-runtime.mjs +933 -3731
- package/src/output-styles/default.md +34 -9
- package/src/output-styles/{oneline.md → extreme-minimal.md} +5 -4
- package/src/output-styles/minimal.md +4 -1
- package/src/output-styles/simple.md +22 -7
- package/src/repl.mjs +5 -5
- package/src/rules/agent/00-common.md +2 -0
- package/src/rules/agent/30-explorer.md +8 -11
- package/src/rules/lead/lead-brief.md +12 -0
- package/src/rules/lead/lead-tool.md +2 -9
- package/src/rules/shared/01-tool.md +11 -5
- package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +25 -0
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +100 -23
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +6 -15
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +362 -0
- package/src/runtime/agent/orchestrator/agent-trace-io.mjs +410 -0
- package/src/runtime/agent/orchestrator/agent-trace.mjs +16 -735
- package/src/runtime/agent/orchestrator/config.mjs +69 -2
- package/src/runtime/agent/orchestrator/context/collect.mjs +51 -0
- package/src/runtime/agent/orchestrator/mcp/client.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +63 -21
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +93 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +209 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +489 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +97 -1343
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +607 -0
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +78 -10
- package/src/runtime/agent/orchestrator/providers/api-usage.mjs +1 -13
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +81 -0
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +248 -0
- package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +303 -0
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +505 -0
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +44 -1014
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +18 -4
- package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +32 -0
- package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +86 -11
- package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +348 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +54 -20
- package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +108 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +19 -12
- package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +58 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +368 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +760 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +41 -1142
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +732 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +193 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +303 -2119
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +140 -995
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +227 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-events.mjs +67 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +436 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +1105 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +38 -12
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +7 -8
- package/src/runtime/agent/orchestrator/session/compact/budget.mjs +288 -0
- package/src/runtime/agent/orchestrator/session/compact/constants.mjs +85 -0
- package/src/runtime/agent/orchestrator/session/compact/engine.mjs +749 -0
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +82 -0
- package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +315 -0
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +643 -0
- package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +326 -0
- package/src/runtime/agent/orchestrator/session/compact.mjs +40 -2282
- package/src/runtime/agent/orchestrator/session/loop/compact-debug.mjs +28 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +274 -0
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +61 -0
- package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +38 -0
- package/src/runtime/agent/orchestrator/session/loop/env.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/loop/hidden-agents.mjs +21 -0
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +47 -0
- package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +182 -0
- package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +173 -0
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +63 -0
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +100 -0
- package/src/runtime/agent/orchestrator/session/loop/termination.mjs +58 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +52 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +239 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +218 -0
- package/src/runtime/agent/orchestrator/session/loop/transcript-repair.mjs +101 -0
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +35 -0
- package/src/runtime/agent/orchestrator/session/loop.mjs +409 -1304
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +471 -0
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +230 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +235 -0
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +149 -0
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +155 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +406 -0
- package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +80 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +303 -0
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +210 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +226 -2114
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +189 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +74 -179
- package/src/runtime/agent/orchestrator/stall-policy.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +70 -20
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +22 -2
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +33 -42
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +241 -0
- package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +40 -0
- package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +42 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +11 -4
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +29 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +8 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +126 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +81 -87
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +161 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +108 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +78 -304
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +11 -6
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +303 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +43 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +382 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +551 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +295 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +158 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/keyword-match.mjs +82 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/lang-predicates.mjs +128 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +66 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +44 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1080 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/source-access.mjs +81 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/span.mjs +19 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +280 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/text-columns.mjs +45 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +347 -0
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +6 -6
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +36 -4277
- package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/patch/constants.mjs +9 -0
- package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +171 -0
- package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +471 -0
- package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +436 -0
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +342 -0
- package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +359 -0
- package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +340 -0
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +643 -0
- package/src/runtime/agent/orchestrator/tools/patch.mjs +36 -2959
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +1 -23
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +10 -74
- package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +77 -0
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +2 -4
- package/src/runtime/agent/orchestrator/tools/shell-state.mjs +154 -0
- package/src/runtime/channels/backends/discord-access.mjs +32 -0
- package/src/runtime/channels/backends/discord-attachments.mjs +65 -0
- package/src/runtime/channels/backends/discord-gateway.mjs +233 -0
- package/src/runtime/channels/backends/discord.mjs +12 -292
- package/src/runtime/channels/index.mjs +241 -894
- package/src/runtime/channels/lib/backend-dispatch.mjs +44 -0
- package/src/runtime/channels/lib/boot-profile.mjs +23 -0
- package/src/runtime/channels/lib/crash-log.mjs +106 -0
- package/src/runtime/channels/lib/event-pipeline.mjs +18 -1
- package/src/runtime/channels/lib/event-queue.mjs +63 -4
- package/src/runtime/channels/lib/inbound-routing.mjs +111 -0
- package/src/runtime/channels/lib/index-drop-trace.mjs +72 -0
- package/src/runtime/channels/lib/output-forwarder.mjs +9 -1
- package/src/runtime/channels/lib/owner-heartbeat.mjs +75 -0
- package/src/runtime/channels/lib/parent-bridge.mjs +88 -0
- package/src/runtime/channels/lib/runtime-paths.mjs +14 -4
- package/src/runtime/channels/lib/session-discovery.mjs +56 -4
- package/src/runtime/channels/lib/telegram-format.mjs +19 -22
- package/src/runtime/channels/lib/tool-dispatch.mjs +158 -0
- package/src/runtime/channels/lib/tool-format.mjs +1 -1
- package/src/runtime/channels/lib/transcript-discovery.mjs +4 -4
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +6 -3
- package/src/runtime/channels/lib/voice-transcription.mjs +179 -0
- package/src/runtime/channels/lib/webhook/deliveries.mjs +312 -0
- package/src/runtime/channels/lib/webhook/log.mjs +42 -0
- package/src/runtime/channels/lib/webhook/ngrok.mjs +181 -0
- package/src/runtime/channels/lib/webhook/signature.mjs +60 -0
- package/src/runtime/channels/lib/webhook.mjs +36 -570
- package/src/runtime/channels/lib/whisper-language.mjs +42 -0
- package/src/runtime/channels/tool-defs.mjs +11 -130
- package/src/runtime/memory/index.mjs +258 -2050
- package/src/runtime/memory/lib/core-memory-store.mjs +351 -1
- package/src/runtime/memory/lib/cycle-llm-adapters.mjs +58 -0
- package/src/runtime/memory/lib/cycle-scheduler.mjs +497 -0
- package/src/runtime/memory/lib/cycle-signatures.mjs +34 -0
- package/src/runtime/memory/lib/embedding-warmup.mjs +58 -0
- package/src/runtime/memory/lib/http-wire.mjs +57 -0
- package/src/runtime/memory/lib/memory-config-flags.mjs +91 -0
- package/src/runtime/memory/lib/memory-cycle.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2-gate.mjs +515 -0
- package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +324 -0
- package/src/runtime/memory/lib/memory-cycle2-shared.mjs +18 -0
- package/src/runtime/memory/lib/memory-cycle2.mjs +72 -837
- package/src/runtime/memory/lib/memory-embed.mjs +149 -0
- package/src/runtime/memory/lib/memory-process-lock.mjs +162 -0
- package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +24 -0
- package/src/runtime/memory/lib/memory-recall-store.mjs +22 -2
- package/src/runtime/memory/lib/memory-retrievers.mjs +8 -0
- package/src/runtime/memory/lib/memory.mjs +20 -0
- package/src/runtime/memory/lib/pg/supervisor.mjs +1 -1
- package/src/runtime/memory/lib/promotion-fingerprint.mjs +50 -0
- package/src/runtime/memory/lib/query-handlers.mjs +780 -0
- package/src/runtime/memory/lib/recall-format.mjs +238 -0
- package/src/runtime/memory/lib/runtime-fetcher.mjs +8 -3
- package/src/runtime/memory/lib/transcript-ingest.mjs +425 -0
- package/src/runtime/memory/tool-defs.mjs +6 -14
- package/src/runtime/search/lib/http-fetch.mjs +274 -0
- package/src/runtime/search/lib/ssrf-guard.mjs +333 -0
- package/src/runtime/search/lib/web-tools.mjs +24 -602
- package/src/runtime/shared/abort-controller.mjs +1 -1
- package/src/runtime/shared/atomic-file.mjs +26 -1
- package/src/runtime/shared/background-tasks.mjs +2 -3
- package/src/runtime/shared/buffered-appender.mjs +149 -0
- package/src/runtime/shared/launcher-control.mjs +2 -2
- package/src/runtime/shared/task-notification-envelope.mjs +98 -0
- package/src/runtime/shared/tool-execution-contract.mjs +2 -2
- package/src/runtime/shared/tool-primitives.mjs +308 -0
- package/src/runtime/shared/tool-result-summary.mjs +515 -0
- package/src/runtime/shared/tool-surface.mjs +80 -898
- package/src/runtime/shared/transcript-writer.mjs +52 -2
- package/src/runtime/shared/update-checker.mjs +7 -4
- package/src/session-runtime/config-helpers.mjs +291 -0
- package/src/session-runtime/config-lifecycle.mjs +232 -0
- package/src/session-runtime/cwd-plugins.mjs +226 -0
- package/src/session-runtime/effort.mjs +128 -0
- package/src/session-runtime/fs-utils.mjs +10 -0
- package/src/session-runtime/mcp-glue.mjs +177 -0
- package/src/session-runtime/model-capabilities.mjs +130 -0
- package/src/session-runtime/model-recency.mjs +111 -0
- package/src/session-runtime/native-search.mjs +247 -0
- package/src/session-runtime/output-styles.mjs +126 -0
- package/src/session-runtime/plugin-mcp.mjs +114 -0
- package/src/session-runtime/prewarm.mjs +142 -0
- package/src/session-runtime/provider-models.mjs +278 -0
- package/src/session-runtime/provider-usage.mjs +120 -0
- package/src/session-runtime/quick-model-rows.mjs +170 -0
- package/src/session-runtime/quick-search-models.mjs +46 -0
- package/src/session-runtime/session-hooks.mjs +93 -0
- package/src/session-runtime/session-text.mjs +100 -0
- package/src/session-runtime/settings-api.mjs +319 -0
- package/src/session-runtime/statusline-route.mjs +35 -0
- package/src/session-runtime/tool-catalog.mjs +720 -0
- package/src/session-runtime/tool-defs.mjs +84 -0
- package/src/session-runtime/warmup-schedulers.mjs +201 -0
- package/src/session-runtime/workflow.mjs +358 -0
- package/src/standalone/agent-tool/helpers.mjs +237 -0
- package/src/standalone/agent-tool/notify.mjs +107 -0
- package/src/standalone/agent-tool/provider-init.mjs +143 -0
- package/src/standalone/agent-tool/render.mjs +152 -0
- package/src/standalone/agent-tool/tool-def.mjs +55 -0
- package/src/standalone/agent-tool.mjs +155 -677
- package/src/standalone/channel-worker.mjs +7 -9
- package/src/standalone/explore-tool.mjs +40 -12
- package/src/standalone/hook-bus/config.mjs +207 -0
- package/src/standalone/hook-bus/constants.mjs +90 -0
- package/src/standalone/hook-bus/handlers.mjs +481 -0
- package/src/standalone/hook-bus/payload.mjs +31 -0
- package/src/standalone/hook-bus/rules.mjs +77 -0
- package/src/standalone/hook-bus.mjs +110 -746
- package/src/standalone/memory-runtime-proxy.mjs +7 -0
- package/src/standalone/opencode-go-login.mjs +125 -0
- package/src/standalone/provider-admin.mjs +15 -19
- package/src/standalone/usage-dashboard.mjs +3 -1
- package/src/tui/App.jsx +1163 -7571
- package/src/tui/app/app-format.mjs +206 -0
- package/src/tui/app/channel-pickers.mjs +510 -0
- package/src/tui/app/clipboard.mjs +67 -0
- package/src/tui/app/core-memory-picker.mjs +210 -0
- package/src/tui/app/extension-pickers.mjs +506 -0
- package/src/tui/app/input-parsers.mjs +193 -0
- package/src/tui/app/maintenance-pickers.mjs +324 -0
- package/src/tui/app/model-options.mjs +330 -0
- package/src/tui/app/model-picker.mjs +365 -0
- package/src/tui/app/onboarding-steps.mjs +400 -0
- package/src/tui/app/project-picker.mjs +247 -0
- package/src/tui/app/provider-setup-picker.mjs +580 -0
- package/src/tui/app/resume-picker.mjs +55 -0
- package/src/tui/app/route-pickers.mjs +419 -0
- package/src/tui/app/settings-picker.mjs +490 -0
- package/src/tui/app/slash-commands.mjs +101 -0
- package/src/tui/app/slash-dispatch.mjs +427 -0
- package/src/tui/app/text-layout.mjs +46 -0
- package/src/tui/app/theme-effort-pickers.mjs +154 -0
- package/src/tui/app/transcript-window.mjs +671 -0
- package/src/tui/app/use-mouse-input.mjs +460 -0
- package/src/tui/app/use-prompt-handlers.mjs +310 -0
- package/src/tui/app/use-transcript-scroll.mjs +510 -0
- package/src/tui/app/use-transcript-window.mjs +589 -0
- package/src/tui/components/ConfirmBar.jsx +1 -1
- package/src/tui/components/Picker.jsx +32 -4
- package/src/tui/components/PromptInput.jsx +259 -80
- package/src/tui/components/SlashCommandPalette.jsx +8 -1
- package/src/tui/components/StatusLine.jsx +63 -12
- package/src/tui/components/TextEntryPanel.jsx +11 -0
- package/src/tui/components/ToolExecution.jsx +56 -588
- package/src/tui/components/TranscriptItem.jsx +105 -0
- package/src/tui/components/UsagePanel.jsx +18 -4
- package/src/tui/components/prompt-input/edit-helpers.mjs +72 -0
- package/src/tui/components/prompt-input/voice-indicator.mjs +39 -0
- package/src/tui/components/tool-execution/ResultBody.jsx +56 -0
- package/src/tui/components/tool-execution/surface-detail.mjs +405 -0
- package/src/tui/components/tool-execution/text-format.mjs +161 -0
- package/src/tui/components/tool-output-format.mjs +2 -2
- package/src/tui/display-width.mjs +20 -3
- package/src/tui/dist/index.mjs +18034 -17188
- package/src/tui/engine/agent-envelope.mjs +296 -0
- package/src/tui/engine/agent-job-feed.mjs +133 -0
- package/src/tui/engine/boot-profile.mjs +21 -0
- package/src/tui/engine/labels.mjs +67 -0
- package/src/tui/engine/notice-text.mjs +112 -0
- package/src/tui/engine/notification-plan.mjs +76 -0
- package/src/tui/engine/queue-helpers.mjs +161 -0
- package/src/tui/engine/render-timing.mjs +17 -0
- package/src/tui/engine/session-stats.mjs +46 -0
- package/src/tui/engine/tool-approval.mjs +94 -0
- package/src/tui/engine/tool-call-fields.mjs +23 -0
- package/src/tui/engine/tool-card-results.mjs +234 -0
- package/src/tui/engine/tool-result-status.mjs +135 -0
- package/src/tui/engine/tool-result-text.mjs +126 -0
- package/src/tui/engine.mjs +405 -1385
- package/src/tui/figures.mjs +5 -0
- package/src/tui/index.jsx +105 -0
- package/src/tui/input-editing.mjs +60 -10
- package/src/tui/keyboard-protocol.mjs +2 -2
- package/src/tui/lib/voice-recorder.mjs +35 -19
- package/src/tui/markdown/format-token.mjs +11 -9
- package/src/tui/paste-attachments.mjs +38 -0
- package/src/tui/statusline-ansi-bridge.mjs +11 -3
- package/src/tui/theme.mjs +6 -0
- package/src/tui/themes/base.mjs +2 -2
- package/src/tui/themes/kanagawa.mjs +4 -4
- package/src/tui/themes/teal.mjs +4 -5
- package/src/tui/themes/utils.mjs +1 -1
- package/src/ui/statusline-agents.mjs +213 -0
- package/src/ui/statusline-format.mjs +146 -0
- package/src/ui/statusline-segments.mjs +148 -0
- package/src/ui/statusline.mjs +77 -462
- package/src/ui/tool-card.mjs +0 -1
- package/src/vendor/statusline/bin/statusline-route.mjs +15 -2
- package/src/workflows/default/WORKFLOW.md +16 -9
- package/src/workflows/sequential/WORKFLOW.md +16 -11
- package/src/workflows/solo/WORKFLOW.md +5 -1
- package/vendor/ink/build/display-width.js +19 -3
- package/vendor/ink/build/ink.js +103 -6
- package/vendor/ink/build/log-update.js +17 -3
- package/vendor/ink/build/wrap-text.js +125 -0
- package/scripts/_test-folder-dialog.mjs +0 -30
- package/scripts/fix-brief-fn.mjs +0 -35
- package/scripts/fix-format-tool-surface.mjs +0 -24
- package/scripts/fix-tool-exec-visible.mjs +0 -42
- package/scripts/patch-agent-brief.mjs +0 -48
- package/scripts/patch-app.mjs +0 -21
- package/scripts/patch-app2.mjs +0 -18
- package/scripts/patch-dist-brief.mjs +0 -96
- package/scripts/patch-tool-exec.mjs +0 -70
- package/src/examples/schedules/SCHEDULE.example.md +0 -32
- package/src/examples/webhooks/WEBHOOK.example.md +0 -40
- package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +0 -107
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +0 -143
- package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -285
- package/src/runtime/agent/orchestrator/tools/builtin/open-config-tool.mjs +0 -26
- package/src/runtime/shared/channel-notification-routing.test.mjs +0 -45
- package/src/runtime/shared/tool-execution-contract.test.mjs +0 -183
- package/src/standalone/agent-task-status.test.mjs +0 -76
- package/src/tui/components/tool-output-format.test.mjs +0 -399
- package/src/tui/display-width.test.mjs +0 -35
- package/src/tui/engine-runtime-notification.test.mjs +0 -115
- package/src/tui/engine-tool-result-text.test.mjs +0 -75
- package/src/tui/markdown/format-token.test.mjs +0 -354
- package/src/tui/markdown/render-ansi.test.mjs +0 -108
- package/src/tui/markdown/stream-fence.test.mjs +0 -26
- package/src/tui/markdown/streaming-markdown.test.mjs +0 -70
- package/src/tui/prompt-history-store.test.mjs +0 -52
- package/src/tui/statusline-ansi-bridge.test.mjs +0 -159
- package/src/tui/transcript-tool-failures.test.mjs +0 -111
- package/src/ui/markdown.test.mjs +0 -70
- package/src/ui/statusline-context-label.test.mjs +0 -15
- package/src/vendor/statusline/bin/statusline-lib.mjs +0 -186
- package/src/vendor/statusline/bin/statusline-route.test.mjs +0 -80
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
// Background cycle scheduling cluster, extracted from index.mjs (pass 3).
|
|
2
|
+
//
|
|
3
|
+
// This owns the mutually-referential cycle machinery that pass-2 flagged as
|
|
4
|
+
// entangled: cycle-health ledger (_cycleHealth), the run-state file, the
|
|
5
|
+
// cycle1 outer coalesce layer (_startCycle1Run/_awaitCycle1Run), the scheduled
|
|
6
|
+
// enqueue/retry paths for cycle1/2/3, checkCycles(), and the self-rescheduling
|
|
7
|
+
// tick loop. index.mjs keeps lifecycle ownership by injecting live getters
|
|
8
|
+
// (getDb/getConfig/setConfig) plus the cycle runners and LLM adapters.
|
|
9
|
+
//
|
|
10
|
+
// Factory contract — everything the extracted functions closed over in the
|
|
11
|
+
// facade is passed in:
|
|
12
|
+
// getDb() -> live db handle (null before _initStore)
|
|
13
|
+
// getConfig() -> live mainConfig
|
|
14
|
+
// setConfig(cfg) -> checkCycles re-reads config each tick (poll-on-use)
|
|
15
|
+
// dataDir -> DATA_DIR
|
|
16
|
+
// log -> __mixdogMemoryLog
|
|
17
|
+
// getCycleLastRun / setCycleLastRun -> meta-backed cycle timestamps
|
|
18
|
+
// readMainConfig / memoryCyclesEnabled -> config-flag helpers
|
|
19
|
+
// getCycle{1,2,3}CallLlm -> in-process LLM adapters
|
|
20
|
+
// runCycle1 / runCycle2 / runCycle3 / parseInterval / flushRawEmbeddings
|
|
21
|
+
// getInFlightCycle1 -> inner cycle1 guard handle (rebuild drain)
|
|
22
|
+
// claimAndMarkScheduledCycle / resolveCoalesceMaxRetries /
|
|
23
|
+
// scheduleCoalescedCycleRetry -> coalesced queue primitives
|
|
24
|
+
// scheduledCycle{1,2,3}Signature -> queue signatures
|
|
25
|
+
// cycleStateFile -> path to memory-cycle-state.json
|
|
26
|
+
import fs from 'node:fs'
|
|
27
|
+
|
|
28
|
+
const CYCLE1_HEALTH_OVERDUE_MS = 5 * 60_000
|
|
29
|
+
const CYCLE1_AUTO_RESTART_COOLDOWN_MS = 5 * 60_000
|
|
30
|
+
const BACKLOG_WARN_COOLDOWN_MS = 10 * 60_000
|
|
31
|
+
const BACKLOG_WARN_PENDING = 500
|
|
32
|
+
const BACKLOG_WARN_FAILURES = 5
|
|
33
|
+
|
|
34
|
+
export function createCycleScheduler(deps) {
|
|
35
|
+
const {
|
|
36
|
+
getDb,
|
|
37
|
+
getConfig,
|
|
38
|
+
setConfig,
|
|
39
|
+
dataDir,
|
|
40
|
+
log = () => {},
|
|
41
|
+
getCycleLastRun,
|
|
42
|
+
setCycleLastRun,
|
|
43
|
+
readMainConfig,
|
|
44
|
+
memoryCyclesEnabled,
|
|
45
|
+
getCycle1CallLlm,
|
|
46
|
+
getCycle2CallLlm,
|
|
47
|
+
getCycle3CallLlm,
|
|
48
|
+
runCycle1,
|
|
49
|
+
runCycle2,
|
|
50
|
+
runCycle3,
|
|
51
|
+
parseInterval,
|
|
52
|
+
flushRawEmbeddings,
|
|
53
|
+
getInFlightCycle1,
|
|
54
|
+
claimAndMarkScheduledCycle,
|
|
55
|
+
resolveCoalesceMaxRetries,
|
|
56
|
+
scheduleCoalescedCycleRetry,
|
|
57
|
+
scheduledCycle1Signature,
|
|
58
|
+
scheduledCycle2Signature,
|
|
59
|
+
scheduledCycle3Signature,
|
|
60
|
+
cycleStateFile,
|
|
61
|
+
} = deps
|
|
62
|
+
|
|
63
|
+
// ── Cycle health state ────────────────────────────────────────────────────
|
|
64
|
+
const _cycleHealth = {
|
|
65
|
+
cycle1: { last_success_at: 0, last_error_at: 0, last_error: null, consecutive_failures: 0 },
|
|
66
|
+
cycle2: { last_success_at: 0, last_error_at: 0, last_error: null, consecutive_failures: 0 },
|
|
67
|
+
cycle3: { last_success_at: 0, last_error_at: 0, last_error: null, consecutive_failures: 0 },
|
|
68
|
+
}
|
|
69
|
+
let _cycleRunning = null // { cycle, started_at }
|
|
70
|
+
let _cycleBacklogSnapshot = { unchunked: 0, cycle2_pending: 0, at: 0 }
|
|
71
|
+
let _lastBacklogWarnAt = 0
|
|
72
|
+
|
|
73
|
+
// ── Cycle1 outer coalesce layer + tick loop state ─────────────────────────
|
|
74
|
+
let _cycle1InFlight = null
|
|
75
|
+
let _cycle2InFlight = false
|
|
76
|
+
let _cycle3InFlight = false
|
|
77
|
+
let _rawEmbedFlushInFlight = false
|
|
78
|
+
let _checkCyclesInFlight = false
|
|
79
|
+
let _cyclesActive = false
|
|
80
|
+
let _cycleInterval = null
|
|
81
|
+
let _startupTimeout = null
|
|
82
|
+
|
|
83
|
+
function _writeCycleStateFile() {
|
|
84
|
+
try {
|
|
85
|
+
fs.writeFileSync(cycleStateFile, JSON.stringify({
|
|
86
|
+
running: _cycleRunning,
|
|
87
|
+
backlog: _cycleBacklogSnapshot,
|
|
88
|
+
cycles: _cycleHealth,
|
|
89
|
+
updatedAt: Date.now(),
|
|
90
|
+
}))
|
|
91
|
+
} catch { /* best-effort; statusline just shows nothing */ }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function markCycleRunning(cycle) {
|
|
95
|
+
_cycleRunning = { cycle, started_at: Date.now() }
|
|
96
|
+
_writeCycleStateFile()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function markCycleDone(cycle, ok, err = null) {
|
|
100
|
+
const h = _cycleHealth[cycle]
|
|
101
|
+
if (h) {
|
|
102
|
+
const now = Date.now()
|
|
103
|
+
if (ok) { h.last_success_at = now; h.consecutive_failures = 0; h.last_error = null }
|
|
104
|
+
else { h.last_error_at = now; h.consecutive_failures += 1; h.last_error = String(err || 'unknown').slice(0, 200) }
|
|
105
|
+
if (!ok && h.consecutive_failures >= BACKLOG_WARN_FAILURES) {
|
|
106
|
+
_warnCycleHealth(`${cycle} failing repeatedly (consecutive=${h.consecutive_failures}, last="${h.last_error}")`)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (_cycleRunning?.cycle === cycle) _cycleRunning = null
|
|
110
|
+
_writeCycleStateFile()
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function _warnCycleHealth(msg) {
|
|
114
|
+
const now = Date.now()
|
|
115
|
+
if (now - _lastBacklogWarnAt < BACKLOG_WARN_COOLDOWN_MS) return
|
|
116
|
+
_lastBacklogWarnAt = now
|
|
117
|
+
log(`[cycle-health] WARN ${msg}\n`)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function recordCycle1Result(result) {
|
|
121
|
+
const now = Date.now()
|
|
122
|
+
await setCycleLastRun('cycle1_heartbeat', now)
|
|
123
|
+
const skipped = result?.skippedInFlight === true
|
|
124
|
+
const coalescedNoop = result?.coalescedRetryNoop === true
|
|
125
|
+
const allFailed = !skipped
|
|
126
|
+
&& Number(result?.chunks ?? 0) === 0
|
|
127
|
+
&& Number(result?.processed ?? 0) === 0
|
|
128
|
+
&& Number(result?.skipped ?? 0) > 0
|
|
129
|
+
if (!skipped && !coalescedNoop && !allFailed) {
|
|
130
|
+
await setCycleLastRun('cycle1', now)
|
|
131
|
+
}
|
|
132
|
+
if (!skipped && !coalescedNoop) markCycleDone('cycle1', !allFailed, allFailed ? 'all rows skipped' : null)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function _startCycle1Run(config = {}, options = {}) {
|
|
136
|
+
if (typeof options?.callLlm !== 'function') {
|
|
137
|
+
options = { ...options, callLlm: getCycle1CallLlm() }
|
|
138
|
+
}
|
|
139
|
+
markCycleRunning('cycle1')
|
|
140
|
+
_cycle1InFlight = (async () => {
|
|
141
|
+
try {
|
|
142
|
+
const result = await runCycle1(getDb(), config, options, dataDir)
|
|
143
|
+
if (typeof options?.onCoalescedSuccess !== 'function') {
|
|
144
|
+
await recordCycle1Result(result)
|
|
145
|
+
}
|
|
146
|
+
return result
|
|
147
|
+
} catch (err) {
|
|
148
|
+
markCycleDone('cycle1', false, err?.message || err)
|
|
149
|
+
throw err
|
|
150
|
+
} finally {
|
|
151
|
+
if (_cycleRunning?.cycle === 'cycle1') { _cycleRunning = null; _writeCycleStateFile() }
|
|
152
|
+
if (_cycle1InFlight === promise) _cycle1InFlight = null
|
|
153
|
+
}
|
|
154
|
+
})()
|
|
155
|
+
const promise = _cycle1InFlight
|
|
156
|
+
return _cycle1InFlight
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async function _awaitCycle1Run(config = {}, options = {}) {
|
|
160
|
+
const target = _cycle1InFlight || _startCycle1Run(config, options)
|
|
161
|
+
const callerDeadlineMs = Number(options.callerDeadlineMs) || 0
|
|
162
|
+
if (callerDeadlineMs <= 0) return await target
|
|
163
|
+
let timer
|
|
164
|
+
const deadlinePromise = new Promise((resolve) => {
|
|
165
|
+
timer = setTimeout(() => {
|
|
166
|
+
resolve({
|
|
167
|
+
processed: 0,
|
|
168
|
+
chunks: 0,
|
|
169
|
+
skipped: 0,
|
|
170
|
+
sessions: 0,
|
|
171
|
+
skippedInFlight: true,
|
|
172
|
+
timedOutWaiting: true,
|
|
173
|
+
callerDeadlineMs,
|
|
174
|
+
})
|
|
175
|
+
}, callerDeadlineMs)
|
|
176
|
+
})
|
|
177
|
+
try {
|
|
178
|
+
return await Promise.race([target, deadlinePromise])
|
|
179
|
+
} finally {
|
|
180
|
+
clearTimeout(timer)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function periodicCycle1Config() {
|
|
185
|
+
return {
|
|
186
|
+
min_batch: 20,
|
|
187
|
+
session_cap: 2,
|
|
188
|
+
batch_size: 50,
|
|
189
|
+
concurrency: 2,
|
|
190
|
+
...(getConfig()?.cycle1 || {}),
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
async function enqueueScheduledCycle(kind, intervalMs, signature) {
|
|
195
|
+
const claim = await claimAndMarkScheduledCycle(getDb(), kind, intervalMs, signature, { reason: 'scheduled' })
|
|
196
|
+
return claim.claimed === true
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async function enqueueScheduledCycle1(intervalMs, _reason = 'scheduled') {
|
|
200
|
+
const config = periodicCycle1Config()
|
|
201
|
+
const signature = scheduledCycle1Signature(config)
|
|
202
|
+
if (await enqueueScheduledCycle('cycle1', intervalMs, signature)) {
|
|
203
|
+
scheduleScheduledCycle1(config, signature)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async function enqueueScheduledCycle2(intervalMs, _reason = 'scheduled') {
|
|
208
|
+
const config = getConfig()?.cycle2 || {}
|
|
209
|
+
const signature = scheduledCycle2Signature(config)
|
|
210
|
+
if (await enqueueScheduledCycle('cycle2', intervalMs, signature)) {
|
|
211
|
+
scheduleScheduledCycle2(config, signature)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async function enqueueScheduledCycle3(intervalMs, _reason = 'scheduled') {
|
|
216
|
+
const config = getConfig() || {}
|
|
217
|
+
const signature = scheduledCycle3Signature(config)
|
|
218
|
+
if (await enqueueScheduledCycle('cycle3', intervalMs, signature)) {
|
|
219
|
+
scheduleScheduledCycle3(config, signature)
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function scheduleScheduledCycle1(config, signature, attempt = 0) {
|
|
224
|
+
const maxRetries = resolveCoalesceMaxRetries(config, 3)
|
|
225
|
+
if (attempt > maxRetries) {
|
|
226
|
+
log('[cycle1] scheduled queue retry cap reached\n')
|
|
227
|
+
return
|
|
228
|
+
}
|
|
229
|
+
scheduleCoalescedCycleRetry(getDb(), 'cycle1', async () => {
|
|
230
|
+
if (!memoryCyclesEnabled()) return
|
|
231
|
+
if (_cycle1InFlight) {
|
|
232
|
+
scheduleScheduledCycle1(config, signature, attempt + 1)
|
|
233
|
+
return
|
|
234
|
+
}
|
|
235
|
+
const result = await _awaitCycle1Run(config, {
|
|
236
|
+
coalescedRetry: true,
|
|
237
|
+
onCoalescedSuccess: recordCycle1Result,
|
|
238
|
+
})
|
|
239
|
+
if (result?.skippedInFlight) scheduleScheduledCycle1(config, signature, attempt + 1)
|
|
240
|
+
}, config, signature)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function scheduleScheduledCycle2(config, signature, attempt = 0) {
|
|
244
|
+
const maxRetries = resolveCoalesceMaxRetries(config, 3)
|
|
245
|
+
if (attempt > maxRetries) {
|
|
246
|
+
log('[cycle2] scheduled queue retry cap reached\n')
|
|
247
|
+
return
|
|
248
|
+
}
|
|
249
|
+
scheduleCoalescedCycleRetry(getDb(), 'cycle2', async () => {
|
|
250
|
+
if (!memoryCyclesEnabled()) return
|
|
251
|
+
if (_cycle2InFlight) {
|
|
252
|
+
scheduleScheduledCycle2(config, signature, attempt + 1)
|
|
253
|
+
return
|
|
254
|
+
}
|
|
255
|
+
_cycle2InFlight = true
|
|
256
|
+
markCycleRunning('cycle2')
|
|
257
|
+
try {
|
|
258
|
+
let c2Options = {
|
|
259
|
+
coalescedRetry: true,
|
|
260
|
+
onCoalescedSuccess: _finalizeCycle2Run,
|
|
261
|
+
}
|
|
262
|
+
if (typeof c2Options?.callLlm !== 'function') {
|
|
263
|
+
c2Options = { ...c2Options, callLlm: getCycle2CallLlm() }
|
|
264
|
+
}
|
|
265
|
+
const result = await runCycle2(getDb(), config, c2Options, dataDir)
|
|
266
|
+
if (result?.skippedInFlight) {
|
|
267
|
+
scheduleScheduledCycle2(config, signature, attempt + 1)
|
|
268
|
+
} else if (result?.coalescedRetryNoop) {
|
|
269
|
+
log('[cycle2] scheduled queue noop\n')
|
|
270
|
+
} else if (result?.ok === false) {
|
|
271
|
+
await _finalizeCycle2Run(result)
|
|
272
|
+
}
|
|
273
|
+
} catch (err) {
|
|
274
|
+
log(`[cycle2] scheduled queue failed: ${err?.message || err}\n`)
|
|
275
|
+
markCycleDone('cycle2', false, err?.message || err)
|
|
276
|
+
} finally {
|
|
277
|
+
_cycle2InFlight = false
|
|
278
|
+
if (_cycleRunning?.cycle === 'cycle2') { _cycleRunning = null; _writeCycleStateFile() }
|
|
279
|
+
}
|
|
280
|
+
}, config, signature)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function scheduleScheduledCycle3(config, signature, attempt = 0) {
|
|
284
|
+
const retryConfig = config?.cycle3 || config
|
|
285
|
+
const maxRetries = resolveCoalesceMaxRetries(retryConfig, 3)
|
|
286
|
+
if (attempt > maxRetries) {
|
|
287
|
+
log('[cycle3] scheduled queue retry cap reached\n')
|
|
288
|
+
return
|
|
289
|
+
}
|
|
290
|
+
scheduleCoalescedCycleRetry(getDb(), 'cycle3', async () => {
|
|
291
|
+
if (!memoryCyclesEnabled()) return
|
|
292
|
+
if (_cycle3InFlight) {
|
|
293
|
+
scheduleScheduledCycle3(config, signature, attempt + 1)
|
|
294
|
+
return
|
|
295
|
+
}
|
|
296
|
+
_cycle3InFlight = true
|
|
297
|
+
markCycleRunning('cycle3')
|
|
298
|
+
try {
|
|
299
|
+
let c3Options = {
|
|
300
|
+
coalescedRetry: true,
|
|
301
|
+
onCoalescedSuccess: async () => { await setCycleLastRun('cycle3', Date.now()); markCycleDone('cycle3', true) },
|
|
302
|
+
}
|
|
303
|
+
if (typeof c3Options?.callLlm !== 'function') {
|
|
304
|
+
c3Options = { ...c3Options, callLlm: getCycle3CallLlm() }
|
|
305
|
+
}
|
|
306
|
+
const result = await runCycle3(getDb(), config, dataDir, c3Options)
|
|
307
|
+
if (result?.skippedInFlight) {
|
|
308
|
+
scheduleScheduledCycle3(config, signature, attempt + 1)
|
|
309
|
+
} else if (result?.coalescedRetryNoop) {
|
|
310
|
+
log('[cycle3] scheduled queue noop\n')
|
|
311
|
+
}
|
|
312
|
+
} catch (err) {
|
|
313
|
+
log(`[cycle3] scheduled queue failed: ${err?.message || err}\n`)
|
|
314
|
+
markCycleDone('cycle3', false, err?.message || err)
|
|
315
|
+
} finally {
|
|
316
|
+
_cycle3InFlight = false
|
|
317
|
+
if (_cycleRunning?.cycle === 'cycle3') { _cycleRunning = null; _writeCycleStateFile() }
|
|
318
|
+
}
|
|
319
|
+
}, retryConfig, signature)
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
async function _finalizeCycle2Run(result) {
|
|
323
|
+
if (result?.skippedInFlight) {
|
|
324
|
+
log('[cycle2] skipped: in flight\n')
|
|
325
|
+
return
|
|
326
|
+
}
|
|
327
|
+
if (result.ok) {
|
|
328
|
+
await setCycleLastRun('cycle2', Date.now())
|
|
329
|
+
await setCycleLastRun('cycle2_last_error', '')
|
|
330
|
+
log('[cycle2] completed\n')
|
|
331
|
+
markCycleDone('cycle2', true)
|
|
332
|
+
} else {
|
|
333
|
+
await setCycleLastRun('cycle2_last_error', result.error || 'unknown error')
|
|
334
|
+
log(`[cycle2] failed: ${result.error}\n`)
|
|
335
|
+
markCycleDone('cycle2', false, result.error || 'unknown error')
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
async function checkCycles() {
|
|
340
|
+
const mainConfig = readMainConfig()
|
|
341
|
+
setConfig(mainConfig)
|
|
342
|
+
const cyclesOn = memoryCyclesEnabled()
|
|
343
|
+
const db = getDb()
|
|
344
|
+
|
|
345
|
+
const cycle1Ms = parseInterval(mainConfig?.cycle1?.interval || '10m')
|
|
346
|
+
const cycle2Ms = parseInterval(mainConfig?.cycle2?.interval || '1h')
|
|
347
|
+
const cycle3Ms = parseInterval(mainConfig?.cycle3?.interval || '24h')
|
|
348
|
+
|
|
349
|
+
const now = Date.now()
|
|
350
|
+
const last = await getCycleLastRun()
|
|
351
|
+
|
|
352
|
+
if (cyclesOn) {
|
|
353
|
+
const cycle1OverdueMs = last.cycle1 > 0
|
|
354
|
+
? Math.max(0, now - last.cycle1 - cycle1Ms)
|
|
355
|
+
: 0
|
|
356
|
+
if (cycle1OverdueMs > CYCLE1_HEALTH_OVERDUE_MS) {
|
|
357
|
+
const lastSeen = last.cycle1 ? new Date(last.cycle1).toISOString() : 'never'
|
|
358
|
+
log(
|
|
359
|
+
`[cycle1] overdue by ${Math.floor(cycle1OverdueMs / 60_000)}min `
|
|
360
|
+
+ `(last=${lastSeen}). Pool B Anthropic shard may be cold.\n`
|
|
361
|
+
)
|
|
362
|
+
const lastAutoRestart = last.cycle1_autoRestart || 0
|
|
363
|
+
if (now - lastAutoRestart >= CYCLE1_AUTO_RESTART_COOLDOWN_MS) {
|
|
364
|
+
await setCycleLastRun('cycle1_autoRestart_attempt', now)
|
|
365
|
+
try {
|
|
366
|
+
const result = await _awaitCycle1Run(periodicCycle1Config())
|
|
367
|
+
await setCycleLastRun('cycle1_autoRestart', Date.now())
|
|
368
|
+
log(
|
|
369
|
+
`[cycle1] auto-restart completed chunks=${result?.chunks ?? 0} processed=${result?.processed ?? 0}\n`
|
|
370
|
+
)
|
|
371
|
+
return
|
|
372
|
+
} catch (e) {
|
|
373
|
+
log(`[cycle1] auto-restart error: ${e.message}\n`)
|
|
374
|
+
return
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (now - last.cycle1 >= cycle1Ms) {
|
|
380
|
+
await enqueueScheduledCycle1(cycle1Ms, 'scheduled')
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (now - last.cycle2 >= cycle2Ms) {
|
|
384
|
+
await enqueueScheduledCycle2(cycle2Ms, 'scheduled')
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (now - last.cycle3 >= cycle3Ms) {
|
|
388
|
+
await enqueueScheduledCycle3(cycle3Ms, 'scheduled')
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
try {
|
|
393
|
+
const unchunked = Number((await db.query(
|
|
394
|
+
`SELECT COUNT(*) c FROM entries WHERE chunk_root IS NULL AND NULLIF(btrim(session_id), '') IS NOT NULL`,
|
|
395
|
+
)).rows[0]?.c ?? 0)
|
|
396
|
+
const cycle2Pending = Number((await db.query(
|
|
397
|
+
`SELECT COUNT(*) c FROM entries WHERE is_root = 1 AND status = 'pending'`,
|
|
398
|
+
)).rows[0]?.c ?? 0)
|
|
399
|
+
_cycleBacklogSnapshot = { unchunked, cycle2_pending: cycle2Pending, at: now }
|
|
400
|
+
_writeCycleStateFile()
|
|
401
|
+
if (unchunked > BACKLOG_WARN_PENDING || cycle2Pending > BACKLOG_WARN_PENDING) {
|
|
402
|
+
_warnCycleHealth(`backlog unchunked=${unchunked} cycle2_pending=${cycle2Pending}`)
|
|
403
|
+
}
|
|
404
|
+
if (unchunked > 0 && !_rawEmbedFlushInFlight) {
|
|
405
|
+
_rawEmbedFlushInFlight = true
|
|
406
|
+
flushRawEmbeddings(db, { limit: 200 })
|
|
407
|
+
.then((r) => {
|
|
408
|
+
if (r.attempted > 0) log(`[embed] raw fallback flush attempted=${r.attempted} embedded=${r.embedded}\n`)
|
|
409
|
+
})
|
|
410
|
+
.catch((err) => log(`[embed] raw fallback flush failed: ${err?.message || err}\n`))
|
|
411
|
+
.finally(() => { _rawEmbedFlushInFlight = false })
|
|
412
|
+
}
|
|
413
|
+
const SELF_KICK_STALE_MS = 2 * 3600_000
|
|
414
|
+
const c1Stale = (_cycleHealth.cycle1.last_success_at || last.cycle1 || 0) < now - SELF_KICK_STALE_MS
|
|
415
|
+
const c2Stale = (_cycleHealth.cycle2.last_success_at || last.cycle2 || 0) < now - SELF_KICK_STALE_MS
|
|
416
|
+
if (cyclesOn && c1Stale && unchunked > BACKLOG_WARN_PENDING) {
|
|
417
|
+
_warnCycleHealth(`cycle1 self-kick: no success 2h+, unchunked=${unchunked}`)
|
|
418
|
+
await enqueueScheduledCycle1(0, 'self-kick')
|
|
419
|
+
} else if (cyclesOn && c2Stale && cycle2Pending > BACKLOG_WARN_PENDING) {
|
|
420
|
+
_warnCycleHealth(`cycle2 self-kick: no success 2h+, pending=${cycle2Pending}`)
|
|
421
|
+
await enqueueScheduledCycle2(0, 'self-kick')
|
|
422
|
+
}
|
|
423
|
+
} catch { /* counts are best-effort; never fail the tick */ }
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
async function _runCheckCyclesGuarded() {
|
|
427
|
+
if (_checkCyclesInFlight) return
|
|
428
|
+
_checkCyclesInFlight = true
|
|
429
|
+
try { await checkCycles() }
|
|
430
|
+
catch (e) { log(`[cycle-tick] error: ${e.message}\n`) }
|
|
431
|
+
finally { _checkCyclesInFlight = false }
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function _scheduleNextCheck() {
|
|
435
|
+
_cycleInterval = setTimeout(async () => {
|
|
436
|
+
_cycleInterval = null
|
|
437
|
+
try {
|
|
438
|
+
await _runCheckCyclesGuarded()
|
|
439
|
+
} catch (e) {
|
|
440
|
+
log(`[cycle-tick] re-arm guard caught: ${e?.message || e}\n`)
|
|
441
|
+
} finally {
|
|
442
|
+
if (_cyclesActive) _scheduleNextCheck()
|
|
443
|
+
}
|
|
444
|
+
}, 60_000)
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function startCycles() {
|
|
448
|
+
if (_cyclesActive) return
|
|
449
|
+
_cyclesActive = true
|
|
450
|
+
// Boot reset: a previous daemon that crashed mid-run leaves the state
|
|
451
|
+
// file's `running` marker set, and the statusline keeps showing a
|
|
452
|
+
// phantom "Memory cycle running" spinner until its 10-minute stale
|
|
453
|
+
// guard kicks in. No cycle can be running when this scheduler starts,
|
|
454
|
+
// so clear the marker (health/backlog reset to this process's state).
|
|
455
|
+
_cycleRunning = null
|
|
456
|
+
_writeCycleStateFile()
|
|
457
|
+
_scheduleNextCheck()
|
|
458
|
+
_startupTimeout = setTimeout(() => { void _runCheckCyclesGuarded() }, 30_000)
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
function stopCycles() {
|
|
462
|
+
_cyclesActive = false
|
|
463
|
+
if (_cycleInterval) { clearTimeout(_cycleInterval); _cycleInterval = null }
|
|
464
|
+
if (_startupTimeout) { clearTimeout(_startupTimeout); _startupTimeout = null }
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Full-shutdown reset — baseline stop() cleared these module-level flags so
|
|
468
|
+
// a later init() starts from a clean slate instead of coalescing onto (or
|
|
469
|
+
// skipping behind) pre-stop in-flight work / stale running state.
|
|
470
|
+
function resetInFlight() {
|
|
471
|
+
_cycle1InFlight = null
|
|
472
|
+
_cycle2InFlight = false
|
|
473
|
+
_cycle3InFlight = false
|
|
474
|
+
_checkCyclesInFlight = false
|
|
475
|
+
_rawEmbedFlushInFlight = false
|
|
476
|
+
_cycleRunning = null
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
return {
|
|
480
|
+
// health/state accessors (HTTP /health, statusline)
|
|
481
|
+
getCycleHealth: () => _cycleHealth,
|
|
482
|
+
getCycleRunning: () => _cycleRunning,
|
|
483
|
+
getCycleBacklogSnapshot: () => _cycleBacklogSnapshot,
|
|
484
|
+
// cycle1 in-flight handle (rebuild drain in index.mjs)
|
|
485
|
+
getCycle1InFlight: () => _cycle1InFlight,
|
|
486
|
+
// run primitives used by MCP action handlers
|
|
487
|
+
startCycle1Run: _startCycle1Run,
|
|
488
|
+
awaitCycle1Run: _awaitCycle1Run,
|
|
489
|
+
finalizeCycle2Run: _finalizeCycle2Run,
|
|
490
|
+
periodicCycle1Config,
|
|
491
|
+
// lifecycle
|
|
492
|
+
startCycles,
|
|
493
|
+
stopCycles,
|
|
494
|
+
resetInFlight,
|
|
495
|
+
checkCycles,
|
|
496
|
+
}
|
|
497
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Scheduled-cycle request-signature helpers extracted from index.mjs.
|
|
2
|
+
// Pure functions of the passed `config` object; they call the imported
|
|
3
|
+
// makeCycleRequestSignature and touch no module state (no db/timers).
|
|
4
|
+
// index.mjs imports these; signatures and behavior are unchanged.
|
|
5
|
+
|
|
6
|
+
import { makeCycleRequestSignature } from './memory-cycle-requests.mjs'
|
|
7
|
+
|
|
8
|
+
export function scheduledCycle1Signature(config) {
|
|
9
|
+
return makeCycleRequestSignature('cycle1', config, {
|
|
10
|
+
preset: undefined,
|
|
11
|
+
concurrency: undefined,
|
|
12
|
+
maxConcurrent: undefined,
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function scheduledCycle2Signature(config) {
|
|
17
|
+
return makeCycleRequestSignature('cycle2', config, {
|
|
18
|
+
cascadePreset: undefined,
|
|
19
|
+
concurrency: undefined,
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function scheduledCycle3ApplyMode(config) {
|
|
24
|
+
const raw = String(config?.cycle3?.applyMode || 'conservative').trim().toLowerCase()
|
|
25
|
+
return (raw === 'proposal' || raw === 'dry-run' || raw === 'dryrun') ? 'proposal' : 'conservative'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function scheduledCycle3Signature(config) {
|
|
29
|
+
const retryConfig = config?.cycle3 || config
|
|
30
|
+
return makeCycleRequestSignature('cycle3', retryConfig, {
|
|
31
|
+
applyMode: scheduledCycle3ApplyMode(config),
|
|
32
|
+
apply: undefined,
|
|
33
|
+
})
|
|
34
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Boot-edge embedding warmup queue, extracted from index.mjs (pass 2).
|
|
2
|
+
//
|
|
3
|
+
// ONNX session creation on the embedding worker thread is CPU-heavy, so it must
|
|
4
|
+
// not overlap the worker's own init (DB open, schema, cycle wiring). The warmup
|
|
5
|
+
// is queued during _initStore and fired at the _initRuntime completion edge, so
|
|
6
|
+
// it starts the instant boot's CPU-heavy work is done — no magic-number delay.
|
|
7
|
+
//
|
|
8
|
+
// This is a small pure factory: index.mjs owns the DATA_DIR-derived meta path
|
|
9
|
+
// and the embedding-provider imports, injecting them here as callbacks. No
|
|
10
|
+
// import-time side effects.
|
|
11
|
+
export function createEmbeddingWarmup({
|
|
12
|
+
canStart,
|
|
13
|
+
warmup,
|
|
14
|
+
getDims,
|
|
15
|
+
persistMeta,
|
|
16
|
+
log = () => {},
|
|
17
|
+
}) {
|
|
18
|
+
let _pending = null
|
|
19
|
+
|
|
20
|
+
// Queue the warmup; fireDeferred() runs it once boot completes. Re-queuing
|
|
21
|
+
// overwrites any prior pending closure (matches the original single-slot
|
|
22
|
+
// module var). MIXDOG_EMBED_WARMUP=0 (checked via canStart) disables it.
|
|
23
|
+
function schedule(metaPath, metaKey) {
|
|
24
|
+
if (!canStart()) {
|
|
25
|
+
// Silent skip here previously made "warmup never ran" boots
|
|
26
|
+
// indistinguishable from failed warmups. One line, boot-edge only.
|
|
27
|
+
log('[memory-service] embedding warmup skipped (disabled by env/secondary mode) — recall stays lexical until first embed\n')
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
_pending = () => {
|
|
31
|
+
warmup()
|
|
32
|
+
.then(() => {
|
|
33
|
+
const measured = Number(getDims())
|
|
34
|
+
try {
|
|
35
|
+
persistMeta(metaPath, { ...metaKey, dims: measured })
|
|
36
|
+
} catch (e) {
|
|
37
|
+
log(`[memory-service] could not persist embedding-meta: ${e?.message || e}\n`)
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
.catch(err => {
|
|
41
|
+
log(`[memory-service] background warmup failed: ${err?.message || err}\n`)
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function fireDeferred() {
|
|
47
|
+
const fire = _pending
|
|
48
|
+
if (!fire) return
|
|
49
|
+
_pending = null
|
|
50
|
+
fire()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function reset() {
|
|
54
|
+
_pending = null
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return { schedule, fireDeferred, reset }
|
|
58
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// HTTP wire helpers extracted from index.mjs. All pure request/response
|
|
2
|
+
// utilities with no module state — no db, _traceDb, or timer dependencies.
|
|
3
|
+
// index.mjs imports these; behavior and signatures are unchanged.
|
|
4
|
+
|
|
5
|
+
export function readBody(req) {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
const chunks = []
|
|
8
|
+
req.on('data', c => chunks.push(c))
|
|
9
|
+
req.on('end', () => {
|
|
10
|
+
const raw = Buffer.concat(chunks).toString('utf8').trim()
|
|
11
|
+
if (!raw) { resolve({}); return }
|
|
12
|
+
try { resolve(JSON.parse(raw)) }
|
|
13
|
+
catch (error) {
|
|
14
|
+
const e = new Error(`invalid JSON body: ${error.message}`)
|
|
15
|
+
e.statusCode = 400
|
|
16
|
+
reject(e)
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
req.on('error', reject)
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function sendJson(res, data, status = 200) {
|
|
24
|
+
const body = JSON.stringify(data)
|
|
25
|
+
res.writeHead(status, {
|
|
26
|
+
'Content-Type': 'application/json; charset=utf-8',
|
|
27
|
+
'Content-Length': Buffer.byteLength(body),
|
|
28
|
+
})
|
|
29
|
+
res.end(body)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function sendError(res, msg, status = 500) {
|
|
33
|
+
sendJson(res, { error: msg }, status)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Origin/Referer guard for /admin/* mutation routes. Memory-service binds
|
|
37
|
+
// 127.0.0.1, but browser DNS-rebinding or a stray cross-origin fetch could
|
|
38
|
+
// still reach destructive endpoints (purge, backfill, entry mutations).
|
|
39
|
+
// Server-to-server callers (setup-server, hooks) issue raw http.request
|
|
40
|
+
// without a browser Origin/Referer, so absent headers pass; any non-loopback
|
|
41
|
+
// Origin/Referer is rejected. Mirrors setup-server.mjs isAllowedOrigin.
|
|
42
|
+
export function isLocalOrigin(req) {
|
|
43
|
+
const LOOP = /^https?:\/\/(localhost|127\.0\.0\.1|\[::1\])(:\d+)?(\/|$)/i
|
|
44
|
+
const origin = req.headers.origin || ''
|
|
45
|
+
const referer = req.headers.referer || ''
|
|
46
|
+
if (origin && !LOOP.test(origin)) return false
|
|
47
|
+
if (referer && !LOOP.test(referer)) return false
|
|
48
|
+
return true
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function normalizeCoreProjectId(value, { allowStar = false } = {}) {
|
|
52
|
+
if (value == null) return null
|
|
53
|
+
const s = String(value).trim()
|
|
54
|
+
if (!s || s.toLowerCase() === 'common') return null
|
|
55
|
+
if (allowStar && s === '*') return '*'
|
|
56
|
+
return s
|
|
57
|
+
}
|