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,550 @@
|
|
|
1
|
+
// mixdog statusline renderer — function form for in-daemon reuse.
|
|
2
|
+
//
|
|
3
|
+
// Mirrors `bin/statusline.mjs` exactly, but takes the CC stdin JSON as an
|
|
4
|
+
// argument and returns the rendered status text instead of reading fd 0 and
|
|
5
|
+
// writing to process.stdout. This allows the hook-pipe daemon to compute the
|
|
6
|
+
// statusline without paying the ~100ms bun cold-start on every refresh tick.
|
|
7
|
+
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import os from 'os';
|
|
10
|
+
import http from 'node:http';
|
|
11
|
+
import path from 'path';
|
|
12
|
+
|
|
13
|
+
export async function renderStatusLine(ccJsonInput) {
|
|
14
|
+
// ── ANSI palette (identical to bash original) ────────────────────────────────
|
|
15
|
+
const R = '\x1b[0m';
|
|
16
|
+
const B = '\x1b[1m';
|
|
17
|
+
const D = '\x1b[2m';
|
|
18
|
+
const RED = '\x1b[31m';
|
|
19
|
+
const GRN = '\x1b[32m';
|
|
20
|
+
const YLW = '\x1b[33m';
|
|
21
|
+
const CYN = '\x1b[36m';
|
|
22
|
+
const GREY = '\x1b[90m';
|
|
23
|
+
|
|
24
|
+
// ── Terminal width ──────────────────────────────────────────────────────────
|
|
25
|
+
let COLS = parseInt(process.env.COLUMNS || '120', 10);
|
|
26
|
+
if (!Number.isFinite(COLS) || COLS <= 0) COLS = 120;
|
|
27
|
+
|
|
28
|
+
// ── CC stdin JSON (from caller) ─────────────────────────────────────────────
|
|
29
|
+
const CC_JSON = typeof ccJsonInput === 'string' ? ccJsonInput : '';
|
|
30
|
+
|
|
31
|
+
if (process.env.MIXDOG_STATUSLINE_TRACE && CC_JSON && process.env.CLAUDE_PLUGIN_DATA) {
|
|
32
|
+
try {
|
|
33
|
+
fs.writeFileSync(
|
|
34
|
+
path.join(process.env.CLAUDE_PLUGIN_DATA, 'statusline-stdin.json'),
|
|
35
|
+
CC_JSON
|
|
36
|
+
);
|
|
37
|
+
} catch {}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (process.env.MIXDOG_STATUSLINE_TRACE) {
|
|
41
|
+
try {
|
|
42
|
+
const traceFile = path.join(
|
|
43
|
+
os.homedir(), '.claude', 'plugins', 'data', 'mixdog-trib-plugin', 'statusline-trace.log'
|
|
44
|
+
);
|
|
45
|
+
const st = fs.statSync(traceFile);
|
|
46
|
+
if (st.size > 5 * 1024 * 1024) fs.writeFileSync(traceFile, '');
|
|
47
|
+
} catch {}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ── helpers ────────────────────────────────────────────────────────────────
|
|
51
|
+
function extract(json, re) {
|
|
52
|
+
const m = re.exec(json);
|
|
53
|
+
return m ? m[1] : '';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function slice(json, key, stopKey) {
|
|
57
|
+
const idx = json.indexOf(key);
|
|
58
|
+
if (idx < 0) return null;
|
|
59
|
+
const tail = json.slice(idx + key.length);
|
|
60
|
+
if (stopKey) {
|
|
61
|
+
const stop = tail.indexOf(stopKey);
|
|
62
|
+
return stop >= 0 ? tail.slice(0, stop) : tail;
|
|
63
|
+
}
|
|
64
|
+
return tail;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ── Extract CC fields ──────────────────────────────────────────────────────
|
|
68
|
+
let CC_MODEL = extract(CC_JSON, /"display_name"\s*:\s*"([^"]+)"/);
|
|
69
|
+
let CC_CTX_USED = '';
|
|
70
|
+
let CC_RL_5H = '';
|
|
71
|
+
let CC_RL_7D = '';
|
|
72
|
+
let CC_RL_5H_RESET = '';
|
|
73
|
+
|
|
74
|
+
const ctxTail = slice(CC_JSON, '"context_window"', '"rate_limits"');
|
|
75
|
+
if (ctxTail !== null) {
|
|
76
|
+
CC_CTX_USED = extract(ctxTail, /"used_percentage"\s*:\s*([0-9.]+)/);
|
|
77
|
+
}
|
|
78
|
+
const fiveTail = slice(CC_JSON, '"five_hour"', '"seven_day"');
|
|
79
|
+
if (fiveTail !== null) {
|
|
80
|
+
CC_RL_5H = extract(fiveTail, /"used_percentage"\s*:\s*([0-9.]+)/);
|
|
81
|
+
CC_RL_5H_RESET = extract(fiveTail, /"resets_at"\s*:\s*([0-9]+)/);
|
|
82
|
+
}
|
|
83
|
+
const sevenTail = slice(CC_JSON, '"seven_day"', null);
|
|
84
|
+
if (sevenTail !== null) {
|
|
85
|
+
CC_RL_7D = extract(sevenTail, /"used_percentage"\s*:\s*([0-9.]+)/);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
let CC_EFFORT = extract(CC_JSON, /"effort"\s*:\s*\{[^}]*"level"\s*:\s*"([^"]+)"/);
|
|
89
|
+
if (!CC_EFFORT) CC_EFFORT = process.env.CLAUDE_CODE_EFFORT_LEVEL || '';
|
|
90
|
+
if (!CC_EFFORT) {
|
|
91
|
+
try {
|
|
92
|
+
const settingsRaw = fs.readFileSync(
|
|
93
|
+
path.join(os.homedir(), '.claude', 'settings.json'), 'utf8'
|
|
94
|
+
);
|
|
95
|
+
CC_EFFORT = extract(settingsRaw, /"effortLevel"\s*:\s*"([^"]+)"/);
|
|
96
|
+
} catch {}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const CC_SESSION_ID = extract(CC_JSON, /"session_id"\s*:\s*"([^"]+)"/);
|
|
100
|
+
const STATUS_ARGS = (() => {
|
|
101
|
+
try {
|
|
102
|
+
const parsed = JSON.parse(CC_JSON);
|
|
103
|
+
return Array.isArray(parsed?._args) ? parsed._args.map(String) : [];
|
|
104
|
+
} catch { return []; }
|
|
105
|
+
})();
|
|
106
|
+
function statusArg(prefix) {
|
|
107
|
+
return STATUS_ARGS.find(arg => arg.startsWith(prefix))?.slice(prefix.length) || '';
|
|
108
|
+
}
|
|
109
|
+
function positiveInt(value) {
|
|
110
|
+
const n = parseInt(String(value || ''), 10);
|
|
111
|
+
return Number.isFinite(n) && n > 0 ? n : 0;
|
|
112
|
+
}
|
|
113
|
+
const CLIENT_HOST_PID = positiveInt(statusArg('--client-host-pid=')) || positiveInt(process.ppid);
|
|
114
|
+
// Bash-jobs scope pid: ONLY the explicitly passed --client-host-pid (the
|
|
115
|
+
// shim-provided claude.exe pid). No process.ppid fallback here — under a
|
|
116
|
+
// no-shim invocation ppid is the renderer's parent (the daemon/launcher),
|
|
117
|
+
// NOT claude.exe, so falling back would count jobs that merely match that
|
|
118
|
+
// unrelated pid. Absent ⇒ 0 ⇒ the segment attributes nothing.
|
|
119
|
+
const CLIENT_HOST_PID_JOBS = positiveInt(statusArg('--client-host-pid='));
|
|
120
|
+
function advertPidAlive(content) {
|
|
121
|
+
const pid = positiveInt(extract(content, /"pid"\s*:\s*([0-9]+)/));
|
|
122
|
+
if (!pid) return false;
|
|
123
|
+
try { process.kill(pid, 0); return true; } catch { return false; }
|
|
124
|
+
}
|
|
125
|
+
function advertCcMatches(content) {
|
|
126
|
+
return !!(CC_SESSION_ID && content.includes('"cc_session_id"') && content.includes(`"${CC_SESSION_ID}"`));
|
|
127
|
+
}
|
|
128
|
+
function advertClaimed(content) {
|
|
129
|
+
return content.includes('"cc_session_id"');
|
|
130
|
+
}
|
|
131
|
+
function advertClientHostPid(content) {
|
|
132
|
+
return positiveInt(extract(content, /"clientHostPid"\s*:\s*([0-9]+)/))
|
|
133
|
+
|| positiveInt(extract(content, /"client_host_pid"\s*:\s*([0-9]+)/));
|
|
134
|
+
}
|
|
135
|
+
function advertHostMatches(content, { allowUnclaimed = false } = {}) {
|
|
136
|
+
if (!CLIENT_HOST_PID) return true;
|
|
137
|
+
const clientHostPid = advertClientHostPid(content);
|
|
138
|
+
if (clientHostPid) return clientHostPid === CLIENT_HOST_PID;
|
|
139
|
+
if (allowUnclaimed && !advertClaimed(content)) return true;
|
|
140
|
+
const ownerHostPid = positiveInt(extract(content, /"ownerHostPid"\s*:\s*([0-9]+)/));
|
|
141
|
+
return ownerHostPid === CLIENT_HOST_PID;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ── Advert routing ─────────────────────────────────────────────────────────
|
|
145
|
+
let statusAdvert = '';
|
|
146
|
+
let needClaim = false;
|
|
147
|
+
const advertDir = path.join(os.homedir(), '.claude', 'mixdog-status');
|
|
148
|
+
const mappingPath = CC_SESSION_ID
|
|
149
|
+
? path.join(advertDir, `.cc-${CC_SESSION_ID}.path`)
|
|
150
|
+
: '';
|
|
151
|
+
|
|
152
|
+
if (mappingPath) {
|
|
153
|
+
try {
|
|
154
|
+
const cached = fs.readFileSync(mappingPath, 'utf8').trim();
|
|
155
|
+
if (cached) {
|
|
156
|
+
const cachedAdvert = path.isAbsolute(cached) ? cached : path.join(advertDir, cached);
|
|
157
|
+
const advertContent = fs.readFileSync(cachedAdvert, 'utf8');
|
|
158
|
+
if (advertPidAlive(advertContent) && advertCcMatches(advertContent) && advertHostMatches(advertContent)) {
|
|
159
|
+
statusAdvert = cachedAdvert;
|
|
160
|
+
needClaim = false;
|
|
161
|
+
} else {
|
|
162
|
+
try { fs.unlinkSync(mappingPath); } catch {}
|
|
163
|
+
}
|
|
164
|
+
} else {
|
|
165
|
+
try { fs.unlinkSync(mappingPath); } catch {}
|
|
166
|
+
}
|
|
167
|
+
} catch {
|
|
168
|
+
try { fs.unlinkSync(mappingPath); } catch {}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (!statusAdvert) {
|
|
173
|
+
try {
|
|
174
|
+
const files = fs.readdirSync(advertDir)
|
|
175
|
+
.filter(f => f.endsWith('.json'))
|
|
176
|
+
.map(f => path.join(advertDir, f));
|
|
177
|
+
for (const f of files) {
|
|
178
|
+
let content;
|
|
179
|
+
try { content = fs.readFileSync(f, 'utf8'); } catch { continue; }
|
|
180
|
+
if (!advertPidAlive(content)) continue;
|
|
181
|
+
if (advertCcMatches(content)) {
|
|
182
|
+
if (!advertHostMatches(content)) continue;
|
|
183
|
+
statusAdvert = f;
|
|
184
|
+
needClaim = false;
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
if (!statusAdvert && CC_SESSION_ID && !advertClaimed(content) && advertHostMatches(content, { allowUnclaimed: true })) {
|
|
188
|
+
statusAdvert = f;
|
|
189
|
+
needClaim = true;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (!statusAdvert && !CC_SESSION_ID) {
|
|
193
|
+
for (const f of files) {
|
|
194
|
+
try { fs.readFileSync(f, 'utf8'); statusAdvert = f; break; } catch {}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
} catch {}
|
|
198
|
+
if (statusAdvert && mappingPath && !needClaim) {
|
|
199
|
+
try { fs.writeFileSync(mappingPath, statusAdvert); } catch {}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (!statusAdvert && !CC_SESSION_ID) {
|
|
203
|
+
statusAdvert = path.join(os.homedir(), '.claude', 'mixdog-status.json');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ── Read port from advert ──────────────────────────────────────────────────
|
|
207
|
+
let statusPort = '';
|
|
208
|
+
try {
|
|
209
|
+
const advertContent = fs.readFileSync(statusAdvert, 'utf8');
|
|
210
|
+
statusPort = extract(advertContent, /"port"\s*:\s*([0-9]+)/);
|
|
211
|
+
} catch {}
|
|
212
|
+
|
|
213
|
+
if (needClaim && CC_SESSION_ID && statusPort) {
|
|
214
|
+
const claimPayload = { cc_session_id: CC_SESSION_ID };
|
|
215
|
+
if (CLIENT_HOST_PID) claimPayload.client_host_pid = CLIENT_HOST_PID;
|
|
216
|
+
const body = JSON.stringify(claimPayload);
|
|
217
|
+
try {
|
|
218
|
+
const req = http.request({
|
|
219
|
+
hostname: '127.0.0.1',
|
|
220
|
+
port: parseInt(statusPort, 10),
|
|
221
|
+
path: '/register-cc-session',
|
|
222
|
+
method: 'POST',
|
|
223
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) },
|
|
224
|
+
}, (res) => { res.resume(); });
|
|
225
|
+
req.on('error', () => {});
|
|
226
|
+
req.setTimeout(800, () => { try { req.destroy(); } catch {} });
|
|
227
|
+
req.write(body);
|
|
228
|
+
req.end();
|
|
229
|
+
} catch {}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ── Fetch /bridge/status ───────────────────────────────────────────────────
|
|
233
|
+
let bridgeJson = '';
|
|
234
|
+
if (statusPort) {
|
|
235
|
+
bridgeJson = await new Promise(resolve => {
|
|
236
|
+
try {
|
|
237
|
+
const statusUrl = `http://127.0.0.1:${statusPort}/bridge/status?format=statusline-json`
|
|
238
|
+
+ (CLIENT_HOST_PID ? `&clientHostPid=${CLIENT_HOST_PID}` : '');
|
|
239
|
+
const req = http.get(
|
|
240
|
+
statusUrl,
|
|
241
|
+
{ timeout: 500 },
|
|
242
|
+
res => {
|
|
243
|
+
let data = '';
|
|
244
|
+
res.on('data', chunk => { data += chunk; });
|
|
245
|
+
res.on('end', () => resolve(data));
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
req.on('error', () => resolve(''));
|
|
249
|
+
req.on('timeout', () => { req.destroy(); resolve(''); });
|
|
250
|
+
} catch { resolve(''); }
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
if (!bridgeJson.startsWith('{')) bridgeJson = '';
|
|
254
|
+
|
|
255
|
+
if (!bridgeJson && process.env.MIXDOG_STATUSLINE_TRACE) {
|
|
256
|
+
try {
|
|
257
|
+
const traceDir = path.join(os.homedir(), '.claude', 'plugins', 'data', 'mixdog-trib-plugin');
|
|
258
|
+
if (fs.existsSync(traceDir)) {
|
|
259
|
+
const advertPresent = (() => { try { fs.accessSync(statusAdvert); return 'present'; } catch { return 'missing'; } })();
|
|
260
|
+
const ts = new Date().toISOString().replace('T', ' ').slice(0, 19);
|
|
261
|
+
fs.appendFileSync(
|
|
262
|
+
path.join(traceDir, 'statusline-trace.log'),
|
|
263
|
+
`${ts} NOBRIDGE port=${statusPort || '?'} advert=${advertPresent}\n`
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
} catch {}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ── Extract bridge fields ──────────────────────────────────────────────────
|
|
270
|
+
let bSessRoles = '';
|
|
271
|
+
let bSchedNextAt = '';
|
|
272
|
+
let bSchedNextName = '';
|
|
273
|
+
// Worker list carrying running/idle status alongside each tag, surfaced by
|
|
274
|
+
// the aggregator's sessions.workers segment. Falls back to roles (running-
|
|
275
|
+
// only) when an older aggregator payload lacks the workers array.
|
|
276
|
+
let bWorkers = [];
|
|
277
|
+
|
|
278
|
+
if (bridgeJson) {
|
|
279
|
+
const sessRaw = extract(bridgeJson, /"sessions"\s*:\s*\{[^}]*"roles"\s*:\s*\[([^\]]*)\]/);
|
|
280
|
+
if (sessRaw) bSessRoles = sessRaw.replace(/"/g, '').replace(/\s/g, '');
|
|
281
|
+
const workersRaw = extract(bridgeJson, /"workers"\s*:\s*\[([^\]]*)\]/);
|
|
282
|
+
if (workersRaw) {
|
|
283
|
+
// Parse [{"tag":"x","status":"running"},...] without a full JSON.parse
|
|
284
|
+
// of the whole payload (matches the existing regex-extract approach).
|
|
285
|
+
const re = /\{[^}]*?"tag"\s*:\s*"([^"]*)"[^}]*?"status"\s*:\s*"([^"]*)"[^}]*?\}/g;
|
|
286
|
+
let m;
|
|
287
|
+
while ((m = re.exec(workersRaw)) !== null) {
|
|
288
|
+
bWorkers.push({ tag: m[1], status: m[2] === 'idle' ? 'idle' : 'running' });
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
bSchedNextAt = extract(bridgeJson, /"next"\s*:\s*\{[^}]*"fireAt"\s*:\s*([0-9]+)/);
|
|
292
|
+
bSchedNextName = extract(bridgeJson, /"next"\s*:\s*\{[^}]*"name"\s*:\s*"([^"]*)"/);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// ── Format helpers ─────────────────────────────────────────────────────────
|
|
296
|
+
let modelStr = '';
|
|
297
|
+
if (CC_MODEL) {
|
|
298
|
+
let raw = CC_MODEL.replace('(1M context)', '(1M)');
|
|
299
|
+
if (raw.includes('Opus')) modelStr = 'Opus' + raw.slice(raw.indexOf('Opus') + 4);
|
|
300
|
+
else if (raw.includes('Sonnet')) modelStr = 'Sonnet' + raw.slice(raw.indexOf('Sonnet') + 6);
|
|
301
|
+
else if (raw.includes('Haiku')) modelStr = 'Haiku' + raw.slice(raw.indexOf('Haiku') + 5);
|
|
302
|
+
else modelStr = raw;
|
|
303
|
+
}
|
|
304
|
+
const modelShort = modelStr.split(' ')[0];
|
|
305
|
+
const effortStr = CC_EFFORT ? CC_EFFORT.toUpperCase() : '';
|
|
306
|
+
|
|
307
|
+
function roundPct(s) {
|
|
308
|
+
const n = parseFloat(s);
|
|
309
|
+
return Number.isFinite(n) ? Math.round(n) : null;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const ctxInt = roundPct(CC_CTX_USED);
|
|
313
|
+
const rl5hInt = roundPct(CC_RL_5H);
|
|
314
|
+
const rl7dInt = roundPct(CC_RL_7D);
|
|
315
|
+
|
|
316
|
+
function epochMsToHHMM(ms) {
|
|
317
|
+
const d = new Date(parseInt(ms, 10));
|
|
318
|
+
if (isNaN(d.getTime())) return '';
|
|
319
|
+
return d.toLocaleTimeString('sv-SE', { hour: '2-digit', minute: '2-digit', hour12: false });
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const resetStr = CC_RL_5H_RESET ? epochMsToHHMM(CC_RL_5H_RESET * 1000) : '';
|
|
323
|
+
const schedNextHHMM = bSchedNextAt ? epochMsToHHMM(parseInt(bSchedNextAt, 10)) : '';
|
|
324
|
+
|
|
325
|
+
function colourPct(p) {
|
|
326
|
+
if (p >= 90) return `${RED}${p}%${R}`;
|
|
327
|
+
if (p >= 70) return `${YLW}${p}%${R}`;
|
|
328
|
+
return `${GRN}${p}%${R}`;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function makeBar(pct, cells) {
|
|
332
|
+
if (pct === null || cells <= 0) return '';
|
|
333
|
+
let filled = Math.floor(pct * cells / 100);
|
|
334
|
+
if (filled < 0) filled = 0;
|
|
335
|
+
if (filled > cells) filled = cells;
|
|
336
|
+
if (pct > 0 && filled === 0) filled = 1;
|
|
337
|
+
return '▓'.repeat(filled) + '░'.repeat(cells - filled);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// ── Build L1 ───────────────────────────────────────────────────────────────
|
|
341
|
+
const SEP = `${D}│${R}`;
|
|
342
|
+
const l1Parts = [];
|
|
343
|
+
function addL1(seg) { if (seg) l1Parts.push(seg); }
|
|
344
|
+
|
|
345
|
+
if (modelStr) {
|
|
346
|
+
const m = COLS >= 120 ? modelStr : modelShort;
|
|
347
|
+
if (effortStr) {
|
|
348
|
+
addL1(`${CYN}◆${R} ${B}${m}${R} ${D}·${R} ${B}${effortStr}${R}`);
|
|
349
|
+
} else {
|
|
350
|
+
addL1(`${CYN}◆${R} ${B}${m}${R}`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (ctxInt !== null) {
|
|
355
|
+
const fill = ctxInt >= 90 ? RED : ctxInt >= 70 ? YLW : GRN;
|
|
356
|
+
let barOut = '';
|
|
357
|
+
if (COLS >= 120) barOut = makeBar(ctxInt, 14);
|
|
358
|
+
else if (COLS >= 80) barOut = makeBar(ctxInt, 8);
|
|
359
|
+
if (barOut) {
|
|
360
|
+
const filledPart = barOut.replace(/░/g, '');
|
|
361
|
+
const emptyPart = barOut.replace(/▓/g, '');
|
|
362
|
+
const bar = `${fill}${filledPart}${R}${D}${emptyPart}${R}`;
|
|
363
|
+
addL1(`${bar} ${ctxInt}%`);
|
|
364
|
+
} else {
|
|
365
|
+
addL1(`${fill}${ctxInt}%${R}`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
if (rl5hInt !== null) {
|
|
370
|
+
addL1(`${D}5H${R} ${colourPct(rl5hInt)}`);
|
|
371
|
+
}
|
|
372
|
+
if (COLS >= 80) {
|
|
373
|
+
if (rl7dInt !== null) addL1(`${D}7D${R} ${colourPct(rl7dInt)}`);
|
|
374
|
+
if (resetStr) addL1(`${D}↻ ${resetStr}${R}`);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// ── Role classification ────────────────────────────────────────────────────
|
|
378
|
+
let workCount = 0;
|
|
379
|
+
let workOrder = '';
|
|
380
|
+
let hasCycle1 = false;
|
|
381
|
+
let hasCycle2 = false;
|
|
382
|
+
let hasCycle3 = false;
|
|
383
|
+
let hasSched = false;
|
|
384
|
+
let hasWebhook = false;
|
|
385
|
+
let hasExplorer = false;
|
|
386
|
+
|
|
387
|
+
function classifyMaint(role) {
|
|
388
|
+
switch (role) {
|
|
389
|
+
case 'cycle1-agent': hasCycle1 = true; return true;
|
|
390
|
+
case 'cycle2-agent': hasCycle2 = true; return true;
|
|
391
|
+
case 'cycle3-agent': hasCycle3 = true; return true;
|
|
392
|
+
case 'scheduler-task': hasSched = true; return true;
|
|
393
|
+
case 'webhook-handler': hasWebhook = true; return true;
|
|
394
|
+
case 'explorer': hasExplorer = true; return true;
|
|
395
|
+
default: return false;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Idle worker tags (greyed in L2), threaded from the aggregator's
|
|
400
|
+
// sessions.workers[].status. Running user-workers still feed workCount /
|
|
401
|
+
// workOrder so the existing "N Running (tags)" badge is unchanged.
|
|
402
|
+
const idleWorkers = [];
|
|
403
|
+
if (bWorkers.length) {
|
|
404
|
+
// Preferred path: per-worker running/idle status from the aggregator.
|
|
405
|
+
for (const w of bWorkers) {
|
|
406
|
+
if (classifyMaint(w.tag)) continue; // maintenance → L1, not the worker badge
|
|
407
|
+
if (w.status === 'idle') {
|
|
408
|
+
idleWorkers.push(w.tag);
|
|
409
|
+
} else {
|
|
410
|
+
workCount++;
|
|
411
|
+
workOrder = workOrder ? `${workOrder}, ${w.tag}` : w.tag;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
} else if (bSessRoles) {
|
|
415
|
+
// Fallback: legacy roles array (running-only, no idle/status info).
|
|
416
|
+
for (const role of bSessRoles.split(',')) {
|
|
417
|
+
if (!role) continue;
|
|
418
|
+
if (classifyMaint(role)) continue;
|
|
419
|
+
workCount++;
|
|
420
|
+
workOrder = workOrder ? `${workOrder}, ${role}` : role;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const maintParts = [];
|
|
425
|
+
if (hasCycle1) maintParts.push(`${GRN}↻${R} ${B}cycle1${R}`);
|
|
426
|
+
if (hasCycle2) maintParts.push(`${GRN}↻${R} ${B}cycle2${R}`);
|
|
427
|
+
if (hasCycle3) maintParts.push(`${GRN}↻${R} ${B}cycle3${R}`);
|
|
428
|
+
if (hasSched) maintParts.push(`${GRN}↻${R} ${B}scheduler${R}`);
|
|
429
|
+
if (hasWebhook) maintParts.push(`${GRN}↻${R} ${B}webhook${R}`);
|
|
430
|
+
if (hasExplorer) maintParts.push(`${GRN}↻${R} ${B}explorer${R}`);
|
|
431
|
+
if (maintParts.length) addL1(maintParts.join(' '));
|
|
432
|
+
|
|
433
|
+
// Background bash jobs: a running job is a `<jobId>.json` whose sibling
|
|
434
|
+
// `<jobId>.done` (written on exit) is absent. Surviving candidates are then
|
|
435
|
+
// liveness-filtered — the `.json` carries the wrapper `pid`; an orphaned job
|
|
436
|
+
// (wrapper crashed, `.done` never written, pid dead for days) is skipped via
|
|
437
|
+
// process.kill(pid, 0). Bounded per tick: candidates are ordered newest-first
|
|
438
|
+
// (the jobId embeds its spawn Date.now()) and at most JOB_SCAN_CAP of them are
|
|
439
|
+
// read — keeping each render O(cap), not O(total on-disk jobs). When the scan
|
|
440
|
+
// is truncated a trailing `+` overflow marker is appended to the count. One
|
|
441
|
+
// readFileSync/statSync per scanned job for the oldest startedAt (the .json is
|
|
442
|
+
// written at job start); tolerate the dir being missing and never throw.
|
|
443
|
+
const JOB_SCAN_CAP = 30;
|
|
444
|
+
const bashJobsSeg = (() => {
|
|
445
|
+
try {
|
|
446
|
+
const dir = path.join(os.homedir(), '.claude', 'plugins', 'data', 'mixdog-trib-plugin', 'shell-jobs');
|
|
447
|
+
const names = fs.readdirSync(dir);
|
|
448
|
+
const done = new Set();
|
|
449
|
+
const jobs = [];
|
|
450
|
+
const ownerByJob = new Map();
|
|
451
|
+
for (const n of names) {
|
|
452
|
+
if (n.endsWith('.done')) done.add(n.slice(0, -5));
|
|
453
|
+
else if (n.endsWith('.json')) jobs.push(n.slice(0, -5));
|
|
454
|
+
else {
|
|
455
|
+
// Owner sidecar `<jobId>.owner-<pid>` — a zero-byte marker whose NAME
|
|
456
|
+
// carries the owning CC host pid, written next to the .json at spawn.
|
|
457
|
+
const i = n.lastIndexOf('.owner-');
|
|
458
|
+
if (i > 0) { const pid = positiveInt(n.slice(i + 7)); if (pid) ownerByJob.set(n.slice(0, i), pid); }
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
// Owner-filter BEFORE the scan cap, from the directory listing alone: each
|
|
462
|
+
// job's owning claude.exe pid is read from its `.owner-<pid>` marker name
|
|
463
|
+
// (no JSON read), so another session's newer jobs can never evict ours at
|
|
464
|
+
// the cap. Only jobs whose marker pid equals THIS statusline's
|
|
465
|
+
// --client-host-pid survive; legacy jobs without a marker — and every job
|
|
466
|
+
// when no host pid was passed (CLIENT_HOST_PID_JOBS absent) — are excluded.
|
|
467
|
+
// Then ordered newest-first by the spawn timestamp embedded in
|
|
468
|
+
// `job_<ms>_<rand>`, so truncation drops only this session's oldest tail.
|
|
469
|
+
const jobStampMs = (id) => { const m = /^job_(\d+)/.exec(id); return m ? Number(m[1]) : 0; };
|
|
470
|
+
const candidates = jobs
|
|
471
|
+
.filter((id) => !done.has(id) && CLIENT_HOST_PID_JOBS && ownerByJob.get(id) === CLIENT_HOST_PID_JOBS)
|
|
472
|
+
.sort((a, b) => jobStampMs(b) - jobStampMs(a));
|
|
473
|
+
if (candidates.length === 0) return '';
|
|
474
|
+
const scan = candidates.slice(0, JOB_SCAN_CAP);
|
|
475
|
+
const truncated = candidates.length > JOB_SCAN_CAP;
|
|
476
|
+
let count = 0;
|
|
477
|
+
let oldestMs = Infinity;
|
|
478
|
+
for (const id of scan) {
|
|
479
|
+
const p = path.join(dir, `${id}.json`);
|
|
480
|
+
let pid, tmo, enforced;
|
|
481
|
+
try {
|
|
482
|
+
const d = JSON.parse(fs.readFileSync(p, 'utf-8'));
|
|
483
|
+
pid = d.pid; tmo = Number(d.timeoutMs);
|
|
484
|
+
// Runtime enforcement proof: PS records timeoutEnforced:true; the
|
|
485
|
+
// posix wrapper touches <id>.enforced iff its `timeout` branch ran.
|
|
486
|
+
enforced = d.timeoutEnforced === true || fs.existsSync(path.join(dir, `${id}.enforced`));
|
|
487
|
+
}
|
|
488
|
+
catch { continue; } // unreadable/unparseable → skip
|
|
489
|
+
let st;
|
|
490
|
+
try { st = fs.statSync(p); }
|
|
491
|
+
catch { continue; }
|
|
492
|
+
// Deadline: the wrapper force-kills at timeoutMs, so a job older than
|
|
493
|
+
// timeoutMs + grace is dead even when its pid was recycled by an
|
|
494
|
+
// unrelated live process (pid-reuse-proof, mirrors the sweep). Trusted
|
|
495
|
+
// only when the record proves in-wrapper enforcement (timeoutEnforced).
|
|
496
|
+
if (enforced && Number.isFinite(tmo) && tmo > 0 && (Date.now() - st.mtimeMs) > tmo + 30 * 60_000) continue;
|
|
497
|
+
// kill(0, 0) probes the whole process group and "succeeds" — a
|
|
498
|
+
// malformed pid (0, "", []) must be rejected before the probe.
|
|
499
|
+
pid = Number(pid);
|
|
500
|
+
if (!Number.isInteger(pid) || pid <= 0) continue;
|
|
501
|
+
// Liveness: process.kill(pid, 0) succeeds or throws EPERM → alive;
|
|
502
|
+
// ESRCH/invalid pid → dead → skip.
|
|
503
|
+
let alive = false;
|
|
504
|
+
try { process.kill(pid, 0); alive = true; }
|
|
505
|
+
catch (e) { alive = e && e.code === 'EPERM'; }
|
|
506
|
+
if (!alive) continue;
|
|
507
|
+
count++;
|
|
508
|
+
if (st.mtimeMs < oldestMs) oldestMs = st.mtimeMs;
|
|
509
|
+
}
|
|
510
|
+
if (count === 0) return '';
|
|
511
|
+
let elapsed = '';
|
|
512
|
+
if (Number.isFinite(oldestMs)) {
|
|
513
|
+
const secs = Math.max(0, Math.floor((Date.now() - oldestMs) / 1000));
|
|
514
|
+
elapsed = secs < 60 ? ` ${secs}s` : ` ${Math.floor(secs / 60)}m`;
|
|
515
|
+
}
|
|
516
|
+
// `+` overflow marker: more live/recent candidates existed than the
|
|
517
|
+
// per-tick scan cap, so the rendered count is a floor, not the ground.
|
|
518
|
+
const overflow = truncated ? '+' : '';
|
|
519
|
+
return `${GREY}⚙ bash:${count}${overflow}${elapsed}${R}`;
|
|
520
|
+
} catch { return ''; }
|
|
521
|
+
})();
|
|
522
|
+
if (bashJobsSeg) addL1(bashJobsSeg);
|
|
523
|
+
|
|
524
|
+
// ── Build L2 ───────────────────────────────────────────────────────────────
|
|
525
|
+
const l2Parts = [];
|
|
526
|
+
function addL2(seg) { if (seg) l2Parts.push(seg); }
|
|
527
|
+
|
|
528
|
+
if (workCount > 0 && workOrder) {
|
|
529
|
+
addL2(`${GRN}●${R} ${B}${workCount} Running${R} ${D}(${R}${CYN}${workOrder}${R}${D})${R}`);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
if (idleWorkers.length) {
|
|
533
|
+
// Idle workers: filled grey dot (●) + explicit 'idle' marker + tag list.
|
|
534
|
+
// Filled (not hollow ○) so the glyph matches the running ● weight; only
|
|
535
|
+
// the colour (grey vs green) distinguishes idle from running.
|
|
536
|
+
const idleTags = idleWorkers.join(', ');
|
|
537
|
+
addL2(`${GREY}● ${idleWorkers.length} idle (${idleTags})${R}`);
|
|
538
|
+
}
|
|
539
|
+
if (bSchedNextName && schedNextHHMM) {
|
|
540
|
+
addL2(`${YLW}⏰${R} ${B}${bSchedNextName}${R} ${D}${schedNextHHMM}${R}`);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
const l1 = l1Parts.join(` ${SEP} `) || 'mixdog';
|
|
544
|
+
let l2 = l2Parts.join(` ${SEP} `);
|
|
545
|
+
if (l2 === 'Idle') l2 = '';
|
|
546
|
+
|
|
547
|
+
let out = l1 + '\n';
|
|
548
|
+
if (l2) out += l2 + '\n';
|
|
549
|
+
return out;
|
|
550
|
+
}
|