mixdog 0.9.2 → 0.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (417) hide show
  1. package/package.json +8 -3
  2. package/scripts/anthropic-maxtokens-test.mjs +119 -0
  3. package/scripts/bench/lead-review-tasks-r3.json +20 -0
  4. package/scripts/bench/lead-review-tasks.json +20 -0
  5. package/scripts/bench/r4-mixed-tasks.json +20 -0
  6. package/scripts/bench/review-tasks.json +20 -0
  7. package/scripts/bench/round-codex.json +114 -0
  8. package/scripts/bench/round-mixdog-lead-r3.json +269 -0
  9. package/scripts/bench/round-mixdog-lead.json +269 -0
  10. package/scripts/bench/round-mixdog.json +126 -0
  11. package/scripts/bench/round-r10-bigsample.json +679 -0
  12. package/scripts/bench/round-r11-codexalign.json +257 -0
  13. package/scripts/bench/round-r4-codex.json +114 -0
  14. package/scripts/bench/round-r4-mixed.json +225 -0
  15. package/scripts/bench/round-r5-gpt-lead.json +259 -0
  16. package/scripts/bench/round-r6-codex.json +114 -0
  17. package/scripts/bench/round-r6-solo.json +257 -0
  18. package/scripts/bench/round-r7-full.json +254 -0
  19. package/scripts/bench/round-r8-fulldefault.json +255 -0
  20. package/scripts/bench-run.mjs +215 -29
  21. package/scripts/build-tui.mjs +13 -1
  22. package/scripts/explore-bench.mjs +124 -0
  23. package/scripts/freevar-smoke.mjs +95 -0
  24. package/scripts/hook-bus-test.mjs +191 -0
  25. package/scripts/internal-comms-bench.mjs +1 -0
  26. package/scripts/internal-comms-smoke.mjs +10 -9
  27. package/scripts/mouse-probe.mjs +45 -0
  28. package/scripts/output-style-bench.mjs +13 -6
  29. package/scripts/output-style-smoke.mjs +4 -4
  30. package/scripts/path-suffix-test.mjs +57 -0
  31. package/scripts/provider-toolcall-test.mjs +7 -3
  32. package/scripts/recall-bench.mjs +207 -0
  33. package/scripts/recall-usecase-cases.json +18 -0
  34. package/scripts/recall-usecase-probe.json +6 -0
  35. package/scripts/session-bench.mjs +152 -6
  36. package/scripts/tool-smoke.mjs +30 -67
  37. package/scripts/tui-render-smoke.mjs +90 -0
  38. package/scripts/webhook-smoke.mjs +208 -0
  39. package/src/agents/debugger/AGENT.md +5 -2
  40. package/src/agents/heavy-worker/AGENT.md +21 -11
  41. package/src/agents/maintainer/AGENT.md +4 -0
  42. package/src/agents/reviewer/AGENT.md +3 -2
  43. package/src/agents/worker/AGENT.md +21 -11
  44. package/src/lib/rules-builder.cjs +4 -0
  45. package/src/mixdog-session-runtime.mjs +933 -3731
  46. package/src/output-styles/default.md +34 -9
  47. package/src/output-styles/{oneline.md → extreme-minimal.md} +5 -4
  48. package/src/output-styles/minimal.md +4 -1
  49. package/src/output-styles/simple.md +22 -7
  50. package/src/repl.mjs +5 -5
  51. package/src/rules/agent/00-common.md +2 -0
  52. package/src/rules/agent/30-explorer.md +8 -11
  53. package/src/rules/lead/lead-brief.md +12 -0
  54. package/src/rules/lead/lead-tool.md +2 -9
  55. package/src/rules/shared/01-tool.md +11 -5
  56. package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +25 -0
  57. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +100 -23
  58. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +6 -15
  59. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +362 -0
  60. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +410 -0
  61. package/src/runtime/agent/orchestrator/agent-trace.mjs +16 -735
  62. package/src/runtime/agent/orchestrator/config.mjs +69 -2
  63. package/src/runtime/agent/orchestrator/context/collect.mjs +51 -0
  64. package/src/runtime/agent/orchestrator/mcp/client.mjs +6 -2
  65. package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +63 -21
  66. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +93 -0
  67. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +209 -0
  68. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +489 -0
  69. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +97 -1343
  70. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +607 -0
  71. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +78 -10
  72. package/src/runtime/agent/orchestrator/providers/api-usage.mjs +1 -13
  73. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +81 -0
  74. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +248 -0
  75. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +303 -0
  76. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +505 -0
  77. package/src/runtime/agent/orchestrator/providers/gemini.mjs +44 -1014
  78. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +18 -4
  79. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +32 -0
  80. package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +86 -11
  81. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +348 -0
  82. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +54 -20
  83. package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +108 -0
  84. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +19 -12
  85. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +58 -0
  86. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +368 -0
  87. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +760 -0
  88. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +41 -1142
  89. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +732 -0
  90. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +193 -0
  91. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +303 -2119
  92. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +140 -995
  93. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +227 -0
  94. package/src/runtime/agent/orchestrator/providers/openai-ws-events.mjs +67 -0
  95. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +436 -0
  96. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +1105 -0
  97. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -1
  98. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +38 -12
  99. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +7 -8
  100. package/src/runtime/agent/orchestrator/session/compact/budget.mjs +288 -0
  101. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +85 -0
  102. package/src/runtime/agent/orchestrator/session/compact/engine.mjs +749 -0
  103. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +82 -0
  104. package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +315 -0
  105. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +643 -0
  106. package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +326 -0
  107. package/src/runtime/agent/orchestrator/session/compact.mjs +40 -2282
  108. package/src/runtime/agent/orchestrator/session/loop/compact-debug.mjs +28 -0
  109. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +274 -0
  110. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +61 -0
  111. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +38 -0
  112. package/src/runtime/agent/orchestrator/session/loop/env.mjs +14 -0
  113. package/src/runtime/agent/orchestrator/session/loop/hidden-agents.mjs +21 -0
  114. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +47 -0
  115. package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +182 -0
  116. package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +173 -0
  117. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +63 -0
  118. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +100 -0
  119. package/src/runtime/agent/orchestrator/session/loop/termination.mjs +58 -0
  120. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +52 -0
  121. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +239 -0
  122. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +218 -0
  123. package/src/runtime/agent/orchestrator/session/loop/transcript-repair.mjs +101 -0
  124. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +35 -0
  125. package/src/runtime/agent/orchestrator/session/loop.mjs +409 -1304
  126. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +471 -0
  127. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +230 -0
  128. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +235 -0
  129. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +149 -0
  130. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +155 -0
  131. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +406 -0
  132. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +80 -0
  133. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +303 -0
  134. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +210 -0
  135. package/src/runtime/agent/orchestrator/session/manager.mjs +226 -2114
  136. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +189 -0
  137. package/src/runtime/agent/orchestrator/session/store.mjs +74 -179
  138. package/src/runtime/agent/orchestrator/stall-policy.mjs +3 -3
  139. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +70 -20
  140. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +22 -2
  141. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +33 -42
  142. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +241 -0
  143. package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
  144. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +40 -0
  145. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +42 -2
  146. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +1 -1
  147. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +11 -4
  148. package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +29 -0
  149. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +8 -0
  150. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +126 -0
  151. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +81 -87
  152. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +161 -0
  153. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +108 -0
  154. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +78 -304
  155. package/src/runtime/agent/orchestrator/tools/builtin.mjs +11 -6
  156. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +303 -0
  157. package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +43 -0
  158. package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +382 -0
  159. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +551 -0
  160. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +295 -0
  161. package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +158 -0
  162. package/src/runtime/agent/orchestrator/tools/code-graph/keyword-match.mjs +82 -0
  163. package/src/runtime/agent/orchestrator/tools/code-graph/lang-predicates.mjs +128 -0
  164. package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +66 -0
  165. package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +44 -0
  166. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1080 -0
  167. package/src/runtime/agent/orchestrator/tools/code-graph/source-access.mjs +81 -0
  168. package/src/runtime/agent/orchestrator/tools/code-graph/span.mjs +19 -0
  169. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +280 -0
  170. package/src/runtime/agent/orchestrator/tools/code-graph/text-columns.mjs +45 -0
  171. package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +347 -0
  172. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +6 -6
  173. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +36 -4277
  174. package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +6 -3
  175. package/src/runtime/agent/orchestrator/tools/patch/constants.mjs +9 -0
  176. package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +171 -0
  177. package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +471 -0
  178. package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +436 -0
  179. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +342 -0
  180. package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +359 -0
  181. package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +340 -0
  182. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +643 -0
  183. package/src/runtime/agent/orchestrator/tools/patch.mjs +36 -2959
  184. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +1 -23
  185. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +10 -74
  186. package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +77 -0
  187. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +2 -4
  188. package/src/runtime/agent/orchestrator/tools/shell-state.mjs +154 -0
  189. package/src/runtime/channels/backends/discord-access.mjs +32 -0
  190. package/src/runtime/channels/backends/discord-attachments.mjs +65 -0
  191. package/src/runtime/channels/backends/discord-gateway.mjs +233 -0
  192. package/src/runtime/channels/backends/discord.mjs +12 -292
  193. package/src/runtime/channels/index.mjs +241 -894
  194. package/src/runtime/channels/lib/backend-dispatch.mjs +44 -0
  195. package/src/runtime/channels/lib/boot-profile.mjs +23 -0
  196. package/src/runtime/channels/lib/crash-log.mjs +106 -0
  197. package/src/runtime/channels/lib/event-pipeline.mjs +18 -1
  198. package/src/runtime/channels/lib/event-queue.mjs +63 -4
  199. package/src/runtime/channels/lib/inbound-routing.mjs +111 -0
  200. package/src/runtime/channels/lib/index-drop-trace.mjs +72 -0
  201. package/src/runtime/channels/lib/output-forwarder.mjs +9 -1
  202. package/src/runtime/channels/lib/owner-heartbeat.mjs +75 -0
  203. package/src/runtime/channels/lib/parent-bridge.mjs +88 -0
  204. package/src/runtime/channels/lib/runtime-paths.mjs +14 -4
  205. package/src/runtime/channels/lib/session-discovery.mjs +56 -4
  206. package/src/runtime/channels/lib/telegram-format.mjs +19 -22
  207. package/src/runtime/channels/lib/tool-dispatch.mjs +158 -0
  208. package/src/runtime/channels/lib/tool-format.mjs +1 -1
  209. package/src/runtime/channels/lib/transcript-discovery.mjs +4 -4
  210. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +6 -3
  211. package/src/runtime/channels/lib/voice-transcription.mjs +179 -0
  212. package/src/runtime/channels/lib/webhook/deliveries.mjs +312 -0
  213. package/src/runtime/channels/lib/webhook/log.mjs +42 -0
  214. package/src/runtime/channels/lib/webhook/ngrok.mjs +181 -0
  215. package/src/runtime/channels/lib/webhook/signature.mjs +60 -0
  216. package/src/runtime/channels/lib/webhook.mjs +36 -570
  217. package/src/runtime/channels/lib/whisper-language.mjs +42 -0
  218. package/src/runtime/channels/tool-defs.mjs +11 -130
  219. package/src/runtime/memory/index.mjs +258 -2050
  220. package/src/runtime/memory/lib/core-memory-store.mjs +351 -1
  221. package/src/runtime/memory/lib/cycle-llm-adapters.mjs +58 -0
  222. package/src/runtime/memory/lib/cycle-scheduler.mjs +497 -0
  223. package/src/runtime/memory/lib/cycle-signatures.mjs +34 -0
  224. package/src/runtime/memory/lib/embedding-warmup.mjs +58 -0
  225. package/src/runtime/memory/lib/http-wire.mjs +57 -0
  226. package/src/runtime/memory/lib/memory-config-flags.mjs +91 -0
  227. package/src/runtime/memory/lib/memory-cycle.mjs +1 -1
  228. package/src/runtime/memory/lib/memory-cycle2-gate.mjs +515 -0
  229. package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +324 -0
  230. package/src/runtime/memory/lib/memory-cycle2-shared.mjs +18 -0
  231. package/src/runtime/memory/lib/memory-cycle2.mjs +72 -837
  232. package/src/runtime/memory/lib/memory-embed.mjs +149 -0
  233. package/src/runtime/memory/lib/memory-process-lock.mjs +162 -0
  234. package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +24 -0
  235. package/src/runtime/memory/lib/memory-recall-store.mjs +22 -2
  236. package/src/runtime/memory/lib/memory-retrievers.mjs +8 -0
  237. package/src/runtime/memory/lib/memory.mjs +20 -0
  238. package/src/runtime/memory/lib/pg/supervisor.mjs +1 -1
  239. package/src/runtime/memory/lib/promotion-fingerprint.mjs +50 -0
  240. package/src/runtime/memory/lib/query-handlers.mjs +780 -0
  241. package/src/runtime/memory/lib/recall-format.mjs +238 -0
  242. package/src/runtime/memory/lib/runtime-fetcher.mjs +8 -3
  243. package/src/runtime/memory/lib/transcript-ingest.mjs +425 -0
  244. package/src/runtime/memory/tool-defs.mjs +6 -14
  245. package/src/runtime/search/lib/http-fetch.mjs +274 -0
  246. package/src/runtime/search/lib/ssrf-guard.mjs +333 -0
  247. package/src/runtime/search/lib/web-tools.mjs +24 -602
  248. package/src/runtime/shared/abort-controller.mjs +1 -1
  249. package/src/runtime/shared/atomic-file.mjs +26 -1
  250. package/src/runtime/shared/background-tasks.mjs +2 -3
  251. package/src/runtime/shared/buffered-appender.mjs +149 -0
  252. package/src/runtime/shared/launcher-control.mjs +2 -2
  253. package/src/runtime/shared/task-notification-envelope.mjs +98 -0
  254. package/src/runtime/shared/tool-execution-contract.mjs +2 -2
  255. package/src/runtime/shared/tool-primitives.mjs +308 -0
  256. package/src/runtime/shared/tool-result-summary.mjs +515 -0
  257. package/src/runtime/shared/tool-surface.mjs +80 -898
  258. package/src/runtime/shared/transcript-writer.mjs +52 -2
  259. package/src/runtime/shared/update-checker.mjs +7 -4
  260. package/src/session-runtime/config-helpers.mjs +291 -0
  261. package/src/session-runtime/config-lifecycle.mjs +232 -0
  262. package/src/session-runtime/cwd-plugins.mjs +226 -0
  263. package/src/session-runtime/effort.mjs +128 -0
  264. package/src/session-runtime/fs-utils.mjs +10 -0
  265. package/src/session-runtime/mcp-glue.mjs +177 -0
  266. package/src/session-runtime/model-capabilities.mjs +130 -0
  267. package/src/session-runtime/model-recency.mjs +111 -0
  268. package/src/session-runtime/native-search.mjs +247 -0
  269. package/src/session-runtime/output-styles.mjs +126 -0
  270. package/src/session-runtime/plugin-mcp.mjs +114 -0
  271. package/src/session-runtime/prewarm.mjs +142 -0
  272. package/src/session-runtime/provider-models.mjs +278 -0
  273. package/src/session-runtime/provider-usage.mjs +120 -0
  274. package/src/session-runtime/quick-model-rows.mjs +170 -0
  275. package/src/session-runtime/quick-search-models.mjs +46 -0
  276. package/src/session-runtime/session-hooks.mjs +93 -0
  277. package/src/session-runtime/session-text.mjs +100 -0
  278. package/src/session-runtime/settings-api.mjs +319 -0
  279. package/src/session-runtime/statusline-route.mjs +35 -0
  280. package/src/session-runtime/tool-catalog.mjs +720 -0
  281. package/src/session-runtime/tool-defs.mjs +84 -0
  282. package/src/session-runtime/warmup-schedulers.mjs +201 -0
  283. package/src/session-runtime/workflow.mjs +358 -0
  284. package/src/standalone/agent-tool/helpers.mjs +237 -0
  285. package/src/standalone/agent-tool/notify.mjs +107 -0
  286. package/src/standalone/agent-tool/provider-init.mjs +143 -0
  287. package/src/standalone/agent-tool/render.mjs +152 -0
  288. package/src/standalone/agent-tool/tool-def.mjs +55 -0
  289. package/src/standalone/agent-tool.mjs +155 -677
  290. package/src/standalone/channel-worker.mjs +7 -9
  291. package/src/standalone/explore-tool.mjs +40 -12
  292. package/src/standalone/hook-bus/config.mjs +207 -0
  293. package/src/standalone/hook-bus/constants.mjs +90 -0
  294. package/src/standalone/hook-bus/handlers.mjs +481 -0
  295. package/src/standalone/hook-bus/payload.mjs +31 -0
  296. package/src/standalone/hook-bus/rules.mjs +77 -0
  297. package/src/standalone/hook-bus.mjs +110 -746
  298. package/src/standalone/memory-runtime-proxy.mjs +7 -0
  299. package/src/standalone/opencode-go-login.mjs +125 -0
  300. package/src/standalone/provider-admin.mjs +15 -19
  301. package/src/standalone/usage-dashboard.mjs +3 -1
  302. package/src/tui/App.jsx +1163 -7571
  303. package/src/tui/app/app-format.mjs +206 -0
  304. package/src/tui/app/channel-pickers.mjs +510 -0
  305. package/src/tui/app/clipboard.mjs +67 -0
  306. package/src/tui/app/core-memory-picker.mjs +210 -0
  307. package/src/tui/app/extension-pickers.mjs +506 -0
  308. package/src/tui/app/input-parsers.mjs +193 -0
  309. package/src/tui/app/maintenance-pickers.mjs +324 -0
  310. package/src/tui/app/model-options.mjs +330 -0
  311. package/src/tui/app/model-picker.mjs +365 -0
  312. package/src/tui/app/onboarding-steps.mjs +400 -0
  313. package/src/tui/app/project-picker.mjs +247 -0
  314. package/src/tui/app/provider-setup-picker.mjs +580 -0
  315. package/src/tui/app/resume-picker.mjs +55 -0
  316. package/src/tui/app/route-pickers.mjs +419 -0
  317. package/src/tui/app/settings-picker.mjs +490 -0
  318. package/src/tui/app/slash-commands.mjs +101 -0
  319. package/src/tui/app/slash-dispatch.mjs +427 -0
  320. package/src/tui/app/text-layout.mjs +46 -0
  321. package/src/tui/app/theme-effort-pickers.mjs +154 -0
  322. package/src/tui/app/transcript-window.mjs +671 -0
  323. package/src/tui/app/use-mouse-input.mjs +460 -0
  324. package/src/tui/app/use-prompt-handlers.mjs +310 -0
  325. package/src/tui/app/use-transcript-scroll.mjs +510 -0
  326. package/src/tui/app/use-transcript-window.mjs +589 -0
  327. package/src/tui/components/ConfirmBar.jsx +1 -1
  328. package/src/tui/components/Picker.jsx +32 -4
  329. package/src/tui/components/PromptInput.jsx +259 -80
  330. package/src/tui/components/SlashCommandPalette.jsx +8 -1
  331. package/src/tui/components/StatusLine.jsx +63 -12
  332. package/src/tui/components/TextEntryPanel.jsx +11 -0
  333. package/src/tui/components/ToolExecution.jsx +56 -588
  334. package/src/tui/components/TranscriptItem.jsx +105 -0
  335. package/src/tui/components/UsagePanel.jsx +18 -4
  336. package/src/tui/components/prompt-input/edit-helpers.mjs +72 -0
  337. package/src/tui/components/prompt-input/voice-indicator.mjs +39 -0
  338. package/src/tui/components/tool-execution/ResultBody.jsx +56 -0
  339. package/src/tui/components/tool-execution/surface-detail.mjs +405 -0
  340. package/src/tui/components/tool-execution/text-format.mjs +161 -0
  341. package/src/tui/components/tool-output-format.mjs +2 -2
  342. package/src/tui/display-width.mjs +20 -3
  343. package/src/tui/dist/index.mjs +18034 -17188
  344. package/src/tui/engine/agent-envelope.mjs +296 -0
  345. package/src/tui/engine/agent-job-feed.mjs +133 -0
  346. package/src/tui/engine/boot-profile.mjs +21 -0
  347. package/src/tui/engine/labels.mjs +67 -0
  348. package/src/tui/engine/notice-text.mjs +112 -0
  349. package/src/tui/engine/notification-plan.mjs +76 -0
  350. package/src/tui/engine/queue-helpers.mjs +161 -0
  351. package/src/tui/engine/render-timing.mjs +17 -0
  352. package/src/tui/engine/session-stats.mjs +46 -0
  353. package/src/tui/engine/tool-approval.mjs +94 -0
  354. package/src/tui/engine/tool-call-fields.mjs +23 -0
  355. package/src/tui/engine/tool-card-results.mjs +234 -0
  356. package/src/tui/engine/tool-result-status.mjs +135 -0
  357. package/src/tui/engine/tool-result-text.mjs +126 -0
  358. package/src/tui/engine.mjs +405 -1385
  359. package/src/tui/figures.mjs +5 -0
  360. package/src/tui/index.jsx +105 -0
  361. package/src/tui/input-editing.mjs +60 -10
  362. package/src/tui/keyboard-protocol.mjs +2 -2
  363. package/src/tui/lib/voice-recorder.mjs +35 -19
  364. package/src/tui/markdown/format-token.mjs +11 -9
  365. package/src/tui/paste-attachments.mjs +38 -0
  366. package/src/tui/statusline-ansi-bridge.mjs +11 -3
  367. package/src/tui/theme.mjs +6 -0
  368. package/src/tui/themes/base.mjs +2 -2
  369. package/src/tui/themes/kanagawa.mjs +4 -4
  370. package/src/tui/themes/teal.mjs +4 -5
  371. package/src/tui/themes/utils.mjs +1 -1
  372. package/src/ui/statusline-agents.mjs +213 -0
  373. package/src/ui/statusline-format.mjs +146 -0
  374. package/src/ui/statusline-segments.mjs +148 -0
  375. package/src/ui/statusline.mjs +77 -462
  376. package/src/ui/tool-card.mjs +0 -1
  377. package/src/vendor/statusline/bin/statusline-route.mjs +15 -2
  378. package/src/workflows/default/WORKFLOW.md +16 -9
  379. package/src/workflows/sequential/WORKFLOW.md +16 -11
  380. package/src/workflows/solo/WORKFLOW.md +5 -1
  381. package/vendor/ink/build/display-width.js +19 -3
  382. package/vendor/ink/build/ink.js +103 -6
  383. package/vendor/ink/build/log-update.js +17 -3
  384. package/vendor/ink/build/wrap-text.js +125 -0
  385. package/scripts/_test-folder-dialog.mjs +0 -30
  386. package/scripts/fix-brief-fn.mjs +0 -35
  387. package/scripts/fix-format-tool-surface.mjs +0 -24
  388. package/scripts/fix-tool-exec-visible.mjs +0 -42
  389. package/scripts/patch-agent-brief.mjs +0 -48
  390. package/scripts/patch-app.mjs +0 -21
  391. package/scripts/patch-app2.mjs +0 -18
  392. package/scripts/patch-dist-brief.mjs +0 -96
  393. package/scripts/patch-tool-exec.mjs +0 -70
  394. package/src/examples/schedules/SCHEDULE.example.md +0 -32
  395. package/src/examples/webhooks/WEBHOOK.example.md +0 -40
  396. package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +0 -107
  397. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +0 -143
  398. package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -285
  399. package/src/runtime/agent/orchestrator/tools/builtin/open-config-tool.mjs +0 -26
  400. package/src/runtime/shared/channel-notification-routing.test.mjs +0 -45
  401. package/src/runtime/shared/tool-execution-contract.test.mjs +0 -183
  402. package/src/standalone/agent-task-status.test.mjs +0 -76
  403. package/src/tui/components/tool-output-format.test.mjs +0 -399
  404. package/src/tui/display-width.test.mjs +0 -35
  405. package/src/tui/engine-runtime-notification.test.mjs +0 -115
  406. package/src/tui/engine-tool-result-text.test.mjs +0 -75
  407. package/src/tui/markdown/format-token.test.mjs +0 -354
  408. package/src/tui/markdown/render-ansi.test.mjs +0 -108
  409. package/src/tui/markdown/stream-fence.test.mjs +0 -26
  410. package/src/tui/markdown/streaming-markdown.test.mjs +0 -70
  411. package/src/tui/prompt-history-store.test.mjs +0 -52
  412. package/src/tui/statusline-ansi-bridge.test.mjs +0 -159
  413. package/src/tui/transcript-tool-failures.test.mjs +0 -111
  414. package/src/ui/markdown.test.mjs +0 -70
  415. package/src/ui/statusline-context-label.test.mjs +0 -15
  416. package/src/vendor/statusline/bin/statusline-lib.mjs +0 -186
  417. package/src/vendor/statusline/bin/statusline-route.test.mjs +0 -80
@@ -0,0 +1,295 @@
1
+ // Native mixdog-graph binary runner — single source of truth for per-file
2
+ // parsing. NO JS parse fallback: absent binary throws. Extracted verbatim
3
+ // from code-graph.mjs, except _graphBinaryPath's local-build relative path,
4
+ // which gains one extra `../` because this module sits one directory deeper
5
+ // (tools/code-graph/ vs tools/). The resolved absolute path is unchanged.
6
+ import { resolve as pathResolve, dirname } from 'node:path';
7
+ import { existsSync } from 'node:fs';
8
+ import { fileURLToPath } from 'node:url';
9
+ import { getPluginData } from '../../config.mjs';
10
+ import { ensureGraphBinary, findCachedGraphBinary } from '../graph-binary-fetcher.mjs';
11
+ import { acquire as acquireChildSpawnSlot } from '../../../../shared/child-spawn-gate.mjs';
12
+ import { CODE_GRAPH_BINARY_TIMEOUT_MS, CODE_GRAPH_MAX_FILES } from './constants.mjs';
13
+
14
+ // ── Native graph binary (mixdog-graph) — single source of truth for
15
+ // per-file parsing. There is NO JS parsing fallback: if the binary is
16
+ // absent the build throws so the caller surfaces a clear, fixable error
17
+ // instead of silently degrading to a slow path.
18
+ function _graphBinaryPath() {
19
+ const override = process.env.MIXDOG_GRAPH_BIN;
20
+ if (override && existsSync(override)) return override;
21
+ // fileURLToPath correctly decodes percent-encoded bytes (spaces, non-ASCII)
22
+ // and strips the leading-slash/drive-letter quirk on Windows. Using
23
+ // URL.pathname directly leaves `%20` etc. encoded, breaking paths with
24
+ // spaces or non-ASCII characters.
25
+ const moduleDir = dirname(fileURLToPath(import.meta.url));
26
+ const binName = process.platform === 'win32' ? 'mixdog-graph.exe' : 'mixdog-graph';
27
+ // Prefer a local cargo build, then a previously fetched/cached prebuilt.
28
+ // This module is one dir deeper than the legacy code-graph.mjs, so the
29
+ // relative walk to repo-root native/ needs six `../` hops
30
+ // (code-graph → tools → orchestrator → agent → runtime → src → root).
31
+ const localBuild = pathResolve(moduleDir, '../../../../../../native/mixdog-graph/target/release', binName);
32
+ if (existsSync(localBuild)) return localBuild;
33
+ try { return findCachedGraphBinary(getPluginData()); } catch { return null; }
34
+ }
35
+
36
+ async function _runGraphBinaryJsonl(absRoot, extraArgs, stdinLines = null) {
37
+ let binPath = _graphBinaryPath();
38
+ if (!binPath) {
39
+ // No local build or cached binary — fetch the prebuilt from the release
40
+ // manifest (sha256-verified). No JS parse fallback: if the platform has
41
+ // no asset or the download fails, the build throws with a fixable error.
42
+ try {
43
+ binPath = await ensureGraphBinary(getPluginData());
44
+ } catch (err) {
45
+ throw new Error(
46
+ `[code-graph] mixdog-graph binary unavailable and could not be fetched: ${err?.message || err}. `
47
+ + 'Build it (cargo build --release in native/mixdog-graph) or check network/release manifest.',
48
+ );
49
+ }
50
+ }
51
+ const { spawn } = await import('node:child_process');
52
+ const timeoutMs = CODE_GRAPH_BINARY_TIMEOUT_MS;
53
+ let retried = false;
54
+
55
+ // Inner spawn + promise — extracted so we can retry once on EAGAIN.
56
+ //
57
+ // child-spawn-gate is NOT acquired here. This function runs inside the
58
+ // code-graph prewarm WORKER THREAD (via _buildCodeGraph), and worker_threads
59
+ // do not share module-level state with the main thread — acquiring here would
60
+ // create a SECOND, independent semaphore that never coordinates with the
61
+ // main-thread rg gate. Instead the gate is held on the MAIN THREAD across the
62
+ // whole graph-build worker's lifetime (see buildCodeGraphAsync). The binary
63
+ // child is spawned exclusively from this worker path, so one main-side slot
64
+ // per worker correctly bounds native graph spawns against rg.
65
+ const _spawnOnce = () => new Promise((resolve, reject) => {
66
+ // When stdinLines is supplied (--files mode), stream one JSON object per
67
+ // line to the child's STDIN — the reused nodes' metadata — so Rust can
68
+ // resolve imports across the WHOLE tree (fresh + reused) while only
69
+ // full-parsing the changed subset passed as argv.
70
+ const wantsStdin = Array.isArray(stdinLines);
71
+ const proc = spawn(binPath, [absRoot, ...extraArgs], {
72
+ stdio: [wantsStdin ? 'pipe' : 'ignore', 'pipe', 'pipe'],
73
+ // windowsHide: native code-graph binary is a console exe; without this each
74
+ // call flashes a console window when spawned under the detached daemon.
75
+ windowsHide: true,
76
+ });
77
+ const chunks = [];
78
+ let stderrText = '';
79
+ const STDERR_CAP = 8 * 1024;
80
+ let settled = false;
81
+ let timedOut = false;
82
+
83
+ // ── timeout + kill helpers (mirrors rg-runner's _killRgProc/_escalateRgKill) ──
84
+ let timeoutTimer = null;
85
+ let killGraceTimer = null;
86
+ let forceSettleTimer = null;
87
+
88
+ const _procGone = () => proc.exitCode != null || proc.signalCode != null;
89
+
90
+ const _escalateKill = () => {
91
+ if (_procGone()) return;
92
+ const pid = proc.pid;
93
+ if (!pid) return;
94
+ try {
95
+ if (process.platform === 'win32') {
96
+ spawn('taskkill', ['/pid', String(pid), '/t', '/f'], {
97
+ windowsHide: true,
98
+ stdio: 'ignore',
99
+ });
100
+ } else {
101
+ try { proc.kill('SIGKILL'); } catch { /* ignore */ }
102
+ }
103
+ } catch { /* ignore */ }
104
+ };
105
+
106
+ const _killProc = () => {
107
+ if (_procGone()) return;
108
+ try { proc.kill('SIGTERM'); } catch { /* ignore */ }
109
+ if (killGraceTimer) {
110
+ clearTimeout(killGraceTimer);
111
+ killGraceTimer = null;
112
+ }
113
+ killGraceTimer = setTimeout(() => {
114
+ killGraceTimer = null;
115
+ _escalateKill();
116
+ }, 3000);
117
+ if (killGraceTimer.unref) killGraceTimer.unref();
118
+ };
119
+
120
+ const _clearTimers = () => {
121
+ if (timeoutTimer) {
122
+ clearTimeout(timeoutTimer);
123
+ timeoutTimer = null;
124
+ }
125
+ if (killGraceTimer) {
126
+ clearTimeout(killGraceTimer);
127
+ killGraceTimer = null;
128
+ }
129
+ if (forceSettleTimer) {
130
+ clearTimeout(forceSettleTimer);
131
+ forceSettleTimer = null;
132
+ }
133
+ };
134
+
135
+ // Arm timeout — unref so it doesn't keep the process alive. On timeout we
136
+ // start SIGTERM→grace→force-kill but do NOT settle yet: the promise stays
137
+ // pending until the child's 'close' fires (so the build worker — and the
138
+ // main-thread gate slot it holds — is only released once the process is
139
+ // actually gone). A separate force-settle deadline guarantees the promise
140
+ // still resolves if 'close' never arrives. Mirrors rg-runner exactly.
141
+ timeoutTimer = setTimeout(() => {
142
+ timeoutTimer = null;
143
+ timedOut = true;
144
+ _killProc();
145
+ // Hard backstop: if 'close' never fires after the kill escalation,
146
+ // escalate again and settle so we never hang (and never release the
147
+ // gate while the child is provably still alive without a final attempt).
148
+ if (forceSettleTimer) clearTimeout(forceSettleTimer);
149
+ forceSettleTimer = setTimeout(() => {
150
+ forceSettleTimer = null;
151
+ if (settled) return;
152
+ _escalateKill();
153
+ settled = true;
154
+ _clearTimers();
155
+ reject(new Error(`[code-graph] mixdog-graph timed out after ${timeoutMs}ms`));
156
+ }, 5000);
157
+ if (forceSettleTimer.unref) forceSettleTimer.unref();
158
+ }, timeoutMs);
159
+ if (timeoutTimer.unref) timeoutTimer.unref();
160
+
161
+ proc.stdout.on('data', (c) => chunks.push(c));
162
+ proc.stderr.on('data', (c) => {
163
+ if (stderrText.length >= STDERR_CAP) return;
164
+ const piece = c.toString('utf8');
165
+ const room = STDERR_CAP - stderrText.length;
166
+ stderrText += piece.length > room ? piece.slice(0, room) : piece;
167
+ });
168
+ proc.on('error', (err) => {
169
+ if (settled) return;
170
+ settled = true;
171
+ _clearTimers();
172
+ reject(err);
173
+ });
174
+ if (wantsStdin) {
175
+ proc.stdin.on('error', () => { /* child may close stdin early; ignore EPIPE */ });
176
+ proc.stdin.write(stdinLines.length ? `${stdinLines.join('\n')}\n` : '');
177
+ proc.stdin.end();
178
+ }
179
+ proc.on('close', (code) => {
180
+ if (settled) return;
181
+ settled = true;
182
+ _clearTimers();
183
+ if (timedOut) {
184
+ // Our timeout kill won the race: the child is gone now, so the gate
185
+ // slot releases here (not at timeout-fire time). Report as a timeout.
186
+ reject(new Error(`[code-graph] mixdog-graph timed out after ${timeoutMs}ms`));
187
+ return;
188
+ }
189
+ if (code !== 0) {
190
+ reject(new Error(`[code-graph] mixdog-graph exited ${code}: ${stderrText.trim().slice(0, 200)}`));
191
+ return;
192
+ }
193
+ const out = [];
194
+ const buf = Buffer.concat(chunks).toString('utf8');
195
+ for (const line of buf.split('\n')) {
196
+ const trimmed = line.trim();
197
+ if (!trimmed) continue;
198
+ try {
199
+ const rec = JSON.parse(trimmed);
200
+ if (rec && typeof rec.rel === 'string') out.push(rec);
201
+ } catch { /* skip malformed line */ }
202
+ }
203
+ resolve(out);
204
+ });
205
+ });
206
+
207
+ // Outer call with one EAGAIN retry (mirrors rg-runner runRg / runRgWindowedLines).
208
+ try {
209
+ return await _spawnOnce();
210
+ } catch (err) {
211
+ if (!retried && (err?.code === 'EAGAIN' || /EAGAIN/i.test(String(err?.message || err?.stderr || '')))) {
212
+ retried = true;
213
+ return _spawnOnce();
214
+ }
215
+ throw err;
216
+ }
217
+ }
218
+ export function _runGraphManifest(absRoot) { return _runGraphBinaryJsonl(absRoot, ['--manifest']); }
219
+ export function _runGraphWalk(absRoot) { return _runGraphBinaryJsonl(absRoot, []); }
220
+ // --files (design A: full-graph resolution) full-parses only `rels` (argv) but
221
+ // resolves imports across the WHOLE tree. The reused nodes' metas are streamed
222
+ // to the child via STDIN as JSONL — one JSON object per line:
223
+ // {rel, lang, rawImports, packageName, namespaceName, goPackageName,
224
+ // topLevelTypes}. Rust builds the index + resolves over ALL nodes (fresh +
225
+ // reused) and emits fresh rels as full records, reused rels as lightweight
226
+ // {rel, resolvedImports, importedBy}.
227
+ export function _runGraphFiles(absRoot, rels, reusedMetas) {
228
+ const lines = Array.isArray(reusedMetas)
229
+ ? reusedMetas.map((m) => JSON.stringify({
230
+ rel: m.rel,
231
+ lang: m.lang,
232
+ rawImports: Array.isArray(m.rawImports) ? m.rawImports : [],
233
+ packageName: m.packageName || '',
234
+ namespaceName: m.namespaceName || '',
235
+ goPackageName: m.goPackageName || '',
236
+ topLevelTypes: Array.isArray(m.topLevelTypes) ? m.topLevelTypes : [],
237
+ }))
238
+ : [];
239
+ return _runGraphBinaryJsonl(absRoot, ['--files', ...rels], lines);
240
+ }
241
+
242
+ // Map a Rust FileRecord (rel/lang/fp/tokens/rawImports/resolvedImports/
243
+ // importedBy/...) onto the JS fileInfo shape the graph assembler expects.
244
+ // Import resolution — including Go module paths — now happens entirely in
245
+ // Rust; resolvedImports/importedBy are repo-relative path lists passed
246
+ // straight through.
247
+ export function _fileInfoFromRustRecord(rec, absRoot) {
248
+ const rel = rec.rel;
249
+ const abs = pathResolve(absRoot, rel);
250
+ const lang = rec.lang;
251
+ return {
252
+ abs,
253
+ rel,
254
+ lang,
255
+ fingerprint: typeof rec.fp === 'string' ? rec.fp : '',
256
+ sourceText: null,
257
+ rawImports: Array.isArray(rec.rawImports) ? rec.rawImports : [],
258
+ resolvedImports: Array.isArray(rec.resolvedImports)
259
+ ? rec.resolvedImports.filter((v) => typeof v === 'string')
260
+ : [],
261
+ importedBy: Array.isArray(rec.importedBy)
262
+ ? rec.importedBy.filter((v) => typeof v === 'string')
263
+ : [],
264
+ packageName: typeof rec.packageName === 'string' ? rec.packageName : '',
265
+ namespaceName: typeof rec.namespaceName === 'string' ? rec.namespaceName : '',
266
+ goPackageName: typeof rec.goPackageName === 'string' ? rec.goPackageName : '',
267
+ topLevelTypes: Array.isArray(rec.topLevelTypes) ? rec.topLevelTypes : [],
268
+ tokenSymbols: Array.isArray(rec.tokens) ? rec.tokens : null,
269
+ symbols: Array.isArray(rec.symbols) ? rec.symbols : [],
270
+ };
271
+ }
272
+
273
+ // Reuse a node from the previous graph whose fp is unchanged — skips both
274
+ // the Rust call and re-parsing for files that did not change.
275
+ export function _reuseFileInfo(prevNode, previousGraph, absRoot) {
276
+ const rel = prevNode.rel;
277
+ const fp = prevNode.fingerprint || '';
278
+ const cachedText = previousGraph?._sourceTextCache?.get(rel);
279
+ return {
280
+ abs: prevNode.abs || pathResolve(absRoot, rel),
281
+ rel,
282
+ lang: prevNode.lang,
283
+ fingerprint: fp,
284
+ sourceText: cachedText?.fingerprint === fp ? cachedText.text : null,
285
+ rawImports: Array.isArray(prevNode.rawImports) ? prevNode.rawImports : [],
286
+ resolvedImports: Array.isArray(prevNode.resolvedImportsRel) ? prevNode.resolvedImportsRel : [],
287
+ importedBy: Array.isArray(prevNode.importedBy) ? prevNode.importedBy : [],
288
+ packageName: prevNode.packageName || '',
289
+ namespaceName: prevNode.namespaceName || '',
290
+ goPackageName: prevNode.goPackageName || '',
291
+ topLevelTypes: Array.isArray(prevNode.topLevelTypes) ? prevNode.topLevelTypes : [],
292
+ tokenSymbols: Array.isArray(prevNode.tokenSymbols) ? prevNode.tokenSymbols : null,
293
+ symbols: Array.isArray(prevNode.symbols) ? prevNode.symbols : [],
294
+ };
295
+ }
@@ -0,0 +1,158 @@
1
+ // Graph (de)serialization, runtime-cache lifecycle, and signature hashing.
2
+ // Extracted verbatim from code-graph.mjs. Graph shape: { cwd, nodes:
3
+ // Map<rel,node>, reverse: Map<rel,Set<rel>>, schemaVersion, builtAt,
4
+ // signature, +runtime caches }. Persisted form omits empty fields.
5
+ import { createHash } from 'node:crypto';
6
+ import { resolve as pathResolve } from 'node:path';
7
+ import { SYMBOL_SCHEMA_VERSION, CODE_GRAPH_MAX_FILES } from './constants.mjs';
8
+
9
+ export function _computeGraphSignature(fileMetas) {
10
+ const hash = createHash('sha1');
11
+ hash.update(`${SYMBOL_SCHEMA_VERSION}\n`);
12
+ // R5-③: include rel/path alongside fp so renames and path-swaps (same
13
+ // bytes moved to a different rel, or two files exchanging paths) flip
14
+ // the signature and invalidate the memory/disk cache checks at the
15
+ // call sites just below in buildCodeGraphAsync. Without rel, an fp-only
16
+ // hash collides across rename pairs and the cache serves stale graph
17
+ // topology where node.rel no longer matches what's on disk.
18
+ for (const meta of fileMetas) hash.update(`${meta.rel || ''}\0${meta.fp}\n`);
19
+ return hash.digest('hex');
20
+ }
21
+
22
+ export function _serializeGraph(graph) {
23
+ // Compact-on-disk: omit empty / falsy fields. Saves ~30-50% on disk
24
+ // for typical mixed-language graphs because most nodes don't carry
25
+ // packageName / namespaceName / topLevelTypes. Smaller
26
+ // payload → faster JSON.parse on cold-process boot. _deserializeGraph
27
+ // tolerates missing fields by defaulting to '' / [].
28
+ return {
29
+ schemaVersion: SYMBOL_SCHEMA_VERSION,
30
+ builtAt: Number(graph?.builtAt || Date.now()),
31
+ signature: String(graph?.signature || ''),
32
+ truncated: Boolean(graph?.truncated),
33
+ maxFiles: CODE_GRAPH_MAX_FILES,
34
+ nodes: [...(graph?.nodes?.values?.() || [])].map((node) => {
35
+ const out = {
36
+ rel: node.rel,
37
+ lang: node.lang,
38
+ };
39
+ if (node.fingerprint) out.fingerprint = node.fingerprint;
40
+ if (Array.isArray(node.rawImports) && node.rawImports.length) out.rawImports = node.rawImports;
41
+ if (Array.isArray(node.resolvedImportsRel) && node.resolvedImportsRel.length) {
42
+ out.resolvedImports = node.resolvedImportsRel;
43
+ }
44
+ if (Array.isArray(node.importedBy) && node.importedBy.length) {
45
+ out.importedBy = node.importedBy;
46
+ }
47
+ if (node.packageName) out.packageName = node.packageName;
48
+ if (node.namespaceName) out.namespaceName = node.namespaceName;
49
+ if (node.goPackageName) out.goPackageName = node.goPackageName;
50
+ if (Array.isArray(node.topLevelTypes) && node.topLevelTypes.length) {
51
+ out.topLevelTypes = node.topLevelTypes;
52
+ }
53
+ if (Array.isArray(node.tokenSymbols) && node.tokenSymbols.length) {
54
+ out.tokenSymbols = node.tokenSymbols;
55
+ }
56
+ if (Array.isArray(node.symbols) && node.symbols.length) {
57
+ out.symbols = node.symbols;
58
+ }
59
+ return out;
60
+ }),
61
+ };
62
+ }
63
+
64
+ export function _deserializeGraph(cwd, payload) {
65
+ if (!payload || typeof payload !== 'object' || !Array.isArray(payload.nodes)) return null;
66
+ const nodes = new Map();
67
+ const reverse = new Map();
68
+ for (const item of payload.nodes) {
69
+ if (!item || typeof item.rel !== 'string' || typeof item.lang !== 'string') continue;
70
+ // Persisted fields are repo-relative, mirroring the live build. The
71
+ // JS resolution layer is gone — resolvedImports/resolvedImportsRel are
72
+ // restored straight from disk; the reverse index is rederived below from
73
+ // the forward edges of every node.
74
+ const resolvedImportsRel = Array.isArray(item.resolvedImports) ? item.resolvedImports.filter((v) => typeof v === 'string') : [];
75
+ const importedBy = Array.isArray(item.importedBy) ? item.importedBy.filter((v) => typeof v === 'string') : [];
76
+ const node = {
77
+ abs: pathResolve(cwd, item.rel),
78
+ rel: item.rel,
79
+ lang: item.lang,
80
+ fingerprint: item.fingerprint || '',
81
+ rawImports: Array.isArray(item.rawImports) ? item.rawImports : [],
82
+ resolvedImportsRel,
83
+ resolvedImports: resolvedImportsRel.map((rel) => pathResolve(cwd, rel)),
84
+ importedBy,
85
+ packageName: item.packageName || '',
86
+ namespaceName: item.namespaceName || '',
87
+ goPackageName: item.goPackageName || '',
88
+ topLevelTypes: Array.isArray(item.topLevelTypes) ? item.topLevelTypes : [],
89
+ tokenSymbols: Array.isArray(item.tokenSymbols) ? item.tokenSymbols : null,
90
+ symbols: Array.isArray(item.symbols) ? item.symbols : [],
91
+ };
92
+ nodes.set(node.rel, node);
93
+ // reverse is derived from the FORWARD edges of every node, not from the
94
+ // persisted importedBy. On the incremental --files path reused nodes carry
95
+ // a stale importedBy, so a fresh edge A→B (A parsed, B reused) would drop
96
+ // B's reverse entry. Walking resolvedImportsRel keeps reverse self-consistent.
97
+ for (const rel of resolvedImportsRel) {
98
+ if (!reverse.has(rel)) reverse.set(rel, new Set());
99
+ reverse.get(rel).add(node.rel);
100
+ }
101
+ }
102
+ const graph = _attachGraphRuntimeCaches({
103
+ cwd,
104
+ nodes,
105
+ reverse,
106
+ // Pre-endLine disk payloads have no schemaVersion → null → dropped by the
107
+ // previousGraph schema guard so their endLine-less nodes never seed reuse.
108
+ schemaVersion: typeof payload.schemaVersion === 'string' ? payload.schemaVersion : null,
109
+ builtAt: Number(payload.builtAt || Date.now()),
110
+ signature: String(payload.signature || ''),
111
+ });
112
+ // Restore the truncation flag persisted from the live build so disk-cache
113
+ // hits keep emitting the WARN line in find_symbol/overview output instead
114
+ // of silently working with a partial graph.
115
+ if (graph && payload.truncated) graph.truncated = true;
116
+ return graph;
117
+ }
118
+
119
+ export function _attachGraphRuntimeCaches(graph) {
120
+ if (!graph || typeof graph !== 'object') return graph;
121
+ if (!graph._referenceSearchCache) graph._referenceSearchCache = new Map();
122
+ if (!graph._maskedLinesCache) graph._maskedLinesCache = new Map();
123
+ if (!graph._sourceLinesCache) graph._sourceLinesCache = new Map();
124
+ if (!graph._sourceTextCache) graph._sourceTextCache = new Map();
125
+ if (!graph._symbolTokenIndex) graph._symbolTokenIndex = new Map();
126
+ if (typeof graph._symbolTokenIndexDirty !== 'boolean') graph._symbolTokenIndexDirty = true;
127
+ return graph;
128
+ }
129
+
130
+ export function _estimateGraphRuntimeCacheBytes(graph) {
131
+ if (!graph) return 0;
132
+ let total = 0;
133
+ for (const entry of graph._sourceTextCache?.values() || []) {
134
+ total += Buffer.byteLength(String(entry?.text || ''), 'utf8');
135
+ }
136
+ for (const lines of graph._maskedLinesCache?.values() || []) {
137
+ if (!Array.isArray(lines)) continue;
138
+ for (const line of lines) total += Buffer.byteLength(String(line || ''), 'utf8');
139
+ }
140
+ for (const lines of graph._sourceLinesCache?.values() || []) {
141
+ if (!Array.isArray(lines)) continue;
142
+ for (const line of lines) total += Buffer.byteLength(String(line || ''), 'utf8');
143
+ }
144
+ for (const memo of graph._referenceSearchCache?.values() || []) {
145
+ total += Buffer.byteLength(String(memo || ''), 'utf8');
146
+ }
147
+ return total;
148
+ }
149
+
150
+ export function _clearGraphRuntimeCaches(graph) {
151
+ if (!graph) return;
152
+ graph._sourceTextCache?.clear();
153
+ graph._maskedLinesCache?.clear();
154
+ graph._sourceLinesCache?.clear();
155
+ graph._referenceSearchCache?.clear();
156
+ graph._symbolTokenIndex?.clear();
157
+ graph._symbolTokenIndexDirty = true;
158
+ }
@@ -0,0 +1,82 @@
1
+ // Keyword-to-symbol fuzzy matching: tokenization, token-aligned contiguous
2
+ // match, ordered token match, and ranking key. Pure string helpers with no
3
+ // graph/cache state. Extracted from search.mjs.
4
+
5
+ export function _keywordSymbolSortKey(symbolName, keyword) {
6
+ const lowerName = String(symbolName || '').toLowerCase();
7
+ const lowerKey = String(keyword || '').toLowerCase();
8
+ const idx = lowerName.indexOf(lowerKey);
9
+ if (idx < 0) return null;
10
+ const atStart = idx === 0 ? 0 : 1;
11
+ return [lowerName.length, atStart, idx, symbolName];
12
+ }
13
+
14
+ export function _tokenizeKeyword(s) {
15
+ return String(s || '')
16
+ .replace(/([a-z0-9])([A-Z])/g, '$1 $2')
17
+ .split(/[^a-zA-Z0-9]+/)
18
+ .filter(Boolean)
19
+ .map((t) => t.toLowerCase());
20
+ }
21
+
22
+ function _tokenStartOffsets(sym) {
23
+ const starts = new Set();
24
+ let prevAlnum = false;
25
+ let prevUpper = false;
26
+ for (let i = 0; i < sym.length; i += 1) {
27
+ const c = sym[i];
28
+ const isAlnum = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
29
+ if (!isAlnum) { prevAlnum = false; prevUpper = false; continue; }
30
+ const isUpper = c >= 'A' && c <= 'Z';
31
+ if (!prevAlnum) starts.add(i);
32
+ else if (isUpper && !prevUpper) starts.add(i);
33
+ prevAlnum = true;
34
+ prevUpper = isUpper;
35
+ }
36
+ return starts;
37
+ }
38
+
39
+ function _contiguousMatchTokenAligned(sym, lowerKey) {
40
+ const len = lowerKey.length;
41
+ if (!len) return false;
42
+ const symLower = sym.toLowerCase();
43
+ const starts = _tokenStartOffsets(sym);
44
+ let lead = 0;
45
+ while (lead < len) {
46
+ const c = lowerKey[lead];
47
+ const isAlnum = (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9');
48
+ if (isAlnum) break;
49
+ lead += 1;
50
+ }
51
+ let from = 0;
52
+ for (;;) {
53
+ const idx = symLower.indexOf(lowerKey, from);
54
+ if (idx < 0) return false;
55
+ const end = idx + len;
56
+ const effectiveIdx = idx + lead;
57
+ if (starts.has(effectiveIdx)) return true;
58
+ let interiorBoundary = false;
59
+ for (const s of starts) {
60
+ if (s > effectiveIdx && s < end) { interiorBoundary = true; break; }
61
+ }
62
+ if (!interiorBoundary) return true;
63
+ from = idx + 1;
64
+ }
65
+ }
66
+
67
+ function _orderedTokenMatch(symLower, tokens) {
68
+ let from = 0;
69
+ for (const t of tokens) {
70
+ const i = symLower.indexOf(t, from);
71
+ if (i < 0) return false;
72
+ from = i + t.length;
73
+ }
74
+ return true;
75
+ }
76
+
77
+ export function _keywordMatchesSymbolName(name, lowerKey, keyTokens) {
78
+ const sym = String(name || '').trim();
79
+ if (!sym || !lowerKey) return false;
80
+ if (_contiguousMatchTokenAligned(sym, lowerKey)) return true;
81
+ return keyTokens.length >= 2 && _orderedTokenMatch(sym.toLowerCase(), keyTokens);
82
+ }
@@ -0,0 +1,128 @@
1
+ // Per-language lexical predicates + JS tokenizer character/keyword sets.
2
+ // Pure functions, no state. Extracted verbatim from code-graph.mjs; shared
3
+ // by the text masker, symbol index, and search/format layers.
4
+
5
+ export function _langUsesDollarInIdentifiers(lang) {
6
+ // `$` is a valid identifier char only in JS/TS/PHP. The 5 new langs are
7
+ // deliberately excluded: kotlin/swift/scala/lua have no `$` in identifiers,
8
+ // and bash's `$` is a variable-expansion sigil (`$var`), not an identifier
9
+ // char — treating it as a word-boundary char would mis-tokenize.
10
+ // Second batch (dart/objc/elixir/zig/r) likewise excluded: none use `$` as
11
+ // an identifier char (objc `$` is invalid; elixir/dart/zig/r have no `$` in
12
+ // names), so they stay out.
13
+ return lang === 'javascript' || lang === 'typescript' || lang === 'php';
14
+ }
15
+
16
+ export function _langAllowsBangQuestionSuffix(lang) {
17
+ // Method names may end in `!`/`?` only in ruby (`save!`/`empty?`) and rust
18
+ // (`!` macros). Kotlin is NOT here: its `!!` is the not-null assertion
19
+ // OPERATOR, not an identifier suffix — including it would fold `foo!!` into
20
+ // the `foo` reference and break matching. swift `?`/`!` are optional/
21
+ // force-unwrap operators (not name chars); scala/bash/lua have no suffix.
22
+ // Second batch: elixir function names may end in `?`/`!` (`valid?`/`save!`)
23
+ // exactly like ruby → included. dart/objc/zig/r have no such suffix.
24
+ return lang === 'ruby' || lang === 'rust' || lang === 'elixir';
25
+ }
26
+
27
+ export function _supportsHashComments(lang) {
28
+ // Hash-comment langs: python/ruby/php plus bash. lua is NOT hash — it uses
29
+ // `--` line + `--[[ ]]` block comments (see _maskNonCodeText). kotlin/
30
+ // swift/scala are slash-comment C-family (see _supportsSlashComments).
31
+ // Second batch: elixir and r are `#`-only line-comment langs → included.
32
+ // (dart/objc/zig are slash-comment, handled by _supportsSlashComments.)
33
+ return lang === 'python' || lang === 'ruby' || lang === 'php'
34
+ || lang === 'bash' || lang === 'elixir' || lang === 'r';
35
+ }
36
+
37
+ export function _supportsSlashComments(lang) {
38
+ // Slash-comment langs: everything C-family, incl. new kotlin/swift/scala.
39
+ // Excluded: python/ruby/bash (hash) and lua (`--` comments; `//` is lua
40
+ // integer division, so it must not be treated as a comment opener).
41
+ // Second batch: dart/objc/zig are C-family slash-comment (kept by the
42
+ // default). Excluded here: elixir/r (hash-only, see _supportsHashComments).
43
+ return lang !== 'python' && lang !== 'ruby'
44
+ && lang !== 'bash' && lang !== 'lua'
45
+ && lang !== 'elixir' && lang !== 'r';
46
+ }
47
+
48
+ export function _supportsSingleQuoteStrings(lang) {
49
+ return lang === 'typescript'
50
+ || lang === 'javascript'
51
+ || lang === 'python'
52
+ || lang === 'ruby'
53
+ || lang === 'php'
54
+ // New langs with single-quote string literals: swift uses double quotes
55
+ // only (excluded); kotlin uses double/triple-double (excluded); scala
56
+ // single-quotes are Char literals not strings (excluded); bash and lua
57
+ // both support `'...'` single-quoted strings.
58
+ || lang === 'bash'
59
+ || lang === 'lua'
60
+ // Second batch. dart: `'...'` is a primary string form → included. r:
61
+ // `'...'` is a string literal equivalent to `"..."` → included. objc:
62
+ // `'x'` is a char literal — INCLUDED here so its contents are masked as a
63
+ // single-quote string. This deliberately DIVERGES from c/cpp, which are
64
+ // NOT in this list: objc's masker benefits from neutralizing char-literal
65
+ // bytes, whereas c/cpp char literals are left unmasked.
66
+ // elixir: EXCLUDED — `'...'` is a charlist, not a string; but charlists
67
+ // are single-line and `\\`-escaped just like a string, so masking them as
68
+ // strings would be safe — they are nonetheless left out to keep elixir
69
+ // string handling limited to `"..."`/`"""` (charlist contents are rare in
70
+ // code-graph anchors and excluding avoids masking a stray apostrophe in a
71
+ // comment-less context). zig: EXCLUDED — `'c'` is a char literal only and
72
+ // zig multiline strings are `\\`-prefixed lines (out of scope), so no
73
+ // single-quote string form applies.
74
+ || lang === 'dart'
75
+ || lang === 'r'
76
+ || lang === 'objc';
77
+ }
78
+
79
+ export function _supportsBacktickStrings(lang) {
80
+ return lang === 'typescript' || lang === 'javascript' || lang === 'go';
81
+ }
82
+
83
+ export function _supportsTripleSingleQuoteStrings(lang) {
84
+ // `'''` triple-single-quote strings: python, and dart (which supports BOTH
85
+ // `'''` and `"""` multiline strings). kotlin/scala/swift have `"""` but NOT
86
+ // `'''`; treating `'''` as a string opener there would mis-mask a
87
+ // single-quote char/string followed by an empty string.
88
+ return lang === 'python' || lang === 'dart';
89
+ }
90
+
91
+ export function _supportsTripleDoubleQuoteStrings(lang) {
92
+ // `"""` triple-double-quote raw/multiline strings: python, kotlin, scala
93
+ // and swift. bash/lua have no triple-quote form (lua long strings use
94
+ // `[[ ]]`).
95
+ // Second batch: elixir `"""` heredoc docstrings → included. dart supports
96
+ // BOTH `'''` and `"""` multiline strings → included here (and in the triple-
97
+ // single predicate). objc/zig/r have no `"""` form.
98
+ return lang === 'python' || lang === 'kotlin'
99
+ || lang === 'scala' || lang === 'swift' || lang === 'elixir'
100
+ || lang === 'dart';
101
+ }
102
+
103
+ export function _isJsLike(lang) {
104
+ return lang === 'javascript' || lang === 'typescript';
105
+ }
106
+
107
+ export function _isWordStartChar(c) {
108
+ return c === '_' || c === '$'
109
+ || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
110
+ }
111
+
112
+ export function _isWordChar(c) {
113
+ return _isWordStartChar(c) || (c >= '0' && c <= '9');
114
+ }
115
+
116
+ // ECMAScript expression-context keywords that can precede a regex literal.
117
+ // After any of these, a `/` opens a RegExp literal; after a value (identifier,
118
+ // number, `)`, `]`), `/` is the division operator. This list is from the
119
+ // language spec — not a heuristic — and resolves the `/`-ambiguity.
120
+ export const REGEX_PRECEDENT_KEYWORDS = new Set([
121
+ 'return', 'typeof', 'delete', 'void', 'new', 'throw', 'await', 'yield',
122
+ 'in', 'of', 'instanceof', 'case', 'do', 'else', 'if', 'while',
123
+ ]);
124
+
125
+ export const REGEX_PRECEDENT_CHARS = new Set([
126
+ '=', '(', ',', ';', ':', '?', '!', '~', '&', '|', '^', '+', '-',
127
+ '*', '%', '<', '>', '{', '[',
128
+ ]);