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,89 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import { getDestructiveCommandWarning } from './destructive-warning.mjs';
|
|
4
|
+
import { isBlockedCommand, WRAPPER_NAMES } from './shell-policy.mjs';
|
|
5
|
+
|
|
6
|
+
/** @typedef {'allow'|'warn-prompt'|'deny'} ExecPolicyDecision */
|
|
7
|
+
|
|
8
|
+
const EXEC_POLICY_DENY_PATTERNS = [
|
|
9
|
+
/\b(curl|wget|fetch|Invoke-WebRequest|iwr)\b[^\n|&;]*\|[^\n|&;]*\b(sh|bash|zsh|dash|pwsh|powershell)(?:\.exe)?\b/i,
|
|
10
|
+
/\|\s*(sh|bash|zsh|dash|pwsh|powershell)(?:\.exe)?\b/i,
|
|
11
|
+
/\b(?:sh|bash|zsh|dash|pwsh|powershell)(?:\.exe)?\s+<\s*\(/i,
|
|
12
|
+
/\bInvoke-Expression\b/i,
|
|
13
|
+
/\biex\s+/i,
|
|
14
|
+
/\bStart-Process\b[^\n]*\b-Verb\s+RunAs\b/i,
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const EXEC_POLICY_DENY_COMMANDS = new Set([
|
|
18
|
+
'dd', 'diskpart', 'shutdown', 'reboot', 'halt', 'poweroff', 'init', 'telinit',
|
|
19
|
+
'mkfs', 'mkfs.ext4', 'mkfs.ntfs', 'format', 'fdisk', 'parted',
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
const _POLICY_RANK = { allow: 0, 'warn-prompt': 1, deny: 2 };
|
|
23
|
+
|
|
24
|
+
function _firstCommandName(command) {
|
|
25
|
+
const seg = String(command || '').split(/[;&|\n]+/)[0] || '';
|
|
26
|
+
const tokens = seg.trim().split(/\s+/).filter(Boolean);
|
|
27
|
+
let i = 0;
|
|
28
|
+
while (i < tokens.length) {
|
|
29
|
+
const t = tokens[i];
|
|
30
|
+
if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(t)) { i++; continue; }
|
|
31
|
+
if (WRAPPER_NAMES.has(t.toLowerCase())) {
|
|
32
|
+
i++;
|
|
33
|
+
while (i < tokens.length && (/^[-+]/.test(tokens[i]) || /^\d+[smhd]?$/.test(tokens[i]))) i++;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const base = t.replace(/^.*[\\/]/, '').toLowerCase();
|
|
37
|
+
return base.replace(/\.(exe|cmd|bat|com)$/i, '');
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function classifyExecPolicy(command) {
|
|
43
|
+
const text = String(command || '');
|
|
44
|
+
if (!text.trim()) return { decision: 'allow', reason: '' };
|
|
45
|
+
if (isBlockedCommand(text)) {
|
|
46
|
+
return { decision: 'deny', reason: 'destructive or system-destabilising pattern (hard block)' };
|
|
47
|
+
}
|
|
48
|
+
for (const pat of EXEC_POLICY_DENY_PATTERNS) {
|
|
49
|
+
if (pat.test(text)) {
|
|
50
|
+
return { decision: 'deny', reason: 'high-risk shell invocation (pipe-to-shell, elevated launcher, or remote-exec pattern)' };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const name = _firstCommandName(text);
|
|
54
|
+
if (name && EXEC_POLICY_DENY_COMMANDS.has(name)) {
|
|
55
|
+
return { decision: 'deny', reason: `command "${name}" is not permitted without sandbox` };
|
|
56
|
+
}
|
|
57
|
+
const warn = getDestructiveCommandWarning(text);
|
|
58
|
+
if (warn) {
|
|
59
|
+
return { decision: 'warn-prompt', reason: warn };
|
|
60
|
+
}
|
|
61
|
+
return { decision: 'allow', reason: '' };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function mergeExecPolicyDecisions(a, b) {
|
|
65
|
+
const left = a && a.decision ? a : { decision: 'allow', reason: '' };
|
|
66
|
+
const right = b && b.decision ? b : { decision: 'allow', reason: '' };
|
|
67
|
+
if (_POLICY_RANK[right.decision] > _POLICY_RANK[left.decision]) return right;
|
|
68
|
+
if (_POLICY_RANK[right.decision] < _POLICY_RANK[left.decision]) return left;
|
|
69
|
+
return right.reason ? right : left;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function evaluateExecPolicyFromTargets(targets) {
|
|
73
|
+
let worst = { decision: 'allow', reason: '' };
|
|
74
|
+
for (const t of targets || []) {
|
|
75
|
+
if (typeof t !== 'string' || !t) continue;
|
|
76
|
+
worst = mergeExecPolicyDecisions(worst, classifyExecPolicy(t));
|
|
77
|
+
if (worst.decision === 'deny') break;
|
|
78
|
+
}
|
|
79
|
+
return worst;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Pre-spawn block message — deny only. warn-prompt is non-blocking (see destructive-warning prepend). */
|
|
83
|
+
export function formatExecPolicyBlockMessage(policyResult) {
|
|
84
|
+
const r = policyResult || { decision: 'allow' };
|
|
85
|
+
if (r.decision === 'deny') {
|
|
86
|
+
return `Error: command blocked by exec policy${r.reason ? ` — ${r.reason}` : ''}`;
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/** Catastrophic delete targets (shared rm / Remove-Item / del guards). */
|
|
4
|
+
export function isDangerousDeleteTarget(rawTarget) {
|
|
5
|
+
if (rawTarget == null) return false;
|
|
6
|
+
const t = String(rawTarget).trim().replace(/^['"]|['"]$/g, '').trim();
|
|
7
|
+
if (t === '') return false;
|
|
8
|
+
if (t === '*' || t === '.' || t === './' || t === '.\\' || t === '.*') return true;
|
|
9
|
+
const low = t.toLowerCase();
|
|
10
|
+
if (/^\$home(\b|[\\/])/.test(low)) return true;
|
|
11
|
+
if (/^\$env:(userprofile|homepath|home|homedrive|systemroot|windir|programfiles|programdata|systemdrive|allusersprofile|public|appdata|localappdata)\b/.test(low)) return true;
|
|
12
|
+
if (/^%(userprofile|homepath|home|homedrive|systemroot|windir|programfiles|programdata|systemdrive|allusersprofile|public|appdata|localappdata)%/i.test(t)) return true;
|
|
13
|
+
if (/^\$\{(home|userprofile|homepath|homedrive|systemroot|windir|programfiles|programdata|systemdrive)\}/i.test(t)) return true;
|
|
14
|
+
if (/^\$\(home\)/i.test(t)) return true;
|
|
15
|
+
if (/^\\\\[^\\]+\\[^\\]+\\\*?$/.test(t) || /^\\\\[^\\]+\\[^\\]*$/.test(t)) return true;
|
|
16
|
+
if (t.startsWith('$') || t.includes('$(') || /^%[^%]*%/.test(t)) return false;
|
|
17
|
+
if (t === '~' || t.startsWith('~/') || t.startsWith('~\\')) return true;
|
|
18
|
+
if (t === '/' || t === '\\') return true;
|
|
19
|
+
if (t === '/*' || t === '\\*' || t === '/.' || t === '/*.*') return true;
|
|
20
|
+
const unix = t.replace(/\\/g, '/').replace(/\/+$/, '').toLowerCase();
|
|
21
|
+
if (/^\/(etc|usr|bin|sbin|lib|lib64|boot|sys|proc|dev|root|var|home|opt|srv|system|library|applications|users|private|volumes)(\/\*)?$/.test(unix)) return true;
|
|
22
|
+
const win = t.replace(/\//g, '\\').replace(/\\+$/, '').toLowerCase();
|
|
23
|
+
if (/^[a-z]:$/.test(win)) return true;
|
|
24
|
+
if (/^[a-z]:\\\*/.test(win)) return true;
|
|
25
|
+
if (/^[a-z]:\\(windows|program files( \(x86\))?|programdata|users)$/.test(win)) return true;
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import { isDangerousDeleteTarget as _isDangerousDeleteTarget } from './shell-policy-danger-target.mjs';
|
|
4
|
+
export { isDangerousDeleteTarget } from './shell-policy-danger-target.mjs';
|
|
5
|
+
// Shell execution security policy — shared constants used by both
|
|
6
|
+
// destructive-warning.mjs (heuristic classifier) and bash-session.mjs
|
|
7
|
+
// (hard block list). Centralised here so the two files stay in sync
|
|
8
|
+
// without requiring manual "drift should be fixed in BOTH files" notes.
|
|
9
|
+
//
|
|
10
|
+
// These are documented security-policy allowlists, not heuristic
|
|
11
|
+
// classifiers: membership is explicit and reviewed on addition.
|
|
12
|
+
|
|
13
|
+
// Shells whose `-c` payloads must be recursively scanned for destructive
|
|
14
|
+
// commands. Expand when a new shell interpreter is supported.
|
|
15
|
+
export const SHELL_NAMES = new Set([
|
|
16
|
+
'bash', 'sh', 'zsh', 'dash', 'ksh', 'ash',
|
|
17
|
+
]);
|
|
18
|
+
|
|
19
|
+
// Wrapper programs that transparently exec their first non-option argument.
|
|
20
|
+
// We peel these (and their option args) before reading the real command name.
|
|
21
|
+
export const WRAPPER_NAMES = new Set([
|
|
22
|
+
'env', 'sudo', 'doas', 'nice', 'stdbuf', 'chronic', 'time', 'timeout',
|
|
23
|
+
'nohup', 'setpriv', 'ionice', 'taskset',
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
// Hard-block patterns shared by the stateless bash tool (builtin.mjs) and
|
|
27
|
+
// the persistent bash_session tool (bash-session.mjs). Adding a pattern
|
|
28
|
+
// here propagates to both without manual sync.
|
|
29
|
+
//
|
|
30
|
+
// These block outright data-destructive or system-destabilising operations
|
|
31
|
+
// that the agent must never execute regardless of context. Informational
|
|
32
|
+
// warnings (non-blocking) live in destructive-warning.mjs instead.
|
|
33
|
+
// A command-runner wrapper (sudo, env, timeout, …) or VAR=val assignment may
|
|
34
|
+
// precede the real command. A destructive verb following such a peeled wrapper
|
|
35
|
+
// chain is still at command position, so `sudo shutdown` / `env timeout 5 dd …`
|
|
36
|
+
// stay hard-blocked, while a bare prose token before the verb (e.g. "graceful
|
|
37
|
+
// shutdown" in a commit message) does NOT satisfy command position and passes.
|
|
38
|
+
// Wrapper names are sourced from WRAPPER_NAMES above so this path and the
|
|
39
|
+
// destructive-warning peeler cannot drift apart. Each chain unit ends in \s+
|
|
40
|
+
// (no zero-width iteration) so the nested quantifier cannot backtrack-blow.
|
|
41
|
+
const _WRAP_CHAIN =
|
|
42
|
+
'(?:' +
|
|
43
|
+
'(?:[A-Za-z_]\\w*=\\S*\\s+)' +
|
|
44
|
+
'|(?:(?:' + [...WRAPPER_NAMES].join('|') + ')\\s+(?:(?:[-+]\\S*|\\d+[smhd]?|\\d+m\\d+s?)\\s+)*)' +
|
|
45
|
+
')*';
|
|
46
|
+
const _CMD_START = '(?:^|[;&|\\n(){}]\\s*|\\$[\\({]\\s*|[<>]\\(\\s*|`\\s*)' + _WRAP_CHAIN;
|
|
47
|
+
// Wrapper chain for the token-level rm guard. Same shape as _WRAP_CHAIN
|
|
48
|
+
// (backtrack-safe: every unit ends in \s+) but also peels `command`, the
|
|
49
|
+
// bash builtin that execs its first non-option argument. Lets the rm guard
|
|
50
|
+
// see `sudo rm -r -f /`, `env X=1 rm -r -f ~`, `timeout 5 rm -rf /`, etc.
|
|
51
|
+
const _RM_WRAP_CHAIN =
|
|
52
|
+
'(?:' +
|
|
53
|
+
'(?:[A-Za-z_]\\w*=\\S*\\s+)' +
|
|
54
|
+
'|(?:(?:' + [...WRAPPER_NAMES, 'command'].join('|') + ')\\s+(?:(?:[-+]\\S*|\\d+[smhd]?|\\d+m\\d+s?)\\s+)*)' +
|
|
55
|
+
')*';
|
|
56
|
+
const BLOCKED_PATTERNS = [
|
|
57
|
+
// Recursive deletes (bash `rm -rf`, PowerShell `Remove-Item -Recurse -Force`,
|
|
58
|
+
// cmd `del /s` / `rd /s`) are NOT blocked outright — each is target-checked
|
|
59
|
+
// by a dedicated guard below via _isDangerousDeleteTarget, blocking only
|
|
60
|
+
// filesystem-root / home / top-level-system / whole-cwd targets (CC-level).
|
|
61
|
+
// `git reset --hard` is likewise no longer hard-blocked (CC prompts; the
|
|
62
|
+
// agent workflow already gates destructive git ops).
|
|
63
|
+
// Bare `git push --force` (and `--force=`) still blocks; the safer
|
|
64
|
+
// `--force-with-lease` / `--force-if-includes` variants pass.
|
|
65
|
+
/\bgit\s+push\b[^\n]*?\s--force(?![\w-])/i,
|
|
66
|
+
/\bformat\s+[a-z]:/i,
|
|
67
|
+
new RegExp(_CMD_START + '(?:shutdown|reboot|halt)\\b', 'i'),
|
|
68
|
+
new RegExp(_CMD_START + 'mkfs(?:\\.|\\b)', 'i'),
|
|
69
|
+
new RegExp(_CMD_START + 'dd\\s+[^\\n]*\\b(?:if|of)=/dev/', 'i'),
|
|
70
|
+
new RegExp(_CMD_START + 'diskpart\\b[^\\n]*\\bclean\\b', 'i'),
|
|
71
|
+
/:\(\)\s*\{[^}]*:\|:&[^}]*\};\s*:/, // bash fork-bomb signature
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
// PowerShell `-EncodedCommand <base64>` (also `-enc`, `-e` short forms)
|
|
75
|
+
// transparently runs a UTF-16LE/base64 script that bypasses the literal-text
|
|
76
|
+
// BLOCKED_PATTERNS scan. Recognise the flag, decode the payload, and re-test
|
|
77
|
+
// the decoded text so a `powershell -EncodedCommand <Remove-Item ...>` smuggle
|
|
78
|
+
// still hits the policy. Bad base64 / decode failure falls through silently
|
|
79
|
+
// — the original literal scan still applies.
|
|
80
|
+
// Option names accept PowerShell's unambiguous prefix abbreviations so that
|
|
81
|
+
// `-nop` (NoProfile), `-nol` (NoLogo), `-noni` (NonInteractive), `-ep`
|
|
82
|
+
// (ExecutionPolicy), `-w hidden` (WindowStyle), etc. preceding the encoded
|
|
83
|
+
// flag no longer make the regex miss and skip decoding. Widening the option
|
|
84
|
+
// whitelist only makes more payloads get decoded + re-scanned; it never lets
|
|
85
|
+
// a previously-blocked command through.
|
|
86
|
+
const _ENCODED_CMD_RE = /(?:^|\s)(?:powershell(?:\.exe)?|pwsh(?:\.exe)?)\s+(?:[-/](?:NoP(?:rofile)?|NoL(?:ogo)?|NonI(?:nteractive)?|Sta|Mta|(?:ExecutionPolicy|Ep|Ex)\s+\S+|(?:WindowStyle|Win|W)\s+\S+|(?:InputFormat|Inp|If)\s+\S+|(?:OutputFormat|Out|Of)\s+\S+|Command|(?:File|Fi)\s+\S+|(?:Version|Ver)\s+\S+)\s+)*[-/](?:EncodedCommand|enc|e)\s+["']?([A-Za-z0-9+/=]+)["']?/gi;
|
|
87
|
+
function _decodePowerShellEncodedCommand(command) {
|
|
88
|
+
const cmd = String(command || '');
|
|
89
|
+
// Scan ALL -EncodedCommand occurrences (quoted or unquoted) so a chained
|
|
90
|
+
// payload like `powershell -enc A...; powershell -enc B...` exposes both
|
|
91
|
+
// decoded scripts to BLOCKED_PATTERNS. PowerShell -EncodedCommand expects
|
|
92
|
+
// UTF-16LE. Bad base64 / decode failure is skipped silently per match.
|
|
93
|
+
const decoded = [];
|
|
94
|
+
for (const m of cmd.matchAll(_ENCODED_CMD_RE)) {
|
|
95
|
+
try {
|
|
96
|
+
const buf = Buffer.from(m[1], 'base64');
|
|
97
|
+
decoded.push(buf.toString('utf16le'));
|
|
98
|
+
} catch { /* skip bad base64 */ }
|
|
99
|
+
}
|
|
100
|
+
return decoded.length > 0 ? decoded.join('\n') : null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Shared decode for policy scan targets (hard-block + destructive warnings).
|
|
104
|
+
export function decodePowerShellEncodedCommand(command) {
|
|
105
|
+
return _decodePowerShellEncodedCommand(command);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Shared catastrophic-delete target test — see shell-policy-danger-target.mjs
|
|
109
|
+
|
|
110
|
+
// Token-level rm guard. BLOCKED_PATTERNS catches inline split-flag forms
|
|
111
|
+
// (`rm -rf /`, `rm -r -f /`, `rm -fr /`), but the regex misses arbitrary
|
|
112
|
+
// flag interleaving (`rm -r -f -v /`, `rm -v -r -f /`). Tokenise rm args
|
|
113
|
+
// and block any recursive+force combination whose target resolves to
|
|
114
|
+
// root, home, or $HOME — independent of flag order or extra options.
|
|
115
|
+
function _rmRecursiveForceUnsafe(command) {
|
|
116
|
+
const text = String(command || '');
|
|
117
|
+
const RM_RE = new RegExp('(?:^|[;&|\\n(){}]\\s*|\\$[\\({]\\s*|`\\s*)' + _RM_WRAP_CHAIN + '\\brm\\s+([^|;&\\n`)]+)', 'gi');
|
|
118
|
+
for (const m of text.matchAll(RM_RE)) {
|
|
119
|
+
const args = m[1].split(/\s+/).filter(Boolean);
|
|
120
|
+
let recursive = false;
|
|
121
|
+
let force = false;
|
|
122
|
+
const targets = [];
|
|
123
|
+
let endOfOpts = false;
|
|
124
|
+
for (const arg of args) {
|
|
125
|
+
if (endOfOpts) { targets.push(arg); continue; }
|
|
126
|
+
if (arg === '--') { endOfOpts = true; continue; }
|
|
127
|
+
if (arg === '--recursive') { recursive = true; continue; }
|
|
128
|
+
if (arg === '--force') { force = true; continue; }
|
|
129
|
+
if (/^-[a-zA-Z]+$/.test(arg)) {
|
|
130
|
+
if (/[rR]/.test(arg)) recursive = true;
|
|
131
|
+
if (/[fF]/.test(arg)) force = true;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (arg.startsWith('-')) continue;
|
|
135
|
+
targets.push(arg);
|
|
136
|
+
}
|
|
137
|
+
if (!(recursive && force)) continue;
|
|
138
|
+
for (const t of targets) {
|
|
139
|
+
if (_isDangerousDeleteTarget(t)) return true;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// PowerShell `Remove-Item -Recurse -Force` target guard. Uses the shared
|
|
146
|
+
// _isDangerousDeleteTarget test (parity with the bash rm guard): blocks only
|
|
147
|
+
// root / home / top-level-system / whole-cwd targets, plus a MISSING target.
|
|
148
|
+
// Generic variables ($x, $env:TEMP) are allowed (CC-level) — only known
|
|
149
|
+
// home/system env vars are treated as dangerous.
|
|
150
|
+
// -Force is matched at its minimum unambiguous PowerShell prefix `-fo` (NOT
|
|
151
|
+
// bare `-f`, which is ambiguous with -Filter); -Recurse matches `-r`/`-rec`.
|
|
152
|
+
function _removeItemRecursiveForceUnsafe(command) {
|
|
153
|
+
const text = String(command || '');
|
|
154
|
+
const RI_RE = /(?:^|[;&|\n(){}]\s*|`\s*)\s*(?:Remove-Item|ri|rm|rmdir|rd|del|erase)\b([^\n;|]*)/gi;
|
|
155
|
+
for (const m of text.matchAll(RI_RE)) {
|
|
156
|
+
const toks = m[1].split(/\s+/).filter(Boolean);
|
|
157
|
+
let recursive = false;
|
|
158
|
+
let force = false;
|
|
159
|
+
const targets = [];
|
|
160
|
+
for (let i = 0; i < toks.length; i += 1) {
|
|
161
|
+
const low = toks[i].toLowerCase();
|
|
162
|
+
if (low.startsWith('-')) {
|
|
163
|
+
if (/^-r(ec(urse)?)?$/.test(low)) { recursive = true; continue; }
|
|
164
|
+
if (/^-r(ec(urse)?)?:\$true$/i.test(low)) { recursive = true; continue; }
|
|
165
|
+
if (/^-fo(rce)?$/.test(low)) { force = true; continue; }
|
|
166
|
+
if (/^-fo(rce)?:\$true$/i.test(low)) { force = true; continue; }
|
|
167
|
+
if (low === '-path' || low === '-literalpath' || low === '-lp') {
|
|
168
|
+
if (toks[i + 1] !== undefined) { targets.push(toks[i + 1]); i += 1; }
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
continue; // unrelated switch
|
|
172
|
+
}
|
|
173
|
+
targets.push(toks[i]);
|
|
174
|
+
}
|
|
175
|
+
if (!(recursive && force)) continue;
|
|
176
|
+
if (targets.length === 0) return true; // recursive+force with no target
|
|
177
|
+
for (const raw of targets) {
|
|
178
|
+
const parts = raw.replace(/^@\(/, '').replace(/\)$/, '').split(',');
|
|
179
|
+
for (const p0 of parts) {
|
|
180
|
+
if (_isDangerousDeleteTarget(p0)) return true;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// cmd.exe recursive delete guard: `del /s [..] <path>`, `rd /s [..] <path>`,
|
|
188
|
+
// `rmdir /s <path>`. Only the recursive `/s` form is dangerous (plain `rd`
|
|
189
|
+
// removes empty dirs only; plain `del` is non-recursive), so we block solely
|
|
190
|
+
// when `/s` is present AND the target is catastrophic (via the shared
|
|
191
|
+
// _isDangerousDeleteTarget) or missing. Safe concrete paths pass (CC-level).
|
|
192
|
+
function _cmdRecursiveDeleteUnsafe(command) {
|
|
193
|
+
const text = String(command || '');
|
|
194
|
+
const RE = /(?:^|[;&|\n(){}]\s*|`\s*)\s*(?:del|erase|rd|rmdir)\b([^\n;|&]*)/gi;
|
|
195
|
+
for (const m of text.matchAll(RE)) {
|
|
196
|
+
const toks = m[1].split(/\s+/).filter(Boolean);
|
|
197
|
+
let recursive = false;
|
|
198
|
+
const targets = [];
|
|
199
|
+
for (const tk of toks) {
|
|
200
|
+
if (tk.startsWith('/')) { // cmd switch: /s /q /f /a …
|
|
201
|
+
if (/^\/s/i.test(tk)) recursive = true;
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (tk.startsWith('-')) continue; // stray POSIX-style flag
|
|
205
|
+
targets.push(tk);
|
|
206
|
+
}
|
|
207
|
+
if (!recursive) continue;
|
|
208
|
+
if (targets.length === 0) return true; // `del /s` / `rd /s` with no target
|
|
209
|
+
for (const t of targets) if (_isDangerousDeleteTarget(t)) return true;
|
|
210
|
+
}
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export function isBlockedCommand(command) {
|
|
215
|
+
for (const pat of BLOCKED_PATTERNS) {
|
|
216
|
+
if (pat.test(command)) return true;
|
|
217
|
+
}
|
|
218
|
+
// Token-level rm guard catches split-flag forms the inline regex misses
|
|
219
|
+
// (e.g. `rm -r -f -v /`, `rm -v -R -F ~`).
|
|
220
|
+
if (_rmRecursiveForceUnsafe(command)) return true;
|
|
221
|
+
// PowerShell Remove-Item recursive+force guard — target-checked, parity
|
|
222
|
+
// with the bash rm guard above (and its decoded-payload variant below).
|
|
223
|
+
if (_removeItemRecursiveForceUnsafe(command)) return true;
|
|
224
|
+
// cmd-style recursive delete (`del /s`, `rd /s`, `rmdir /s`) — target-checked.
|
|
225
|
+
if (_cmdRecursiveDeleteUnsafe(command)) return true;
|
|
226
|
+
const decodedForRm = _decodePowerShellEncodedCommand(command);
|
|
227
|
+
if (decodedForRm && _rmRecursiveForceUnsafe(decodedForRm)) return true;
|
|
228
|
+
if (decodedForRm && _removeItemRecursiveForceUnsafe(decodedForRm)) return true;
|
|
229
|
+
if (decodedForRm && _cmdRecursiveDeleteUnsafe(decodedForRm)) return true;
|
|
230
|
+
// Re-scan decoded PowerShell -EncodedCommand payload. A destructive script
|
|
231
|
+
// smuggled as base64 (UTF-16LE) was previously invisible to the literal
|
|
232
|
+
// pattern match. Decode is best-effort; bad base64 / non-text bytes just
|
|
233
|
+
// return null and the function below skips. The decoded form is fed
|
|
234
|
+
// through the same BLOCKED_PATTERNS so any future addition automatically
|
|
235
|
+
// covers the encoded variant too.
|
|
236
|
+
const decoded = _decodePowerShellEncodedCommand(command);
|
|
237
|
+
if (decoded) {
|
|
238
|
+
for (const pat of BLOCKED_PATTERNS) {
|
|
239
|
+
if (pat.test(decoded)) return true;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const WMIC_PROCESS_DEFAULT_FIELDS = Object.freeze([
|
|
246
|
+
'ProcessId',
|
|
247
|
+
'Name',
|
|
248
|
+
'CreationDate',
|
|
249
|
+
'ExecutablePath',
|
|
250
|
+
'CommandLine',
|
|
251
|
+
]);
|
|
252
|
+
|
|
253
|
+
const WMIC_PROCESS_FIELD_MAP = new Map([
|
|
254
|
+
['processid', 'ProcessId'],
|
|
255
|
+
['name', 'Name'],
|
|
256
|
+
['creationdate', 'CreationDate'],
|
|
257
|
+
['executablepath', 'ExecutablePath'],
|
|
258
|
+
['commandline', 'CommandLine'],
|
|
259
|
+
['parentprocessid', 'ParentProcessId'],
|
|
260
|
+
['workingsetsize', 'WorkingSetSize'],
|
|
261
|
+
['threadcount', 'ThreadCount'],
|
|
262
|
+
['handlecount', 'HandleCount'],
|
|
263
|
+
]);
|
|
264
|
+
|
|
265
|
+
function _psQuote(value) {
|
|
266
|
+
return `'${String(value).replace(/'/g, "''")}'`;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function _psArray(values) {
|
|
270
|
+
return `@(${values.map(_psQuote).join(', ')})`;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function _encodePowerShellCommand(script) {
|
|
274
|
+
return Buffer.from(script, 'utf16le').toString('base64');
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function _parseWmicProcessFields(command) {
|
|
278
|
+
const normalized = String(command || '').replace(/\\"/g, '"');
|
|
279
|
+
const m = normalized.match(/\bget\s+([\s\S]+?)(?:\s+\/format:\w+)?\s*["']?\s*$/i);
|
|
280
|
+
if (!m) return [...WMIC_PROCESS_DEFAULT_FIELDS];
|
|
281
|
+
const fields = [];
|
|
282
|
+
for (const raw of m[1].split(/[,\s]+/)) {
|
|
283
|
+
const key = raw.trim().replace(/[^A-Za-z0-9_]/g, '').toLowerCase();
|
|
284
|
+
const field = WMIC_PROCESS_FIELD_MAP.get(key);
|
|
285
|
+
if (field && !fields.includes(field)) fields.push(field);
|
|
286
|
+
}
|
|
287
|
+
return fields.length ? fields : [...WMIC_PROCESS_DEFAULT_FIELDS];
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Rewrite deprecated `wmic process ... get ...` probes to a bounded
|
|
292
|
+
* PowerShell/CIM equivalent. WMIC routinely stalls for the full shell timeout
|
|
293
|
+
* on Windows hosts; EncodedCommand also protects PowerShell's `$_` token from
|
|
294
|
+
* any outer shell parsing before PowerShell sees it.
|
|
295
|
+
*
|
|
296
|
+
* Returns null for non-matching commands.
|
|
297
|
+
*/
|
|
298
|
+
export function maybeRewriteWmicProcessCommand(command) {
|
|
299
|
+
const text = typeof command === 'string' ? command : '';
|
|
300
|
+
// Composite shell structure detection (pipes / && / ; / $( / backtick).
|
|
301
|
+
// The full-command rewrite below replaces the entire `text`, which would
|
|
302
|
+
// silently drop surrounding `cd`, pipes, `&&`/`;` segments. For composite
|
|
303
|
+
// commands containing wmic, return null so the caller falls back to other
|
|
304
|
+
// policy handling instead of dropping context.
|
|
305
|
+
if (/[|&;]|\$\(|`/.test(text) && /\bwmic(?:\.exe)?\s+process\b/i.test(text)) return null;
|
|
306
|
+
if (!/\bwmic(?:\.exe)?\s+process\b/i.test(text)) return null;
|
|
307
|
+
if (!/\bget\b/i.test(text)) {
|
|
308
|
+
return {
|
|
309
|
+
error: 'wmic process commands are disabled because WMIC can stall for minutes; use PowerShell Get-CimInstance/Get-Process instead.',
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const normalized = text.replace(/\\"/g, '"');
|
|
314
|
+
const names = [...normalized.matchAll(/\bname\s*=\s*['"]([^'"]+)['"]/ig)]
|
|
315
|
+
.map(m => m[1])
|
|
316
|
+
.filter(Boolean);
|
|
317
|
+
const pids = [...normalized.matchAll(/\bprocessid\s*=\s*(\d+)/ig)]
|
|
318
|
+
.map(m => Number(m[1]))
|
|
319
|
+
.filter(Number.isFinite);
|
|
320
|
+
const fields = _parseWmicProcessFields(normalized);
|
|
321
|
+
|
|
322
|
+
const filters = [];
|
|
323
|
+
const setup = [`$fields = ${_psArray(fields)}`];
|
|
324
|
+
if (names.length > 0) {
|
|
325
|
+
setup.push(`$names = ${_psArray([...new Set(names)])}`);
|
|
326
|
+
filters.push('($names -contains $_.Name)');
|
|
327
|
+
}
|
|
328
|
+
if (pids.length > 0) {
|
|
329
|
+
setup.push(`$pids = @(${[...new Set(pids)].join(', ')})`);
|
|
330
|
+
filters.push('($pids -contains [int]$_.ProcessId)');
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const where = filters.length ? ` | Where-Object { ${filters.join(' -or ')} }` : '';
|
|
334
|
+
const script = [
|
|
335
|
+
...setup,
|
|
336
|
+
`$ErrorActionPreference = 'Stop'`,
|
|
337
|
+
`Get-CimInstance Win32_Process${where} | Select-Object -Property $fields | Format-List`,
|
|
338
|
+
].join('; ');
|
|
339
|
+
|
|
340
|
+
return {
|
|
341
|
+
command: `powershell.exe -NoProfile -EncodedCommand ${_encodePowerShellCommand(script)}`,
|
|
342
|
+
timeoutMs: 30_000,
|
|
343
|
+
note: '[auto-rewrite: deprecated wmic process query -> PowerShell Get-CimInstance; timeout capped at 30000ms]',
|
|
344
|
+
};
|
|
345
|
+
}
|