mixdog 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +31 -0
- package/.claude-plugin/plugin.json +20 -0
- package/.gitattributes +34 -0
- package/.mcp.json +14 -0
- package/ARCHITECTURE.md +77 -0
- package/CHANGELOG.md +7 -0
- package/CONTRIBUTING.md +45 -0
- package/DATA-FLOW.md +79 -0
- package/LICENSE +21 -0
- package/README.md +389 -0
- package/SECURITY.md +138 -0
- package/UNINSTALL.md +112 -0
- package/agents/maintenance.md +5 -0
- package/agents/memory-classification.md +30 -0
- package/agents/scheduler-task.md +18 -0
- package/agents/webhook-handler.md +27 -0
- package/agents/worker.md +24 -0
- package/bin/bridge +133 -0
- package/bin/statusline-launcher.mjs +78 -0
- package/bin/statusline-lib.mjs +550 -0
- package/bin/statusline.mjs +607 -0
- package/bun.lock +802 -0
- package/commands/config.md +16 -0
- package/commands/doctor.md +13 -0
- package/commands/setup.md +17 -0
- package/defaults/cycle3-review-prompt.md +90 -0
- package/defaults/hidden-roles.json +65 -0
- package/defaults/memory-chunk-prompt.md +63 -0
- package/defaults/memory-promote-prompt.md +135 -0
- package/defaults/mixdog-config.template.json +27 -0
- package/defaults/user-workflow.json +8 -0
- package/defaults/user-workflow.md +12 -0
- package/hooks/hooks.json +73 -0
- package/hooks/lib/active-instance.cjs +77 -0
- package/hooks/lib/permission-evaluator.cjs +411 -0
- package/hooks/lib/permission-route.cjs +63 -0
- package/hooks/lib/permission-rules.cjs +170 -0
- package/hooks/lib/settings-loader.cjs +116 -0
- package/hooks/post-tool-use.cjs +84 -0
- package/hooks/pre-mcp-sandbox.cjs +158 -0
- package/hooks/pre-tool-subagent.cjs +253 -0
- package/hooks/session-start.cjs +1372 -0
- package/hooks/turn-timer.cjs +82 -0
- package/lib/claude-md-writer.cjs +386 -0
- package/lib/config-cjs.cjs +61 -0
- package/lib/hook-pipe-path.cjs +10 -0
- package/lib/keychain-cjs.cjs +263 -0
- package/lib/plugin-paths.cjs +61 -0
- package/lib/rules-builder.cjs +241 -0
- package/lib/text-utils.cjs +61 -0
- package/native/README.md +117 -0
- package/native/prebuilt/linux-aarch64/mixdog-shim +0 -0
- package/native/prebuilt/linux-x86_64/mixdog-shim +0 -0
- package/native/prebuilt/macos-aarch64/mixdog-shim +0 -0
- package/native/prebuilt/macos-x86_64/mixdog-shim +0 -0
- package/native/prebuilt/windows-x86_64/mixdog-shim.exe +0 -0
- package/package.json +107 -0
- package/prompts/code-review.txt +16 -0
- package/prompts/security-audit.txt +17 -0
- package/rules/bridge/00-common.md +39 -0
- package/rules/bridge/20-skip-protocol.md +18 -0
- package/rules/bridge/30-explorer.md +33 -0
- package/rules/bridge/40-cycle1-agent.md +52 -0
- package/rules/bridge/41-cycle2-agent.md +62 -0
- package/rules/bridge/42-cycle3-agent.md +44 -0
- package/rules/lead/00-tool-lead.md +61 -0
- package/rules/lead/01-general.md +23 -0
- package/rules/lead/02-channels.md +49 -0
- package/rules/lead/03-team.md +27 -0
- package/rules/lead/04-workflow.md +20 -0
- package/rules/shared/00-language.md +14 -0
- package/rules/shared/01-tool.md +138 -0
- package/scripts/bootstrap.mjs +184 -0
- package/scripts/bridge-unify-smoke.mjs +308 -0
- package/scripts/build-runtime-linux.sh +348 -0
- package/scripts/build-runtime-macos.sh +217 -0
- package/scripts/build-runtime-windows.ps1 +242 -0
- package/scripts/builtin-utils-smoke.mjs +392 -0
- package/scripts/check-json.mjs +45 -0
- package/scripts/check-syntax-changed.mjs +102 -0
- package/scripts/check-syntax.mjs +58 -0
- package/scripts/code-graph-batch.test.mjs +33 -0
- package/scripts/config-preserve-smoke.mjs +180 -0
- package/scripts/doctor.mjs +484 -0
- package/scripts/edit-normalize-fuzz.mjs +130 -0
- package/scripts/edit-normalize-smoke.mjs +401 -0
- package/scripts/edit-operation-smoke.mjs +369 -0
- package/scripts/edit2-smoke.mjs +63 -0
- package/scripts/fuzzy-e2e.mjs +28 -0
- package/scripts/fuzzy-smoke.mjs +26 -0
- package/scripts/generate-runtime-manifest.mjs +166 -0
- package/scripts/guard-smoke.mjs +66 -0
- package/scripts/hidden-role-schema-smoke.mjs +162 -0
- package/scripts/hook-routing-smoke.mjs +29 -0
- package/scripts/inject-input.ps1 +204 -0
- package/scripts/io-complex-smoke.mjs +667 -0
- package/scripts/io-explore-bench.mjs +424 -0
- package/scripts/io-guardrails-smoke.mjs +205 -0
- package/scripts/io-mini-bench-baseline.json +11 -0
- package/scripts/io-mini-bench.mjs +216 -0
- package/scripts/io-route-harness.mjs +933 -0
- package/scripts/io-telemetry-report.mjs +691 -0
- package/scripts/mutation-bench.mjs +564 -0
- package/scripts/mutation-io-smoke.mjs +1081 -0
- package/scripts/native-patch-bridge-smoke.mjs +288 -0
- package/scripts/native-patch-smoke.mjs +304 -0
- package/scripts/patch-interior-context-smoke.mjs +49 -0
- package/scripts/patch-newline-utf8-smoke.mjs +157 -0
- package/scripts/perf-hook-smoke.mjs +71 -0
- package/scripts/permission-eval-smoke.mjs +426 -0
- package/scripts/prep-patch.mjs +53 -0
- package/scripts/prep-shim.mjs +96 -0
- package/scripts/provider-cache-smoke.mjs +687 -0
- package/scripts/report-runtime-health.mjs +132 -0
- package/scripts/run-mcp.mjs +1547 -0
- package/scripts/salvage-v4a-shatter.test.mjs +58 -0
- package/scripts/scoped-cache-io-smoke.mjs +103 -0
- package/scripts/shell-policy-round3-smoke.mjs +46 -0
- package/scripts/smoke-runtime-negative.ps1 +100 -0
- package/scripts/smoke-runtime-negative.sh +95 -0
- package/scripts/stall-policy-smoke.mjs +50 -0
- package/scripts/start-memory-worker.mjs +23 -0
- package/scripts/statusline-launcher-smoke.mjs +82 -0
- package/scripts/stress-atomic-write.mjs +1028 -0
- package/scripts/test-config-rmw-restore.mjs +122 -0
- package/scripts/test-fault-inject.mjs +164 -0
- package/scripts/test-large-file.mjs +174 -0
- package/scripts/tool-edge-smoke.mjs +209 -0
- package/scripts/uninstall.mjs +201 -0
- package/scripts/webhook-selfheal-smoke.mjs +29 -0
- package/scripts/write-overwrite-guard-smoke.mjs +56 -0
- package/server-main.mjs +3055 -0
- package/server.mjs +468 -0
- package/setup/config-merge.mjs +254 -0
- package/setup/install.mjs +120 -0
- package/setup/launch-core.mjs +507 -0
- package/setup/launch.mjs +101 -0
- package/setup/setup-server.mjs +3206 -0
- package/setup/setup.html +3693 -0
- package/skills/retro-skill-proposer/SKILL.md +92 -0
- package/skills/schedule-add/SKILL.md +77 -0
- package/skills/setup/SKILL.md +346 -0
- package/skills/webhook-add/SKILL.md +81 -0
- package/src/agent/bridge-stall-watchdog.mjs +337 -0
- package/src/agent/index.mjs +2138 -0
- package/src/agent/orchestrator/activity-bus.mjs +38 -0
- package/src/agent/orchestrator/ai-wrapped-dispatch.mjs +1010 -0
- package/src/agent/orchestrator/bridge-retry.mjs +220 -0
- package/src/agent/orchestrator/bridge-trace.mjs +583 -0
- package/src/agent/orchestrator/cache-mtime.mjs +58 -0
- package/src/agent/orchestrator/config.mjs +358 -0
- package/src/agent/orchestrator/context/collect.mjs +651 -0
- package/src/agent/orchestrator/dispatch-persist.mjs +549 -0
- package/src/agent/orchestrator/drain-registry.mjs +50 -0
- package/src/agent/orchestrator/explore-validator.mjs +8 -0
- package/src/agent/orchestrator/internal-roles.mjs +118 -0
- package/src/agent/orchestrator/internal-tools.mjs +88 -0
- package/src/agent/orchestrator/jobs.mjs +116 -0
- package/src/agent/orchestrator/mcp/client.mjs +364 -0
- package/src/agent/orchestrator/providers/anthropic-betas.mjs +21 -0
- package/src/agent/orchestrator/providers/anthropic-oauth.mjs +1745 -0
- package/src/agent/orchestrator/providers/anthropic.mjs +437 -0
- package/src/agent/orchestrator/providers/gemini.mjs +1175 -0
- package/src/agent/orchestrator/providers/grok-oauth.mjs +782 -0
- package/src/agent/orchestrator/providers/model-catalog.mjs +241 -0
- package/src/agent/orchestrator/providers/openai-compat.mjs +1467 -0
- package/src/agent/orchestrator/providers/openai-oauth-ws.mjs +1890 -0
- package/src/agent/orchestrator/providers/openai-oauth.mjs +1307 -0
- package/src/agent/orchestrator/providers/openai-ws.mjs +104 -0
- package/src/agent/orchestrator/providers/registry.mjs +192 -0
- package/src/agent/orchestrator/providers/retry-classifier.mjs +325 -0
- package/src/agent/orchestrator/session/abort-lookup.mjs +13 -0
- package/src/agent/orchestrator/session/cache/post-edit-marks.mjs +42 -0
- package/src/agent/orchestrator/session/cache/prefetch-cache.mjs +142 -0
- package/src/agent/orchestrator/session/cache/read-cache.mjs +319 -0
- package/src/agent/orchestrator/session/cache/scoped-cache-outcome.mjs +11 -0
- package/src/agent/orchestrator/session/cache/scoped-cache.mjs +361 -0
- package/src/agent/orchestrator/session/cache/util.mjs +49 -0
- package/src/agent/orchestrator/session/loop.mjs +1478 -0
- package/src/agent/orchestrator/session/manager.mjs +1975 -0
- package/src/agent/orchestrator/session/read-dedup.mjs +6 -0
- package/src/agent/orchestrator/session/result-classification.mjs +65 -0
- package/src/agent/orchestrator/session/save-session-worker.mjs +18 -0
- package/src/agent/orchestrator/session/store.mjs +624 -0
- package/src/agent/orchestrator/session/stream-watchdog.mjs +130 -0
- package/src/agent/orchestrator/session/tool-result-offload.mjs +166 -0
- package/src/agent/orchestrator/session/trim.mjs +491 -0
- package/src/agent/orchestrator/smart-bridge/CACHE-SHARD.md +115 -0
- package/src/agent/orchestrator/smart-bridge/bridge-llm.mjs +327 -0
- package/src/agent/orchestrator/smart-bridge/cache-obs.mjs +150 -0
- package/src/agent/orchestrator/smart-bridge/cache-strategy.mjs +228 -0
- package/src/agent/orchestrator/smart-bridge/index.mjs +215 -0
- package/src/agent/orchestrator/smart-bridge/profiles.mjs +37 -0
- package/src/agent/orchestrator/smart-bridge/registry.mjs +348 -0
- package/src/agent/orchestrator/smart-bridge/session-builder.mjs +116 -0
- package/src/agent/orchestrator/stall-policy.mjs +195 -0
- package/src/agent/orchestrator/tool-loop-guard.mjs +75 -0
- package/src/agent/orchestrator/tools/bash-policy-scan.mjs +77 -0
- package/src/agent/orchestrator/tools/bash-session.mjs +721 -0
- package/src/agent/orchestrator/tools/builtin/advisory-lock.mjs +171 -0
- package/src/agent/orchestrator/tools/builtin/arg-guard.mjs +455 -0
- package/src/agent/orchestrator/tools/builtin/atomic-write.mjs +236 -0
- package/src/agent/orchestrator/tools/builtin/bash-tool.mjs +480 -0
- package/src/agent/orchestrator/tools/builtin/binary-file.mjs +76 -0
- package/src/agent/orchestrator/tools/builtin/builtin-tools.mjs +256 -0
- package/src/agent/orchestrator/tools/builtin/cache-layers.mjs +386 -0
- package/src/agent/orchestrator/tools/builtin/cwd-utils.mjs +37 -0
- package/src/agent/orchestrator/tools/builtin/device-paths.mjs +154 -0
- package/src/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +292 -0
- package/src/agent/orchestrator/tools/builtin/diff-utils.mjs +109 -0
- package/src/agent/orchestrator/tools/builtin/edit-base-guard.mjs +58 -0
- package/src/agent/orchestrator/tools/builtin/edit-byte-plan.mjs +240 -0
- package/src/agent/orchestrator/tools/builtin/edit-byte-utils.mjs +113 -0
- package/src/agent/orchestrator/tools/builtin/edit-commit.mjs +74 -0
- package/src/agent/orchestrator/tools/builtin/edit-context-utils.mjs +242 -0
- package/src/agent/orchestrator/tools/builtin/edit-diagnostics.mjs +211 -0
- package/src/agent/orchestrator/tools/builtin/edit-engine.mjs +1364 -0
- package/src/agent/orchestrator/tools/builtin/edit-failure-context.mjs +126 -0
- package/src/agent/orchestrator/tools/builtin/edit-hint.mjs +141 -0
- package/src/agent/orchestrator/tools/builtin/edit-match-utils.mjs +194 -0
- package/src/agent/orchestrator/tools/builtin/edit-partial-write.mjs +60 -0
- package/src/agent/orchestrator/tools/builtin/edit-stale-refresh.mjs +168 -0
- package/src/agent/orchestrator/tools/builtin/edit-tool.mjs +173 -0
- package/src/agent/orchestrator/tools/builtin/edit-utf8-guard.mjs +48 -0
- package/src/agent/orchestrator/tools/builtin/fs-reachability.mjs +48 -0
- package/src/agent/orchestrator/tools/builtin/fuzzy-match.mjs +99 -0
- package/src/agent/orchestrator/tools/builtin/glob-walk.mjs +170 -0
- package/src/agent/orchestrator/tools/builtin/grep-formatting.mjs +113 -0
- package/src/agent/orchestrator/tools/builtin/hash-utils.mjs +6 -0
- package/src/agent/orchestrator/tools/builtin/list-formatting.mjs +7 -0
- package/src/agent/orchestrator/tools/builtin/list-tool.mjs +593 -0
- package/src/agent/orchestrator/tools/builtin/native-edit-runner.mjs +89 -0
- package/src/agent/orchestrator/tools/builtin/notebook-edit-tool.mjs +300 -0
- package/src/agent/orchestrator/tools/builtin/open-config-tool.mjs +26 -0
- package/src/agent/orchestrator/tools/builtin/path-diagnostics.mjs +152 -0
- package/src/agent/orchestrator/tools/builtin/path-locks.mjs +35 -0
- package/src/agent/orchestrator/tools/builtin/path-utils.mjs +201 -0
- package/src/agent/orchestrator/tools/builtin/read-args.mjs +103 -0
- package/src/agent/orchestrator/tools/builtin/read-batch.mjs +172 -0
- package/src/agent/orchestrator/tools/builtin/read-constants.mjs +40 -0
- package/src/agent/orchestrator/tools/builtin/read-formatting.mjs +118 -0
- package/src/agent/orchestrator/tools/builtin/read-image-resize.mjs +189 -0
- package/src/agent/orchestrator/tools/builtin/read-image.mjs +88 -0
- package/src/agent/orchestrator/tools/builtin/read-lines.mjs +12 -0
- package/src/agent/orchestrator/tools/builtin/read-mode-tool.mjs +455 -0
- package/src/agent/orchestrator/tools/builtin/read-open.mjs +190 -0
- package/src/agent/orchestrator/tools/builtin/read-range-index.mjs +271 -0
- package/src/agent/orchestrator/tools/builtin/read-ranges.mjs +26 -0
- package/src/agent/orchestrator/tools/builtin/read-single-tool.mjs +728 -0
- package/src/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +173 -0
- package/src/agent/orchestrator/tools/builtin/read-special-files.mjs +268 -0
- package/src/agent/orchestrator/tools/builtin/read-streaming.mjs +602 -0
- package/src/agent/orchestrator/tools/builtin/read-tool.mjs +530 -0
- package/src/agent/orchestrator/tools/builtin/read-windows.mjs +107 -0
- package/src/agent/orchestrator/tools/builtin/rename-tool.mjs +196 -0
- package/src/agent/orchestrator/tools/builtin/rg-runner.mjs +422 -0
- package/src/agent/orchestrator/tools/builtin/search-builders.mjs +158 -0
- package/src/agent/orchestrator/tools/builtin/search-tool.mjs +869 -0
- package/src/agent/orchestrator/tools/builtin/shell-analysis.mjs +653 -0
- package/src/agent/orchestrator/tools/builtin/shell-jobs.mjs +936 -0
- package/src/agent/orchestrator/tools/builtin/shell-output.mjs +36 -0
- package/src/agent/orchestrator/tools/builtin/shell-runtime.mjs +214 -0
- package/src/agent/orchestrator/tools/builtin/snapshot-helpers.mjs +143 -0
- package/src/agent/orchestrator/tools/builtin/snapshot-store.mjs +206 -0
- package/src/agent/orchestrator/tools/builtin/snapshot-validation.mjs +98 -0
- package/src/agent/orchestrator/tools/builtin/text-stats.mjs +69 -0
- package/src/agent/orchestrator/tools/builtin/windows-roots.mjs +23 -0
- package/src/agent/orchestrator/tools/builtin/write-tool.mjs +401 -0
- package/src/agent/orchestrator/tools/builtin.mjs +500 -0
- package/src/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +39 -0
- package/src/agent/orchestrator/tools/code-graph-tool-defs.mjs +24 -0
- package/src/agent/orchestrator/tools/code-graph.mjs +4095 -0
- package/src/agent/orchestrator/tools/cwd-tool.mjs +298 -0
- package/src/agent/orchestrator/tools/destructive-warning.mjs +323 -0
- package/src/agent/orchestrator/tools/edit-normalize.mjs +603 -0
- package/src/agent/orchestrator/tools/env-scrub.mjs +100 -0
- package/src/agent/orchestrator/tools/graph-binary-fetcher.mjs +144 -0
- package/src/agent/orchestrator/tools/graph-manifest.json +26 -0
- package/src/agent/orchestrator/tools/host-input.mjs +204 -0
- package/src/agent/orchestrator/tools/mutation-content-cache.mjs +67 -0
- package/src/agent/orchestrator/tools/mutation-planner.mjs +75 -0
- package/src/agent/orchestrator/tools/next-call-utils.mjs +48 -0
- package/src/agent/orchestrator/tools/patch-binary-fetcher.mjs +133 -0
- package/src/agent/orchestrator/tools/patch-manifest.json +26 -0
- package/src/agent/orchestrator/tools/patch-tool-defs.mjs +20 -0
- package/src/agent/orchestrator/tools/patch.mjs +2754 -0
- package/src/agent/orchestrator/tools/progress-message.mjs +118 -0
- package/src/agent/orchestrator/tools/result-compression.mjs +279 -0
- package/src/agent/orchestrator/tools/shell-command.mjs +865 -0
- package/src/agent/orchestrator/tools/shell-exec-policy.mjs +89 -0
- package/src/agent/orchestrator/tools/shell-policy-danger-target.mjs +27 -0
- package/src/agent/orchestrator/tools/shell-policy-imports.mjs +7 -0
- package/src/agent/orchestrator/tools/shell-policy.mjs +345 -0
- package/src/agent/orchestrator/tools/shell-snapshot.mjs +313 -0
- package/src/agent/orchestrator/workflow-store.mjs +93 -0
- package/src/agent/tool-defs.mjs +103 -0
- package/src/channels/backends/discord.mjs +784 -0
- package/src/channels/data/voice-runtime-manifest.json +138 -0
- package/src/channels/index.mjs +3229 -0
- package/src/channels/lib/cli-worker-host.mjs +12 -0
- package/src/channels/lib/config-lock.mjs +13 -0
- package/src/channels/lib/config.mjs +292 -0
- package/src/channels/lib/drop-trace.mjs +71 -0
- package/src/channels/lib/event-pipeline.mjs +81 -0
- package/src/channels/lib/event-queue.mjs +345 -0
- package/src/channels/lib/executor.mjs +168 -0
- package/src/channels/lib/format.mjs +188 -0
- package/src/channels/lib/holidays.mjs +138 -0
- package/src/channels/lib/hook-pipe-server.mjs +802 -0
- package/src/channels/lib/interaction-workflows.mjs +184 -0
- package/src/channels/lib/memory-client.mjs +149 -0
- package/src/channels/lib/output-forwarder.mjs +765 -0
- package/src/channels/lib/runtime-paths.mjs +479 -0
- package/src/channels/lib/scheduler.mjs +723 -0
- package/src/channels/lib/session-control.mjs +36 -0
- package/src/channels/lib/session-discovery.mjs +103 -0
- package/src/channels/lib/settings.mjs +11 -0
- package/src/channels/lib/state-file.mjs +68 -0
- package/src/channels/lib/status-snapshot.mjs +219 -0
- package/src/channels/lib/tool-format.mjs +140 -0
- package/src/channels/lib/transcript-discovery.mjs +195 -0
- package/src/channels/lib/voice-runtime-fetcher.mjs +734 -0
- package/src/channels/lib/webhook.mjs +1179 -0
- package/src/channels/lib/whisper-server.mjs +477 -0
- package/src/channels/tool-defs.mjs +170 -0
- package/src/daemon/host.mjs +118 -0
- package/src/daemon/mcp-transport.mjs +47 -0
- package/src/daemon/session.mjs +100 -0
- package/src/daemon/thin-client.mjs +71 -0
- package/src/daemon/transport.mjs +163 -0
- package/src/memory/data/runtime-manifest.json +40 -0
- package/src/memory/index.mjs +3305 -0
- package/src/memory/lib/agent-ipc.mjs +93 -0
- package/src/memory/lib/bridge-trace-queries.mjs +120 -0
- package/src/memory/lib/core-memory-store.mjs +330 -0
- package/src/memory/lib/embedding-provider.mjs +269 -0
- package/src/memory/lib/embedding-worker.mjs +323 -0
- package/src/memory/lib/llm-worker-host.mjs +17 -0
- package/src/memory/lib/memory-cycle.mjs +11 -0
- package/src/memory/lib/memory-cycle1.mjs +641 -0
- package/src/memory/lib/memory-cycle2.mjs +1284 -0
- package/src/memory/lib/memory-cycle3.mjs +540 -0
- package/src/memory/lib/memory-embed.mjs +299 -0
- package/src/memory/lib/memory-extraction.mjs +5 -0
- package/src/memory/lib/memory-maintenance-store.mjs +32 -0
- package/src/memory/lib/memory-ops-policy.mjs +190 -0
- package/src/memory/lib/memory-recall-id-patch.mjs +15 -0
- package/src/memory/lib/memory-recall-read-query.mjs +7 -0
- package/src/memory/lib/memory-recall-scope-filter.mjs +63 -0
- package/src/memory/lib/memory-recall-store.mjs +621 -0
- package/src/memory/lib/memory-retrievers.mjs +112 -0
- package/src/memory/lib/memory-score.mjs +71 -0
- package/src/memory/lib/memory-text-utils.mjs +58 -0
- package/src/memory/lib/memory.mjs +412 -0
- package/src/memory/lib/model-profile.mjs +85 -0
- package/src/memory/lib/pg/adapter.mjs +308 -0
- package/src/memory/lib/pg/process.mjs +360 -0
- package/src/memory/lib/pg/supervisor.mjs +396 -0
- package/src/memory/lib/project-id-resolver.mjs +86 -0
- package/src/memory/lib/runtime-fetcher.mjs +442 -0
- package/src/memory/lib/trace-store.mjs +728 -0
- package/src/memory/tool-defs.mjs +79 -0
- package/src/search/index.mjs +1173 -0
- package/src/search/lib/backends/anthropic-oauth.mjs +98 -0
- package/src/search/lib/backends/exa.mjs +50 -0
- package/src/search/lib/backends/firecrawl.mjs +61 -0
- package/src/search/lib/backends/gemini-api.mjs +83 -0
- package/src/search/lib/backends/grok-oauth.mjs +86 -0
- package/src/search/lib/backends/index.mjs +150 -0
- package/src/search/lib/backends/openai-api.mjs +144 -0
- package/src/search/lib/backends/openai-oauth.mjs +98 -0
- package/src/search/lib/backends/openai-web-search.mjs +76 -0
- package/src/search/lib/backends/tavily.mjs +55 -0
- package/src/search/lib/backends/xai-api.mjs +113 -0
- package/src/search/lib/cache.mjs +131 -0
- package/src/search/lib/config.mjs +192 -0
- package/src/search/lib/formatter.mjs +115 -0
- package/src/search/lib/provider-usage.mjs +67 -0
- package/src/search/lib/providers.mjs +47 -0
- package/src/search/lib/search-intent.mjs +109 -0
- package/src/search/lib/setup-handler.mjs +261 -0
- package/src/search/lib/state.mjs +201 -0
- package/src/search/lib/web-tools.mjs +1207 -0
- package/src/search/tool-defs.mjs +83 -0
- package/src/setup/defender-exclusion.mjs +183 -0
- package/src/shared/abort-controller.mjs +15 -0
- package/src/shared/atomic-file.mjs +420 -0
- package/src/shared/config.mjs +350 -0
- package/src/shared/daemon-recycle.mjs +108 -0
- package/src/shared/disable-claude-builtins.mjs +88 -0
- package/src/shared/err-text.mjs +12 -0
- package/src/shared/llm/cost.mjs +66 -0
- package/src/shared/llm/http-agent.mjs +123 -0
- package/src/shared/llm/index.mjs +41 -0
- package/src/shared/llm/pid-cleanup.mjs +27 -0
- package/src/shared/llm/usage-log.mjs +47 -0
- package/src/shared/plugin-paths.mjs +58 -0
- package/src/shared/schedules-store.mjs +70 -0
- package/src/shared/seed.mjs +119 -0
- package/src/shared/user-cwd.mjs +213 -0
- package/src/shared/user-data-guard.mjs +238 -0
- package/src/status/aggregator.mjs +584 -0
- package/src/status/server.mjs +413 -0
- package/tools.json +1653 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge stall watchdog — per-session ticker that fires a `notifyFn` alert
|
|
3
|
+
* when a bridge worker's SSE stream goes silent for too long.
|
|
4
|
+
*
|
|
5
|
+
* Motivation (v0.6.233):
|
|
6
|
+
* The global stream-watchdog already aborts on a hard 600s stall, but the
|
|
7
|
+
* bridge worker's `notifyFn` only fires on the completion path. A stall
|
|
8
|
+
* that never reaches the hard-abort boundary (e.g. provider goes quiet
|
|
9
|
+
* mid-iteration and the lead gives up waiting) left the lead waiting
|
|
10
|
+
* indefinitely with no "worker finished" notification.
|
|
11
|
+
*
|
|
12
|
+
* This watchdog sits inside the bridge worker lifecycle, not the
|
|
13
|
+
* orchestrator. It uses the same staleness signal (lastStreamDeltaAt
|
|
14
|
+
* falling back to askStartedAt) and emits a user-facing notification
|
|
15
|
+
* via the existing notifyFn path once the per-session threshold is
|
|
16
|
+
* crossed — then aborts the session so the outer try/catch renders
|
|
17
|
+
* the normal error footer.
|
|
18
|
+
*
|
|
19
|
+
* Non-goals:
|
|
20
|
+
* - Does not replace the global stream-watchdog (that still runs at
|
|
21
|
+
* 300s/600s for provider-level stalls that never dispatched via bridge).
|
|
22
|
+
* - Treats normal tool work as expected silence, but still aborts tools
|
|
23
|
+
* that exceed the role's toolRunningSeconds cap.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { flushSessionMetrics, hideSessionFromList, closeSession } from './orchestrator/session/manager.mjs';
|
|
27
|
+
import {
|
|
28
|
+
DEFAULT_STALL_ABORT_S,
|
|
29
|
+
DEFAULT_STALL_WARN_S,
|
|
30
|
+
STALL_TICK_MS,
|
|
31
|
+
envThresholdSeconds,
|
|
32
|
+
resolveBridgeStallThresholds,
|
|
33
|
+
resolveBridgeToolThresholdSeconds,
|
|
34
|
+
} from './orchestrator/stall-policy.mjs';
|
|
35
|
+
|
|
36
|
+
// How long a terminal-stage session must sit idle before the watchdog
|
|
37
|
+
// flushes metrics, closes/tombstones it, and hides it from bridge type=list
|
|
38
|
+
// output. Aligned to 1h (3600s) to match index.mjs's _scheduleBridgeReap so
|
|
39
|
+
// the bridge worker lifecycle has ONE consistent terminal window — the 1h
|
|
40
|
+
// reap keeps a finished worker resumable for same-task reuse; without this
|
|
41
|
+
// alignment the watchdog would hide a session long before the reap timer.
|
|
42
|
+
const TERMINAL_REAP_MS = 3_600_000;
|
|
43
|
+
|
|
44
|
+
const TICK_MS = STALL_TICK_MS;
|
|
45
|
+
// DEFAULT_WARN_S / DEFAULT_ABORT_S — two-stage stall envelope for roles not
|
|
46
|
+
// declared in defaults/hidden-roles.json (public / custom user-workflow roles
|
|
47
|
+
// such as "worker", "reviewer", or any user-defined name). These roles carry
|
|
48
|
+
// no stallCap entry so the fallback keeps watchdog coverage without requiring
|
|
49
|
+
// every custom role to be registered.
|
|
50
|
+
// warn=abort=600s → mid-stream "slow" notify is disabled; the watchdog emits a
|
|
51
|
+
// single notification at the abort deadline ("stalled — aborting") and aborts
|
|
52
|
+
// the session. (resolveBridgeStallThresholds sets warn === abort.)
|
|
53
|
+
const DEFAULT_WARN_S = DEFAULT_STALL_WARN_S;
|
|
54
|
+
const DEFAULT_ABORT_S = DEFAULT_STALL_ABORT_S;
|
|
55
|
+
|
|
56
|
+
// Read stallCap from the declarative hidden-role config (defaults/hidden-roles.json).
|
|
57
|
+
// User-workflow roles (worker, reviewer, custom names) carry no stallCap and fall
|
|
58
|
+
// through to DEFAULT_WARN_S / DEFAULT_ABORT_S — no per-role code branches here.
|
|
59
|
+
// STALL_TIMEOUT_S env override sets the abort boundary; warn is clamped to
|
|
60
|
+
// min(300, abort/2) so it always fires before abort.
|
|
61
|
+
function resolveStallThresholds(role) {
|
|
62
|
+
return resolveBridgeStallThresholds(role);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function resolveToolThresholdSeconds(role, thresholdSeconds) {
|
|
66
|
+
return resolveBridgeToolThresholdSeconds(role, thresholdSeconds);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Decide whether an entry is stalled right now.
|
|
71
|
+
* Pure function — exposed for tests so we can feed synthetic runtime shapes.
|
|
72
|
+
*
|
|
73
|
+
* Returns one of:
|
|
74
|
+
* 'skip' — entry missing, closed, or in tool_running / terminal stage.
|
|
75
|
+
* 'ok' — entry live but below threshold.
|
|
76
|
+
* 'stall' — stale beyond threshold; caller should notify + abort.
|
|
77
|
+
*
|
|
78
|
+
* `tool_running` is treated as a stall ONLY when the per-tool runtime exceeds
|
|
79
|
+
* the role-specific threshold from `resolveToolThresholdSeconds` (defaults are
|
|
80
|
+
* generous so normal long-running tools — build, test, archive — do not trip).
|
|
81
|
+
* Below that threshold the verdict is `skip`, because tool work is client-side
|
|
82
|
+
* and the server is not silent.
|
|
83
|
+
* Terminal stages (idle/done/error/cancelling) are skipped too since
|
|
84
|
+
* askSession has already returned or is unwinding.
|
|
85
|
+
*/
|
|
86
|
+
export function inspectBridgeEntry(entry, abortSeconds = DEFAULT_ABORT_S, now = Date.now(), role = null, firstByteAbortSeconds = abortSeconds) {
|
|
87
|
+
if (!entry) return { verdict: 'skip' };
|
|
88
|
+
// Success-path empty synthesis — the loop finished without emitting
|
|
89
|
+
// any content/reasoning, but it is NOT a stall: no abort, no notify.
|
|
90
|
+
// Classified explicitly AHEAD of closed/stage so the stall verdict can
|
|
91
|
+
// never mask it, and so an entry that is both closed and empty-final
|
|
92
|
+
// still reports its empty-synthesis classification rather than 'skip'.
|
|
93
|
+
if (entry.emptyFinal) {
|
|
94
|
+
return { verdict: 'empty-synthesis', stage: entry.stage || null };
|
|
95
|
+
}
|
|
96
|
+
if (entry.closed) return { verdict: 'skip' };
|
|
97
|
+
const stage = entry.stage || null;
|
|
98
|
+
if (stage === 'tool_running') {
|
|
99
|
+
const toolStart = entry.toolStartedAt;
|
|
100
|
+
const toolThreshold = resolveToolThresholdSeconds(role, abortSeconds);
|
|
101
|
+
if (toolStart) {
|
|
102
|
+
const toolRuntimeS = Math.round((now - toolStart) / 1000);
|
|
103
|
+
if (toolRuntimeS >= toolThreshold) {
|
|
104
|
+
return { verdict: 'stall', staleSeconds: toolRuntimeS, stage, reason: 'tool-runtime-exceeded', toolName: entry.lastToolCall || null };
|
|
105
|
+
}
|
|
106
|
+
return { verdict: 'skip' };
|
|
107
|
+
}
|
|
108
|
+
// toolStartedAt missing — fall back to last stream delta / ask start so a
|
|
109
|
+
// session pinned in tool_running with no per-tool clock can still recover.
|
|
110
|
+
const ref = entry.lastStreamDeltaAt || entry.lastProgressAt || entry.updatedAt || entry.askStartedAt;
|
|
111
|
+
if (!ref) return { verdict: 'skip' };
|
|
112
|
+
const staleSeconds = Math.round((now - ref) / 1000);
|
|
113
|
+
if (staleSeconds < toolThreshold) return { verdict: 'ok', staleSeconds, stage };
|
|
114
|
+
return { verdict: 'stall', staleSeconds, stage, reason: 'tool-runtime-fallback', toolName: entry.lastToolCall || null };
|
|
115
|
+
}
|
|
116
|
+
if (stage === 'idle' || stage === 'done' || stage === 'error' || stage === 'cancelling') {
|
|
117
|
+
// Terminal stages never abort, but may need flush+hide after 120s (fix B).
|
|
118
|
+
const progressRef = entry.lastProgressAt || entry.doneAt || entry.updatedAt;
|
|
119
|
+
if (progressRef && (now - progressRef) >= TERMINAL_REAP_MS) {
|
|
120
|
+
return { verdict: 'terminal-reap', staleSeconds: Math.round((now - progressRef) / 1000), stage };
|
|
121
|
+
}
|
|
122
|
+
return { verdict: 'skip' };
|
|
123
|
+
}
|
|
124
|
+
// No first byte yet: still 'requesting' and never produced a single SSE
|
|
125
|
+
// delta — the stream never started, so it is hung, not slow reasoning.
|
|
126
|
+
// Abort on the shorter first-byte deadline so the lead gets a
|
|
127
|
+
// 'no first byte — aborting' notice in minutes, not the full 10-min window.
|
|
128
|
+
//
|
|
129
|
+
// Per-provider-call scoping: lastStreamDeltaAt persists across turns on
|
|
130
|
+
// the same session, so after a tool call the next 'requesting' phase
|
|
131
|
+
// still observes the previous turn's delta timestamp. Treat any
|
|
132
|
+
// lastStreamDeltaAt that predates the current 'requesting' phase
|
|
133
|
+
// (lastProgressAt is updated on the stage transition) as belonging to a
|
|
134
|
+
// prior call — the first-byte deadline applies to this fresh
|
|
135
|
+
// post-tool request, measured from the phase start rather than the
|
|
136
|
+
// original askStartedAt (which would be a stale pre-tool timestamp).
|
|
137
|
+
if (stage === 'requesting' && entry.askStartedAt) {
|
|
138
|
+
const phaseStart = entry.lastProgressAt || entry.askStartedAt;
|
|
139
|
+
const sawFirstByteThisCall = entry.lastStreamDeltaAt && entry.lastStreamDeltaAt >= phaseStart;
|
|
140
|
+
if (!sawFirstByteThisCall) {
|
|
141
|
+
const waitS = Math.round((now - phaseStart) / 1000);
|
|
142
|
+
if (waitS >= firstByteAbortSeconds) return { verdict: 'stall', staleSeconds: waitS, stage, reason: 'no-first-byte' };
|
|
143
|
+
return { verdict: 'ok', staleSeconds: waitS, stage };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const ref = entry.lastStreamDeltaAt || entry.lastProgressAt || entry.updatedAt || entry.askStartedAt;
|
|
147
|
+
if (!ref) return { verdict: 'skip' };
|
|
148
|
+
const staleSeconds = Math.round((now - ref) / 1000);
|
|
149
|
+
if (staleSeconds < abortSeconds) return { verdict: 'ok', staleSeconds, stage };
|
|
150
|
+
return { verdict: 'stall', staleSeconds, stage };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Start a per-session stall watchdog.
|
|
155
|
+
*
|
|
156
|
+
* @param {object} params
|
|
157
|
+
* @param {string} params.sessionId
|
|
158
|
+
* @param {() => object|null} params.getRuntime returns manager.getSessionRuntime(sessionId)
|
|
159
|
+
* @param {() => number} params.getIteration returns latest known iteration count
|
|
160
|
+
* @param {(reason: Error) => void} params.abort aborts the session controller
|
|
161
|
+
* @param {(msg: string) => void} params.notify notifyFn-style emitter
|
|
162
|
+
* @param {string} [params.modelTag] `[model] ` prefix to match other bridge emits
|
|
163
|
+
* @param {string} [params.role]
|
|
164
|
+
* @param {number} [params.warnSeconds] override for tests; falls back to resolveStallThresholds
|
|
165
|
+
* @param {number} [params.abortSeconds] override for tests; falls back to resolveStallThresholds
|
|
166
|
+
* @param {number} [params.tickMs] override for tests
|
|
167
|
+
* @returns {{ stop: () => void, fired: () => boolean }}
|
|
168
|
+
*/
|
|
169
|
+
export function startBridgeStallWatchdog(params) {
|
|
170
|
+
const {
|
|
171
|
+
sessionId,
|
|
172
|
+
// Caller may supply getSessionId() so the watchdog reads the *current*
|
|
173
|
+
// session id at flush/hide time. Detached bridge dispatch replaces
|
|
174
|
+
// activeSession on each retry attempt; without this the watchdog would
|
|
175
|
+
// flush/hide the original (already-closed) id and miss the replacement.
|
|
176
|
+
getSessionId,
|
|
177
|
+
getRuntime,
|
|
178
|
+
getIteration,
|
|
179
|
+
abort,
|
|
180
|
+
notify,
|
|
181
|
+
modelTag = '',
|
|
182
|
+
role = 'worker',
|
|
183
|
+
tickMs = TICK_MS,
|
|
184
|
+
} = params;
|
|
185
|
+
const currentSessionId = () => {
|
|
186
|
+
if (typeof getSessionId === 'function') {
|
|
187
|
+
try { return getSessionId() || sessionId; } catch { return sessionId; }
|
|
188
|
+
}
|
|
189
|
+
return sessionId;
|
|
190
|
+
};
|
|
191
|
+
const _defaults = resolveStallThresholds(role);
|
|
192
|
+
const warnSeconds = params.warnSeconds ?? _defaults.warn;
|
|
193
|
+
const abortSeconds = params.abortSeconds ?? _defaults.abort;
|
|
194
|
+
const firstByteAbortSeconds = params.firstByteAbortSeconds ?? _defaults.firstByteAbort ?? abortSeconds;
|
|
195
|
+
|
|
196
|
+
let fired = false;
|
|
197
|
+
let warned = false;
|
|
198
|
+
let handle = null;
|
|
199
|
+
// Tracks whether the stall-abort notify(msg) actually delivered. The outer
|
|
200
|
+
// bridge catch in src/agent/index.mjs used to set _delivered=true solely on
|
|
201
|
+
// fired(), which dropped the pending record even when notify rejected and
|
|
202
|
+
// the fallback addPending was the only surviving trace. Expose this so the
|
|
203
|
+
// caller only marks delivered when the user-facing notice really landed.
|
|
204
|
+
let _stallNotifyDelivered = false;
|
|
205
|
+
|
|
206
|
+
// Track which sessions have already been reaped to avoid repeat flushes.
|
|
207
|
+
let _reaped = false;
|
|
208
|
+
// Whether getRuntime() has ever returned a non-null entry. Once true, a
|
|
209
|
+
// subsequent null entry means the session was closed/reaped externally
|
|
210
|
+
// (e.g. closeSession() cleared _runtimeState before the watchdog's
|
|
211
|
+
// terminal-reap path could observe a terminal stage). Fix (3) uses this
|
|
212
|
+
// to stop the interval instead of polling a vanished entry forever.
|
|
213
|
+
let _seenEntry = false;
|
|
214
|
+
|
|
215
|
+
const tick = async () => {
|
|
216
|
+
let entry = null;
|
|
217
|
+
try { entry = getRuntime(); } catch { entry = null; }
|
|
218
|
+
if (entry) {
|
|
219
|
+
_seenEntry = true;
|
|
220
|
+
} else if (_seenEntry) {
|
|
221
|
+
// Entry vanished after at least one live observation — the session
|
|
222
|
+
// was closed externally. Clear the interval so the timer can't
|
|
223
|
+
// outlive the session and keep polling a null runtime forever.
|
|
224
|
+
if (handle) { clearInterval(handle); handle = null; }
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const res = inspectBridgeEntry(entry, abortSeconds, Date.now(), role, firstByteAbortSeconds);
|
|
228
|
+
const now = Date.now();
|
|
229
|
+
const _stage = entry?.stage ?? 'unknown';
|
|
230
|
+
const _askAgeS = entry?.askStartedAt ? ((now - entry.askStartedAt) / 1000).toFixed(1) : 'unknown';
|
|
231
|
+
const _lastDeltaAgeS = entry?.lastStreamDeltaAt ? ((now - entry.lastStreamDeltaAt) / 1000).toFixed(1) : 'never';
|
|
232
|
+
const _lastToolCall = entry?.lastToolCall || 'none';
|
|
233
|
+
|
|
234
|
+
// Shared message construction for the warn ("slow") and abort
|
|
235
|
+
// ("stalled") stages — both pull iter/iterPart/isToolStall/toolPart/
|
|
236
|
+
// causePart from the same `res` / `getIteration()` and only differ
|
|
237
|
+
// in the verb used for a tool stall ("tool slow" vs "tool stalled")
|
|
238
|
+
// and a trailing suffix. Closed over the per-tick `_stage`/`_askAgeS`/
|
|
239
|
+
// `_lastDeltaAgeS`/`_lastToolCall` snapshot above.
|
|
240
|
+
const buildStallMessage = ({ verb, toolVerb, suffix }) => {
|
|
241
|
+
const iter = (() => { try { return getIteration(); } catch { return null; } })();
|
|
242
|
+
const iterPart = typeof iter === 'number' && iter > 0 ? ` at iter ${iter}` : '';
|
|
243
|
+
const isToolStall = res.reason === 'tool-runtime-exceeded' || res.reason === 'tool-runtime-fallback';
|
|
244
|
+
const toolPart = isToolStall && res.toolName ? ` in tool ${res.toolName}` : '';
|
|
245
|
+
const causePart = isToolStall
|
|
246
|
+
? `${toolVerb}${toolPart}`
|
|
247
|
+
: (res.reason === 'no-first-byte' ? 'no first byte (request never streamed)' : 'no SSE delta');
|
|
248
|
+
return `${modelTag}${role} ${verb} — ${causePart} for ${res.staleSeconds}s${iterPart} stage=${_stage} askAgeS=${_askAgeS} lastDeltaAgeS=${_lastDeltaAgeS} lastToolCall=${_lastToolCall}${suffix}`;
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
// Fix B / #3: terminal-reap path — flush metrics, hide, AND
|
|
252
|
+
// close/tombstone the persisted session, no abort. hideSessionFromList
|
|
253
|
+
// alone only flips in-memory listHidden; the statusline aggregator
|
|
254
|
+
// reads the on-disk JSON and keeps rendering a non-closed bridge worker
|
|
255
|
+
// as idle until the store sweep. closeSession plants closed===true so
|
|
256
|
+
// the aggregator drops it immediately — one consistent 300s lifecycle.
|
|
257
|
+
if (res.verdict === 'terminal-reap' && !_reaped) {
|
|
258
|
+
_reaped = true;
|
|
259
|
+
const reapId = currentSessionId();
|
|
260
|
+
try { await flushSessionMetrics(reapId); } catch (e) { process.stderr.write(`[stall-watchdog] flushSessionMetrics failed: ${e?.message ?? e}\n`); }
|
|
261
|
+
try { hideSessionFromList(reapId); } catch (e) { process.stderr.write(`[stall-watchdog] hideSessionFromList failed: ${e?.message ?? e}\n`); }
|
|
262
|
+
try { closeSession(reapId, 'terminal-reap'); } catch (e) { process.stderr.write(`[stall-watchdog] closeSession failed: ${e?.message ?? e}\n`); }
|
|
263
|
+
if (handle) { clearInterval(handle); handle = null; }
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Warn stage: stale >= warnSeconds but < abortSeconds — notify once, keep running.
|
|
268
|
+
if (!warned && !fired && res.verdict === 'ok' && res.staleSeconds >= warnSeconds) {
|
|
269
|
+
warned = true;
|
|
270
|
+
const warnMsg = buildStallMessage({ verb: 'slow', toolVerb: 'tool slow', suffix: '' });
|
|
271
|
+
try { notify(warnMsg); } catch (e) { process.stderr.write(`[stall-watchdog] notify(warn) failed: ${e?.message ?? e}\n`); }
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (fired) return;
|
|
275
|
+
// Empty-synthesis is a success-path terminal state. Skip stall
|
|
276
|
+
// handling entirely so the watchdog never aborts/notifies on a
|
|
277
|
+
// legitimately finished (but content-empty) bridge worker.
|
|
278
|
+
if (res.verdict === 'empty-synthesis') {
|
|
279
|
+
if (handle) { clearInterval(handle); handle = null; }
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
if (res.verdict !== 'stall') return;
|
|
283
|
+
fired = true;
|
|
284
|
+
// stale >= abortSeconds: notify abort + abort session.
|
|
285
|
+
const msg = buildStallMessage({ verb: 'stalled', toolVerb: 'tool stalled', suffix: ' — aborting' });
|
|
286
|
+
// Await the notify so an async rejection (channel down, transport
|
|
287
|
+
// teardown) routes to the fallback addPending instead of being
|
|
288
|
+
// swallowed by an unobserved promise. Only flag _stallNotifyDelivered
|
|
289
|
+
// on actual success — the outer catch reads this to decide whether to
|
|
290
|
+
// drop the pending record or keep it replayable on next boot.
|
|
291
|
+
let _notifyOk = false;
|
|
292
|
+
try {
|
|
293
|
+
await Promise.resolve(notify(msg));
|
|
294
|
+
_notifyOk = true;
|
|
295
|
+
} catch (e) {
|
|
296
|
+
// notify rejected (sync throw or async rejection) — persist so
|
|
297
|
+
// recoverPending surfaces it on next boot.
|
|
298
|
+
const _dataDir = process.env.CLAUDE_PLUGIN_DATA;
|
|
299
|
+
const _sid = currentSessionId();
|
|
300
|
+
if (_dataDir && _sid) {
|
|
301
|
+
const _p = import('./orchestrator/dispatch-persist.mjs').then(({ addPending }) => {
|
|
302
|
+
addPending(_dataDir, `stall_${_sid}_${Date.now()}`, 'bridge', [msg]);
|
|
303
|
+
});
|
|
304
|
+
_p.catch((err) => {
|
|
305
|
+
process.stderr.write(`[stall-watchdog] addPending failed: ${err?.message ?? err}\n`);
|
|
306
|
+
process.emit('unhandledRejection', err, _p);
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
process.stderr.write(`[stall-watchdog] notify(abort) failed: ${e?.message ?? e}\n`);
|
|
310
|
+
}
|
|
311
|
+
if (_notifyOk) _stallNotifyDelivered = true;
|
|
312
|
+
try {
|
|
313
|
+
const reason = new Error(`bridge stall watchdog: ${res.staleSeconds}s`);
|
|
314
|
+
reason.name = 'BridgeStallAbortError';
|
|
315
|
+
abort(reason);
|
|
316
|
+
} catch { /* controller already gone / non-Error rejection — let outer flow finish */ }
|
|
317
|
+
// Don't keep ticking once we've fired; outer finally will stop() us
|
|
318
|
+
// but clear eagerly so a slow unwind can't double-notify.
|
|
319
|
+
if (handle) { clearInterval(handle); handle = null; }
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
handle = setInterval(tick, tickMs);
|
|
323
|
+
if (typeof handle.unref === 'function') handle.unref();
|
|
324
|
+
|
|
325
|
+
return {
|
|
326
|
+
stop() {
|
|
327
|
+
if (handle) { clearInterval(handle); handle = null; }
|
|
328
|
+
},
|
|
329
|
+
fired() { return fired; },
|
|
330
|
+
// True only when the stall-abort notify(msg) actually delivered. The
|
|
331
|
+
// outer bridge catch consults this before clearing the pending record
|
|
332
|
+
// so a notify rejection keeps the loss replayable on next boot.
|
|
333
|
+
delivered() { return _stallNotifyDelivered; },
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export const _internals = { TICK_MS, DEFAULT_WARN_S, DEFAULT_ABORT_S, resolveStallThresholds, envThresholdSeconds };
|