@unerr-ai/unerr 0.0.1 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (556) hide show
  1. package/README.md +215 -35
  2. package/dist/__tests__/architecture-guard.test.js +122 -0
  3. package/dist/__tests__/arg-validator.test.js +205 -0
  4. package/dist/__tests__/ast-extractor.test.js +203 -0
  5. package/dist/__tests__/auto-bootstrap.test.js +280 -0
  6. package/dist/__tests__/background-indexer.test.js +228 -0
  7. package/dist/__tests__/blast-radius-engine.test.js +200 -0
  8. package/dist/__tests__/bridge-isolation.test.js +37 -0
  9. package/dist/__tests__/budget-enforcer.test.js +53 -0
  10. package/dist/__tests__/cfg-test-detection-perf.test.js +82 -0
  11. package/dist/__tests__/change-narrative.test.js +190 -0
  12. package/dist/__tests__/check-commit.test.js +258 -0
  13. package/dist/__tests__/checksum.test.js +34 -0
  14. package/dist/__tests__/commit-watcher.test.js +154 -0
  15. package/dist/__tests__/community-detection.test.js +179 -0
  16. package/dist/__tests__/community-tools.test.js +299 -0
  17. package/dist/__tests__/components.test.js +449 -0
  18. package/dist/__tests__/compression-log.test.js +174 -0
  19. package/dist/__tests__/compression-quality-monitor.test.js +40 -0
  20. package/dist/__tests__/config-healer.test.js +165 -0
  21. package/dist/__tests__/context-ledger.test.js +58 -0
  22. package/dist/__tests__/convention-detector.test.js +99 -0
  23. package/dist/__tests__/convention-learner.test.js +86 -0
  24. package/dist/__tests__/correction-detector.test.js +330 -0
  25. package/dist/__tests__/daemon-autostart-install.test.js +283 -0
  26. package/dist/__tests__/daemon-bridge.test.js +222 -0
  27. package/dist/__tests__/daemon-dashboard.test.js +202 -0
  28. package/dist/__tests__/daemon-registry.test.js +240 -0
  29. package/dist/__tests__/daemon-supervisor.test.js +318 -0
  30. package/dist/__tests__/daemon-version-check.test.js +275 -0
  31. package/dist/__tests__/decision-point-detector.test.js +98 -0
  32. package/dist/__tests__/deep-link.test.js +143 -0
  33. package/dist/__tests__/disallowed-tools.test.js +115 -0
  34. package/dist/__tests__/drift-tracker.test.js +582 -0
  35. package/dist/__tests__/durability-scorer.test.js +152 -0
  36. package/dist/__tests__/efficiency-tracker.test.js +65 -0
  37. package/dist/__tests__/enrich.test.js +144 -0
  38. package/dist/__tests__/entity-rewind.test.js +248 -0
  39. package/dist/__tests__/ephemeral.test.js +111 -0
  40. package/dist/__tests__/exploration-cost.test.js +93 -0
  41. package/dist/__tests__/fact-generator.test.js +197 -0
  42. package/dist/__tests__/file-l0-graph.test.js +244 -0
  43. package/dist/__tests__/file-logger.test.js +82 -0
  44. package/dist/__tests__/file-outline.test.js +141 -0
  45. package/dist/__tests__/file-read-protocol.test.js +188 -0
  46. package/dist/__tests__/format-encoder.test.js +233 -0
  47. package/dist/__tests__/git-attribution.test.js +259 -0
  48. package/dist/__tests__/graph-temporal-joiner.test.js +219 -0
  49. package/dist/__tests__/health-grade-enhanced.test.js +138 -0
  50. package/dist/__tests__/health-map-data.test.js +173 -0
  51. package/dist/__tests__/helpers/mcp-harness.js +45 -0
  52. package/dist/__tests__/helpers/mcp-harness.test.js +68 -0
  53. package/dist/__tests__/hook-dedup.test.js +112 -0
  54. package/dist/__tests__/hook-runner.test.js +253 -0
  55. package/dist/__tests__/indexer-cfg.test.js +185 -0
  56. package/dist/__tests__/indexer-cross-file.test.js +172 -0
  57. package/dist/__tests__/indexer-extraction.test.js +245 -0
  58. package/dist/__tests__/indexer-incremental.test.js +232 -0
  59. package/dist/__tests__/indexer-language-expansion.test.js +165 -0
  60. package/dist/__tests__/init-push.test.js +131 -0
  61. package/dist/__tests__/instruction-writer.test.js +179 -0
  62. package/dist/__tests__/intelligence-integration.test.js +217 -0
  63. package/dist/__tests__/intent-correlator.test.js +175 -0
  64. package/dist/__tests__/intent-detector.test.js +235 -0
  65. package/dist/__tests__/intent-encoder.test.js +167 -0
  66. package/dist/__tests__/java-build-tool-detection.test.js +174 -0
  67. package/dist/__tests__/layer3-sprint-q.test.js +160 -0
  68. package/dist/__tests__/layer3-sprint-r.test.js +91 -0
  69. package/dist/__tests__/layer3-sprint-s.test.js +183 -0
  70. package/dist/__tests__/layer3-sprint-t.test.js +201 -0
  71. package/dist/__tests__/layer3-sprint-u.test.js +174 -0
  72. package/dist/__tests__/layer4-sprint-ba2.test.js +354 -0
  73. package/dist/__tests__/layer4-sprint-ba4.test.js +84 -0
  74. package/dist/__tests__/layer4-sprint-vs.test.js +105 -0
  75. package/dist/__tests__/ledger-chains.test.js +162 -0
  76. package/dist/__tests__/lifecycle-machine.test.js +226 -0
  77. package/dist/__tests__/local-chat-provider.test.js +170 -0
  78. package/dist/__tests__/local-convention-detector.test.js +308 -0
  79. package/dist/__tests__/local-embeddings.test.js +422 -0
  80. package/dist/__tests__/local-graph.test.js +540 -0
  81. package/dist/__tests__/local-indexer.test.js +228 -0
  82. package/dist/__tests__/local-intelligence-l3.test.js +332 -0
  83. package/dist/__tests__/local-llm.test.js +253 -0
  84. package/dist/__tests__/local-mode-offline.test.js +187 -0
  85. package/dist/__tests__/local-mode-stats.test.js +273 -0
  86. package/dist/__tests__/local-mode-tui.test.js +343 -0
  87. package/dist/__tests__/local-parse.test.js +199 -0
  88. package/dist/__tests__/log-tailer.test.js +208 -0
  89. package/dist/__tests__/loop-breaker.test.js +276 -0
  90. package/dist/__tests__/loop-miner.test.js +226 -0
  91. package/dist/__tests__/mcp-config.test.js +126 -0
  92. package/dist/__tests__/mcp-content-json.test.js +10 -0
  93. package/dist/__tests__/mcp-envelope.test.js +124 -0
  94. package/dist/__tests__/metrics-store.test.js +223 -0
  95. package/dist/__tests__/native-watcher.test.js +191 -0
  96. package/dist/__tests__/navigation-hooks-agent-aware.test.js +145 -0
  97. package/dist/__tests__/negative-knowledge.test.js +116 -0
  98. package/dist/__tests__/network-boundary.test.js +190 -0
  99. package/dist/__tests__/network-firewall.test.js +112 -0
  100. package/dist/__tests__/nudge-invariants.test.js +160 -0
  101. package/dist/__tests__/nudge-v2.test.js +225 -0
  102. package/dist/__tests__/offline-rewind.test.js +251 -0
  103. package/dist/__tests__/open-threads.test.js +89 -0
  104. package/dist/__tests__/output-compressor.test.js +93 -0
  105. package/dist/__tests__/pending-violations.test.js +112 -0
  106. package/dist/__tests__/persistence-effectiveness.test.js +143 -0
  107. package/dist/__tests__/provider-factory.test.js +42 -0
  108. package/dist/__tests__/providers.test.js +24 -0
  109. package/dist/__tests__/proxy.test.js +314 -0
  110. package/dist/__tests__/query-router.test.js +1018 -0
  111. package/dist/__tests__/reasoning-quality-route.test.js +138 -0
  112. package/dist/__tests__/redactor.test.js +120 -0
  113. package/dist/__tests__/resource-monitor.test.js +57 -0
  114. package/dist/__tests__/response-envelope.test.js +100 -0
  115. package/dist/__tests__/risk-classifier.test.js +101 -0
  116. package/dist/__tests__/risk-signal-scope.test.js +75 -0
  117. package/dist/__tests__/rule-evaluator.test.js +280 -0
  118. package/dist/__tests__/scip-decoder.test.js +49 -0
  119. package/dist/__tests__/scip-downloader.test.js +201 -0
  120. package/dist/__tests__/scip-merger.test.js +103 -0
  121. package/dist/__tests__/search-index.test.js +422 -0
  122. package/dist/__tests__/semantic-enrichment.test.js +360 -0
  123. package/dist/__tests__/session-brief-builder.test.js +187 -0
  124. package/dist/__tests__/session-context.test.js +221 -0
  125. package/dist/__tests__/session-continuity.test.js +144 -0
  126. package/dist/__tests__/session-dedup.test.js +74 -0
  127. package/dist/__tests__/session-event-wiring.test.js +206 -0
  128. package/dist/__tests__/session-events.test.js +149 -0
  129. package/dist/__tests__/session-legend.test.js +20 -0
  130. package/dist/__tests__/session-persistence.test.js +131 -0
  131. package/dist/__tests__/session-resume-block.test.js +107 -0
  132. package/dist/__tests__/session-resume.test.js +97 -0
  133. package/dist/__tests__/session-summary-writer.test.js +134 -0
  134. package/dist/__tests__/shadow-ledger.test.js +203 -0
  135. package/dist/__tests__/shell-classifier.test.js +151 -0
  136. package/dist/__tests__/shell-compression-floor.test.js +189 -0
  137. package/dist/__tests__/shell-compression-v2.test.js +339 -0
  138. package/dist/__tests__/shell-compressor.test.js +35 -0
  139. package/dist/__tests__/shell-hooks.test.js +128 -0
  140. package/dist/__tests__/shell-strategies.test.js +644 -0
  141. package/dist/__tests__/shell-tee.test.js +133 -0
  142. package/dist/__tests__/signal-dedup.test.js +158 -0
  143. package/dist/__tests__/signal-reinforcer.test.js +77 -0
  144. package/dist/__tests__/signal-scorer.test.js +251 -0
  145. package/dist/__tests__/signal-show-store.test.js +108 -0
  146. package/dist/__tests__/smart-truncate.test.js +215 -0
  147. package/dist/__tests__/snapshot-v2.test.js +113 -0
  148. package/dist/__tests__/sprint-l1-local-mode.test.js +130 -0
  149. package/dist/__tests__/sprint-l10-boot.test.js +220 -0
  150. package/dist/__tests__/sprint-l9-offline-commands.test.js +189 -0
  151. package/dist/__tests__/sprint-q-persistent-context.test.js +198 -0
  152. package/dist/__tests__/sprint-s1-wiring.test.js +215 -0
  153. package/dist/__tests__/sprint-s2-wiring.test.js +256 -0
  154. package/dist/__tests__/sprint-s3-wiring.test.js +195 -0
  155. package/dist/__tests__/sprint-s4-wiring.test.js +213 -0
  156. package/dist/__tests__/sprint-s6-hooks.test.js +222 -0
  157. package/dist/__tests__/sprint-s7-persistent.test.js +263 -0
  158. package/dist/__tests__/sprint-s8-value.test.js +167 -0
  159. package/dist/__tests__/sprint-s9-behavioral.test.js +179 -0
  160. package/dist/__tests__/sprint3-intelligence.test.js +297 -0
  161. package/dist/__tests__/sprint5-mcp-server.test.js +136 -0
  162. package/dist/__tests__/startup-display.test.js +302 -0
  163. package/dist/__tests__/startup-log-file.test.js +97 -0
  164. package/dist/__tests__/stash-manager.test.js +229 -0
  165. package/dist/__tests__/state-detector.test.js +92 -0
  166. package/dist/__tests__/status-dashboard.test.js +142 -0
  167. package/dist/__tests__/temporal-facts.test.js +292 -0
  168. package/dist/__tests__/temporal-routes.test.js +142 -0
  169. package/dist/__tests__/test-detector.test.js +174 -0
  170. package/dist/__tests__/theme.test.js +72 -0
  171. package/dist/__tests__/timeline-agents.test.js +122 -0
  172. package/dist/__tests__/timeline-bootstrap.test.js +176 -0
  173. package/dist/__tests__/timeline-filters.test.js +193 -0
  174. package/dist/__tests__/timeline-markers.test.js +151 -0
  175. package/dist/__tests__/timeline-routes.test.js +156 -0
  176. package/dist/__tests__/timeline-store.test.js +171 -0
  177. package/dist/__tests__/token-counter.test.js +86 -0
  178. package/dist/__tests__/token-estimator.test.js +96 -0
  179. package/dist/__tests__/token-flow-api.test.js +239 -0
  180. package/dist/__tests__/token-flow-instrumentation.test.js +437 -0
  181. package/dist/__tests__/token-flow-persistence.test.js +356 -0
  182. package/dist/__tests__/token-flow-routes.test.js +199 -0
  183. package/dist/__tests__/token-flow.test.js +695 -0
  184. package/dist/__tests__/tool-clusters.test.js +177 -0
  185. package/dist/__tests__/transport-mux.test.js +283 -0
  186. package/dist/__tests__/turn-segmenter.test.js +166 -0
  187. package/dist/__tests__/uninstall.test.js +141 -0
  188. package/dist/__tests__/warm-start-policy.test.js +271 -0
  189. package/dist/__tests__/wire-cap-nudge.test.js +77 -0
  190. package/dist/__tests__/worker-pool.test.js +101 -0
  191. package/dist/behaviors/agent-llm-bridge.js +166 -0
  192. package/dist/behaviors/architecture-guard.js +256 -0
  193. package/dist/behaviors/auto-doc.js +247 -0
  194. package/dist/behaviors/cascade-guard.js +289 -0
  195. package/dist/behaviors/change-narrative.js +270 -0
  196. package/dist/behaviors/convention-drift.js +290 -0
  197. package/dist/behaviors/framework.js +235 -0
  198. package/dist/behaviors/guard-formatter.js +44 -0
  199. package/dist/behaviors/incomplete-work.js +270 -0
  200. package/dist/behaviors/loop-breaker.js +300 -0
  201. package/dist/behaviors/session-continuity.js +208 -0
  202. package/dist/cli.js +6446 -2227
  203. package/dist/commands/branches.js +97 -0
  204. package/dist/commands/check-commit.js +225 -0
  205. package/dist/commands/compress-output.js +64 -0
  206. package/dist/commands/config-verify.js +243 -0
  207. package/dist/commands/daemon.js +905 -0
  208. package/dist/commands/dashboard.js +52 -0
  209. package/dist/commands/debug.js +200 -0
  210. package/dist/commands/enrich.js +184 -0
  211. package/dist/commands/exec.js +233 -0
  212. package/dist/commands/gain.js +156 -0
  213. package/dist/commands/hook.js +88 -0
  214. package/dist/commands/index.js +88 -0
  215. package/dist/commands/init.js +74 -0
  216. package/dist/commands/install.js +505 -0
  217. package/dist/commands/learn.js +116 -0
  218. package/dist/commands/manifest.js +193 -0
  219. package/dist/commands/rewind.js +103 -0
  220. package/dist/commands/serve.js +19 -0
  221. package/dist/commands/setup-wizard.js +414 -0
  222. package/dist/commands/skills.js +64 -0
  223. package/dist/commands/stats.js +20 -0
  224. package/dist/commands/status.js +654 -0
  225. package/dist/commands/timeline.js +139 -0
  226. package/dist/commands/uninstall.js +230 -0
  227. package/dist/components/App.js +109 -0
  228. package/dist/components/Banner.js +12 -0
  229. package/dist/components/ConfirmPrompt.js +25 -0
  230. package/dist/components/DriftSummary.js +23 -0
  231. package/dist/components/GradeBadge.js +15 -0
  232. package/dist/components/HealthCard.js +18 -0
  233. package/dist/components/InkSpinner.js +22 -0
  234. package/dist/components/InputBox.js +17 -0
  235. package/dist/components/KeyValue.js +13 -0
  236. package/dist/components/MessageList.js +14 -0
  237. package/dist/components/ProgressBar.js +26 -0
  238. package/dist/components/Section.js +16 -0
  239. package/dist/components/SessionSummaryCard.js +73 -0
  240. package/dist/components/StartupDisplay.js +24 -0
  241. package/dist/components/StatusDashboard.js +57 -0
  242. package/dist/components/StatusLine.js +8 -0
  243. package/dist/components/StepLine.js +22 -0
  244. package/dist/components/Theme.js +20 -0
  245. package/dist/components/ToolProgress.js +8 -0
  246. package/dist/components/ViolationList.js +21 -0
  247. package/dist/components/render.js +13 -0
  248. package/dist/config/agent-registry.js +237 -0
  249. package/dist/config/claude-settings-hooks.js +304 -0
  250. package/dist/config/hook-installer.js +65 -0
  251. package/dist/config/instruction-writer.js +388 -0
  252. package/dist/config/mcp-config-writer.js +266 -0
  253. package/dist/config/settings.js +174 -0
  254. package/dist/config/tool-detector.js +42 -0
  255. package/dist/config/value-surfacing.js +119 -0
  256. package/dist/core/context-assembly.js +108 -0
  257. package/dist/core/conversation.js +33 -0
  258. package/dist/core/local-chat-provider.js +475 -0
  259. package/dist/core/provider-factory.js +55 -0
  260. package/dist/core/providers.js +90 -0
  261. package/dist/core/query-engine.js +174 -0
  262. package/dist/daemon/api.js +312 -0
  263. package/dist/daemon/autostart.js +119 -0
  264. package/dist/daemon/bootstrap.js +39 -0
  265. package/dist/daemon/client.js +164 -0
  266. package/dist/daemon/detect-ci.js +81 -0
  267. package/dist/daemon/platform-linux.js +146 -0
  268. package/dist/daemon/platform-macos.js +134 -0
  269. package/dist/daemon/platform-windows.js +116 -0
  270. package/dist/daemon/process-manager.js +299 -0
  271. package/dist/daemon/protocol.js +23 -0
  272. package/dist/daemon/registry.js +270 -0
  273. package/dist/daemon/settings-schema.js +72 -0
  274. package/dist/daemon/system-health.js +134 -0
  275. package/dist/daemon/version-checker.js +262 -0
  276. package/dist/daemon/warm-start.js +223 -0
  277. package/dist/entrypoints/cli.js +1043 -0
  278. package/dist/entrypoints/daemon.js +380 -0
  279. package/dist/entrypoints/repl.js +147 -0
  280. package/dist/hooks/adapters/claude-code.js +90 -0
  281. package/dist/hooks/adapters/cline.js +100 -0
  282. package/dist/hooks/adapters/cursor.js +98 -0
  283. package/dist/hooks/hook-dedup.js +79 -0
  284. package/dist/hooks/hook-runner.js +113 -0
  285. package/dist/hooks/navigation-hooks.js +175 -0
  286. package/dist/hooks/prompt-hooks.js +63 -0
  287. package/dist/hooks/shell-hooks.js +47 -0
  288. package/dist/ignore.js +111 -0
  289. package/dist/intelligence/approach-suggester.js +61 -0
  290. package/dist/intelligence/ast-extractor.js +2615 -0
  291. package/dist/intelligence/ast-worker.js +34 -0
  292. package/dist/intelligence/background-indexer.js +121 -0
  293. package/dist/intelligence/blast-radius.js +200 -0
  294. package/dist/intelligence/community-detection.js +691 -0
  295. package/dist/intelligence/community-detector.js +184 -0
  296. package/dist/intelligence/computation-scheduler.js +75 -0
  297. package/dist/intelligence/confidence-propagation.js +47 -0
  298. package/dist/intelligence/convention-detector.js +242 -0
  299. package/dist/intelligence/convention-learner.js +205 -0
  300. package/dist/intelligence/convention-matcher.js +205 -0
  301. package/dist/intelligence/cozo-schema.js +376 -0
  302. package/dist/intelligence/decision-point-detector.js +90 -0
  303. package/dist/intelligence/deep-dive-tools.js +586 -0
  304. package/dist/intelligence/durability-scorer.js +84 -0
  305. package/dist/intelligence/exploration-cost.js +204 -0
  306. package/dist/intelligence/exploration-pattern-tracker.js +61 -0
  307. package/dist/intelligence/fact-generator.js +322 -0
  308. package/dist/intelligence/facts-schema.js +90 -0
  309. package/dist/intelligence/file-intelligence.js +59 -0
  310. package/dist/intelligence/graph-holder.js +220 -0
  311. package/dist/intelligence/graph-temporal-joiner.js +238 -0
  312. package/dist/intelligence/health-grade.js +423 -0
  313. package/dist/intelligence/health-grader.js +200 -0
  314. package/dist/intelligence/health-map-data.js +259 -0
  315. package/dist/intelligence/import-symbols.js +136 -0
  316. package/dist/intelligence/incremental-indexer.js +658 -0
  317. package/dist/intelligence/indexer/centrality.js +62 -0
  318. package/dist/intelligence/indexer/cfg-context.js +95 -0
  319. package/dist/intelligence/indexer/confidence.js +34 -0
  320. package/dist/intelligence/indexer/cross-file-resolver.js +104 -0
  321. package/dist/intelligence/indexer/edge-repair.js +89 -0
  322. package/dist/intelligence/indexer/entity-key.js +17 -0
  323. package/dist/intelligence/indexer/export-map.js +132 -0
  324. package/dist/intelligence/indexer/git-cochange.js +128 -0
  325. package/dist/intelligence/indexer/graph-patch.js +147 -0
  326. package/dist/intelligence/indexer/incremental.js +78 -0
  327. package/dist/intelligence/indexer/ingest.js +160 -0
  328. package/dist/intelligence/indexer/language-detect.js +226 -0
  329. package/dist/intelligence/indexer/metadata.js +63 -0
  330. package/dist/intelligence/indexer/mutation-tracker.js +79 -0
  331. package/dist/intelligence/indexer/orchestrator.js +155 -0
  332. package/dist/intelligence/indexer/plugin-interface.js +31 -0
  333. package/dist/intelligence/indexer/plugins/csharp.js +440 -0
  334. package/dist/intelligence/indexer/plugins/go.js +335 -0
  335. package/dist/intelligence/indexer/plugins/java.js +370 -0
  336. package/dist/intelligence/indexer/plugins/python.js +358 -0
  337. package/dist/intelligence/indexer/plugins/regex-fallback.js +82 -0
  338. package/dist/intelligence/indexer/plugins/ruby.js +290 -0
  339. package/dist/intelligence/indexer/plugins/rust.js +484 -0
  340. package/dist/intelligence/indexer/plugins/tier2-generic.js +310 -0
  341. package/dist/intelligence/indexer/plugins/typescript.js +456 -0
  342. package/dist/intelligence/indexer/resource-monitor.js +93 -0
  343. package/dist/intelligence/indexer/scip/decoder.js +253 -0
  344. package/dist/intelligence/indexer/scip/detector.js +232 -0
  345. package/dist/intelligence/indexer/scip/downloader.js +427 -0
  346. package/dist/intelligence/indexer/scip/fallback.js +34 -0
  347. package/dist/intelligence/indexer/scip/merger.js +109 -0
  348. package/dist/intelligence/indexer/scip/orchestrator.js +433 -0
  349. package/dist/intelligence/indexer/scip/runner.js +98 -0
  350. package/dist/intelligence/indexer/snapshot.js +66 -0
  351. package/dist/intelligence/indexer/test-detector.js +196 -0
  352. package/dist/intelligence/indexer/watch-integration.js +61 -0
  353. package/dist/intelligence/indexer/worker.js +85 -0
  354. package/dist/intelligence/local-convention-detector.js +437 -0
  355. package/dist/intelligence/local-embeddings.js +190 -0
  356. package/dist/intelligence/local-graph.js +1946 -0
  357. package/dist/intelligence/local-indexer.js +1575 -0
  358. package/dist/intelligence/local-llm.js +163 -0
  359. package/dist/intelligence/local-rule-generator.js +154 -0
  360. package/dist/intelligence/local-snapshot.js +213 -0
  361. package/dist/intelligence/negative-knowledge.js +103 -0
  362. package/dist/intelligence/persistent-db.js +85 -0
  363. package/dist/intelligence/query-router.js +2556 -0
  364. package/dist/intelligence/risk-classifier.js +116 -0
  365. package/dist/intelligence/rule-evaluator.js +380 -0
  366. package/dist/intelligence/rule-generator.js +49 -0
  367. package/dist/intelligence/search-index.js +173 -0
  368. package/dist/intelligence/semantic/docstring-extractor.js +67 -0
  369. package/dist/intelligence/semantic/embedding-store.js +52 -0
  370. package/dist/intelligence/semantic/enrichment-orchestrator.js +48 -0
  371. package/dist/intelligence/semantic/git-message-miner.js +114 -0
  372. package/dist/intelligence/semantic/identifier-tokenizer.js +51 -0
  373. package/dist/intelligence/semantic/node2vec-embeddings.js +71 -0
  374. package/dist/intelligence/semantic/node2vec-walks.js +103 -0
  375. package/dist/intelligence/semantic/path-domain-inference.js +112 -0
  376. package/dist/intelligence/semantic/similarity-engine.js +60 -0
  377. package/dist/intelligence/semantic/tfidf-vectors.js +88 -0
  378. package/dist/intelligence/session-brief-builder.js +159 -0
  379. package/dist/intelligence/session-context.js +221 -0
  380. package/dist/intelligence/session-health-monitor.js +211 -0
  381. package/dist/intelligence/session-narrative.js +197 -0
  382. package/dist/intelligence/session-pattern-analyzer.js +218 -0
  383. package/dist/intelligence/signal-scorer.js +390 -0
  384. package/dist/intelligence/signal-show-store.js +182 -0
  385. package/dist/intelligence/smart-truncate.js +158 -0
  386. package/dist/intelligence/subgraph-cache.js +88 -0
  387. package/dist/intelligence/temporal-facts.js +494 -0
  388. package/dist/intelligence/token-estimator.js +100 -0
  389. package/dist/intelligence/tool-injector.js +87 -0
  390. package/dist/intelligence/tree-sitter-loader.js +71 -0
  391. package/dist/intelligence/worker-pool.js +116 -0
  392. package/dist/proxy/arg-validator.js +79 -0
  393. package/dist/proxy/auto-bootstrap.js +167 -0
  394. package/dist/proxy/bridge.js +147 -0
  395. package/dist/proxy/budget-enforcer.js +70 -0
  396. package/dist/proxy/compression-quality-monitor.js +160 -0
  397. package/dist/proxy/compression-stats.js +51 -0
  398. package/dist/proxy/context-rot-detector.js +137 -0
  399. package/dist/proxy/drift-detector.js +139 -0
  400. package/dist/proxy/efficiency-tracker.js +79 -0
  401. package/dist/proxy/fact-ranking.js +154 -0
  402. package/dist/proxy/format-encoder.js +266 -0
  403. package/dist/proxy/http-transport.js +90 -0
  404. package/dist/proxy/lifecycle-actor.js +55 -0
  405. package/dist/proxy/lifecycle-machine.js +187 -0
  406. package/dist/proxy/log-tailer.js +265 -0
  407. package/dist/proxy/model-pricing.js +98 -0
  408. package/dist/proxy/network-firewall.js +141 -0
  409. package/dist/proxy/nudge-state.js +93 -0
  410. package/dist/proxy/output-compressor.js +185 -0
  411. package/dist/proxy/pid-lock.js +291 -0
  412. package/dist/proxy/proxy-context.js +11 -0
  413. package/dist/proxy/proxy.js +2633 -0
  414. package/dist/proxy/response-enrichment.js +32 -0
  415. package/dist/proxy/response-envelope.js +313 -0
  416. package/dist/proxy/session-dedup.js +82 -0
  417. package/dist/proxy/session-legend.js +30 -0
  418. package/dist/proxy/session-persistence.js +210 -0
  419. package/dist/proxy/session-resume.js +94 -0
  420. package/dist/proxy/session-stats.js +513 -0
  421. package/dist/proxy/shell-classifier.js +1346 -0
  422. package/dist/proxy/shell-compression-log.js +93 -0
  423. package/dist/proxy/shell-compressor.js +390 -0
  424. package/dist/proxy/shell-graph-boost.js +202 -0
  425. package/dist/proxy/shell-monitor-map.js +18 -0
  426. package/dist/proxy/shell-stats.js +54 -0
  427. package/dist/proxy/shell-strategies/cloud.js +215 -0
  428. package/dist/proxy/shell-strategies/diff.js +159 -0
  429. package/dist/proxy/shell-strategies/error-diagnostic.js +796 -0
  430. package/dist/proxy/shell-strategies/filter-dsl.js +358 -0
  431. package/dist/proxy/shell-strategies/git-status.js +177 -0
  432. package/dist/proxy/shell-strategies/key-value.js +193 -0
  433. package/dist/proxy/shell-strategies/log-text.js +154 -0
  434. package/dist/proxy/shell-strategies/omni.js +188 -0
  435. package/dist/proxy/shell-strategies/progress.js +55 -0
  436. package/dist/proxy/shell-strategies/redact.js +76 -0
  437. package/dist/proxy/shell-strategies/structured.js +241 -0
  438. package/dist/proxy/shell-strategies/tabular.js +243 -0
  439. package/dist/proxy/shell-strategies/test-results-types.js +13 -0
  440. package/dist/proxy/shell-strategies/test-results.js +784 -0
  441. package/dist/proxy/shell-strategies/tree-paths.js +144 -0
  442. package/dist/proxy/shell-strategies/yaml.js +182 -0
  443. package/dist/proxy/shell-tee.js +111 -0
  444. package/dist/proxy/signal-dedup.js +171 -0
  445. package/dist/proxy/startup-renderer.js +158 -0
  446. package/dist/proxy/task-token-display.js +38 -0
  447. package/dist/proxy/token-counter.js +61 -0
  448. package/dist/proxy/tool-clusters.js +273 -0
  449. package/dist/proxy/tool-definitions.js +525 -0
  450. package/dist/proxy/transport-mux.js +229 -0
  451. package/dist/proxy/wire-cap.js +268 -0
  452. package/dist/schemas/api/skills.js +19 -0
  453. package/dist/schemas/common/errors.js +7 -0
  454. package/dist/schemas/common/headers.js +5 -0
  455. package/dist/schemas/entities/edge.js +25 -0
  456. package/dist/schemas/entities/entity.js +22 -0
  457. package/dist/schemas/entities/rule.js +18 -0
  458. package/dist/schemas/index.js +14 -0
  459. package/dist/server/event-bus.js +59 -0
  460. package/dist/server/http.js +156 -0
  461. package/dist/server/middleware.js +70 -0
  462. package/dist/server/routes/drift.js +97 -0
  463. package/dist/server/routes/intelligence.js +1217 -0
  464. package/dist/server/routes/reasoning-quality.js +444 -0
  465. package/dist/server/routes/session.js +86 -0
  466. package/dist/server/routes/stream.js +120 -0
  467. package/dist/server/routes/system.js +73 -0
  468. package/dist/server/routes/temporal.js +170 -0
  469. package/dist/server/routes/timeline.js +232 -0
  470. package/dist/server/routes/token-flow.js +403 -0
  471. package/dist/skills/effectiveness-tracker.js +93 -0
  472. package/dist/skills/local-pack.js +380 -0
  473. package/dist/skills/resolver.js +495 -0
  474. package/dist/state-detector.js +83 -0
  475. package/dist/timeline/intent-detector.js +263 -0
  476. package/dist/timeline/loop-miner.js +140 -0
  477. package/dist/timeline/open-threads.js +49 -0
  478. package/dist/timeline/signal-reinforcer.js +62 -0
  479. package/dist/timeline/timeline-bootstrap.js +151 -0
  480. package/dist/timeline/timeline-store.js +618 -0
  481. package/dist/tools/coding/bash.js +49 -0
  482. package/dist/tools/coding/file-edit.js +72 -0
  483. package/dist/tools/coding/file-outline.js +227 -0
  484. package/dist/tools/coding/file-read-protocol.js +425 -0
  485. package/dist/tools/coding/file-read.js +35 -0
  486. package/dist/tools/coding/file-write.js +43 -0
  487. package/dist/tools/coding/glob-tool.js +109 -0
  488. package/dist/tools/coding/grep.js +162 -0
  489. package/dist/tools/coding/index.js +27 -0
  490. package/dist/tools/intelligence/index.js +269 -0
  491. package/dist/tools/intelligence/record-fact.js +48 -0
  492. package/dist/tools/intelligence/timeline-markers.js +130 -0
  493. package/dist/tools/registry.js +47 -0
  494. package/dist/tools/types.js +8 -0
  495. package/dist/tracking/auto-snapshot-triggers.js +246 -0
  496. package/dist/tracking/branch-context.js +115 -0
  497. package/dist/tracking/branch-snapshot.js +217 -0
  498. package/dist/tracking/causal-bridge.js +317 -0
  499. package/dist/tracking/circuit-breaker.js +147 -0
  500. package/dist/tracking/commit-watcher.js +114 -0
  501. package/dist/tracking/context-ledger.js +119 -0
  502. package/dist/tracking/correction-detector.js +324 -0
  503. package/dist/tracking/drift-tracker.js +874 -0
  504. package/dist/tracking/durability-tracker.js +94 -0
  505. package/dist/tracking/entity-rewind.js +200 -0
  506. package/dist/tracking/file-hash-state.js +114 -0
  507. package/dist/tracking/git-attribution.js +132 -0
  508. package/dist/tracking/git-trailers.js +171 -0
  509. package/dist/tracking/intelligence-counter.js +46 -0
  510. package/dist/tracking/intent-correlator.js +202 -0
  511. package/dist/tracking/intent-encoder.js +52 -0
  512. package/dist/tracking/intent-token-tracker.js +159 -0
  513. package/dist/tracking/ledger-archiver.js +94 -0
  514. package/dist/tracking/ledger-chains.js +245 -0
  515. package/dist/tracking/metrics-store.js +361 -0
  516. package/dist/tracking/native-watcher.js +131 -0
  517. package/dist/tracking/offline-rewind.js +295 -0
  518. package/dist/tracking/pending-violations.js +74 -0
  519. package/dist/tracking/persistence-effectiveness.js +167 -0
  520. package/dist/tracking/prompt-durability.js +202 -0
  521. package/dist/tracking/quality-signals.js +213 -0
  522. package/dist/tracking/redactor.js +73 -0
  523. package/dist/tracking/rewind-engine.js +161 -0
  524. package/dist/tracking/session-history.js +128 -0
  525. package/dist/tracking/session-receipt.js +88 -0
  526. package/dist/tracking/session-summary-writer.js +157 -0
  527. package/dist/tracking/shadow-ledger.js +321 -0
  528. package/dist/tracking/stash-manager.js +258 -0
  529. package/dist/tracking/timeline-fork.js +213 -0
  530. package/dist/tracking/timeline.js +69 -0
  531. package/dist/tracking/token-flow.js +276 -0
  532. package/dist/tracking/turn-segmenter.js +122 -0
  533. package/dist/tracking/weekly-accumulator.js +179 -0
  534. package/dist/tracking/working-snapshots.js +188 -0
  535. package/dist/tracking/workspace-manifest.js +176 -0
  536. package/dist/transport/http.js +102 -0
  537. package/dist/ui/assets/index-7gl3mIuY.css +1 -0
  538. package/dist/ui/assets/index-BsMTQdhX.js +10 -0
  539. package/dist/ui/index.html +2 -2
  540. package/dist/utils/counterfactual.js +65 -0
  541. package/dist/utils/deep-link.js +34 -0
  542. package/dist/utils/detect.js +193 -0
  543. package/dist/utils/exec.js +73 -0
  544. package/dist/utils/file-logger.js +87 -0
  545. package/dist/utils/format-error.js +29 -0
  546. package/dist/utils/git.js +181 -0
  547. package/dist/utils/log.js +57 -0
  548. package/dist/utils/logger.js +35 -0
  549. package/dist/utils/mcp-content-json.js +8 -0
  550. package/dist/utils/session-logger.js +154 -0
  551. package/dist/utils/startup-log.js +512 -0
  552. package/dist/utils/ui.js +56 -0
  553. package/package.json +5 -3
  554. package/scripts/postinstall.mjs +299 -0
  555. package/dist/ui/assets/index-BISLlJyc.js +0 -10
  556. package/dist/ui/assets/index-BUChTv4H.css +0 -1
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Intelligence Response Enrichment — populates the internal `meta` / `context`
3
+ * carrier with risk, confidence, and convention data. These fields never reach
4
+ * the wire — `buildSignalPrefix()` drains them into `ur|<tag>` prefix lines at
5
+ * the wire boundary (MCP clients strip `_meta`/`_context` envelopes).
6
+ *
7
+ * P.9: Every intelligence query response carries (on the internal envelope):
8
+ * - meta.confidence: propagated confidence level
9
+ * - meta.risk_level: entity risk classification → `ur|rsk` when high
10
+ * - meta.resolution_ms: query execution time
11
+ * - context.conventions: applicable conventions → `ur|hnt` / `ur|fct` lines
12
+ */
13
+ import { confidenceToScore } from "../intelligence/confidence-propagation.js";
14
+ /**
15
+ * Enrich a query response with intelligence metadata.
16
+ */
17
+ export function enrichResponse(content, meta, context) {
18
+ const result = {
19
+ content,
20
+ _meta: {
21
+ confidence: meta.confidence,
22
+ confidence_score: confidenceToScore(meta.confidence),
23
+ risk_level: meta.riskLevel,
24
+ resolution_ms: Math.round(meta.resolutionMs * 100) / 100,
25
+ edge_sources: meta.edgeSources,
26
+ },
27
+ };
28
+ if (context && Object.keys(context).length > 0) {
29
+ result._context = context;
30
+ }
31
+ return result;
32
+ }
@@ -0,0 +1,313 @@
1
+ /**
2
+ * MCP Response Envelope — standardized wrapper for every tool response.
3
+ *
4
+ * Every MCP tool response is enriched with:
5
+ * _meta: { "dev.unerr/tokens_saved", "dev.unerr/latency_ms", "dev.unerr/version" }
6
+ * _context: { optional intelligence injections from blast-radius, conventions, etc. }
7
+ *
8
+ * The envelope pipeline is composable: injectors register themselves and
9
+ * are invoked in order for each response. The session dedup layer sits
10
+ * on top, filtering context that has already been delivered.
11
+ *
12
+ * Token estimation uses char/4 as a fast approximation.
13
+ * Sprint G will replace this with a proper tiktoken-based engine.
14
+ */
15
+ import { estimateTokens } from "../intelligence/token-estimator.js";
16
+ export { estimateTokens };
17
+ const VERSION = "0.1.0";
18
+ /**
19
+ * Update notification state — set by the daemon's version checker.
20
+ * When set, tool responses include `_meta["dev.unerr/update_available"]`.
21
+ * Only injected when >2 minor versions behind (high signal, low noise).
22
+ */
23
+ let updateNotification = null;
24
+ export function setUpdateNotification(latest, current) {
25
+ updateNotification = { latest, current };
26
+ }
27
+ export function clearUpdateNotification() {
28
+ updateNotification = null;
29
+ }
30
+ /**
31
+ * Create a response envelope pipeline with registered context injectors.
32
+ */
33
+ export function createEnvelopePipeline(injectors = []) {
34
+ /**
35
+ * Wrap a raw tool response in the standard envelope.
36
+ *
37
+ * @param content - The original tool response content
38
+ * @param latencyMs - Time taken to execute the tool (ms)
39
+ * @param toolName - Name of the MCP tool that was called
40
+ * @param toolArgs - Arguments passed to the tool
41
+ * @param originalTokens - Token count of the raw input (for savings calculation)
42
+ */
43
+ async function wrapResponse(content, latencyMs, toolName = "", toolArgs = {}, originalTokens = 0) {
44
+ const responseTokens = estimateTokens(content);
45
+ const tokensSaved = Math.max(0, originalTokens - responseTokens);
46
+ const _meta = {
47
+ "dev.unerr/tokens_saved": tokensSaved,
48
+ "dev.unerr/latency_ms": Math.round(latencyMs * 100) / 100,
49
+ "dev.unerr/version": VERSION,
50
+ };
51
+ if (updateNotification) {
52
+ _meta["dev.unerr/update_available"] =
53
+ `${updateNotification.current} → ${updateNotification.latest}`;
54
+ }
55
+ const _context = {};
56
+ for (const injector of injectors) {
57
+ try {
58
+ const injected = await injector.inject({
59
+ toolName,
60
+ toolArgs,
61
+ content,
62
+ latencyMs,
63
+ });
64
+ if (injected) {
65
+ for (const [k, v] of Object.entries(injected)) {
66
+ _context[k] = v;
67
+ }
68
+ }
69
+ }
70
+ catch {
71
+ /* injector failures are silently swallowed — never break the response */
72
+ }
73
+ }
74
+ const envelope = { content, _meta };
75
+ if (Object.keys(_context).length > 0) {
76
+ envelope._context = _context;
77
+ }
78
+ return envelope;
79
+ }
80
+ return { wrapResponse };
81
+ }
82
+ /**
83
+ * Tier-2 strip: trim wire-only fields from `_meta` before serialization.
84
+ *
85
+ * Internal callers (proxy stats, eventBus, dashboard SSE) read meta BEFORE this
86
+ * runs; the wire envelope drops fields the agent never acts on.
87
+ *
88
+ * Rules — silent by default, vocal only when actionable:
89
+ * - source / mode / mode_reason: always "local" in OSS → strip (mode kept when degraded)
90
+ * - latency_ms: stderr telemetry only → strip
91
+ * - format / columns / columnar_legend / output_format_legend: in-band
92
+ * `_fmt:columnar` body header is canonical; _meta duplicates → strip
93
+ * - tokens_budget: caller already knows what they asked for → strip
94
+ * - tokens_used / truncated: meaningful only when truncated:true → conditional
95
+ */
96
+ const WIRE_STRIP_ALWAYS = new Set([
97
+ "source",
98
+ "latency_ms",
99
+ "format",
100
+ "columns",
101
+ "columnar_legend",
102
+ "output_format_legend",
103
+ "tokens_budget",
104
+ ]);
105
+ export function wireifyMeta(meta) {
106
+ if (!meta)
107
+ return meta;
108
+ const out = {};
109
+ const isLocalMode = meta.mode === "local";
110
+ const isTruncated = meta.truncated === true;
111
+ for (const [k, v] of Object.entries(meta)) {
112
+ if (WIRE_STRIP_ALWAYS.has(k))
113
+ continue;
114
+ if ((k === "mode" || k === "mode_reason") && isLocalMode)
115
+ continue;
116
+ if (k === "tokens_used" && !isTruncated)
117
+ continue;
118
+ if (k === "truncated" && !isTruncated)
119
+ continue;
120
+ if (v === undefined)
121
+ continue;
122
+ out[k] = v;
123
+ }
124
+ return out;
125
+ }
126
+ /**
127
+ * Tier-3 strip: build a leading "ur|<tag>" signal block that goes INTO the
128
+ * tool response body (`content[].text`).
129
+ *
130
+ * Why: per the MCP 2025-06-18 spec and confirmed in Claude Code / OpenAI Agents
131
+ * SDK, `_meta` and custom envelope fields like `_context` are filtered by the
132
+ * client and never reach the LLM context window. To keep anti-drift signals
133
+ * actually visible to the model, we prepend them into the body.
134
+ *
135
+ * Token-optimized prefix format (no brackets/colons — minimal token cost):
136
+ * "ur|<tag> <message>"
137
+ *
138
+ * `ur|` is typically a single BPE token in modern tokenizers. The 3-char tag
139
+ * is also one token. So the entire signal prefix costs ~2-3 tokens of overhead
140
+ * vs ~5 with bracketed notation. Legend lives in agent instruction files
141
+ * (CLAUDE.md, .cursor/rules/*, etc.) via instruction-writer.ts so the LLM
142
+ * knows what each one means without paying for the full word every call.
143
+ *
144
+ * hlt halt loop/circuit break — stop retrying
145
+ * dft drift file/entity changed — re-read before edit
146
+ * rsk risk high blast radius — verify callers
147
+ * wrn warn anti-pattern / negative fact
148
+ * hnt hint guidance / co-change suggestion
149
+ * fct fact surfaced project fact (procedural / convention / semantic)
150
+ * ctx context already delivered — don't re-query
151
+ * hth health session degraded — consider new session
152
+ * hst hist prior failures on this entity
153
+ * ur| generic nudge (no tag)
154
+ *
155
+ * Only emitted when actionable. Marketing/metrics/"survived" causal histories
156
+ * are dropped.
157
+ */
158
+ export const SIGNAL_PREFIX_LEGEND = `ur|<tag> is an unerr signal appended to MCP responses (as a footer). Tags:
159
+ hlt halt — loop/circuit break: stop retrying this entity, mark_blocker and switch approach
160
+ dft drift — file/entity changed: re-read with file_read/get_entity before edit
161
+ rsk risk — high blast radius: call get_references({direction:'callers'}) before edit
162
+ wrn warn — anti-pattern / negative fact: do not reintroduce the listed pattern
163
+ hnt hint — guidance: apply the named pattern or co-modify the listed files
164
+ fct fact — surfaced project fact (procedural / convention / semantic). Fact subtype is in [brackets] in the message.
165
+ hth health — session degraded: start a new session before the next non-trivial task
166
+ hst hist — prior failure modes: read each mode before retrying the same approach
167
+ pg page — pagination/wire-cap: response was capped. Format: "ur|pg <tool> +<remaining> — <cursorArg>:<nextValue>". Paste <nextValue> back into the same arg to fetch the next slice; the values are concrete numbers, not placeholders.
168
+ ur| generic nudge (no tag)`;
169
+ /** Map signal-scorer types → 3-char wire tag. The scorer emits exactly 4
170
+ * types (see SignalType in signal-scorer.ts): warning, guidance, context,
171
+ * history. The fact_type ([procedural], [convention], etc.) is already
172
+ * embedded in the message content by the scorer. */
173
+ export function signalTag(type) {
174
+ switch (type) {
175
+ case "warning":
176
+ return "wrn";
177
+ case "guidance":
178
+ return "hnt";
179
+ case "context":
180
+ return "fct"; // surfaced fact (procedural / convention / semantic)
181
+ case "history":
182
+ return "hst";
183
+ // Direct fact-type passthrough (not currently emitted but reserved):
184
+ case "convention":
185
+ return "cnv";
186
+ case "procedural":
187
+ return "pro";
188
+ case "semantic":
189
+ return "sem";
190
+ case "episodic":
191
+ return "epi";
192
+ case "negative":
193
+ return "wrn";
194
+ default:
195
+ return (type ?? "inf").slice(0, 3);
196
+ }
197
+ }
198
+ /**
199
+ * Hard caps applied AFTER per-tag dedup. The goal is "high-signal, low-noise":
200
+ * - MAX_LINES keeps the model from being drowned in stacked hints.
201
+ * - MAX_BYTES is a final safety net for pathological message payloads.
202
+ */
203
+ const MAX_SIGNAL_LINES = 2;
204
+ const MAX_SIGNAL_BYTES = 240;
205
+ import { getSignalDedup } from "./signal-dedup.js";
206
+ export function buildSignalPrefix(meta, context, entityKey = null) {
207
+ const dedup = getSignalDedup();
208
+ const lines = [];
209
+ function tryPush(tag, scopeKey, body) {
210
+ if (lines.length >= MAX_SIGNAL_LINES)
211
+ return;
212
+ if (!dedup.shouldEmit(tag, scopeKey, body))
213
+ return;
214
+ lines.push(`ur|${tag} ${body}`);
215
+ }
216
+ if (meta?.circuit_breaker) {
217
+ const cb = meta.circuit_breaker;
218
+ // Build the message from whatever is concrete; if we have neither attempts
219
+ // nor entity AND no explicit message, the line would be "? failed attempts
220
+ // on entity" — useless. Suppress in that case rather than emit a sentinel.
221
+ let msg = null;
222
+ if (cb.message) {
223
+ msg = cb.message;
224
+ }
225
+ else if (typeof cb.attempts === "number" && cb.entity) {
226
+ msg = `${cb.attempts} failed attempts on ${cb.entity} — stop retrying; mark_blocker and switch approach`;
227
+ }
228
+ else if (cb.entity) {
229
+ msg = `repeated failures on ${cb.entity} — stop retrying; mark_blocker and switch approach`;
230
+ }
231
+ if (msg)
232
+ tryPush("hlt", cb.entity ?? entityKey, msg);
233
+ }
234
+ if (meta?.drift) {
235
+ const d = meta.drift;
236
+ if (d.entityStatus) {
237
+ const by = d.lastModifiedBy ? ` by ${d.lastModifiedBy}` : "";
238
+ const where = d.branch ? ` on ${d.branch}` : "";
239
+ tryPush("dft", entityKey, `${d.entityStatus}${where}${by} — re-read before edit`);
240
+ }
241
+ }
242
+ if (meta?.entity_risk) {
243
+ const r = meta.entity_risk;
244
+ if (r.risk_level === "high") {
245
+ // For array/envelope results (e.g. get_references), `r.entity_key` is the
246
+ // max-risk reference's key, NOT the queried entity. Scoping dedup on that
247
+ // key means each new high-risk neighbor re-fires `ur|rsk` instead of
248
+ // being suppressed by `on_change` against the queried entity.
249
+ const refKey = r.entity_key
250
+ ? `${entityKey ?? "?"}:ref:${r.entity_key}`
251
+ : entityKey;
252
+ // Table row #15 TRIM — replace vague "verify blast radius" imperative
253
+ // with a concrete next-call the agent can paste.
254
+ tryPush("rsk", refKey, `fan_in=${r.fan_in ?? 0} fan_out=${r.fan_out ?? 0} (high blast radius — get_references first)`);
255
+ }
256
+ }
257
+ if (meta?.causal_history) {
258
+ const ch = meta.causal_history;
259
+ const realFailures = (ch.failure_modes ?? []).filter((m) => m !== "survived");
260
+ if (realFailures.length > 0) {
261
+ tryPush("hst", entityKey, `${ch.interactions ?? 0} interactions, prior: ${realFailures.join(",")}`);
262
+ }
263
+ }
264
+ // Dropped: untagged value_guard (no tag → can't be deduped per-tag, low signal).
265
+ // Dropped: meta.context_complete ur|ctx — session-dedup already gates the
266
+ // underlying context keys; "ctx" line was pure noise.
267
+ if (meta?.session_health) {
268
+ const h = meta.session_health;
269
+ if (typeof h.health === "number" && h.health < 0.6) {
270
+ // Table row #20 TRIM — replace "consider new session" hedge with a
271
+ // concrete action the agent / user can execute.
272
+ tryPush("hth", null, `${(h.health * 100).toFixed(0)}% — ${h.recommendation ?? "start a new session before next task"}`);
273
+ }
274
+ }
275
+ if (context?.signals && Array.isArray(context.signals)) {
276
+ const signals = context.signals;
277
+ for (const s of signals) {
278
+ if (lines.length >= MAX_SIGNAL_LINES)
279
+ break;
280
+ if (!s.content)
281
+ continue;
282
+ const tag = signalTag(s.type);
283
+ const action = s.action ? ` — ${s.action}` : "";
284
+ tryPush(tag, s.entity ?? entityKey, `${s.content}${action}`);
285
+ }
286
+ }
287
+ // Dropped: context.tool_adoption.hint — appeared on every call regardless of
288
+ // whether tool was already adopted; the instruction-writer surfaces this at
289
+ // session boot.
290
+ if (lines.length === 0)
291
+ return "";
292
+ let block = `${lines.join("\n")}\n\n`;
293
+ if (block.length > MAX_SIGNAL_BYTES) {
294
+ // Trim from the tail; first signals are typically the most critical
295
+ // (hlt > dft > rsk > hst > hth > scorer signals).
296
+ const truncated = [];
297
+ let used = 0;
298
+ for (const line of lines) {
299
+ if (used + line.length + 1 > MAX_SIGNAL_BYTES - 2)
300
+ break;
301
+ truncated.push(line);
302
+ used += line.length + 1;
303
+ }
304
+ block = truncated.length > 0 ? `${truncated.join("\n")}\n\n` : "";
305
+ }
306
+ return block;
307
+ }
308
+ /**
309
+ * Convenience: wrap a single response without a pipeline.
310
+ */
311
+ export async function wrapResponse(content, latencyMs, originalTokens = 0) {
312
+ return await createEnvelopePipeline().wrapResponse(content, latencyMs, "", {}, originalTokens);
313
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Session-Aware Context Deduplication — tracks which _context keys have been
3
+ * delivered in this session and filters out repeats.
4
+ *
5
+ * Design: in-memory only (no persistence across sessions — that's Sprint H).
6
+ * Bounded to MAX_TRACKED_KEYS to prevent memory leaks in long sessions.
7
+ *
8
+ * Temporal intelligence note: the dedup window corresponds to the episodic
9
+ * memory tier (Section 13.2). Within a session, repeated context has near-zero
10
+ * value. Cross-session dedup requires the warm/cold tier architecture (Sprint H).
11
+ */
12
+ const MAX_TRACKED_KEYS = 10_000;
13
+ /**
14
+ * Create a session dedup tracker.
15
+ * Filters context keys that have already been delivered for a given entity.
16
+ */
17
+ export function createSessionDedup() {
18
+ const delivered = new Map();
19
+ let totalKeys = 0;
20
+ function compoundKey(entityKey, contextKey) {
21
+ return `${entityKey}::${contextKey}`;
22
+ }
23
+ function hasDelivered(entityKey, contextKey) {
24
+ const entitySet = delivered.get(entityKey);
25
+ return entitySet?.has(contextKey) ?? false;
26
+ }
27
+ function markDelivered(entityKey, contextKeys) {
28
+ let entitySet = delivered.get(entityKey);
29
+ if (!entitySet) {
30
+ entitySet = new Set();
31
+ delivered.set(entityKey, entitySet);
32
+ }
33
+ for (const key of contextKeys) {
34
+ if (!entitySet.has(key)) {
35
+ entitySet.add(key);
36
+ totalKeys++;
37
+ }
38
+ }
39
+ if (totalKeys > MAX_TRACKED_KEYS) {
40
+ evictOldest();
41
+ }
42
+ }
43
+ function evictOldest() {
44
+ const iterator = delivered.keys();
45
+ let evicted = 0;
46
+ const target = Math.floor(MAX_TRACKED_KEYS * 0.2);
47
+ while (evicted < target) {
48
+ const result = iterator.next();
49
+ if (result.done)
50
+ break;
51
+ const entityKey = result.value;
52
+ const entitySet = delivered.get(entityKey);
53
+ if (entitySet) {
54
+ evicted += entitySet.size;
55
+ totalKeys -= entitySet.size;
56
+ delivered.delete(entityKey);
57
+ }
58
+ }
59
+ }
60
+ function filter(entityKey, context) {
61
+ const filtered = {};
62
+ const newKeys = [];
63
+ for (const [key, value] of Object.entries(context)) {
64
+ if (!hasDelivered(entityKey, key)) {
65
+ filtered[key] = value;
66
+ newKeys.push(key);
67
+ }
68
+ }
69
+ if (newKeys.length > 0) {
70
+ markDelivered(entityKey, newKeys);
71
+ }
72
+ return filtered;
73
+ }
74
+ function getDeliveredCount() {
75
+ return totalKeys;
76
+ }
77
+ function reset() {
78
+ delivered.clear();
79
+ totalKeys = 0;
80
+ }
81
+ return { filter, hasDelivered, markDelivered, getDeliveredCount, reset };
82
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Layer 6 Sprint FE-E — session-scoped legend delivery (columnar protocol + output format).
3
+ * Legends attach once per session until invalidated (e.g. retry detected).
4
+ */
5
+ /** One-time output format legend text (~30 tokens). */
6
+ export const OUTPUT_FORMAT_LEGEND = "Output conventions: use unified diff (---/+++/@@ hunks) for edits. " +
7
+ "When a response begins with `ur|ctx`, all context for this entity was already delivered — skip restatement. " +
8
+ "Prefer file path references over content repetition.";
9
+ export function createSessionLegendTracker() {
10
+ let columnarSent = false;
11
+ let outputFormatSent = false;
12
+ return {
13
+ consumeColumnarLegend() {
14
+ if (columnarSent)
15
+ return false;
16
+ columnarSent = true;
17
+ return true;
18
+ },
19
+ consumeOutputFormatLegend() {
20
+ if (outputFormatSent)
21
+ return false;
22
+ outputFormatSent = true;
23
+ return true;
24
+ },
25
+ invalidateAll() {
26
+ columnarSent = false;
27
+ outputFormatSent = false;
28
+ },
29
+ };
30
+ }
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Session Persistence — cross-session continuity for --mcp mode.
3
+ *
4
+ * Layer 9 PI-4: On reconnect, loads the previous session's summary and
5
+ * generates a targeted resume context that includes:
6
+ * - What was in progress (hot files, incomplete entities)
7
+ * - Relevant facts from facts.db for those hot files
8
+ * - Session metrics (duration, tools used, revert count)
9
+ *
10
+ * Staleness rule: sessions older than 24h are considered too stale.
11
+ * The agent gets fresh fact recall but no session continuity context.
12
+ *
13
+ * Graceful degradation: if any step fails, returns null (no crash).
14
+ */
15
+ // ── Constants ────────────────────────────────────────────────────────
16
+ const STALENESS_THRESHOLD_MS = 24 * 60 * 60 * 1000; // 24 hours
17
+ const WARM_THRESHOLD_MS = 4 * 60 * 60 * 1000; // 4 hours
18
+ // ── Public API ───────────────────────────────────────────────────────
19
+ /**
20
+ * Generate a session resume payload from the last session's summary.
21
+ * Integrates with facts.db if a fact store is available.
22
+ *
23
+ * Returns null if:
24
+ * - No prior session exists
25
+ * - Last session is older than 24h (too stale)
26
+ * - Any error occurs (graceful degradation)
27
+ */
28
+ export async function generateSessionResumePayload(unerrDir, factStore) {
29
+ try {
30
+ const { readLastSession } = await import("../tracking/session-summary-writer.js");
31
+ const lastSession = readLastSession(unerrDir);
32
+ if (!lastSession)
33
+ return null;
34
+ const endedAt = new Date(lastSession.ended_at).getTime();
35
+ const elapsed = Date.now() - endedAt;
36
+ if (elapsed > STALENESS_THRESHOLD_MS)
37
+ return null;
38
+ const staleness = elapsed < WARM_THRESHOLD_MS ? "fresh" : "warm";
39
+ const hotFiles = computeHotFiles(lastSession);
40
+ const incompleteHint = generateIncompleteHint(lastSession);
41
+ const recalledFacts = await recallFactsForSession(lastSession, factStore);
42
+ // Query facts that recently decayed below recall threshold
43
+ let decayedFacts = [];
44
+ if (factStore?.recallDecaying) {
45
+ try {
46
+ const decaying = await factStore.recallDecaying(0.05, 0.2);
47
+ decayedFacts = decaying.slice(0, 5).map((f) => ({
48
+ fact_id: f.fact_id,
49
+ type: f.fact_type,
50
+ content: f.content,
51
+ confidence: Math.round(f.effective_confidence * 100) / 100,
52
+ }));
53
+ }
54
+ catch {
55
+ // Non-critical
56
+ }
57
+ }
58
+ return {
59
+ session_resumed: true,
60
+ previous_session: {
61
+ session_id: lastSession.session_id,
62
+ duration_ms: lastSession.duration_ms,
63
+ tool_calls: lastSession.tool_calls,
64
+ chains: lastSession.chains,
65
+ files_modified: lastSession.files_modified.slice(0, 10),
66
+ entities_touched: lastSession.entities_touched.slice(0, 10),
67
+ tools_used: lastSession.tools_used,
68
+ feature_areas: lastSession.feature_areas,
69
+ revert_count: lastSession.revert_count,
70
+ facts_recorded: lastSession.facts_recorded,
71
+ branch: lastSession.branch,
72
+ ended_at: lastSession.ended_at,
73
+ },
74
+ continuity: {
75
+ hot_files: hotFiles,
76
+ incomplete_hint: incompleteHint,
77
+ staleness,
78
+ },
79
+ recalled_facts: recalledFacts,
80
+ decayed_since_last_session: decayedFacts,
81
+ };
82
+ }
83
+ catch {
84
+ return null;
85
+ }
86
+ }
87
+ // ── Internal Helpers ─────────────────────────────────────────────────
88
+ /**
89
+ * Compute the "hot files" — files most likely to be worked on again.
90
+ * Prioritizes files that appeared most frequently in tool calls.
91
+ */
92
+ function computeHotFiles(session) {
93
+ return session.files_modified.slice(0, 5);
94
+ }
95
+ /**
96
+ * Generate a human-readable hint about what was incomplete.
97
+ */
98
+ function generateIncompleteHint(session) {
99
+ const parts = [];
100
+ if (session.revert_count > 0) {
101
+ parts.push(`${session.revert_count} revert(s) in last session — approach may need rethinking`);
102
+ }
103
+ if (session.files_modified.length > 5) {
104
+ parts.push(`Large change set (${session.files_modified.length} files) — verify consistency`);
105
+ }
106
+ const highUseTools = Object.entries(session.tools_used)
107
+ .filter(([_, count]) => count > 10)
108
+ .map(([tool]) => tool);
109
+ if (highUseTools.length > 0) {
110
+ parts.push(`Heavy usage: ${highUseTools.join(", ")}`);
111
+ }
112
+ if (parts.length === 0) {
113
+ return session.files_modified.length > 0
114
+ ? `Continuing work on ${session.files_modified.slice(0, 3).join(", ")}`
115
+ : "No specific continuity context";
116
+ }
117
+ return parts.join(". ");
118
+ }
119
+ /**
120
+ * Recall facts relevant to the previous session's hot files.
121
+ * Returns up to 5 facts with highest effective confidence.
122
+ */
123
+ async function recallFactsForSession(session, factStore) {
124
+ if (!factStore)
125
+ return [];
126
+ try {
127
+ const allFacts = [];
128
+ for (const file of session.files_modified.slice(0, 5)) {
129
+ const facts = await factStore.recallByScope(file);
130
+ for (const f of facts) {
131
+ if (!allFacts.some((existing) => existing.fact_id === f.fact_id)) {
132
+ allFacts.push(f);
133
+ }
134
+ }
135
+ }
136
+ const projectFacts = await factStore.recallByScope("project");
137
+ for (const f of projectFacts) {
138
+ if (f.fact_type === "negative" &&
139
+ !allFacts.some((existing) => existing.fact_id === f.fact_id)) {
140
+ allFacts.push(f);
141
+ }
142
+ }
143
+ return allFacts
144
+ .sort((a, b) => b.effective_confidence - a.effective_confidence)
145
+ .slice(0, 5)
146
+ .map((f) => ({
147
+ fact_id: f.fact_id,
148
+ type: f.fact_type,
149
+ content: f.content,
150
+ confidence: Math.round(f.effective_confidence * 100) / 100,
151
+ source: f.source,
152
+ }));
153
+ }
154
+ catch {
155
+ return [];
156
+ }
157
+ }
158
+ // ── Visible Resume Block ────────────────────────────────────────────
159
+ /**
160
+ * Format session resume payload as a visible text block that agents will read.
161
+ * This is prepended to the first tool response content so it's impossible to miss.
162
+ * Keeps total output under 500 chars.
163
+ */
164
+ export function formatSessionResumeBlock(payload) {
165
+ if (!payload)
166
+ return "";
167
+ const parts = [];
168
+ // Elapsed time
169
+ const endedMs = new Date(payload.previous_session.ended_at).getTime();
170
+ const elapsedMs = Date.now() - endedMs;
171
+ const elapsed = formatElapsed(elapsedMs);
172
+ // Hot files
173
+ const hotFiles = payload.continuity.hot_files.slice(0, 3);
174
+ const filesStr = hotFiles.length > 0 ? hotFiles.join(", ") : "various files";
175
+ parts.push(`[unerr:session-resume] Previous session (${elapsed} ago): worked on ${filesStr}.`);
176
+ // High-confidence recalled facts
177
+ const importantFacts = payload.recalled_facts
178
+ .filter((f) => f.confidence >= 0.5)
179
+ .slice(0, 3);
180
+ for (const f of importantFacts) {
181
+ const pct = Math.round(f.confidence * 100);
182
+ parts.push(`▸ ${f.content} (${pct}%).`);
183
+ }
184
+ // Decayed facts warning
185
+ if (payload.decayed_since_last_session.length > 0) {
186
+ const n = payload.decayed_since_last_session.length;
187
+ const subjects = payload.decayed_since_last_session
188
+ .slice(0, 2)
189
+ .map((f) => `"${f.content.slice(0, 40)}"`);
190
+ parts.push(`⚠ ${n} fact(s) expired since last session: ${subjects.join(", ")}. Use record_fact to re-record if still relevant.`);
191
+ }
192
+ // Incomplete hint if meaningful
193
+ if (payload.continuity.incomplete_hint &&
194
+ payload.continuity.incomplete_hint !== "No specific continuity context") {
195
+ parts.push(`▸ ${payload.continuity.incomplete_hint}`);
196
+ }
197
+ const result = parts.join("\n");
198
+ // Truncate to 500 chars max
199
+ return result.length > 500 ? `${result.slice(0, 497)}...` : result;
200
+ }
201
+ function formatElapsed(ms) {
202
+ const minutes = Math.floor(ms / 60000);
203
+ if (minutes < 60)
204
+ return `${minutes}m`;
205
+ const hours = Math.floor(minutes / 60);
206
+ if (hours < 24)
207
+ return `${hours}h`;
208
+ const days = Math.floor(hours / 24);
209
+ return `${days}d`;
210
+ }