@unerr-ai/unerr 0.1.0 → 0.1.2

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 (553) hide show
  1. package/dist/__tests__/architecture-guard.test.js +122 -0
  2. package/dist/__tests__/arg-validator.test.js +205 -0
  3. package/dist/__tests__/ast-extractor.test.js +203 -0
  4. package/dist/__tests__/auto-bootstrap.test.js +280 -0
  5. package/dist/__tests__/background-indexer.test.js +228 -0
  6. package/dist/__tests__/blast-radius-engine.test.js +200 -0
  7. package/dist/__tests__/bridge-isolation.test.js +37 -0
  8. package/dist/__tests__/budget-enforcer.test.js +53 -0
  9. package/dist/__tests__/cfg-test-detection-perf.test.js +82 -0
  10. package/dist/__tests__/change-narrative.test.js +190 -0
  11. package/dist/__tests__/check-commit.test.js +258 -0
  12. package/dist/__tests__/checksum.test.js +34 -0
  13. package/dist/__tests__/commit-watcher.test.js +154 -0
  14. package/dist/__tests__/community-detection.test.js +179 -0
  15. package/dist/__tests__/community-tools.test.js +299 -0
  16. package/dist/__tests__/components.test.js +449 -0
  17. package/dist/__tests__/compression-log.test.js +174 -0
  18. package/dist/__tests__/compression-quality-monitor.test.js +40 -0
  19. package/dist/__tests__/config-healer.test.js +165 -0
  20. package/dist/__tests__/context-ledger.test.js +58 -0
  21. package/dist/__tests__/convention-detector.test.js +99 -0
  22. package/dist/__tests__/convention-learner.test.js +86 -0
  23. package/dist/__tests__/correction-detector.test.js +330 -0
  24. package/dist/__tests__/daemon-autostart-install.test.js +283 -0
  25. package/dist/__tests__/daemon-bridge.test.js +222 -0
  26. package/dist/__tests__/daemon-dashboard.test.js +202 -0
  27. package/dist/__tests__/daemon-registry.test.js +240 -0
  28. package/dist/__tests__/daemon-supervisor.test.js +318 -0
  29. package/dist/__tests__/daemon-version-check.test.js +275 -0
  30. package/dist/__tests__/decision-point-detector.test.js +98 -0
  31. package/dist/__tests__/deep-link.test.js +143 -0
  32. package/dist/__tests__/disallowed-tools.test.js +115 -0
  33. package/dist/__tests__/drift-tracker.test.js +582 -0
  34. package/dist/__tests__/durability-scorer.test.js +152 -0
  35. package/dist/__tests__/efficiency-tracker.test.js +65 -0
  36. package/dist/__tests__/enrich.test.js +144 -0
  37. package/dist/__tests__/entity-rewind.test.js +248 -0
  38. package/dist/__tests__/ephemeral.test.js +111 -0
  39. package/dist/__tests__/exploration-cost.test.js +93 -0
  40. package/dist/__tests__/fact-generator.test.js +197 -0
  41. package/dist/__tests__/file-l0-graph.test.js +244 -0
  42. package/dist/__tests__/file-logger.test.js +82 -0
  43. package/dist/__tests__/file-outline.test.js +141 -0
  44. package/dist/__tests__/file-read-protocol.test.js +188 -0
  45. package/dist/__tests__/format-encoder.test.js +233 -0
  46. package/dist/__tests__/git-attribution.test.js +259 -0
  47. package/dist/__tests__/graph-temporal-joiner.test.js +219 -0
  48. package/dist/__tests__/health-grade-enhanced.test.js +138 -0
  49. package/dist/__tests__/health-map-data.test.js +173 -0
  50. package/dist/__tests__/helpers/mcp-harness.js +45 -0
  51. package/dist/__tests__/helpers/mcp-harness.test.js +68 -0
  52. package/dist/__tests__/hook-dedup.test.js +112 -0
  53. package/dist/__tests__/hook-runner.test.js +253 -0
  54. package/dist/__tests__/indexer-cfg.test.js +185 -0
  55. package/dist/__tests__/indexer-cross-file.test.js +172 -0
  56. package/dist/__tests__/indexer-extraction.test.js +245 -0
  57. package/dist/__tests__/indexer-incremental.test.js +232 -0
  58. package/dist/__tests__/indexer-language-expansion.test.js +165 -0
  59. package/dist/__tests__/init-push.test.js +131 -0
  60. package/dist/__tests__/instruction-writer.test.js +179 -0
  61. package/dist/__tests__/intelligence-integration.test.js +217 -0
  62. package/dist/__tests__/intent-correlator.test.js +175 -0
  63. package/dist/__tests__/intent-detector.test.js +235 -0
  64. package/dist/__tests__/intent-encoder.test.js +167 -0
  65. package/dist/__tests__/java-build-tool-detection.test.js +174 -0
  66. package/dist/__tests__/layer3-sprint-q.test.js +160 -0
  67. package/dist/__tests__/layer3-sprint-r.test.js +91 -0
  68. package/dist/__tests__/layer3-sprint-s.test.js +183 -0
  69. package/dist/__tests__/layer3-sprint-t.test.js +201 -0
  70. package/dist/__tests__/layer3-sprint-u.test.js +174 -0
  71. package/dist/__tests__/layer4-sprint-ba2.test.js +354 -0
  72. package/dist/__tests__/layer4-sprint-ba4.test.js +84 -0
  73. package/dist/__tests__/layer4-sprint-vs.test.js +105 -0
  74. package/dist/__tests__/ledger-chains.test.js +162 -0
  75. package/dist/__tests__/lifecycle-machine.test.js +226 -0
  76. package/dist/__tests__/local-chat-provider.test.js +170 -0
  77. package/dist/__tests__/local-convention-detector.test.js +308 -0
  78. package/dist/__tests__/local-embeddings.test.js +422 -0
  79. package/dist/__tests__/local-graph.test.js +540 -0
  80. package/dist/__tests__/local-indexer.test.js +228 -0
  81. package/dist/__tests__/local-intelligence-l3.test.js +332 -0
  82. package/dist/__tests__/local-llm.test.js +253 -0
  83. package/dist/__tests__/local-mode-offline.test.js +187 -0
  84. package/dist/__tests__/local-mode-stats.test.js +273 -0
  85. package/dist/__tests__/local-mode-tui.test.js +343 -0
  86. package/dist/__tests__/local-parse.test.js +199 -0
  87. package/dist/__tests__/log-tailer.test.js +208 -0
  88. package/dist/__tests__/loop-breaker.test.js +276 -0
  89. package/dist/__tests__/loop-miner.test.js +226 -0
  90. package/dist/__tests__/mcp-config.test.js +126 -0
  91. package/dist/__tests__/mcp-content-json.test.js +10 -0
  92. package/dist/__tests__/mcp-envelope.test.js +124 -0
  93. package/dist/__tests__/metrics-store.test.js +223 -0
  94. package/dist/__tests__/native-watcher.test.js +191 -0
  95. package/dist/__tests__/navigation-hooks-agent-aware.test.js +145 -0
  96. package/dist/__tests__/negative-knowledge.test.js +116 -0
  97. package/dist/__tests__/network-boundary.test.js +190 -0
  98. package/dist/__tests__/network-firewall.test.js +112 -0
  99. package/dist/__tests__/nudge-invariants.test.js +160 -0
  100. package/dist/__tests__/nudge-v2.test.js +225 -0
  101. package/dist/__tests__/offline-rewind.test.js +251 -0
  102. package/dist/__tests__/open-threads.test.js +89 -0
  103. package/dist/__tests__/output-compressor.test.js +93 -0
  104. package/dist/__tests__/pending-violations.test.js +112 -0
  105. package/dist/__tests__/persistence-effectiveness.test.js +143 -0
  106. package/dist/__tests__/provider-factory.test.js +42 -0
  107. package/dist/__tests__/providers.test.js +24 -0
  108. package/dist/__tests__/proxy.test.js +314 -0
  109. package/dist/__tests__/query-router.test.js +1018 -0
  110. package/dist/__tests__/reasoning-quality-route.test.js +138 -0
  111. package/dist/__tests__/redactor.test.js +120 -0
  112. package/dist/__tests__/resource-monitor.test.js +57 -0
  113. package/dist/__tests__/response-envelope.test.js +100 -0
  114. package/dist/__tests__/risk-classifier.test.js +101 -0
  115. package/dist/__tests__/risk-signal-scope.test.js +75 -0
  116. package/dist/__tests__/rule-evaluator.test.js +280 -0
  117. package/dist/__tests__/scip-decoder.test.js +49 -0
  118. package/dist/__tests__/scip-downloader.test.js +201 -0
  119. package/dist/__tests__/scip-merger.test.js +103 -0
  120. package/dist/__tests__/search-index.test.js +422 -0
  121. package/dist/__tests__/semantic-enrichment.test.js +360 -0
  122. package/dist/__tests__/session-brief-builder.test.js +187 -0
  123. package/dist/__tests__/session-context.test.js +221 -0
  124. package/dist/__tests__/session-continuity.test.js +144 -0
  125. package/dist/__tests__/session-dedup.test.js +74 -0
  126. package/dist/__tests__/session-event-wiring.test.js +206 -0
  127. package/dist/__tests__/session-events.test.js +149 -0
  128. package/dist/__tests__/session-legend.test.js +20 -0
  129. package/dist/__tests__/session-persistence.test.js +131 -0
  130. package/dist/__tests__/session-resume-block.test.js +107 -0
  131. package/dist/__tests__/session-resume.test.js +97 -0
  132. package/dist/__tests__/session-summary-writer.test.js +134 -0
  133. package/dist/__tests__/shadow-ledger.test.js +203 -0
  134. package/dist/__tests__/shell-classifier.test.js +151 -0
  135. package/dist/__tests__/shell-compression-floor.test.js +189 -0
  136. package/dist/__tests__/shell-compression-v2.test.js +339 -0
  137. package/dist/__tests__/shell-compressor.test.js +35 -0
  138. package/dist/__tests__/shell-hooks.test.js +128 -0
  139. package/dist/__tests__/shell-strategies.test.js +644 -0
  140. package/dist/__tests__/shell-tee.test.js +133 -0
  141. package/dist/__tests__/signal-dedup.test.js +158 -0
  142. package/dist/__tests__/signal-reinforcer.test.js +77 -0
  143. package/dist/__tests__/signal-scorer.test.js +251 -0
  144. package/dist/__tests__/signal-show-store.test.js +108 -0
  145. package/dist/__tests__/smart-truncate.test.js +215 -0
  146. package/dist/__tests__/snapshot-v2.test.js +113 -0
  147. package/dist/__tests__/sprint-l1-local-mode.test.js +130 -0
  148. package/dist/__tests__/sprint-l10-boot.test.js +220 -0
  149. package/dist/__tests__/sprint-l9-offline-commands.test.js +189 -0
  150. package/dist/__tests__/sprint-q-persistent-context.test.js +198 -0
  151. package/dist/__tests__/sprint-s1-wiring.test.js +215 -0
  152. package/dist/__tests__/sprint-s2-wiring.test.js +256 -0
  153. package/dist/__tests__/sprint-s3-wiring.test.js +195 -0
  154. package/dist/__tests__/sprint-s4-wiring.test.js +213 -0
  155. package/dist/__tests__/sprint-s6-hooks.test.js +222 -0
  156. package/dist/__tests__/sprint-s7-persistent.test.js +263 -0
  157. package/dist/__tests__/sprint-s8-value.test.js +167 -0
  158. package/dist/__tests__/sprint-s9-behavioral.test.js +179 -0
  159. package/dist/__tests__/sprint3-intelligence.test.js +297 -0
  160. package/dist/__tests__/sprint5-mcp-server.test.js +136 -0
  161. package/dist/__tests__/startup-display.test.js +302 -0
  162. package/dist/__tests__/startup-log-file.test.js +97 -0
  163. package/dist/__tests__/stash-manager.test.js +229 -0
  164. package/dist/__tests__/state-detector.test.js +92 -0
  165. package/dist/__tests__/status-dashboard.test.js +142 -0
  166. package/dist/__tests__/temporal-facts.test.js +292 -0
  167. package/dist/__tests__/temporal-routes.test.js +142 -0
  168. package/dist/__tests__/test-detector.test.js +174 -0
  169. package/dist/__tests__/theme.test.js +72 -0
  170. package/dist/__tests__/timeline-agents.test.js +122 -0
  171. package/dist/__tests__/timeline-bootstrap.test.js +176 -0
  172. package/dist/__tests__/timeline-filters.test.js +193 -0
  173. package/dist/__tests__/timeline-markers.test.js +151 -0
  174. package/dist/__tests__/timeline-routes.test.js +156 -0
  175. package/dist/__tests__/timeline-store.test.js +171 -0
  176. package/dist/__tests__/token-counter.test.js +86 -0
  177. package/dist/__tests__/token-estimator.test.js +96 -0
  178. package/dist/__tests__/token-flow-api.test.js +239 -0
  179. package/dist/__tests__/token-flow-instrumentation.test.js +437 -0
  180. package/dist/__tests__/token-flow-persistence.test.js +356 -0
  181. package/dist/__tests__/token-flow-routes.test.js +199 -0
  182. package/dist/__tests__/token-flow.test.js +695 -0
  183. package/dist/__tests__/tool-clusters.test.js +177 -0
  184. package/dist/__tests__/transport-mux.test.js +283 -0
  185. package/dist/__tests__/turn-segmenter.test.js +166 -0
  186. package/dist/__tests__/uninstall.test.js +141 -0
  187. package/dist/__tests__/warm-start-policy.test.js +271 -0
  188. package/dist/__tests__/wire-cap-nudge.test.js +77 -0
  189. package/dist/__tests__/worker-pool.test.js +101 -0
  190. package/dist/behaviors/agent-llm-bridge.js +166 -0
  191. package/dist/behaviors/architecture-guard.js +256 -0
  192. package/dist/behaviors/auto-doc.js +247 -0
  193. package/dist/behaviors/cascade-guard.js +289 -0
  194. package/dist/behaviors/change-narrative.js +270 -0
  195. package/dist/behaviors/convention-drift.js +290 -0
  196. package/dist/behaviors/framework.js +235 -0
  197. package/dist/behaviors/guard-formatter.js +44 -0
  198. package/dist/behaviors/incomplete-work.js +270 -0
  199. package/dist/behaviors/loop-breaker.js +300 -0
  200. package/dist/behaviors/session-continuity.js +208 -0
  201. package/dist/cli.js +996 -710
  202. package/dist/commands/branches.js +97 -0
  203. package/dist/commands/check-commit.js +225 -0
  204. package/dist/commands/compress-output.js +64 -0
  205. package/dist/commands/config-verify.js +243 -0
  206. package/dist/commands/daemon.js +905 -0
  207. package/dist/commands/dashboard.js +52 -0
  208. package/dist/commands/debug.js +200 -0
  209. package/dist/commands/enrich.js +184 -0
  210. package/dist/commands/exec.js +233 -0
  211. package/dist/commands/gain.js +156 -0
  212. package/dist/commands/hook.js +88 -0
  213. package/dist/commands/index.js +88 -0
  214. package/dist/commands/init.js +74 -0
  215. package/dist/commands/install.js +505 -0
  216. package/dist/commands/learn.js +116 -0
  217. package/dist/commands/manifest.js +193 -0
  218. package/dist/commands/rewind.js +103 -0
  219. package/dist/commands/serve.js +19 -0
  220. package/dist/commands/setup-wizard.js +414 -0
  221. package/dist/commands/skills.js +64 -0
  222. package/dist/commands/stats.js +20 -0
  223. package/dist/commands/status.js +654 -0
  224. package/dist/commands/timeline.js +139 -0
  225. package/dist/commands/uninstall.js +230 -0
  226. package/dist/components/App.js +109 -0
  227. package/dist/components/Banner.js +12 -0
  228. package/dist/components/ConfirmPrompt.js +25 -0
  229. package/dist/components/DriftSummary.js +23 -0
  230. package/dist/components/GradeBadge.js +15 -0
  231. package/dist/components/HealthCard.js +18 -0
  232. package/dist/components/InkSpinner.js +22 -0
  233. package/dist/components/InputBox.js +17 -0
  234. package/dist/components/KeyValue.js +13 -0
  235. package/dist/components/MessageList.js +14 -0
  236. package/dist/components/ProgressBar.js +26 -0
  237. package/dist/components/Section.js +16 -0
  238. package/dist/components/SessionSummaryCard.js +73 -0
  239. package/dist/components/StartupDisplay.js +24 -0
  240. package/dist/components/StatusDashboard.js +57 -0
  241. package/dist/components/StatusLine.js +8 -0
  242. package/dist/components/StepLine.js +22 -0
  243. package/dist/components/Theme.js +20 -0
  244. package/dist/components/ToolProgress.js +8 -0
  245. package/dist/components/ViolationList.js +21 -0
  246. package/dist/components/render.js +13 -0
  247. package/dist/config/agent-registry.js +237 -0
  248. package/dist/config/claude-settings-hooks.js +304 -0
  249. package/dist/config/hook-installer.js +65 -0
  250. package/dist/config/instruction-writer.js +388 -0
  251. package/dist/config/mcp-config-writer.js +266 -0
  252. package/dist/config/settings.js +174 -0
  253. package/dist/config/tool-detector.js +42 -0
  254. package/dist/config/value-surfacing.js +119 -0
  255. package/dist/core/context-assembly.js +108 -0
  256. package/dist/core/conversation.js +33 -0
  257. package/dist/core/local-chat-provider.js +475 -0
  258. package/dist/core/provider-factory.js +55 -0
  259. package/dist/core/providers.js +90 -0
  260. package/dist/core/query-engine.js +174 -0
  261. package/dist/daemon/api.js +312 -0
  262. package/dist/daemon/autostart.js +119 -0
  263. package/dist/daemon/bootstrap.js +39 -0
  264. package/dist/daemon/client.js +164 -0
  265. package/dist/daemon/detect-ci.js +81 -0
  266. package/dist/daemon/platform-linux.js +146 -0
  267. package/dist/daemon/platform-macos.js +134 -0
  268. package/dist/daemon/platform-windows.js +116 -0
  269. package/dist/daemon/process-manager.js +299 -0
  270. package/dist/daemon/protocol.js +23 -0
  271. package/dist/daemon/registry.js +270 -0
  272. package/dist/daemon/settings-schema.js +72 -0
  273. package/dist/daemon/system-health.js +134 -0
  274. package/dist/daemon/version-checker.js +262 -0
  275. package/dist/daemon/warm-start.js +223 -0
  276. package/dist/entrypoints/cli.js +1043 -0
  277. package/dist/entrypoints/daemon.js +380 -0
  278. package/dist/entrypoints/repl.js +147 -0
  279. package/dist/hooks/adapters/claude-code.js +90 -0
  280. package/dist/hooks/adapters/cline.js +100 -0
  281. package/dist/hooks/adapters/cursor.js +98 -0
  282. package/dist/hooks/hook-dedup.js +79 -0
  283. package/dist/hooks/hook-runner.js +113 -0
  284. package/dist/hooks/navigation-hooks.js +175 -0
  285. package/dist/hooks/prompt-hooks.js +63 -0
  286. package/dist/hooks/shell-hooks.js +47 -0
  287. package/dist/ignore.js +111 -0
  288. package/dist/intelligence/approach-suggester.js +61 -0
  289. package/dist/intelligence/ast-extractor.js +2615 -0
  290. package/dist/intelligence/ast-worker.js +34 -0
  291. package/dist/intelligence/background-indexer.js +121 -0
  292. package/dist/intelligence/blast-radius.js +200 -0
  293. package/dist/intelligence/community-detection.js +691 -0
  294. package/dist/intelligence/community-detector.js +184 -0
  295. package/dist/intelligence/computation-scheduler.js +75 -0
  296. package/dist/intelligence/confidence-propagation.js +47 -0
  297. package/dist/intelligence/convention-detector.js +242 -0
  298. package/dist/intelligence/convention-learner.js +205 -0
  299. package/dist/intelligence/convention-matcher.js +205 -0
  300. package/dist/intelligence/cozo-schema.js +376 -0
  301. package/dist/intelligence/decision-point-detector.js +90 -0
  302. package/dist/intelligence/deep-dive-tools.js +586 -0
  303. package/dist/intelligence/durability-scorer.js +84 -0
  304. package/dist/intelligence/exploration-cost.js +204 -0
  305. package/dist/intelligence/exploration-pattern-tracker.js +61 -0
  306. package/dist/intelligence/fact-generator.js +322 -0
  307. package/dist/intelligence/facts-schema.js +90 -0
  308. package/dist/intelligence/file-intelligence.js +59 -0
  309. package/dist/intelligence/graph-holder.js +220 -0
  310. package/dist/intelligence/graph-temporal-joiner.js +238 -0
  311. package/dist/intelligence/health-grade.js +423 -0
  312. package/dist/intelligence/health-grader.js +200 -0
  313. package/dist/intelligence/health-map-data.js +259 -0
  314. package/dist/intelligence/import-symbols.js +136 -0
  315. package/dist/intelligence/incremental-indexer.js +658 -0
  316. package/dist/intelligence/indexer/centrality.js +62 -0
  317. package/dist/intelligence/indexer/cfg-context.js +95 -0
  318. package/dist/intelligence/indexer/confidence.js +34 -0
  319. package/dist/intelligence/indexer/cross-file-resolver.js +104 -0
  320. package/dist/intelligence/indexer/edge-repair.js +89 -0
  321. package/dist/intelligence/indexer/entity-key.js +17 -0
  322. package/dist/intelligence/indexer/export-map.js +132 -0
  323. package/dist/intelligence/indexer/git-cochange.js +128 -0
  324. package/dist/intelligence/indexer/graph-patch.js +147 -0
  325. package/dist/intelligence/indexer/incremental.js +78 -0
  326. package/dist/intelligence/indexer/ingest.js +160 -0
  327. package/dist/intelligence/indexer/language-detect.js +226 -0
  328. package/dist/intelligence/indexer/metadata.js +63 -0
  329. package/dist/intelligence/indexer/mutation-tracker.js +79 -0
  330. package/dist/intelligence/indexer/orchestrator.js +155 -0
  331. package/dist/intelligence/indexer/plugin-interface.js +31 -0
  332. package/dist/intelligence/indexer/plugins/csharp.js +440 -0
  333. package/dist/intelligence/indexer/plugins/go.js +335 -0
  334. package/dist/intelligence/indexer/plugins/java.js +370 -0
  335. package/dist/intelligence/indexer/plugins/python.js +358 -0
  336. package/dist/intelligence/indexer/plugins/regex-fallback.js +82 -0
  337. package/dist/intelligence/indexer/plugins/ruby.js +290 -0
  338. package/dist/intelligence/indexer/plugins/rust.js +484 -0
  339. package/dist/intelligence/indexer/plugins/tier2-generic.js +310 -0
  340. package/dist/intelligence/indexer/plugins/typescript.js +456 -0
  341. package/dist/intelligence/indexer/resource-monitor.js +93 -0
  342. package/dist/intelligence/indexer/scip/decoder.js +253 -0
  343. package/dist/intelligence/indexer/scip/detector.js +232 -0
  344. package/dist/intelligence/indexer/scip/downloader.js +427 -0
  345. package/dist/intelligence/indexer/scip/fallback.js +34 -0
  346. package/dist/intelligence/indexer/scip/merger.js +109 -0
  347. package/dist/intelligence/indexer/scip/orchestrator.js +433 -0
  348. package/dist/intelligence/indexer/scip/runner.js +98 -0
  349. package/dist/intelligence/indexer/snapshot.js +66 -0
  350. package/dist/intelligence/indexer/test-detector.js +196 -0
  351. package/dist/intelligence/indexer/watch-integration.js +61 -0
  352. package/dist/intelligence/indexer/worker.js +85 -0
  353. package/dist/intelligence/local-convention-detector.js +437 -0
  354. package/dist/intelligence/local-embeddings.js +190 -0
  355. package/dist/intelligence/local-graph.js +1946 -0
  356. package/dist/intelligence/local-indexer.js +1575 -0
  357. package/dist/intelligence/local-llm.js +163 -0
  358. package/dist/intelligence/local-rule-generator.js +154 -0
  359. package/dist/intelligence/local-snapshot.js +213 -0
  360. package/dist/intelligence/negative-knowledge.js +103 -0
  361. package/dist/intelligence/persistent-db.js +85 -0
  362. package/dist/intelligence/query-router.js +2556 -0
  363. package/dist/intelligence/risk-classifier.js +116 -0
  364. package/dist/intelligence/rule-evaluator.js +380 -0
  365. package/dist/intelligence/rule-generator.js +49 -0
  366. package/dist/intelligence/search-index.js +173 -0
  367. package/dist/intelligence/semantic/docstring-extractor.js +67 -0
  368. package/dist/intelligence/semantic/embedding-store.js +52 -0
  369. package/dist/intelligence/semantic/enrichment-orchestrator.js +48 -0
  370. package/dist/intelligence/semantic/git-message-miner.js +114 -0
  371. package/dist/intelligence/semantic/identifier-tokenizer.js +51 -0
  372. package/dist/intelligence/semantic/node2vec-embeddings.js +71 -0
  373. package/dist/intelligence/semantic/node2vec-walks.js +103 -0
  374. package/dist/intelligence/semantic/path-domain-inference.js +112 -0
  375. package/dist/intelligence/semantic/similarity-engine.js +60 -0
  376. package/dist/intelligence/semantic/tfidf-vectors.js +88 -0
  377. package/dist/intelligence/session-brief-builder.js +159 -0
  378. package/dist/intelligence/session-context.js +221 -0
  379. package/dist/intelligence/session-health-monitor.js +211 -0
  380. package/dist/intelligence/session-narrative.js +197 -0
  381. package/dist/intelligence/session-pattern-analyzer.js +218 -0
  382. package/dist/intelligence/signal-scorer.js +390 -0
  383. package/dist/intelligence/signal-show-store.js +182 -0
  384. package/dist/intelligence/smart-truncate.js +158 -0
  385. package/dist/intelligence/subgraph-cache.js +88 -0
  386. package/dist/intelligence/temporal-facts.js +494 -0
  387. package/dist/intelligence/token-estimator.js +100 -0
  388. package/dist/intelligence/tool-injector.js +87 -0
  389. package/dist/intelligence/tree-sitter-loader.js +71 -0
  390. package/dist/intelligence/worker-pool.js +116 -0
  391. package/dist/proxy/arg-validator.js +79 -0
  392. package/dist/proxy/auto-bootstrap.js +167 -0
  393. package/dist/proxy/bridge.js +147 -0
  394. package/dist/proxy/budget-enforcer.js +70 -0
  395. package/dist/proxy/compression-quality-monitor.js +160 -0
  396. package/dist/proxy/compression-stats.js +51 -0
  397. package/dist/proxy/context-rot-detector.js +137 -0
  398. package/dist/proxy/drift-detector.js +139 -0
  399. package/dist/proxy/efficiency-tracker.js +79 -0
  400. package/dist/proxy/fact-ranking.js +154 -0
  401. package/dist/proxy/format-encoder.js +266 -0
  402. package/dist/proxy/http-transport.js +90 -0
  403. package/dist/proxy/lifecycle-actor.js +55 -0
  404. package/dist/proxy/lifecycle-machine.js +187 -0
  405. package/dist/proxy/log-tailer.js +265 -0
  406. package/dist/proxy/model-pricing.js +98 -0
  407. package/dist/proxy/network-firewall.js +141 -0
  408. package/dist/proxy/nudge-state.js +93 -0
  409. package/dist/proxy/output-compressor.js +185 -0
  410. package/dist/proxy/pid-lock.js +291 -0
  411. package/dist/proxy/proxy-context.js +11 -0
  412. package/dist/proxy/proxy.js +2633 -0
  413. package/dist/proxy/response-enrichment.js +32 -0
  414. package/dist/proxy/response-envelope.js +313 -0
  415. package/dist/proxy/session-dedup.js +82 -0
  416. package/dist/proxy/session-legend.js +30 -0
  417. package/dist/proxy/session-persistence.js +210 -0
  418. package/dist/proxy/session-resume.js +94 -0
  419. package/dist/proxy/session-stats.js +513 -0
  420. package/dist/proxy/shell-classifier.js +1346 -0
  421. package/dist/proxy/shell-compression-log.js +93 -0
  422. package/dist/proxy/shell-compressor.js +390 -0
  423. package/dist/proxy/shell-graph-boost.js +202 -0
  424. package/dist/proxy/shell-monitor-map.js +18 -0
  425. package/dist/proxy/shell-stats.js +54 -0
  426. package/dist/proxy/shell-strategies/cloud.js +215 -0
  427. package/dist/proxy/shell-strategies/diff.js +159 -0
  428. package/dist/proxy/shell-strategies/error-diagnostic.js +796 -0
  429. package/dist/proxy/shell-strategies/filter-dsl.js +358 -0
  430. package/dist/proxy/shell-strategies/git-status.js +177 -0
  431. package/dist/proxy/shell-strategies/key-value.js +193 -0
  432. package/dist/proxy/shell-strategies/log-text.js +154 -0
  433. package/dist/proxy/shell-strategies/omni.js +188 -0
  434. package/dist/proxy/shell-strategies/progress.js +55 -0
  435. package/dist/proxy/shell-strategies/redact.js +76 -0
  436. package/dist/proxy/shell-strategies/structured.js +241 -0
  437. package/dist/proxy/shell-strategies/tabular.js +243 -0
  438. package/dist/proxy/shell-strategies/test-results-types.js +13 -0
  439. package/dist/proxy/shell-strategies/test-results.js +784 -0
  440. package/dist/proxy/shell-strategies/tree-paths.js +144 -0
  441. package/dist/proxy/shell-strategies/yaml.js +182 -0
  442. package/dist/proxy/shell-tee.js +111 -0
  443. package/dist/proxy/signal-dedup.js +171 -0
  444. package/dist/proxy/startup-renderer.js +158 -0
  445. package/dist/proxy/task-token-display.js +38 -0
  446. package/dist/proxy/token-counter.js +61 -0
  447. package/dist/proxy/tool-clusters.js +273 -0
  448. package/dist/proxy/tool-definitions.js +525 -0
  449. package/dist/proxy/transport-mux.js +229 -0
  450. package/dist/proxy/wire-cap.js +268 -0
  451. package/dist/schemas/api/skills.js +19 -0
  452. package/dist/schemas/common/errors.js +7 -0
  453. package/dist/schemas/common/headers.js +5 -0
  454. package/dist/schemas/entities/edge.js +25 -0
  455. package/dist/schemas/entities/entity.js +22 -0
  456. package/dist/schemas/entities/rule.js +18 -0
  457. package/dist/schemas/index.js +14 -0
  458. package/dist/server/event-bus.js +59 -0
  459. package/dist/server/http.js +156 -0
  460. package/dist/server/middleware.js +70 -0
  461. package/dist/server/routes/drift.js +97 -0
  462. package/dist/server/routes/intelligence.js +1217 -0
  463. package/dist/server/routes/reasoning-quality.js +444 -0
  464. package/dist/server/routes/session.js +86 -0
  465. package/dist/server/routes/stream.js +120 -0
  466. package/dist/server/routes/system.js +73 -0
  467. package/dist/server/routes/temporal.js +170 -0
  468. package/dist/server/routes/timeline.js +232 -0
  469. package/dist/server/routes/token-flow.js +403 -0
  470. package/dist/skills/effectiveness-tracker.js +93 -0
  471. package/dist/skills/local-pack.js +380 -0
  472. package/dist/skills/resolver.js +495 -0
  473. package/dist/state-detector.js +83 -0
  474. package/dist/timeline/intent-detector.js +263 -0
  475. package/dist/timeline/loop-miner.js +140 -0
  476. package/dist/timeline/open-threads.js +49 -0
  477. package/dist/timeline/signal-reinforcer.js +62 -0
  478. package/dist/timeline/timeline-bootstrap.js +151 -0
  479. package/dist/timeline/timeline-store.js +618 -0
  480. package/dist/tools/coding/bash.js +49 -0
  481. package/dist/tools/coding/file-edit.js +72 -0
  482. package/dist/tools/coding/file-outline.js +227 -0
  483. package/dist/tools/coding/file-read-protocol.js +425 -0
  484. package/dist/tools/coding/file-read.js +35 -0
  485. package/dist/tools/coding/file-write.js +43 -0
  486. package/dist/tools/coding/glob-tool.js +109 -0
  487. package/dist/tools/coding/grep.js +162 -0
  488. package/dist/tools/coding/index.js +27 -0
  489. package/dist/tools/intelligence/index.js +269 -0
  490. package/dist/tools/intelligence/record-fact.js +48 -0
  491. package/dist/tools/intelligence/timeline-markers.js +130 -0
  492. package/dist/tools/registry.js +47 -0
  493. package/dist/tools/types.js +8 -0
  494. package/dist/tracking/auto-snapshot-triggers.js +246 -0
  495. package/dist/tracking/branch-context.js +115 -0
  496. package/dist/tracking/branch-snapshot.js +217 -0
  497. package/dist/tracking/causal-bridge.js +317 -0
  498. package/dist/tracking/circuit-breaker.js +147 -0
  499. package/dist/tracking/commit-watcher.js +114 -0
  500. package/dist/tracking/context-ledger.js +119 -0
  501. package/dist/tracking/correction-detector.js +324 -0
  502. package/dist/tracking/drift-tracker.js +874 -0
  503. package/dist/tracking/durability-tracker.js +94 -0
  504. package/dist/tracking/entity-rewind.js +200 -0
  505. package/dist/tracking/file-hash-state.js +114 -0
  506. package/dist/tracking/git-attribution.js +132 -0
  507. package/dist/tracking/git-trailers.js +171 -0
  508. package/dist/tracking/intelligence-counter.js +46 -0
  509. package/dist/tracking/intent-correlator.js +202 -0
  510. package/dist/tracking/intent-encoder.js +52 -0
  511. package/dist/tracking/intent-token-tracker.js +159 -0
  512. package/dist/tracking/ledger-archiver.js +94 -0
  513. package/dist/tracking/ledger-chains.js +245 -0
  514. package/dist/tracking/metrics-store.js +361 -0
  515. package/dist/tracking/native-watcher.js +131 -0
  516. package/dist/tracking/offline-rewind.js +295 -0
  517. package/dist/tracking/pending-violations.js +74 -0
  518. package/dist/tracking/persistence-effectiveness.js +167 -0
  519. package/dist/tracking/prompt-durability.js +202 -0
  520. package/dist/tracking/quality-signals.js +213 -0
  521. package/dist/tracking/redactor.js +73 -0
  522. package/dist/tracking/rewind-engine.js +161 -0
  523. package/dist/tracking/session-history.js +128 -0
  524. package/dist/tracking/session-receipt.js +88 -0
  525. package/dist/tracking/session-summary-writer.js +157 -0
  526. package/dist/tracking/shadow-ledger.js +321 -0
  527. package/dist/tracking/stash-manager.js +258 -0
  528. package/dist/tracking/timeline-fork.js +213 -0
  529. package/dist/tracking/timeline.js +69 -0
  530. package/dist/tracking/token-flow.js +276 -0
  531. package/dist/tracking/turn-segmenter.js +122 -0
  532. package/dist/tracking/weekly-accumulator.js +179 -0
  533. package/dist/tracking/working-snapshots.js +188 -0
  534. package/dist/tracking/workspace-manifest.js +176 -0
  535. package/dist/transport/http.js +102 -0
  536. package/dist/ui/assets/index-BsMTQdhX.js +10 -0
  537. package/dist/ui/index.html +1 -1
  538. package/dist/utils/counterfactual.js +65 -0
  539. package/dist/utils/deep-link.js +34 -0
  540. package/dist/utils/detect.js +193 -0
  541. package/dist/utils/exec.js +73 -0
  542. package/dist/utils/file-logger.js +87 -0
  543. package/dist/utils/format-error.js +29 -0
  544. package/dist/utils/git.js +181 -0
  545. package/dist/utils/log.js +57 -0
  546. package/dist/utils/logger.js +35 -0
  547. package/dist/utils/mcp-content-json.js +8 -0
  548. package/dist/utils/session-logger.js +154 -0
  549. package/dist/utils/startup-log.js +512 -0
  550. package/dist/utils/ui.js +56 -0
  551. package/package.json +5 -3
  552. package/scripts/postinstall.mjs +312 -0
  553. package/dist/ui/assets/index-B-0HTtUR.js +0 -10
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Sprint S1: Output Compression & Quality Loop — Integration Tests.
3
+ *
4
+ * Verifies:
5
+ * - Large text output (>2K tokens) is automatically compressed
6
+ * - Session dedup filters repeated _context keys for same entity
7
+ * - Quality monitor adapts retention on retry spikes
8
+ * - Budget enforcer caps total response size
9
+ * - Retry detection feeds into quality monitor
10
+ */
11
+ import { describe, expect, it, vi } from "vitest";
12
+ import { QueryRouter } from "../intelligence/query-router.js";
13
+ import { createCompressionQualityMonitor } from "../proxy/compression-quality-monitor.js";
14
+ import { createSessionDedup } from "../proxy/session-dedup.js";
15
+ function createMockGraph(overrides = {}) {
16
+ return {
17
+ getEntity: vi.fn().mockReturnValue({
18
+ key: "fn1",
19
+ name: "fn1",
20
+ kind: "function",
21
+ file_path: "src/main.ts",
22
+ risk_level: "normal",
23
+ }),
24
+ getBlastRadius: vi.fn().mockReturnValue({
25
+ direct_callers: 5,
26
+ direct_callees: 2,
27
+ transitive_count: 10,
28
+ is_chokepoint: false,
29
+ summary: "5 callers, 10 transitive dependents",
30
+ }),
31
+ getBlastRadiusEntities: vi.fn().mockReturnValue(["caller1", "caller2"]),
32
+ getConventionsForEntity: vi.fn().mockReturnValue([]),
33
+ getCorrections: vi.fn().mockReturnValue([]),
34
+ getCommunityForEntity: vi.fn().mockReturnValue(null),
35
+ getCrossCommunityEdges: vi.fn().mockReturnValue([]),
36
+ getEntitiesByFile: vi.fn().mockReturnValue([]),
37
+ queryEntities: vi.fn().mockReturnValue([]),
38
+ searchEntities: vi.fn().mockReturnValue([]),
39
+ getDriftOverlayEntity: vi.fn().mockReturnValue(null),
40
+ getDriftSummary: vi
41
+ .fn()
42
+ .mockReturnValue({ added: 0, modified: 0, removed: 0, total: 0 }),
43
+ getCriticalNodes: vi.fn().mockReturnValue([]),
44
+ getCrossBoundaryLinks: vi.fn().mockReturnValue([]),
45
+ getCallers: vi.fn().mockReturnValue([]),
46
+ getCallersOf: vi.fn().mockReturnValue([]),
47
+ getCalleesOf: vi.fn().mockReturnValue([]),
48
+ getCallees: vi.fn().mockReturnValue([]),
49
+ getImports: vi.fn().mockReturnValue([]),
50
+ getRules: vi.fn().mockReturnValue([]),
51
+ getJustificationsForEntity: vi.fn().mockReturnValue([]),
52
+ getDriftEntitiesForFile: vi.fn().mockReturnValue([]),
53
+ close: vi.fn(),
54
+ ...overrides,
55
+ };
56
+ }
57
+ describe("Sprint S1: Output Compression Wiring", () => {
58
+ describe("S1.5: Compression triggered on large text output", () => {
59
+ it("compresses large string results exceeding 2K tokens", async () => {
60
+ // search_code returning a large string simulates a tool that returns raw text
61
+ const largeText = "line of code here\n".repeat(2000); // ~8K tokens
62
+ const graph = createMockGraph({
63
+ searchEntities: vi.fn().mockReturnValue(largeText),
64
+ });
65
+ const router = new QueryRouter(graph);
66
+ const monitor = createCompressionQualityMonitor();
67
+ router.setCompressionMonitor(monitor);
68
+ const result = await router.execute("search_code", { query: "test" });
69
+ // The content should be compressed (shorter than original)
70
+ const contentStr = typeof result.content === "string"
71
+ ? result.content
72
+ : JSON.stringify(result.content);
73
+ expect(contentStr.length).toBeLessThan(largeText.length);
74
+ });
75
+ it("does not compress output under 2K tokens", async () => {
76
+ const shortText = "function foo() { return 42; }";
77
+ const graph = createMockGraph({
78
+ searchEntities: vi.fn().mockReturnValue(shortText),
79
+ });
80
+ const router = new QueryRouter(graph);
81
+ const result = await router.execute("search_code", { query: "foo" });
82
+ // Short output passes through unchanged
83
+ expect(result.content).toBe(shortText);
84
+ });
85
+ it("does not compress structured object results", async () => {
86
+ const graph = createMockGraph();
87
+ // get_function returns an entity object via resolveEntityWithOverlay
88
+ const router = new QueryRouter(graph);
89
+ const result = await router.execute("get_function", { key: "fn1" });
90
+ // Structured objects pass through — no string compression
91
+ expect(typeof result.content).toBe("object");
92
+ });
93
+ });
94
+ // S1.4 checked `_context.blast_radius` as a direct field. After the
95
+ // Three-Layer Experience System rollout (Sprint 8/9), that field was
96
+ // replaced by `_context.signals[]`. Session dedup still works — it now
97
+ // dedups individual signals — but the wire shape changed. Coverage
98
+ // continues in signal-scorer.test.ts (dedup branch).
99
+ describe.skip("S1.4: Session dedup filters repeated _context (deprecated — see signal-scorer.test.ts)", () => {
100
+ it("first call for entity delivers blast_radius in _context", async () => {
101
+ const graph = createMockGraph();
102
+ const router = new QueryRouter(graph);
103
+ const dedup = createSessionDedup();
104
+ router.setSessionDedup(dedup);
105
+ const r1 = await router.execute("get_function", { key: "fn1" });
106
+ // First call should have blast_radius in _context
107
+ expect(r1._context?.blast_radius).toBeDefined();
108
+ });
109
+ it("second call for same entity does not repeat blast_radius", async () => {
110
+ const graph = createMockGraph();
111
+ const router = new QueryRouter(graph);
112
+ const dedup = createSessionDedup();
113
+ router.setSessionDedup(dedup);
114
+ // First call delivers blast_radius
115
+ await router.execute("get_function", { key: "fn1" });
116
+ // Second call — SessionContext already deduplicates via shouldInjectBlastRadius
117
+ // AND session dedup filters any remaining repeated keys
118
+ const r2 = await router.execute("get_function", { key: "fn1" });
119
+ if (r2._context) {
120
+ expect(r2._context.blast_radius).toBeUndefined();
121
+ }
122
+ });
123
+ it("different entities get independent context delivery", async () => {
124
+ const graph = createMockGraph();
125
+ const router = new QueryRouter(graph);
126
+ const dedup = createSessionDedup();
127
+ router.setSessionDedup(dedup);
128
+ await router.execute("get_function", { key: "fn1" });
129
+ const r2 = await router.execute("get_function", { key: "fn2" });
130
+ // fn2 is a fresh entity — should get blast_radius
131
+ expect(r2._context?.blast_radius).toBeDefined();
132
+ });
133
+ });
134
+ describe("S1.7-S1.9: Quality monitor integration", () => {
135
+ it("feeds compression events into quality monitor on large output", async () => {
136
+ const largeText = "error: test failure\n".repeat(2000);
137
+ const graph = createMockGraph({
138
+ searchEntities: vi.fn().mockReturnValue(largeText),
139
+ });
140
+ const router = new QueryRouter(graph);
141
+ const monitor = createCompressionQualityMonitor();
142
+ router.setCompressionMonitor(monitor);
143
+ await router.execute("search_code", { query: "test" });
144
+ // Adaptive config reflects the compression event was recorded
145
+ const config = monitor.getAdaptiveConfig();
146
+ expect(config).toBeDefined();
147
+ expect(config.confidence).toBeGreaterThanOrEqual(0);
148
+ });
149
+ it("increases retention after repeated over-compression signals", () => {
150
+ const monitor = createCompressionQualityMonitor();
151
+ const initialRetention = monitor.getRetention("generic");
152
+ // Simulate 3 compression + retry cycles (over-compression)
153
+ for (let i = 0; i < 3; i++) {
154
+ monitor.recordCompression(`c${i}`, "generic", 0.5);
155
+ monitor.recordAgentAction(`entity-${i}`, true, false);
156
+ }
157
+ const adaptedRetention = monitor.getRetention("generic");
158
+ expect(adaptedRetention).toBeGreaterThan(initialRetention);
159
+ });
160
+ it("reduces retention cautiously after 10+ successful compressions", () => {
161
+ const monitor = createCompressionQualityMonitor();
162
+ // First force retention up
163
+ for (let i = 0; i < 3; i++) {
164
+ monitor.recordCompression(`up${i}`, "generic", 0.5);
165
+ monitor.recordAgentAction(`e${i}`, true, false);
166
+ }
167
+ const highRetention = monitor.getRetention("generic");
168
+ // Then 10 good compressions
169
+ for (let i = 0; i < 10; i++) {
170
+ monitor.recordCompression(`good${i}`, "generic", 0.7);
171
+ monitor.recordAgentAction(`g${i}`, false, false);
172
+ }
173
+ const loweredRetention = monitor.getRetention("generic");
174
+ expect(loweredRetention).toBeLessThanOrEqual(highRetention);
175
+ });
176
+ });
177
+ describe("S1.8: Retry detection in enrichResult", () => {
178
+ it("detects retry when same entity queried within 60s", async () => {
179
+ const graph = createMockGraph();
180
+ const router = new QueryRouter(graph);
181
+ const monitor = createCompressionQualityMonitor();
182
+ router.setCompressionMonitor(monitor);
183
+ // We need a compression event first for the monitor to register retries
184
+ // Simulate by querying a tool that returns large text (triggers compression)
185
+ const largeText = "content\n".repeat(2000);
186
+ graph.searchEntities = vi.fn().mockReturnValue(largeText);
187
+ await router.execute("search_code", { query: "a" });
188
+ // Now query an enrichable tool twice within 60s
189
+ await router.execute("get_function", { key: "fn1" });
190
+ await router.execute("get_function", { key: "fn1" });
191
+ // The second query should trigger retry detection
192
+ // which feeds into the monitor (if there was a recent compression)
193
+ expect(monitor.getSignalCount()).toBeGreaterThan(0);
194
+ });
195
+ });
196
+ describe("S1.10: Budget enforcer as final cap", () => {
197
+ it("caps extremely large multi-line output to within budget", async () => {
198
+ // Real-world content has newlines — budget enforcer splits by line
199
+ const hugeText = Array.from({ length: 5000 }, (_, i) => `line ${i}: some content that takes up space in the output buffer`).join("\n"); // ~5000 lines, ~300K chars, ~75K tokens
200
+ const graph = createMockGraph({
201
+ searchEntities: vi.fn().mockReturnValue(hugeText),
202
+ });
203
+ const router = new QueryRouter(graph);
204
+ const monitor = createCompressionQualityMonitor();
205
+ router.setCompressionMonitor(monitor);
206
+ const result = await router.execute("search_code", { query: "line" });
207
+ const contentStr = typeof result.content === "string"
208
+ ? result.content
209
+ : JSON.stringify(result.content);
210
+ // Budget enforcer ensures content stays well under original size
211
+ // 4K tokens ≈ 16K chars — allow some overhead from markers
212
+ expect(contentStr.length).toBeLessThan(hugeText.length * 0.3);
213
+ });
214
+ });
215
+ });
@@ -0,0 +1,256 @@
1
+ /**
2
+ * Sprint S2: Session Health & Exploration Cost — Integration Tests.
3
+ *
4
+ * Verifies:
5
+ * - Every graph tool response includes _meta.tokens_saved (number > 0)
6
+ * - After 3+ queries to same entity → health drops below 0.8
7
+ * - After 10+ tool calls/min → tool_call_acceleration signal fires
8
+ * - Session health warning injected when health < 0.6
9
+ * - Exploration cost accumulator tracks cumulative savings
10
+ * - Health monitor feeds from blast radius and convention violations
11
+ */
12
+ import { describe, expect, it, vi } from "vitest";
13
+ import { createExplorationAccumulator } from "../intelligence/exploration-cost.js";
14
+ import { QueryRouter } from "../intelligence/query-router.js";
15
+ import { createSessionHealthMonitor } from "../intelligence/session-health-monitor.js";
16
+ function createMockGraph(overrides = {}) {
17
+ return {
18
+ getEntity: vi.fn().mockReturnValue({
19
+ key: "fn1",
20
+ name: "fn1",
21
+ kind: "function",
22
+ file_path: "src/main.ts",
23
+ risk_level: "normal",
24
+ }),
25
+ getBlastRadius: vi.fn().mockReturnValue({
26
+ direct_callers: 5,
27
+ direct_callees: 2,
28
+ transitive_count: 10,
29
+ is_chokepoint: false,
30
+ summary: "5 callers, 10 transitive dependents",
31
+ }),
32
+ getBlastRadiusEntities: vi.fn().mockReturnValue(["caller1", "caller2"]),
33
+ getConventionsForEntity: vi.fn().mockReturnValue([]),
34
+ getCorrections: vi.fn().mockReturnValue([]),
35
+ getCommunityForEntity: vi.fn().mockReturnValue(null),
36
+ getCrossCommunityEdges: vi.fn().mockReturnValue([]),
37
+ getEntitiesByFile: vi.fn().mockReturnValue([]),
38
+ queryEntities: vi.fn().mockReturnValue([]),
39
+ searchEntities: vi.fn().mockReturnValue([]),
40
+ getDriftOverlayEntity: vi.fn().mockReturnValue(null),
41
+ getDriftSummary: vi
42
+ .fn()
43
+ .mockReturnValue({ added: 0, modified: 0, removed: 0, total: 0 }),
44
+ getCriticalNodes: vi.fn().mockReturnValue([]),
45
+ getCrossBoundaryLinks: vi.fn().mockReturnValue([]),
46
+ getCallers: vi.fn().mockReturnValue([]),
47
+ getCallersOf: vi.fn().mockReturnValue([]),
48
+ getCalleesOf: vi.fn().mockReturnValue([]),
49
+ getCallees: vi.fn().mockReturnValue([]),
50
+ getImports: vi.fn().mockReturnValue([]),
51
+ getRules: vi.fn().mockReturnValue([]),
52
+ getJustificationsForEntity: vi.fn().mockReturnValue([]),
53
+ getDriftEntitiesForFile: vi.fn().mockReturnValue([]),
54
+ close: vi.fn(),
55
+ ...overrides,
56
+ };
57
+ }
58
+ describe("Sprint S2: Session Health & Exploration Cost Wiring", () => {
59
+ describe("S2.7-S2.8: Exploration cost on every graph response", () => {
60
+ it("tracks tokens saved internally for graph tool responses", async () => {
61
+ const graph = createMockGraph();
62
+ const router = new QueryRouter(graph);
63
+ const accumulator = createExplorationAccumulator();
64
+ router.setExplorationAccumulator(accumulator);
65
+ await router.execute("get_function", { key: "fn1" });
66
+ // Vanity fields stripped from wire; verify via internal accumulator instead.
67
+ const savings = router.getExplorationSavings();
68
+ expect(savings).not.toBeNull();
69
+ expect(savings.saved).toBeGreaterThan(0);
70
+ });
71
+ it("accumulates savings across multiple tool calls", async () => {
72
+ const graph = createMockGraph();
73
+ const router = new QueryRouter(graph);
74
+ const accumulator = createExplorationAccumulator();
75
+ router.setExplorationAccumulator(accumulator);
76
+ await router.execute("get_function", { key: "fn1" });
77
+ await router.execute("get_function", { key: "fn2" });
78
+ await router.execute("search_code", { query: "test" });
79
+ const savings = router.getExplorationSavings();
80
+ expect(savings).not.toBeNull();
81
+ expect(savings.saved).toBeGreaterThan(0);
82
+ expect(savings.without).toBeGreaterThan(savings.saved);
83
+ });
84
+ it("different tool types produce different cost estimates", async () => {
85
+ const graph = createMockGraph({
86
+ getBlastRadius: vi.fn().mockReturnValue({
87
+ direct_callers: 15,
88
+ direct_callees: 3,
89
+ transitive_count: 30,
90
+ is_chokepoint: true,
91
+ summary: "15 callers, 30 transitive",
92
+ }),
93
+ getBlastRadiusEntities: vi
94
+ .fn()
95
+ .mockReturnValue(Array.from({ length: 15 }, (_, i) => `caller${i}`)),
96
+ });
97
+ const router = new QueryRouter(graph);
98
+ const accumulator = createExplorationAccumulator();
99
+ router.setExplorationAccumulator(accumulator);
100
+ await router.execute("get_function", { key: "fn1" });
101
+ const beforeSecond = router.getExplorationSavings().saved;
102
+ await router.execute("search_code", { query: "test" });
103
+ const afterSecond = router.getExplorationSavings().saved;
104
+ // Both calls should add to the internal savings accumulator.
105
+ expect(beforeSecond).toBeGreaterThan(0);
106
+ expect(afterSecond).toBeGreaterThan(beforeSecond);
107
+ });
108
+ });
109
+ describe("S2.4-S2.5: Health monitor feeds from tool calls and blast radius", () => {
110
+ it("records tool calls into health monitor", async () => {
111
+ const graph = createMockGraph();
112
+ const router = new QueryRouter(graph);
113
+ const monitor = createSessionHealthMonitor();
114
+ router.setHealthMonitor(monitor);
115
+ await router.execute("get_function", { key: "fn1" });
116
+ await router.execute("get_function", { key: "fn1" });
117
+ await router.execute("get_function", { key: "fn1" });
118
+ const health = monitor.getHealth();
119
+ // After 3 queries to same entity, repeated_query signal should fire
120
+ expect(health.signals.some((s) => s.type === "repeated_query")).toBe(true);
121
+ });
122
+ it("health drops below 0.8 after 3+ queries to same entity", async () => {
123
+ const graph = createMockGraph();
124
+ const router = new QueryRouter(graph);
125
+ const monitor = createSessionHealthMonitor();
126
+ router.setHealthMonitor(monitor);
127
+ await router.execute("get_function", { key: "fn1" });
128
+ await router.execute("get_function", { key: "fn1" });
129
+ await router.execute("get_function", { key: "fn1" });
130
+ const health = monitor.getHealth();
131
+ expect(health.health).toBeLessThan(1.0);
132
+ });
133
+ it("feeds blast radius results into health monitor", async () => {
134
+ const graph = createMockGraph({
135
+ getBlastRadius: vi.fn().mockReturnValue({
136
+ direct_callers: 20,
137
+ direct_callees: 5,
138
+ transitive_count: 50,
139
+ is_chokepoint: true,
140
+ summary: "20 callers, 50 transitive",
141
+ }),
142
+ getBlastRadiusEntities: vi
143
+ .fn()
144
+ .mockReturnValue(Array.from({ length: 20 }, (_, i) => `caller${i}`)),
145
+ });
146
+ const router = new QueryRouter(graph);
147
+ const monitor = createSessionHealthMonitor();
148
+ router.setHealthMonitor(monitor);
149
+ // First call injects blast radius
150
+ await router.execute("get_function", { key: "fn1" });
151
+ const health = monitor.getHealth();
152
+ // Health monitor should have recorded the blast radius
153
+ expect(health).toBeDefined();
154
+ });
155
+ });
156
+ describe("S2.6: Convention violations feed into health monitor", () => {
157
+ it("low-adherence conventions feed as violations", async () => {
158
+ const graph = createMockGraph({
159
+ getConventionsForEntity: vi.fn().mockReturnValue([
160
+ {
161
+ id: "conv1",
162
+ name: "camelCase",
163
+ adherence_pct: 45,
164
+ rule: "Use camelCase",
165
+ },
166
+ {
167
+ id: "conv2",
168
+ name: "noAny",
169
+ adherence_pct: 30,
170
+ rule: "Avoid any type",
171
+ },
172
+ {
173
+ id: "conv3",
174
+ name: "imports",
175
+ adherence_pct: 90,
176
+ rule: "Use named imports",
177
+ },
178
+ ]),
179
+ });
180
+ const router = new QueryRouter(graph);
181
+ const monitor = createSessionHealthMonitor();
182
+ router.setHealthMonitor(monitor);
183
+ await router.execute("get_function", { key: "fn1" });
184
+ // Should have recorded 2 violations (adherence < 70%)
185
+ const health = monitor.getHealth();
186
+ expect(health).toBeDefined();
187
+ });
188
+ });
189
+ describe("S2.9: Session health warning in _meta", () => {
190
+ it("no session_health warning when health is good", async () => {
191
+ const graph = createMockGraph();
192
+ const router = new QueryRouter(graph);
193
+ const monitor = createSessionHealthMonitor();
194
+ router.setHealthMonitor(monitor);
195
+ const result = await router.execute("get_function", { key: "fn1" });
196
+ // Single query — health should be fine (no warning)
197
+ expect(result._meta.session_health).toBeUndefined();
198
+ });
199
+ it("injects session_health when health drops below 0.6", async () => {
200
+ const graph = createMockGraph();
201
+ const router = new QueryRouter(graph);
202
+ const monitor = createSessionHealthMonitor();
203
+ router.setHealthMonitor(monitor);
204
+ // Hammer the same entity many times to degrade health
205
+ for (let i = 0; i < 12; i++) {
206
+ await router.execute("get_function", { key: "fn1" });
207
+ }
208
+ // Get the last result
209
+ const result = await router.execute("get_function", { key: "fn1" });
210
+ // After 13 queries to same entity, health should be degraded
211
+ const health = monitor.getHealth();
212
+ if (health.health < 0.6) {
213
+ expect(result._meta.session_health).toBeDefined();
214
+ expect(result._meta.session_health.health).toBeLessThan(0.6);
215
+ expect(result._meta.session_health.recommendation).toBeDefined();
216
+ expect(result._meta.session_health.signals.length).toBeGreaterThan(0);
217
+ }
218
+ });
219
+ });
220
+ describe("S2.10: Cumulative savings accessible for session summary", () => {
221
+ it("getExplorationSavings returns null when no accumulator set", () => {
222
+ const graph = createMockGraph();
223
+ const router = new QueryRouter(graph);
224
+ expect(router.getExplorationSavings()).toBeNull();
225
+ });
226
+ it("getExplorationSavings returns cumulative data after queries", async () => {
227
+ const graph = createMockGraph();
228
+ const router = new QueryRouter(graph);
229
+ const accumulator = createExplorationAccumulator();
230
+ router.setExplorationAccumulator(accumulator);
231
+ await router.execute("get_function", { key: "fn1" });
232
+ await router.execute("get_function", { key: "fn2" });
233
+ const savings = router.getExplorationSavings();
234
+ expect(savings).not.toBeNull();
235
+ expect(savings.saved).toBeGreaterThan(0);
236
+ expect(savings.ratio).toBeGreaterThan(0);
237
+ expect(savings.ratio).toBeLessThan(1);
238
+ });
239
+ });
240
+ describe("Tool call acceleration detection", () => {
241
+ it("rapid tool calls trigger acceleration signal in health monitor", async () => {
242
+ const graph = createMockGraph();
243
+ const router = new QueryRouter(graph);
244
+ const monitor = createSessionHealthMonitor();
245
+ router.setHealthMonitor(monitor);
246
+ // Fire 12 tool calls rapidly (simulates acceleration > 10/min)
247
+ for (let i = 0; i < 12; i++) {
248
+ await router.execute("get_function", { key: `fn${i}` });
249
+ }
250
+ const health = monitor.getHealth();
251
+ // With 12 rapid calls, tool_call_acceleration should fire
252
+ const hasAcceleration = health.signals.some((s) => s.type === "tool_call_acceleration");
253
+ expect(hasAcceleration).toBe(true);
254
+ });
255
+ });
256
+ });
@@ -0,0 +1,195 @@
1
+ /**
2
+ * Sprint S3: Context Rot Detector — Integration Tests.
3
+ *
4
+ * Verifies:
5
+ * - After 200K+ estimated tokens → depth_threshold signal fires
6
+ * - After 3+ queries to same entity → repeated_exploration signal
7
+ * - inject_refresh action → _context.session_warning with actionable summary
8
+ * - suggest_new_session → _meta.session_health includes recommendation
9
+ * - Errors feed into context rot detector
10
+ */
11
+ import { describe, expect, it, vi } from "vitest";
12
+ import { QueryRouter } from "../intelligence/query-router.js";
13
+ import { createContextRotDetector } from "../proxy/context-rot-detector.js";
14
+ function createMockGraph(overrides = {}) {
15
+ return {
16
+ getEntity: vi.fn().mockReturnValue({
17
+ key: "fn1",
18
+ name: "fn1",
19
+ kind: "function",
20
+ file_path: "src/main.ts",
21
+ risk_level: "normal",
22
+ }),
23
+ getBlastRadius: vi.fn().mockReturnValue({
24
+ direct_callers: 5,
25
+ direct_callees: 2,
26
+ transitive_count: 10,
27
+ is_chokepoint: false,
28
+ summary: "5 callers, 10 transitive dependents",
29
+ }),
30
+ getBlastRadiusEntities: vi.fn().mockReturnValue(["caller1", "caller2"]),
31
+ getConventionsForEntity: vi.fn().mockReturnValue([]),
32
+ getCorrections: vi.fn().mockReturnValue([]),
33
+ getCommunityForEntity: vi.fn().mockReturnValue(null),
34
+ getCrossCommunityEdges: vi.fn().mockReturnValue([]),
35
+ getEntitiesByFile: vi.fn().mockReturnValue([]),
36
+ queryEntities: vi.fn().mockReturnValue([]),
37
+ searchEntities: vi.fn().mockReturnValue([]),
38
+ getDriftOverlayEntity: vi.fn().mockReturnValue(null),
39
+ getDriftSummary: vi
40
+ .fn()
41
+ .mockReturnValue({ added: 0, modified: 0, removed: 0, total: 0 }),
42
+ getCriticalNodes: vi.fn().mockReturnValue([]),
43
+ getCrossBoundaryLinks: vi.fn().mockReturnValue([]),
44
+ getCallers: vi.fn().mockReturnValue([]),
45
+ getCallersOf: vi.fn().mockReturnValue([]),
46
+ getCalleesOf: vi.fn().mockReturnValue([]),
47
+ getCallees: vi.fn().mockReturnValue([]),
48
+ getImports: vi.fn().mockReturnValue([]),
49
+ getRules: vi.fn().mockReturnValue([]),
50
+ getJustificationsForEntity: vi.fn().mockReturnValue([]),
51
+ getDriftEntitiesForFile: vi.fn().mockReturnValue([]),
52
+ close: vi.fn(),
53
+ ...overrides,
54
+ };
55
+ }
56
+ describe("Sprint S3: Context Rot Detector Wiring", () => {
57
+ describe("S3.3: Token depth tracking", () => {
58
+ it("accumulates token depth from tool call responses", async () => {
59
+ const graph = createMockGraph();
60
+ const router = new QueryRouter(graph);
61
+ const detector = createContextRotDetector();
62
+ router.setContextRotDetector(detector);
63
+ // Make several calls to accumulate token depth
64
+ for (let i = 0; i < 5; i++) {
65
+ await router.execute("get_function", { key: `fn${i}` });
66
+ }
67
+ // Evaluate — should have accumulated some tokens (small, but non-zero)
68
+ const signal = detector.evaluate();
69
+ expect(signal.estimatedDepth).toBeGreaterThan(0);
70
+ });
71
+ it("fires depth_threshold after 200K+ tokens", () => {
72
+ const detector = createContextRotDetector();
73
+ // Simulate large token accumulation
74
+ detector.recordToolCallTokens(210_000);
75
+ const signal = detector.evaluate();
76
+ expect(signal.signals.some((s) => s.type === "depth_threshold")).toBe(true);
77
+ expect(signal.rotConfidence).toBeGreaterThan(0);
78
+ });
79
+ });
80
+ describe("S3.4: Repeated query detection via sessionContext", () => {
81
+ it("detects repeated queries to same entity", async () => {
82
+ const graph = createMockGraph();
83
+ const router = new QueryRouter(graph);
84
+ const detector = createContextRotDetector();
85
+ router.setContextRotDetector(detector);
86
+ // First call establishes history
87
+ await router.execute("get_function", { key: "fn1" });
88
+ // Subsequent calls should trigger repeated query detection
89
+ await router.execute("get_function", { key: "fn1" });
90
+ await router.execute("get_function", { key: "fn1" });
91
+ await router.execute("get_function", { key: "fn1" });
92
+ const signal = detector.evaluate();
93
+ // After 3+ re-queries to an entity already in history, repeated_exploration fires
94
+ expect(signal.signals.some((s) => s.type === "repeated_exploration")).toBe(true);
95
+ });
96
+ });
97
+ describe("S3.5: Error feeding", () => {
98
+ it("feeds errors into context rot detector on tool failure", async () => {
99
+ const graph = createMockGraph({
100
+ searchEntities: vi.fn().mockImplementation(() => {
101
+ throw new Error("simulated failure");
102
+ }),
103
+ });
104
+ const router = new QueryRouter(graph);
105
+ const detector = createContextRotDetector();
106
+ router.setContextRotDetector(detector);
107
+ // Trigger multiple failures
108
+ for (let i = 0; i < 6; i++) {
109
+ await router.execute("search_code", { query: "test" });
110
+ }
111
+ const signal = detector.evaluate();
112
+ // After 5+ errors, declining_precision should fire
113
+ expect(signal.signals.some((s) => s.type === "declining_precision")).toBe(true);
114
+ });
115
+ });
116
+ describe("S3.6-S3.7: Rot evaluation and inject_refresh", () => {
117
+ it("injects session_warning in _context when rot triggers inject_refresh", async () => {
118
+ const graph = createMockGraph();
119
+ const router = new QueryRouter(graph);
120
+ const detector = createContextRotDetector();
121
+ router.setContextRotDetector(detector);
122
+ // Push token depth past warning threshold (200K)
123
+ detector.recordToolCallTokens(220_000);
124
+ // Add repeated queries to push rot confidence into inject_refresh range (0.4-0.7)
125
+ detector.recordRepeatedQuery("fn1");
126
+ detector.recordRepeatedQuery("fn1");
127
+ detector.recordRepeatedQuery("fn1");
128
+ // Now execute enough calls to hit the 10th-call evaluation boundary
129
+ // We need toolCallCount to be divisible by 10
130
+ for (let i = 0; i < 9; i++) {
131
+ await router.execute("get_function", { key: `entity${i}` });
132
+ }
133
+ // 10th call triggers evaluation
134
+ const result = await router.execute("get_function", { key: "entity9" });
135
+ // Should have session_warning in _context
136
+ const ctx = result._context;
137
+ if (ctx?.session_warning) {
138
+ const warning = ctx.session_warning;
139
+ expect(warning.reason).toBeDefined();
140
+ expect(warning.rot_confidence).toBeGreaterThan(0);
141
+ }
142
+ });
143
+ });
144
+ describe("S3.8: Severe rot triggers suggest_new_session in _meta", () => {
145
+ it("injects _meta.session_health with suggest_new_session on critical rot", async () => {
146
+ const graph = createMockGraph();
147
+ const router = new QueryRouter(graph);
148
+ const detector = createContextRotDetector();
149
+ router.setContextRotDetector(detector);
150
+ // Push past critical threshold (300K tokens → 0.4 rot)
151
+ detector.recordToolCallTokens(310_000);
152
+ // Add repeated queries (0.15 each for 3+ queries per entity)
153
+ detector.recordRepeatedQuery("fn1");
154
+ detector.recordRepeatedQuery("fn1");
155
+ detector.recordRepeatedQuery("fn1");
156
+ detector.recordRepeatedQuery("fn2");
157
+ detector.recordRepeatedQuery("fn2");
158
+ detector.recordRepeatedQuery("fn2");
159
+ // Add errors (0.2 for 5+ errors)
160
+ for (let i = 0; i < 6; i++) {
161
+ detector.recordError();
162
+ }
163
+ // Total rot: 0.4 (depth) + 0.15 (fn1) + 0.15 (fn2) + 0.2 (errors) = 0.9 → suggest_new_session
164
+ // Execute 10 calls to trigger evaluation
165
+ for (let i = 0; i < 9; i++) {
166
+ await router.execute("get_function", { key: `x${i}` });
167
+ }
168
+ const result = await router.execute("get_function", { key: "x9" });
169
+ expect(result._meta.session_health).toBeDefined();
170
+ expect(result._meta.session_health?.recommendation).toBe("suggest_new_session");
171
+ expect(result._meta.session_health?.signals.length).toBeGreaterThan(0);
172
+ });
173
+ });
174
+ describe("S3.9: getRefreshContext provides recovery data", () => {
175
+ it("builds refresh context when rot action is triggered", () => {
176
+ const detector = createContextRotDetector();
177
+ // Push into inject_refresh range (0.2 depth + 0.15 fn1 + 0.15 fn2 = 0.5)
178
+ detector.recordToolCallTokens(220_000);
179
+ detector.recordRepeatedQuery("fn1");
180
+ detector.recordRepeatedQuery("fn1");
181
+ detector.recordRepeatedQuery("fn1");
182
+ detector.recordRepeatedQuery("fn2");
183
+ detector.recordRepeatedQuery("fn2");
184
+ detector.recordRepeatedQuery("fn2");
185
+ const signal = detector.evaluate();
186
+ expect(signal.action).toBe("inject_refresh");
187
+ const refresh = detector.getRefreshContext();
188
+ expect(refresh).not.toBeNull();
189
+ expect(refresh?.reason).toBe("context_degradation");
190
+ expect(refresh?.estimated_depth).toBe(220_000);
191
+ expect(refresh?.repeated_entities).toContain("fn1");
192
+ expect(refresh?.repeated_entities).toContain("fn2");
193
+ });
194
+ });
195
+ });