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.
Files changed (404) hide show
  1. package/.claude-plugin/marketplace.json +31 -0
  2. package/.claude-plugin/plugin.json +20 -0
  3. package/.gitattributes +34 -0
  4. package/.mcp.json +14 -0
  5. package/ARCHITECTURE.md +77 -0
  6. package/CHANGELOG.md +7 -0
  7. package/CONTRIBUTING.md +45 -0
  8. package/DATA-FLOW.md +79 -0
  9. package/LICENSE +21 -0
  10. package/README.md +389 -0
  11. package/SECURITY.md +138 -0
  12. package/UNINSTALL.md +112 -0
  13. package/agents/maintenance.md +5 -0
  14. package/agents/memory-classification.md +30 -0
  15. package/agents/scheduler-task.md +18 -0
  16. package/agents/webhook-handler.md +27 -0
  17. package/agents/worker.md +24 -0
  18. package/bin/bridge +133 -0
  19. package/bin/statusline-launcher.mjs +78 -0
  20. package/bin/statusline-lib.mjs +550 -0
  21. package/bin/statusline.mjs +607 -0
  22. package/bun.lock +802 -0
  23. package/commands/config.md +16 -0
  24. package/commands/doctor.md +13 -0
  25. package/commands/setup.md +17 -0
  26. package/defaults/cycle3-review-prompt.md +90 -0
  27. package/defaults/hidden-roles.json +65 -0
  28. package/defaults/memory-chunk-prompt.md +63 -0
  29. package/defaults/memory-promote-prompt.md +135 -0
  30. package/defaults/mixdog-config.template.json +27 -0
  31. package/defaults/user-workflow.json +8 -0
  32. package/defaults/user-workflow.md +12 -0
  33. package/hooks/hooks.json +73 -0
  34. package/hooks/lib/active-instance.cjs +77 -0
  35. package/hooks/lib/permission-evaluator.cjs +411 -0
  36. package/hooks/lib/permission-route.cjs +63 -0
  37. package/hooks/lib/permission-rules.cjs +170 -0
  38. package/hooks/lib/settings-loader.cjs +116 -0
  39. package/hooks/post-tool-use.cjs +84 -0
  40. package/hooks/pre-mcp-sandbox.cjs +158 -0
  41. package/hooks/pre-tool-subagent.cjs +253 -0
  42. package/hooks/session-start.cjs +1372 -0
  43. package/hooks/turn-timer.cjs +82 -0
  44. package/lib/claude-md-writer.cjs +386 -0
  45. package/lib/config-cjs.cjs +61 -0
  46. package/lib/hook-pipe-path.cjs +10 -0
  47. package/lib/keychain-cjs.cjs +263 -0
  48. package/lib/plugin-paths.cjs +61 -0
  49. package/lib/rules-builder.cjs +241 -0
  50. package/lib/text-utils.cjs +61 -0
  51. package/native/README.md +117 -0
  52. package/native/prebuilt/linux-aarch64/mixdog-shim +0 -0
  53. package/native/prebuilt/linux-x86_64/mixdog-shim +0 -0
  54. package/native/prebuilt/macos-aarch64/mixdog-shim +0 -0
  55. package/native/prebuilt/macos-x86_64/mixdog-shim +0 -0
  56. package/native/prebuilt/windows-x86_64/mixdog-shim.exe +0 -0
  57. package/package.json +107 -0
  58. package/prompts/code-review.txt +16 -0
  59. package/prompts/security-audit.txt +17 -0
  60. package/rules/bridge/00-common.md +39 -0
  61. package/rules/bridge/20-skip-protocol.md +18 -0
  62. package/rules/bridge/30-explorer.md +33 -0
  63. package/rules/bridge/40-cycle1-agent.md +52 -0
  64. package/rules/bridge/41-cycle2-agent.md +62 -0
  65. package/rules/bridge/42-cycle3-agent.md +44 -0
  66. package/rules/lead/00-tool-lead.md +61 -0
  67. package/rules/lead/01-general.md +23 -0
  68. package/rules/lead/02-channels.md +49 -0
  69. package/rules/lead/03-team.md +27 -0
  70. package/rules/lead/04-workflow.md +20 -0
  71. package/rules/shared/00-language.md +14 -0
  72. package/rules/shared/01-tool.md +138 -0
  73. package/scripts/bootstrap.mjs +184 -0
  74. package/scripts/bridge-unify-smoke.mjs +308 -0
  75. package/scripts/build-runtime-linux.sh +348 -0
  76. package/scripts/build-runtime-macos.sh +217 -0
  77. package/scripts/build-runtime-windows.ps1 +242 -0
  78. package/scripts/builtin-utils-smoke.mjs +392 -0
  79. package/scripts/check-json.mjs +45 -0
  80. package/scripts/check-syntax-changed.mjs +102 -0
  81. package/scripts/check-syntax.mjs +58 -0
  82. package/scripts/code-graph-batch.test.mjs +33 -0
  83. package/scripts/config-preserve-smoke.mjs +180 -0
  84. package/scripts/doctor.mjs +484 -0
  85. package/scripts/edit-normalize-fuzz.mjs +130 -0
  86. package/scripts/edit-normalize-smoke.mjs +401 -0
  87. package/scripts/edit-operation-smoke.mjs +369 -0
  88. package/scripts/edit2-smoke.mjs +63 -0
  89. package/scripts/fuzzy-e2e.mjs +28 -0
  90. package/scripts/fuzzy-smoke.mjs +26 -0
  91. package/scripts/generate-runtime-manifest.mjs +166 -0
  92. package/scripts/guard-smoke.mjs +66 -0
  93. package/scripts/hidden-role-schema-smoke.mjs +162 -0
  94. package/scripts/hook-routing-smoke.mjs +29 -0
  95. package/scripts/inject-input.ps1 +204 -0
  96. package/scripts/io-complex-smoke.mjs +667 -0
  97. package/scripts/io-explore-bench.mjs +424 -0
  98. package/scripts/io-guardrails-smoke.mjs +205 -0
  99. package/scripts/io-mini-bench-baseline.json +11 -0
  100. package/scripts/io-mini-bench.mjs +216 -0
  101. package/scripts/io-route-harness.mjs +933 -0
  102. package/scripts/io-telemetry-report.mjs +691 -0
  103. package/scripts/mutation-bench.mjs +564 -0
  104. package/scripts/mutation-io-smoke.mjs +1081 -0
  105. package/scripts/native-patch-bridge-smoke.mjs +288 -0
  106. package/scripts/native-patch-smoke.mjs +304 -0
  107. package/scripts/patch-interior-context-smoke.mjs +49 -0
  108. package/scripts/patch-newline-utf8-smoke.mjs +157 -0
  109. package/scripts/perf-hook-smoke.mjs +71 -0
  110. package/scripts/permission-eval-smoke.mjs +426 -0
  111. package/scripts/prep-patch.mjs +53 -0
  112. package/scripts/prep-shim.mjs +96 -0
  113. package/scripts/provider-cache-smoke.mjs +687 -0
  114. package/scripts/report-runtime-health.mjs +132 -0
  115. package/scripts/run-mcp.mjs +1547 -0
  116. package/scripts/salvage-v4a-shatter.test.mjs +58 -0
  117. package/scripts/scoped-cache-io-smoke.mjs +103 -0
  118. package/scripts/shell-policy-round3-smoke.mjs +46 -0
  119. package/scripts/smoke-runtime-negative.ps1 +100 -0
  120. package/scripts/smoke-runtime-negative.sh +95 -0
  121. package/scripts/stall-policy-smoke.mjs +50 -0
  122. package/scripts/start-memory-worker.mjs +23 -0
  123. package/scripts/statusline-launcher-smoke.mjs +82 -0
  124. package/scripts/stress-atomic-write.mjs +1028 -0
  125. package/scripts/test-config-rmw-restore.mjs +122 -0
  126. package/scripts/test-fault-inject.mjs +164 -0
  127. package/scripts/test-large-file.mjs +174 -0
  128. package/scripts/tool-edge-smoke.mjs +209 -0
  129. package/scripts/uninstall.mjs +201 -0
  130. package/scripts/webhook-selfheal-smoke.mjs +29 -0
  131. package/scripts/write-overwrite-guard-smoke.mjs +56 -0
  132. package/server-main.mjs +3055 -0
  133. package/server.mjs +468 -0
  134. package/setup/config-merge.mjs +254 -0
  135. package/setup/install.mjs +120 -0
  136. package/setup/launch-core.mjs +507 -0
  137. package/setup/launch.mjs +101 -0
  138. package/setup/setup-server.mjs +3206 -0
  139. package/setup/setup.html +3693 -0
  140. package/skills/retro-skill-proposer/SKILL.md +92 -0
  141. package/skills/schedule-add/SKILL.md +77 -0
  142. package/skills/setup/SKILL.md +346 -0
  143. package/skills/webhook-add/SKILL.md +81 -0
  144. package/src/agent/bridge-stall-watchdog.mjs +337 -0
  145. package/src/agent/index.mjs +2138 -0
  146. package/src/agent/orchestrator/activity-bus.mjs +38 -0
  147. package/src/agent/orchestrator/ai-wrapped-dispatch.mjs +1010 -0
  148. package/src/agent/orchestrator/bridge-retry.mjs +220 -0
  149. package/src/agent/orchestrator/bridge-trace.mjs +583 -0
  150. package/src/agent/orchestrator/cache-mtime.mjs +58 -0
  151. package/src/agent/orchestrator/config.mjs +358 -0
  152. package/src/agent/orchestrator/context/collect.mjs +651 -0
  153. package/src/agent/orchestrator/dispatch-persist.mjs +549 -0
  154. package/src/agent/orchestrator/drain-registry.mjs +50 -0
  155. package/src/agent/orchestrator/explore-validator.mjs +8 -0
  156. package/src/agent/orchestrator/internal-roles.mjs +118 -0
  157. package/src/agent/orchestrator/internal-tools.mjs +88 -0
  158. package/src/agent/orchestrator/jobs.mjs +116 -0
  159. package/src/agent/orchestrator/mcp/client.mjs +364 -0
  160. package/src/agent/orchestrator/providers/anthropic-betas.mjs +21 -0
  161. package/src/agent/orchestrator/providers/anthropic-oauth.mjs +1745 -0
  162. package/src/agent/orchestrator/providers/anthropic.mjs +437 -0
  163. package/src/agent/orchestrator/providers/gemini.mjs +1175 -0
  164. package/src/agent/orchestrator/providers/grok-oauth.mjs +782 -0
  165. package/src/agent/orchestrator/providers/model-catalog.mjs +241 -0
  166. package/src/agent/orchestrator/providers/openai-compat.mjs +1467 -0
  167. package/src/agent/orchestrator/providers/openai-oauth-ws.mjs +1890 -0
  168. package/src/agent/orchestrator/providers/openai-oauth.mjs +1307 -0
  169. package/src/agent/orchestrator/providers/openai-ws.mjs +104 -0
  170. package/src/agent/orchestrator/providers/registry.mjs +192 -0
  171. package/src/agent/orchestrator/providers/retry-classifier.mjs +325 -0
  172. package/src/agent/orchestrator/session/abort-lookup.mjs +13 -0
  173. package/src/agent/orchestrator/session/cache/post-edit-marks.mjs +42 -0
  174. package/src/agent/orchestrator/session/cache/prefetch-cache.mjs +142 -0
  175. package/src/agent/orchestrator/session/cache/read-cache.mjs +319 -0
  176. package/src/agent/orchestrator/session/cache/scoped-cache-outcome.mjs +11 -0
  177. package/src/agent/orchestrator/session/cache/scoped-cache.mjs +361 -0
  178. package/src/agent/orchestrator/session/cache/util.mjs +49 -0
  179. package/src/agent/orchestrator/session/loop.mjs +1478 -0
  180. package/src/agent/orchestrator/session/manager.mjs +1975 -0
  181. package/src/agent/orchestrator/session/read-dedup.mjs +6 -0
  182. package/src/agent/orchestrator/session/result-classification.mjs +65 -0
  183. package/src/agent/orchestrator/session/save-session-worker.mjs +18 -0
  184. package/src/agent/orchestrator/session/store.mjs +624 -0
  185. package/src/agent/orchestrator/session/stream-watchdog.mjs +130 -0
  186. package/src/agent/orchestrator/session/tool-result-offload.mjs +166 -0
  187. package/src/agent/orchestrator/session/trim.mjs +491 -0
  188. package/src/agent/orchestrator/smart-bridge/CACHE-SHARD.md +115 -0
  189. package/src/agent/orchestrator/smart-bridge/bridge-llm.mjs +327 -0
  190. package/src/agent/orchestrator/smart-bridge/cache-obs.mjs +150 -0
  191. package/src/agent/orchestrator/smart-bridge/cache-strategy.mjs +228 -0
  192. package/src/agent/orchestrator/smart-bridge/index.mjs +215 -0
  193. package/src/agent/orchestrator/smart-bridge/profiles.mjs +37 -0
  194. package/src/agent/orchestrator/smart-bridge/registry.mjs +348 -0
  195. package/src/agent/orchestrator/smart-bridge/session-builder.mjs +116 -0
  196. package/src/agent/orchestrator/stall-policy.mjs +195 -0
  197. package/src/agent/orchestrator/tool-loop-guard.mjs +75 -0
  198. package/src/agent/orchestrator/tools/bash-policy-scan.mjs +77 -0
  199. package/src/agent/orchestrator/tools/bash-session.mjs +721 -0
  200. package/src/agent/orchestrator/tools/builtin/advisory-lock.mjs +171 -0
  201. package/src/agent/orchestrator/tools/builtin/arg-guard.mjs +455 -0
  202. package/src/agent/orchestrator/tools/builtin/atomic-write.mjs +236 -0
  203. package/src/agent/orchestrator/tools/builtin/bash-tool.mjs +480 -0
  204. package/src/agent/orchestrator/tools/builtin/binary-file.mjs +76 -0
  205. package/src/agent/orchestrator/tools/builtin/builtin-tools.mjs +256 -0
  206. package/src/agent/orchestrator/tools/builtin/cache-layers.mjs +386 -0
  207. package/src/agent/orchestrator/tools/builtin/cwd-utils.mjs +37 -0
  208. package/src/agent/orchestrator/tools/builtin/device-paths.mjs +154 -0
  209. package/src/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +292 -0
  210. package/src/agent/orchestrator/tools/builtin/diff-utils.mjs +109 -0
  211. package/src/agent/orchestrator/tools/builtin/edit-base-guard.mjs +58 -0
  212. package/src/agent/orchestrator/tools/builtin/edit-byte-plan.mjs +240 -0
  213. package/src/agent/orchestrator/tools/builtin/edit-byte-utils.mjs +113 -0
  214. package/src/agent/orchestrator/tools/builtin/edit-commit.mjs +74 -0
  215. package/src/agent/orchestrator/tools/builtin/edit-context-utils.mjs +242 -0
  216. package/src/agent/orchestrator/tools/builtin/edit-diagnostics.mjs +211 -0
  217. package/src/agent/orchestrator/tools/builtin/edit-engine.mjs +1364 -0
  218. package/src/agent/orchestrator/tools/builtin/edit-failure-context.mjs +126 -0
  219. package/src/agent/orchestrator/tools/builtin/edit-hint.mjs +141 -0
  220. package/src/agent/orchestrator/tools/builtin/edit-match-utils.mjs +194 -0
  221. package/src/agent/orchestrator/tools/builtin/edit-partial-write.mjs +60 -0
  222. package/src/agent/orchestrator/tools/builtin/edit-stale-refresh.mjs +168 -0
  223. package/src/agent/orchestrator/tools/builtin/edit-tool.mjs +173 -0
  224. package/src/agent/orchestrator/tools/builtin/edit-utf8-guard.mjs +48 -0
  225. package/src/agent/orchestrator/tools/builtin/fs-reachability.mjs +48 -0
  226. package/src/agent/orchestrator/tools/builtin/fuzzy-match.mjs +99 -0
  227. package/src/agent/orchestrator/tools/builtin/glob-walk.mjs +170 -0
  228. package/src/agent/orchestrator/tools/builtin/grep-formatting.mjs +113 -0
  229. package/src/agent/orchestrator/tools/builtin/hash-utils.mjs +6 -0
  230. package/src/agent/orchestrator/tools/builtin/list-formatting.mjs +7 -0
  231. package/src/agent/orchestrator/tools/builtin/list-tool.mjs +593 -0
  232. package/src/agent/orchestrator/tools/builtin/native-edit-runner.mjs +89 -0
  233. package/src/agent/orchestrator/tools/builtin/notebook-edit-tool.mjs +300 -0
  234. package/src/agent/orchestrator/tools/builtin/open-config-tool.mjs +26 -0
  235. package/src/agent/orchestrator/tools/builtin/path-diagnostics.mjs +152 -0
  236. package/src/agent/orchestrator/tools/builtin/path-locks.mjs +35 -0
  237. package/src/agent/orchestrator/tools/builtin/path-utils.mjs +201 -0
  238. package/src/agent/orchestrator/tools/builtin/read-args.mjs +103 -0
  239. package/src/agent/orchestrator/tools/builtin/read-batch.mjs +172 -0
  240. package/src/agent/orchestrator/tools/builtin/read-constants.mjs +40 -0
  241. package/src/agent/orchestrator/tools/builtin/read-formatting.mjs +118 -0
  242. package/src/agent/orchestrator/tools/builtin/read-image-resize.mjs +189 -0
  243. package/src/agent/orchestrator/tools/builtin/read-image.mjs +88 -0
  244. package/src/agent/orchestrator/tools/builtin/read-lines.mjs +12 -0
  245. package/src/agent/orchestrator/tools/builtin/read-mode-tool.mjs +455 -0
  246. package/src/agent/orchestrator/tools/builtin/read-open.mjs +190 -0
  247. package/src/agent/orchestrator/tools/builtin/read-range-index.mjs +271 -0
  248. package/src/agent/orchestrator/tools/builtin/read-ranges.mjs +26 -0
  249. package/src/agent/orchestrator/tools/builtin/read-single-tool.mjs +728 -0
  250. package/src/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +173 -0
  251. package/src/agent/orchestrator/tools/builtin/read-special-files.mjs +268 -0
  252. package/src/agent/orchestrator/tools/builtin/read-streaming.mjs +602 -0
  253. package/src/agent/orchestrator/tools/builtin/read-tool.mjs +530 -0
  254. package/src/agent/orchestrator/tools/builtin/read-windows.mjs +107 -0
  255. package/src/agent/orchestrator/tools/builtin/rename-tool.mjs +196 -0
  256. package/src/agent/orchestrator/tools/builtin/rg-runner.mjs +422 -0
  257. package/src/agent/orchestrator/tools/builtin/search-builders.mjs +158 -0
  258. package/src/agent/orchestrator/tools/builtin/search-tool.mjs +869 -0
  259. package/src/agent/orchestrator/tools/builtin/shell-analysis.mjs +653 -0
  260. package/src/agent/orchestrator/tools/builtin/shell-jobs.mjs +936 -0
  261. package/src/agent/orchestrator/tools/builtin/shell-output.mjs +36 -0
  262. package/src/agent/orchestrator/tools/builtin/shell-runtime.mjs +214 -0
  263. package/src/agent/orchestrator/tools/builtin/snapshot-helpers.mjs +143 -0
  264. package/src/agent/orchestrator/tools/builtin/snapshot-store.mjs +206 -0
  265. package/src/agent/orchestrator/tools/builtin/snapshot-validation.mjs +98 -0
  266. package/src/agent/orchestrator/tools/builtin/text-stats.mjs +69 -0
  267. package/src/agent/orchestrator/tools/builtin/windows-roots.mjs +23 -0
  268. package/src/agent/orchestrator/tools/builtin/write-tool.mjs +401 -0
  269. package/src/agent/orchestrator/tools/builtin.mjs +500 -0
  270. package/src/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +39 -0
  271. package/src/agent/orchestrator/tools/code-graph-tool-defs.mjs +24 -0
  272. package/src/agent/orchestrator/tools/code-graph.mjs +4095 -0
  273. package/src/agent/orchestrator/tools/cwd-tool.mjs +298 -0
  274. package/src/agent/orchestrator/tools/destructive-warning.mjs +323 -0
  275. package/src/agent/orchestrator/tools/edit-normalize.mjs +603 -0
  276. package/src/agent/orchestrator/tools/env-scrub.mjs +100 -0
  277. package/src/agent/orchestrator/tools/graph-binary-fetcher.mjs +144 -0
  278. package/src/agent/orchestrator/tools/graph-manifest.json +26 -0
  279. package/src/agent/orchestrator/tools/host-input.mjs +204 -0
  280. package/src/agent/orchestrator/tools/mutation-content-cache.mjs +67 -0
  281. package/src/agent/orchestrator/tools/mutation-planner.mjs +75 -0
  282. package/src/agent/orchestrator/tools/next-call-utils.mjs +48 -0
  283. package/src/agent/orchestrator/tools/patch-binary-fetcher.mjs +133 -0
  284. package/src/agent/orchestrator/tools/patch-manifest.json +26 -0
  285. package/src/agent/orchestrator/tools/patch-tool-defs.mjs +20 -0
  286. package/src/agent/orchestrator/tools/patch.mjs +2754 -0
  287. package/src/agent/orchestrator/tools/progress-message.mjs +118 -0
  288. package/src/agent/orchestrator/tools/result-compression.mjs +279 -0
  289. package/src/agent/orchestrator/tools/shell-command.mjs +865 -0
  290. package/src/agent/orchestrator/tools/shell-exec-policy.mjs +89 -0
  291. package/src/agent/orchestrator/tools/shell-policy-danger-target.mjs +27 -0
  292. package/src/agent/orchestrator/tools/shell-policy-imports.mjs +7 -0
  293. package/src/agent/orchestrator/tools/shell-policy.mjs +345 -0
  294. package/src/agent/orchestrator/tools/shell-snapshot.mjs +313 -0
  295. package/src/agent/orchestrator/workflow-store.mjs +93 -0
  296. package/src/agent/tool-defs.mjs +103 -0
  297. package/src/channels/backends/discord.mjs +784 -0
  298. package/src/channels/data/voice-runtime-manifest.json +138 -0
  299. package/src/channels/index.mjs +3229 -0
  300. package/src/channels/lib/cli-worker-host.mjs +12 -0
  301. package/src/channels/lib/config-lock.mjs +13 -0
  302. package/src/channels/lib/config.mjs +292 -0
  303. package/src/channels/lib/drop-trace.mjs +71 -0
  304. package/src/channels/lib/event-pipeline.mjs +81 -0
  305. package/src/channels/lib/event-queue.mjs +345 -0
  306. package/src/channels/lib/executor.mjs +168 -0
  307. package/src/channels/lib/format.mjs +188 -0
  308. package/src/channels/lib/holidays.mjs +138 -0
  309. package/src/channels/lib/hook-pipe-server.mjs +802 -0
  310. package/src/channels/lib/interaction-workflows.mjs +184 -0
  311. package/src/channels/lib/memory-client.mjs +149 -0
  312. package/src/channels/lib/output-forwarder.mjs +765 -0
  313. package/src/channels/lib/runtime-paths.mjs +479 -0
  314. package/src/channels/lib/scheduler.mjs +723 -0
  315. package/src/channels/lib/session-control.mjs +36 -0
  316. package/src/channels/lib/session-discovery.mjs +103 -0
  317. package/src/channels/lib/settings.mjs +11 -0
  318. package/src/channels/lib/state-file.mjs +68 -0
  319. package/src/channels/lib/status-snapshot.mjs +219 -0
  320. package/src/channels/lib/tool-format.mjs +140 -0
  321. package/src/channels/lib/transcript-discovery.mjs +195 -0
  322. package/src/channels/lib/voice-runtime-fetcher.mjs +734 -0
  323. package/src/channels/lib/webhook.mjs +1179 -0
  324. package/src/channels/lib/whisper-server.mjs +477 -0
  325. package/src/channels/tool-defs.mjs +170 -0
  326. package/src/daemon/host.mjs +118 -0
  327. package/src/daemon/mcp-transport.mjs +47 -0
  328. package/src/daemon/session.mjs +100 -0
  329. package/src/daemon/thin-client.mjs +71 -0
  330. package/src/daemon/transport.mjs +163 -0
  331. package/src/memory/data/runtime-manifest.json +40 -0
  332. package/src/memory/index.mjs +3305 -0
  333. package/src/memory/lib/agent-ipc.mjs +93 -0
  334. package/src/memory/lib/bridge-trace-queries.mjs +120 -0
  335. package/src/memory/lib/core-memory-store.mjs +330 -0
  336. package/src/memory/lib/embedding-provider.mjs +269 -0
  337. package/src/memory/lib/embedding-worker.mjs +323 -0
  338. package/src/memory/lib/llm-worker-host.mjs +17 -0
  339. package/src/memory/lib/memory-cycle.mjs +11 -0
  340. package/src/memory/lib/memory-cycle1.mjs +641 -0
  341. package/src/memory/lib/memory-cycle2.mjs +1284 -0
  342. package/src/memory/lib/memory-cycle3.mjs +540 -0
  343. package/src/memory/lib/memory-embed.mjs +299 -0
  344. package/src/memory/lib/memory-extraction.mjs +5 -0
  345. package/src/memory/lib/memory-maintenance-store.mjs +32 -0
  346. package/src/memory/lib/memory-ops-policy.mjs +190 -0
  347. package/src/memory/lib/memory-recall-id-patch.mjs +15 -0
  348. package/src/memory/lib/memory-recall-read-query.mjs +7 -0
  349. package/src/memory/lib/memory-recall-scope-filter.mjs +63 -0
  350. package/src/memory/lib/memory-recall-store.mjs +621 -0
  351. package/src/memory/lib/memory-retrievers.mjs +112 -0
  352. package/src/memory/lib/memory-score.mjs +71 -0
  353. package/src/memory/lib/memory-text-utils.mjs +58 -0
  354. package/src/memory/lib/memory.mjs +412 -0
  355. package/src/memory/lib/model-profile.mjs +85 -0
  356. package/src/memory/lib/pg/adapter.mjs +308 -0
  357. package/src/memory/lib/pg/process.mjs +360 -0
  358. package/src/memory/lib/pg/supervisor.mjs +396 -0
  359. package/src/memory/lib/project-id-resolver.mjs +86 -0
  360. package/src/memory/lib/runtime-fetcher.mjs +442 -0
  361. package/src/memory/lib/trace-store.mjs +728 -0
  362. package/src/memory/tool-defs.mjs +79 -0
  363. package/src/search/index.mjs +1173 -0
  364. package/src/search/lib/backends/anthropic-oauth.mjs +98 -0
  365. package/src/search/lib/backends/exa.mjs +50 -0
  366. package/src/search/lib/backends/firecrawl.mjs +61 -0
  367. package/src/search/lib/backends/gemini-api.mjs +83 -0
  368. package/src/search/lib/backends/grok-oauth.mjs +86 -0
  369. package/src/search/lib/backends/index.mjs +150 -0
  370. package/src/search/lib/backends/openai-api.mjs +144 -0
  371. package/src/search/lib/backends/openai-oauth.mjs +98 -0
  372. package/src/search/lib/backends/openai-web-search.mjs +76 -0
  373. package/src/search/lib/backends/tavily.mjs +55 -0
  374. package/src/search/lib/backends/xai-api.mjs +113 -0
  375. package/src/search/lib/cache.mjs +131 -0
  376. package/src/search/lib/config.mjs +192 -0
  377. package/src/search/lib/formatter.mjs +115 -0
  378. package/src/search/lib/provider-usage.mjs +67 -0
  379. package/src/search/lib/providers.mjs +47 -0
  380. package/src/search/lib/search-intent.mjs +109 -0
  381. package/src/search/lib/setup-handler.mjs +261 -0
  382. package/src/search/lib/state.mjs +201 -0
  383. package/src/search/lib/web-tools.mjs +1207 -0
  384. package/src/search/tool-defs.mjs +83 -0
  385. package/src/setup/defender-exclusion.mjs +183 -0
  386. package/src/shared/abort-controller.mjs +15 -0
  387. package/src/shared/atomic-file.mjs +420 -0
  388. package/src/shared/config.mjs +350 -0
  389. package/src/shared/daemon-recycle.mjs +108 -0
  390. package/src/shared/disable-claude-builtins.mjs +88 -0
  391. package/src/shared/err-text.mjs +12 -0
  392. package/src/shared/llm/cost.mjs +66 -0
  393. package/src/shared/llm/http-agent.mjs +123 -0
  394. package/src/shared/llm/index.mjs +41 -0
  395. package/src/shared/llm/pid-cleanup.mjs +27 -0
  396. package/src/shared/llm/usage-log.mjs +47 -0
  397. package/src/shared/plugin-paths.mjs +58 -0
  398. package/src/shared/schedules-store.mjs +70 -0
  399. package/src/shared/seed.mjs +119 -0
  400. package/src/shared/user-cwd.mjs +213 -0
  401. package/src/shared/user-data-guard.mjs +238 -0
  402. package/src/status/aggregator.mjs +584 -0
  403. package/src/status/server.mjs +413 -0
  404. package/tools.json +1653 -0
@@ -0,0 +1,653 @@
1
+ import { statSync } from 'fs';
2
+ import { assertPathReachable, assertPathsReachable } from './fs-reachability.mjs';
3
+ import { isAbsolute, resolve } from 'path';
4
+ import {
5
+ cwdRelativePath,
6
+ normalizeInputPath,
7
+ normalizeOutputPath,
8
+ resolveAgainstCwd,
9
+ } from './path-utils.mjs';
10
+
11
+ // Hard-block patterns live exclusively in ../shell-policy.mjs (BLOCKED_PATTERNS /
12
+ // isBlockedCommand). This lighter detector only classifies cache invalidation
13
+ // scope for commands that already passed policy.
14
+ const SHELL_MUTATION_PATTERN = /(?:^|[;&|\n]\s*)(?:touch|mkdir|mktemp|rm|rmdir|mv|cp|install|ln|chmod|chown|truncate|dd|sed\s+-i|perl\s+-pi|npm\s+(?:install|i|ci|uninstall)|pnpm\s+(?:install|i|add|remove|update|up)|yarn\s+(?:install|add|remove|up)|bun\s+(?:install|add|remove|update|up)|pip(?:3)?\s+install|python(?:3)?\s+-m\s+pip\s+install|git\s+(?:checkout|switch|restore|clean|apply|am|cherry-pick|merge|rebase|stash|pull|reset)|cargo\s+(?:build|install|clean)|go\s+(?:build|install|generate)|make|cmake)\b/i;
15
+ // `source` / `.` removed from read-only set: sourced scripts can mutate
16
+ // files, cwd, env, and persistent-shell state arbitrarily. Without static
17
+ // analysis of the target script, treating these as read-only would skip
18
+ // cache invalidation that the sourced script's mutations require. Classify
19
+ // as unknown/global mutation by falling through to the default branch.
20
+ const SHELL_READ_ONLY_SEGMENT_RE = /^(?:cd|pwd|echo|printf|env|printenv|set|unset|export|alias|unalias|type|which|whereis|ls|dir|cat|head|tail|wc|grep|rg|find|git\s+(?:status|diff|show|log|rev-parse|branch|remote|ls-files)|stat|readlink|realpath|basename|dirname|sort|uniq|cut|sed\s+-n|awk|ps|whoami|uname|date|true|false|test|\[)\b/i;
21
+ const SHELL_GLOBAL_MUTATORS = new Set(['npm', 'pnpm', 'yarn', 'bun', 'pip', 'pip3', 'python', 'python3', 'git', 'cargo', 'go', 'make', 'cmake', 'dd']);
22
+
23
+ function shellSplitSegments(command) {
24
+ const parts = [];
25
+ let current = '';
26
+ let quote = null;
27
+ let escape = false;
28
+ for (let i = 0; i < command.length; i++) {
29
+ const ch = command[i];
30
+ if (escape) {
31
+ current += ch;
32
+ escape = false;
33
+ continue;
34
+ }
35
+ if (ch === '\\') {
36
+ current += ch;
37
+ escape = true;
38
+ continue;
39
+ }
40
+ if (quote) {
41
+ current += ch;
42
+ if (ch === quote) quote = null;
43
+ continue;
44
+ }
45
+ if (ch === '\'' || ch === '"') {
46
+ quote = ch;
47
+ current += ch;
48
+ continue;
49
+ }
50
+ if (ch === '\n' || ch === ';') {
51
+ if (current.trim()) parts.push(current.trim());
52
+ current = '';
53
+ continue;
54
+ }
55
+ if ((ch === '&' || ch === '|') && command[i + 1] === ch) {
56
+ if (current.trim()) parts.push(current.trim());
57
+ current = '';
58
+ i++;
59
+ continue;
60
+ }
61
+ current += ch;
62
+ }
63
+ if (current.trim()) parts.push(current.trim());
64
+ return parts;
65
+ }
66
+
67
+ function shellTokenize(segment) {
68
+ const tokens = [];
69
+ let current = '';
70
+ let quote = null;
71
+ let escape = false;
72
+ const push = () => {
73
+ if (current !== '') tokens.push(current);
74
+ current = '';
75
+ };
76
+ for (let i = 0; i < segment.length; i++) {
77
+ const ch = segment[i];
78
+ if (escape) {
79
+ current += ch;
80
+ escape = false;
81
+ continue;
82
+ }
83
+ if (ch === '\\') {
84
+ escape = true;
85
+ continue;
86
+ }
87
+ if (quote) {
88
+ if (ch === quote) quote = null;
89
+ else current += ch;
90
+ continue;
91
+ }
92
+ if (ch === '\'' || ch === '"') {
93
+ quote = ch;
94
+ continue;
95
+ }
96
+ if (/\s/.test(ch)) {
97
+ push();
98
+ continue;
99
+ }
100
+ if (ch === '>') {
101
+ push();
102
+ if (segment[i + 1] === '>') {
103
+ tokens.push('>>');
104
+ i++;
105
+ } else {
106
+ tokens.push('>');
107
+ }
108
+ continue;
109
+ }
110
+ current += ch;
111
+ }
112
+ if (quote) return null;
113
+ push();
114
+ return tokens;
115
+ }
116
+
117
+ function stripShellAssignments(tokens) {
118
+ const out = [...tokens];
119
+ while (out.length > 0 && /^[A-Za-z_][A-Za-z0-9_]*=/.test(out[0])) out.shift();
120
+ return out;
121
+ }
122
+
123
+ function resolveShellPathToken(token, cwd) {
124
+ const value = String(token || '').trim();
125
+ if (!value) return null;
126
+ if (value === '>' || value === '>>') return null;
127
+ if (value.startsWith('-')) return null;
128
+ if (/[`$*?[\]{}]/.test(value)) return null;
129
+ return resolveAgainstCwd(normalizeInputPath(value), cwd);
130
+ }
131
+
132
+ function isShellOutputRedirectToken(tok) {
133
+ const lower = String(tok || '').toLowerCase();
134
+ return lower === '>' || lower === '>>'
135
+ || /^(?:\d+>>?|\d+>|&>>?|&>)$/.test(lower);
136
+ }
137
+
138
+ function isShellInputRedirectToken(tok) {
139
+ const lower = String(tok || '').toLowerCase();
140
+ return lower === '<' || lower === '<<'
141
+ || /^(?:\d*<<?)$/.test(lower);
142
+ }
143
+
144
+ function extractShellPathArgs(tokens, cwd, { minIndex = 1 } = {}) {
145
+ const out = [];
146
+ for (let i = minIndex; i < tokens.length; i++) {
147
+ const tok = tokens[i];
148
+ if (!tok || tok === '--') continue;
149
+ if (/^\d+$/.test(tok) && (isShellOutputRedirectToken(tokens[i + 1]) || isShellInputRedirectToken(tokens[i + 1]))) {
150
+ continue;
151
+ }
152
+ if (isShellOutputRedirectToken(tok)) {
153
+ i++;
154
+ continue;
155
+ }
156
+ if (isShellInputRedirectToken(tok)) {
157
+ const redirected = resolveShellPathToken(tokens[i + 1], cwd);
158
+ if (redirected) out.push(redirected);
159
+ i++;
160
+ continue;
161
+ }
162
+ const outputInline = /^(?:\d+>>?|\d+>|&>>?|&>)(.+)?$/i.exec(tok);
163
+ if (outputInline) continue;
164
+ const inputInline = /^(?:\d*<<?)(.+)$/i.exec(tok);
165
+ if (inputInline) {
166
+ const redirected = resolveShellPathToken(inputInline[1], cwd);
167
+ if (redirected) out.push(redirected);
168
+ continue;
169
+ }
170
+ const resolved = resolveShellPathToken(tok, cwd);
171
+ if (resolved) out.push(resolved);
172
+ }
173
+ return out;
174
+ }
175
+
176
+ const LARGE_SHELL_FILE_PROBE_BYTES = 50 * 1024;
177
+ const LARGE_FILE_READ_CMDS = new Set(['cat', 'less', 'more', 'view', 'bat']);
178
+
179
+ function isExplicitAbsoluteShellPath(value) {
180
+ return isAbsolute(value)
181
+ || /^[A-Za-z]:[\\/]/.test(value)
182
+ || value.startsWith('\\\\');
183
+ }
184
+
185
+ // Truly dynamic shell tokens: parameter expansion (`$VAR`/`${VAR}`),
186
+ // command substitution (`$(...)`), and backtick substitution. These
187
+ // are resolved at runtime and cannot be statically inspected for
188
+ // path/size, so the probe skips them (like glob metachars below)
189
+ // rather than blocking -> an unresolvable path can't be statSync'd.
190
+ function hasShellVariableExpansion(value) {
191
+ return /[`$]/.test(String(value || ''));
192
+ }
193
+
194
+ // Literal shell glob metacharacters (`*`, `?`, `[`, `]`, `{`, `}`)
195
+ // with no `$`/backtick. A token like `docs/styles-*.css` is fully
196
+ // deterministic from the command text — the downstream tool (`rg`,
197
+ // `grep`, ...) expands it safely. We can't statSync a glob, so the
198
+ // large-file probe simply skips it instead of treating it as a
199
+ // dangerous dynamic-path token.
200
+ function hasShellGlobMeta(value) {
201
+ return /[*?[\]{}]/.test(String(value || ''));
202
+ }
203
+
204
+ function hasDynamicShellBits(value) {
205
+ return hasShellVariableExpansion(value) || hasShellGlobMeta(value);
206
+ }
207
+
208
+ function shellSplitPipelineSegments(segment) {
209
+ const parts = [];
210
+ let current = '';
211
+ let quote = null;
212
+ let escape = false;
213
+ for (let i = 0; i < segment.length; i++) {
214
+ const ch = segment[i];
215
+ if (escape) {
216
+ current += ch;
217
+ escape = false;
218
+ continue;
219
+ }
220
+ if (ch === '\\') {
221
+ current += ch;
222
+ escape = true;
223
+ continue;
224
+ }
225
+ if (quote) {
226
+ current += ch;
227
+ if (ch === quote) quote = null;
228
+ continue;
229
+ }
230
+ if (ch === '\'' || ch === '"') {
231
+ quote = ch;
232
+ current += ch;
233
+ continue;
234
+ }
235
+ if (ch === '|') {
236
+ if (current.trim()) parts.push(current.trim());
237
+ current = '';
238
+ if (segment[i + 1] === '&') i++;
239
+ continue;
240
+ }
241
+ current += ch;
242
+ }
243
+ if (current.trim()) parts.push(current.trim());
244
+ return parts;
245
+ }
246
+
247
+ function stripShellProbeWrappers(tokens) {
248
+ const out = stripShellAssignments(tokens || []);
249
+ let idx = 0;
250
+ while (idx < out.length) {
251
+ const tok = String(out[idx] || '').toLowerCase();
252
+ if (!tok) { idx++; continue; }
253
+ if (tok === 'sudo' || tok === 'nohup' || tok === 'exec') {
254
+ out.splice(idx, 1);
255
+ continue;
256
+ }
257
+ if (tok === 'command') {
258
+ out.splice(idx, 1);
259
+ while (idx < out.length && String(out[idx] || '').startsWith('-')) out.splice(idx, 1);
260
+ continue;
261
+ }
262
+ if (tok === 'env') {
263
+ out.splice(idx, 1);
264
+ while (idx < out.length) {
265
+ const cur = String(out[idx] || '');
266
+ const lower = cur.toLowerCase();
267
+ if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(cur) || lower === '-i') {
268
+ out.splice(idx, 1);
269
+ continue;
270
+ }
271
+ if (lower === '-u' && idx + 1 < out.length) {
272
+ out.splice(idx, 2);
273
+ continue;
274
+ }
275
+ break;
276
+ }
277
+ continue;
278
+ }
279
+ break;
280
+ }
281
+ return out;
282
+ }
283
+
284
+ function shellOptionConsumesValue(cmd, tok) {
285
+ const lower = String(tok || '').toLowerCase();
286
+ if (cmd === 'grep' || cmd === 'rg') {
287
+ if (['-e', '-f', '-g', '--glob', '-A', '-B', '-C', '--context', '-t', '--type', '--type-add', '-m', '--max-count'].includes(lower)) return true;
288
+ if (/^-[AABCegfmt]$/.test(lower)) return true;
289
+ }
290
+ if (cmd === 'sed') {
291
+ if (['-e', '-f'].includes(lower)) return true;
292
+ }
293
+ if (cmd === 'awk') {
294
+ if (['-f', '-F', '-v'].includes(lower)) return true;
295
+ }
296
+ return false;
297
+ }
298
+
299
+ function isHeadTailBounded(tokens) {
300
+ for (let i = 1; i < tokens.length; i++) {
301
+ const tok = String(tokens[i] || '').toLowerCase();
302
+ if (tok === '-n' || tok === '-c') return true;
303
+ if (/^-(?:n|c)\d+$/.test(tok)) return true;
304
+ if (/^-\d+$/.test(tok)) return true;
305
+ }
306
+ return false;
307
+ }
308
+
309
+ function isGrepBounded(tokens) {
310
+ for (let i = 1; i < tokens.length; i++) {
311
+ const tok = String(tokens[i] || '').toLowerCase();
312
+ if (tok === '-m' || tok === '--max-count') return true;
313
+ if (/^-m\d+$/.test(tok)) return true;
314
+ if (/^--max-count=/.test(tok)) return true;
315
+ if (tok === '--count' || tok === '--quiet' || tok === '--silent' || tok === '--files-with-matches' || tok === '--files-without-match') return true;
316
+ if (/^-[a-z]*[clq][a-z]*$/.test(tok)) return true;
317
+ }
318
+ return false;
319
+ }
320
+
321
+ function isSedBounded(tokens) {
322
+ const hasN = tokens.some((tok) => String(tok || '').toLowerCase() === '-n');
323
+ if (!hasN) return false;
324
+ const scriptIdx = tokens.findIndex((tok, idx) => idx > 0 && !String(tok || '').startsWith('-'));
325
+ if (scriptIdx === -1) return false;
326
+ const script = String(tokens[scriptIdx] || '');
327
+ return /\b\d+(?:,\d+)?p\b/.test(script) || /^\d+(?:,\d+)?p$/.test(script);
328
+ }
329
+
330
+ function isAwkBounded(tokens) {
331
+ const scriptIdx = tokens.findIndex((tok, idx) => idx > 0 && !String(tok || '').startsWith('-'));
332
+ if (scriptIdx === -1) return false;
333
+ const script = String(tokens[scriptIdx] || '');
334
+ return /\bNR\s*(?:==|<=|<|>=|>)\s*\d+/.test(script) || /NR\s*>=\s*\d+\s*&&\s*NR\s*<=\s*\d+/.test(script);
335
+ }
336
+
337
+ function classifyShellProbeToken(token, cwd, { cwdKnown = true } = {}) {
338
+ const value = String(token || '').trim();
339
+ if (!value || value === '--') return { kind: 'skip' };
340
+ // Real dynamic expansion (`$VAR`, `${VAR}`, `$(...)`, backticks)
341
+ // cannot be statically resolved. Like the glob metacharacters
342
+ // below, an unresolvable path can't be statSync'd for the
343
+ // large-file probe, so skip it (let the shell run) rather than
344
+ // hard-block -> the block fired even on tiny `$VAR` targets.
345
+ if (hasShellVariableExpansion(value)) return { kind: 'skip' };
346
+ // Literal glob metacharacters with no expansion are deterministic
347
+ // from the command text. We cannot statSync a glob pattern, so
348
+ // skip it for the large-file probe heuristic rather than flag it
349
+ // as a dynamic/dangerous path token.
350
+ if (hasShellGlobMeta(value)) return { kind: 'skip' };
351
+ const normalized = normalizeInputPath(value);
352
+ if (!cwdKnown && !isExplicitAbsoluteShellPath(normalized)) {
353
+ return { kind: 'relative-unknown', raw: value };
354
+ }
355
+ return { kind: 'path', path: resolveAgainstCwd(normalized, cwd), raw: value };
356
+ }
357
+
358
+ function extractShellProbeTargets(tokens, cwd, { minIndex = 1, cwdKnown = true } = {}) {
359
+ const out = { paths: [], dynamicToken: null, skippedRelativeUnknown: false };
360
+ for (let i = minIndex; i < tokens.length; i++) {
361
+ const tok = tokens[i];
362
+ if (!tok || tok === '--') continue;
363
+ if (/^\d+$/.test(tok) && (isShellOutputRedirectToken(tokens[i + 1]) || isShellInputRedirectToken(tokens[i + 1]))) {
364
+ continue;
365
+ }
366
+ if (isShellOutputRedirectToken(tok)) {
367
+ i++;
368
+ continue;
369
+ }
370
+ if (isShellInputRedirectToken(tok)) {
371
+ const info = classifyShellProbeToken(tokens[i + 1], cwd, { cwdKnown });
372
+ if (info.kind === 'path') out.paths.push(info.path);
373
+ else if (info.kind === 'dynamic' && !out.dynamicToken) out.dynamicToken = info.raw;
374
+ else if (info.kind === 'relative-unknown') out.skippedRelativeUnknown = true;
375
+ i++;
376
+ continue;
377
+ }
378
+ const outputInline = /^(?:\d+>>?|\d+>|&>>?|&>)(.+)?$/i.exec(tok);
379
+ if (outputInline) continue;
380
+ const inputInline = /^(?:\d*<<?)(.+)$/i.exec(tok);
381
+ if (inputInline) {
382
+ const info = classifyShellProbeToken(inputInline[1], cwd, { cwdKnown });
383
+ if (info.kind === 'path') out.paths.push(info.path);
384
+ else if (info.kind === 'dynamic' && !out.dynamicToken) out.dynamicToken = info.raw;
385
+ else if (info.kind === 'relative-unknown') out.skippedRelativeUnknown = true;
386
+ continue;
387
+ }
388
+ const info = classifyShellProbeToken(tok, cwd, { cwdKnown });
389
+ if (info.kind === 'path') out.paths.push(info.path);
390
+ else if (info.kind === 'dynamic' && !out.dynamicToken) out.dynamicToken = info.raw;
391
+ else if (info.kind === 'relative-unknown') out.skippedRelativeUnknown = true;
392
+ }
393
+ return out;
394
+ }
395
+
396
+ function extractShellProbePaths(tokens, cwd, { cwdKnown = true } = {}) {
397
+ const cmd = String(tokens?.[0] || '').toLowerCase();
398
+ if (!cmd) return { paths: [], dynamicToken: null, skippedRelativeUnknown: false, cmd: '' };
399
+ if (LARGE_FILE_READ_CMDS.has(cmd)) {
400
+ return { ...extractShellProbeTargets(tokens, cwd, { minIndex: 1, cwdKnown }), cmd };
401
+ }
402
+ if (cmd === 'head' || cmd === 'tail') {
403
+ if (isHeadTailBounded(tokens)) return { paths: [], dynamicToken: null, skippedRelativeUnknown: false, cmd };
404
+ return { ...extractShellProbeTargets(tokens, cwd, { minIndex: 1, cwdKnown }), cmd };
405
+ }
406
+ if (cmd === 'grep' || cmd === 'rg') {
407
+ if (isGrepBounded(tokens)) return { paths: [], dynamicToken: null, skippedRelativeUnknown: false, cmd };
408
+ let i = 1;
409
+ let sawPattern = false;
410
+ while (i < tokens.length) {
411
+ const tok = tokens[i];
412
+ if (!tok) { i++; continue; }
413
+ if (!sawPattern) {
414
+ if (tok === '--') { i++; continue; }
415
+ if (tok.startsWith('-')) {
416
+ i += shellOptionConsumesValue(cmd, tok) ? 2 : 1;
417
+ continue;
418
+ }
419
+ sawPattern = true;
420
+ i++;
421
+ continue;
422
+ }
423
+ break;
424
+ }
425
+ return { ...extractShellProbeTargets(tokens, cwd, { minIndex: i, cwdKnown }), cmd };
426
+ }
427
+ if (cmd === 'sed') {
428
+ if (isSedBounded(tokens)) return { paths: [], dynamicToken: null, skippedRelativeUnknown: false, cmd };
429
+ let i = 1;
430
+ while (i < tokens.length) {
431
+ const tok = tokens[i];
432
+ if (!tok) { i++; continue; }
433
+ if (tok === '--') { i++; break; }
434
+ if (tok.startsWith('-')) {
435
+ i += shellOptionConsumesValue(cmd, tok) ? 2 : 1;
436
+ continue;
437
+ }
438
+ // First non-option token is the script/program. Remaining
439
+ // path-like args are candidate target files.
440
+ i++;
441
+ break;
442
+ }
443
+ return { ...extractShellProbeTargets(tokens, cwd, { minIndex: i, cwdKnown }), cmd };
444
+ }
445
+ if (cmd === 'awk') {
446
+ if (isAwkBounded(tokens)) return { paths: [], dynamicToken: null, skippedRelativeUnknown: false, cmd };
447
+ let i = 1;
448
+ while (i < tokens.length) {
449
+ const tok = tokens[i];
450
+ if (!tok) { i++; continue; }
451
+ if (tok === '--') { i++; break; }
452
+ if (tok.startsWith('-')) {
453
+ i += shellOptionConsumesValue(cmd, tok) ? 2 : 1;
454
+ continue;
455
+ }
456
+ i++;
457
+ break;
458
+ }
459
+ return { ...extractShellProbeTargets(tokens, cwd, { minIndex: i, cwdKnown }), cmd };
460
+ }
461
+ return { paths: [], dynamicToken: null, skippedRelativeUnknown: false, cmd };
462
+ }
463
+
464
+ function buildLargeShellFileProbeMessage(fullPath, sizeBytes, cmd, cwd) {
465
+ const kb = Math.round(sizeBytes / 1024);
466
+ const display = normalizeOutputPath(cwdRelativePath(fullPath, cwd));
467
+ return `large-file shell probe blocked: \`${cmd}\` is targeting \`${display}\` (${kb} KB).`;
468
+ }
469
+
470
+ export async function preflightShellLargeFileProbe(command, cwd) {
471
+ const text = String(command || '').trim();
472
+ let localCwd = resolve(cwd || process.cwd());
473
+ let cwdKnown = true;
474
+ if (!text) return null;
475
+ for (const segment of shellSplitSegments(text)) {
476
+ for (const stage of shellSplitPipelineSegments(segment)) {
477
+ const parsed = shellTokenize(stage);
478
+ if (!parsed) return null;
479
+ const tokens = stripShellProbeWrappers(parsed);
480
+ if (tokens.length === 0) continue;
481
+ const joined = tokens.join(' ');
482
+ if (/^cd\b/i.test(joined)) {
483
+ const target = tokens[1] || process.env.HOME || process.env.USERPROFILE || localCwd;
484
+ if (hasDynamicShellBits(target)) {
485
+ cwdKnown = false;
486
+ } else {
487
+ const resolved = resolveShellPathToken(target, localCwd);
488
+ if (resolved) {
489
+ localCwd = resolved;
490
+ cwdKnown = true;
491
+ } else {
492
+ cwdKnown = false;
493
+ }
494
+ }
495
+ continue;
496
+ }
497
+ const probe = extractShellProbePaths(tokens, localCwd, { cwdKnown });
498
+ if (probe.dynamicToken) {
499
+ return {
500
+ cmd: probe.cmd,
501
+ path: null,
502
+ sizeBytes: null,
503
+ message: `shell probe requires an explicit path: \`${probe.cmd}\` is using dynamic path token \`${probe.dynamicToken}\`.`,
504
+ };
505
+ }
506
+ if (probe.skippedRelativeUnknown && probe.paths.length === 0) {
507
+ continue;
508
+ }
509
+ for (const candidate of probe.paths) {
510
+ try {
511
+ await assertPathReachable(candidate);
512
+ } catch (err) {
513
+ if (err?.code === 'EFSUNREACHABLE') continue;
514
+ throw err;
515
+ }
516
+ try {
517
+ const st = statSync(candidate);
518
+ if (!st.isFile()) continue;
519
+ if (st.size < LARGE_SHELL_FILE_PROBE_BYTES) continue;
520
+ return {
521
+ cmd: probe.cmd,
522
+ path: candidate,
523
+ sizeBytes: st.size,
524
+ message: buildLargeShellFileProbeMessage(candidate, st.size, probe.cmd, localCwd),
525
+ };
526
+ } catch {
527
+ // Ignore nonexistent / inaccessible candidates; shell can
528
+ // surface those normally if the command proceeds.
529
+ }
530
+ }
531
+ }
532
+ }
533
+ return null;
534
+ }
535
+
536
+ export async function analyzeShellCommandEffects(command, cwd) {
537
+ const text = String(command || '').trim();
538
+ let localCwd = resolve(cwd || process.cwd());
539
+ if (!text) return { mutationMode: 'none', paths: [], finalCwd: localCwd };
540
+ const hasRedirect = /(?:^|[^0-9&<>])>>?(?!\&)/.test(text) || /\btee\b/.test(text);
541
+ if (!SHELL_MUTATION_PATTERN.test(text) && !hasRedirect) {
542
+ const readOnly = shellSplitSegments(text).every((segment) => {
543
+ const tokens = stripShellProbeWrappers(shellTokenize(segment) || []);
544
+ if (tokens.length === 0) return true;
545
+ const joined = tokens.join(' ');
546
+ if (/^cd\b/i.test(joined)) {
547
+ const target = tokens[1] || process.env.HOME || process.env.USERPROFILE || localCwd;
548
+ const resolved = resolveShellPathToken(target, localCwd);
549
+ if (resolved) localCwd = resolved;
550
+ return true;
551
+ }
552
+ return SHELL_READ_ONLY_SEGMENT_RE.test(joined);
553
+ });
554
+ return { mutationMode: readOnly ? 'none' : 'global', paths: [], finalCwd: localCwd };
555
+ }
556
+ const paths = new Set();
557
+ let global = false;
558
+ for (const segment of shellSplitSegments(text)) {
559
+ const parsed = shellTokenize(segment);
560
+ if (!parsed) return { mutationMode: 'global', paths: [], finalCwd: localCwd };
561
+ const tokens = stripShellProbeWrappers(parsed);
562
+ if (tokens.length === 0) continue;
563
+ const cmd = tokens[0].toLowerCase();
564
+ const joined = tokens.join(' ');
565
+ if (cmd === 'cd') {
566
+ const target = tokens[1] || process.env.HOME || process.env.USERPROFILE || localCwd;
567
+ const resolved = resolveShellPathToken(target, localCwd);
568
+ if (resolved) localCwd = resolved;
569
+ else global = true;
570
+ continue;
571
+ }
572
+ const segmentMutates = tokens.includes('tee') || tokens.includes('>') || tokens.includes('>>');
573
+ if (!segmentMutates && SHELL_READ_ONLY_SEGMENT_RE.test(joined)) continue;
574
+ if (segmentMutates) {
575
+ const segPaths = [];
576
+ const teeIdx = tokens.indexOf('tee');
577
+ if (teeIdx !== -1) {
578
+ segPaths.push(...extractShellPathArgs(tokens, localCwd, { minIndex: teeIdx + 1 }));
579
+ }
580
+ for (let i = 0; i < tokens.length; i++) {
581
+ if (tokens[i] === '>' || tokens[i] === '>>') {
582
+ const r = resolveShellPathToken(tokens[i + 1], localCwd);
583
+ if (r) segPaths.push(r);
584
+ }
585
+ }
586
+ if (segPaths.length === 0) { global = true; continue; }
587
+ for (const p of segPaths) paths.add(p);
588
+ continue;
589
+ }
590
+ if (SHELL_GLOBAL_MUTATORS.has(cmd)) {
591
+ if (cmd === 'git') {
592
+ const sub = String(tokens[1] || '').toLowerCase();
593
+ if (['status', 'diff', 'show', 'log', 'rev-parse', 'branch', 'remote', 'ls-files'].includes(sub)) continue;
594
+ }
595
+ if (cmd === 'python' || cmd === 'python3') {
596
+ if (!(tokens[1] === '-m' && tokens[2] === 'pip' && /^install$/i.test(tokens[3] || ''))) continue;
597
+ }
598
+ global = true;
599
+ continue;
600
+ }
601
+ let segmentPaths = [];
602
+ if (['touch', 'mkdir', 'mktemp', 'rm', 'rmdir', 'chmod', 'chown', 'truncate'].includes(cmd)) {
603
+ segmentPaths = extractShellPathArgs(tokens, localCwd, { minIndex: 1 });
604
+ } else if (['mv', 'cp', 'install', 'ln'].includes(cmd)) {
605
+ segmentPaths = extractShellPathArgs(tokens, localCwd, { minIndex: 1 });
606
+ } else if (cmd === 'sed' && tokens.includes('-i')) {
607
+ segmentPaths = extractShellPathArgs(tokens, localCwd, { minIndex: tokens.lastIndexOf('-i') + 1 });
608
+ } else if (cmd === 'perl' && tokens.some((t) => /^-p/i.test(t) || /^-i/i.test(t))) {
609
+ segmentPaths = extractShellPathArgs(tokens, localCwd, { minIndex: 1 });
610
+ } else if (cmd === 'tee') {
611
+ segmentPaths = extractShellPathArgs(tokens, localCwd, { minIndex: 1 });
612
+ }
613
+ for (let i = 0; i < tokens.length; i++) {
614
+ if (tokens[i] === '>' || tokens[i] === '>>') {
615
+ const redirected = resolveShellPathToken(tokens[i + 1], localCwd);
616
+ if (redirected) segmentPaths.push(redirected);
617
+ }
618
+ }
619
+ if (segmentPaths.length === 0) {
620
+ global = true;
621
+ continue;
622
+ }
623
+ for (const p of segmentPaths) paths.add(p);
624
+ }
625
+ if (global) return { mutationMode: 'global', paths: [], finalCwd: localCwd };
626
+ if (paths.size > 0) {
627
+ const pathList = [...paths];
628
+ await assertPathsReachable(pathList);
629
+ return { mutationMode: 'paths', paths: pathList, finalCwd: localCwd };
630
+ }
631
+ return { mutationMode: 'none', paths: [], finalCwd: localCwd };
632
+ }
633
+
634
+ export function foregroundLongCommandHint(command, timeoutMs, args = {}) {
635
+ if (args.run_in_background === true) return '';
636
+ const cmd = String(command || '').trim();
637
+ if (!cmd) return '';
638
+ const longTimeout = Number(timeoutMs) >= 120_000;
639
+ const watchLike = /^\s*gh\s+run\s+watch(?:\s|$)/i.test(cmd)
640
+ || /^\s*(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:dev|watch|serve)(?:\s|$)/i.test(cmd)
641
+ || /^\s*(?:vite|webpack-dev-server|next|nuxt|astro)\s+(?:dev|start)(?:\s|$)/i.test(cmd);
642
+ const longPowerShellSleep = [...cmd.matchAll(/\bStart-Sleep\b([^;&|\r\n]*)/gi)].some((m) => {
643
+ const part = String(m[1] || '');
644
+ const ms = part.match(/-(?:Milliseconds|m)\s+(\d+)/i);
645
+ if (ms) return Number(ms[1]) >= 30000;
646
+ const sec = part.match(/-(?:Seconds|s)\s+(\d+)/i) || part.match(/^\s+(\d+)/);
647
+ return sec ? Number(sec[1]) >= 30 : false;
648
+ });
649
+ const longSleep = /\bsleep\s+(?:[3-9]\d|\d{3,}|\d+[mh])\b/i.test(cmd) || longPowerShellSleep;
650
+ if (!watchLike && !longSleep) return '';
651
+ if (!longTimeout && !watchLike && !longSleep) return '';
652
+ return 'Error: long foreground command detected.';
653
+ }