@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,1043 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * unerr — Local-first code intelligence CLI.
4
+ *
5
+ * Boot State Machine:
6
+ * unerr — THE command. First-run: wizard → index → serve. Subsequent: resume → serve.
7
+ * unerr chat — Interactive AI assistant (Ink REPL)
8
+ * unerr status — Quick diagnostic dump
9
+ * unerr debug — Full diagnostic for support
10
+ *
11
+ * All other commands are hidden but remain callable for power users and scripts.
12
+ */
13
+ import { existsSync, readFileSync } from "node:fs";
14
+ import { join } from "node:path";
15
+ import { Command } from "commander";
16
+ import { registerBranchesCommand } from "../commands/branches.js";
17
+ import { registerCheckCommitCommand } from "../commands/check-commit.js";
18
+ import { registerCompressOutputCommand } from "../commands/compress-output.js";
19
+ import { registerConfigVerifyCommand } from "../commands/config-verify.js";
20
+ import { registerDaemonCommand } from "../commands/daemon.js";
21
+ import { registerDashboardCommand } from "../commands/dashboard.js";
22
+ import { registerDebugCommand } from "../commands/debug.js";
23
+ import { registerEnrichCommand } from "../commands/enrich.js";
24
+ import { registerExecCommand } from "../commands/exec.js";
25
+ import { registerDiscoverCommand, registerGainCommand, } from "../commands/gain.js";
26
+ import { registerHookCommand } from "../commands/hook.js";
27
+ import { registerIndexCommand } from "../commands/index.js";
28
+ import { registerInitCommand } from "../commands/init.js";
29
+ import { registerInstallCommand } from "../commands/install.js";
30
+ import { registerLearnCommand } from "../commands/learn.js";
31
+ import { registerManifestCommand } from "../commands/manifest.js";
32
+ import { registerRewindCommand } from "../commands/rewind.js";
33
+ import { registerSkillsCommand } from "../commands/skills.js";
34
+ import { registerStatsCommand } from "../commands/stats.js";
35
+ import { registerStatusCommand } from "../commands/status.js";
36
+ import { registerTimelineCommand } from "../commands/timeline.js";
37
+ import { registerUninstallCommand } from "../commands/uninstall.js";
38
+ import { installFileLogger } from "../utils/file-logger.js";
39
+ import { initFileLog } from "../utils/startup-log.js";
40
+ // ── Helpers ─────────────────────────────────────────────────
41
+ /**
42
+ * Start the unified proxy.
43
+ */
44
+ async function startProxy(repoId) {
45
+ const { startProxy: boot } = await import("../proxy/proxy.js");
46
+ const httpPort = Number.parseInt(process.env.UNERR_HTTP_PORT ?? "0", 10);
47
+ await boot({ repoId, httpPort: httpPort || undefined });
48
+ }
49
+ /**
50
+ * Auto-verify and repair IDE MCP configs before proxy start.
51
+ * Silently fixes stale MCP configs → local proxy format.
52
+ */
53
+ async function autoVerifyIdeConfigs() {
54
+ try {
55
+ const { checkIdeConfig, repairIdeConfig } = await import("../commands/config-verify.js");
56
+ const os = await import("node:os");
57
+ const path = await import("node:path");
58
+ const ideConfigs = {
59
+ cursor: path.join(os.homedir(), ".cursor", "mcp.json"),
60
+ vscode: path.join(os.homedir(), ".vscode", "settings.json"),
61
+ windsurf: path.join(os.homedir(), ".windsurf", "mcp.json"),
62
+ };
63
+ for (const [ideName, configPath] of Object.entries(ideConfigs)) {
64
+ const result = checkIdeConfig(ideName, configPath);
65
+ if (result.found && result.needsMigration) {
66
+ const repaired = repairIdeConfig(ideName, configPath);
67
+ if (repaired) {
68
+ process.stderr.write(`[unerr] Auto-repaired ${ideName} MCP config (remote URL → local proxy)\n`);
69
+ }
70
+ }
71
+ }
72
+ }
73
+ catch {
74
+ // Non-blocking — config verification should never prevent proxy startup
75
+ }
76
+ }
77
+ /**
78
+ * Check if we're inside a git repository.
79
+ */
80
+ async function isInsideGitRepo() {
81
+ const { isGitRepo } = await import("../utils/git.js");
82
+ return isGitRepo(process.cwd());
83
+ }
84
+ // ── Project Root Detection (Scored Multi-Signal Analysis) ─────
85
+ /**
86
+ * TIER 1: Definitive project markers — files whose presence at root
87
+ * guarantees this is a project directory. Grouped by ecosystem.
88
+ */
89
+ const DEFINITIVE_MARKERS = [
90
+ // JavaScript / TypeScript
91
+ "package.json",
92
+ "tsconfig.json",
93
+ "jsconfig.json",
94
+ "deno.json",
95
+ "deno.jsonc",
96
+ "bun.lockb",
97
+ "bunfig.toml",
98
+ // Python
99
+ "pyproject.toml",
100
+ "setup.py",
101
+ "setup.cfg",
102
+ "Pipfile",
103
+ "hatch.toml",
104
+ // Rust
105
+ "Cargo.toml",
106
+ // Go
107
+ "go.mod",
108
+ // Java / Kotlin / Gradle
109
+ "pom.xml",
110
+ "build.gradle",
111
+ "build.gradle.kts",
112
+ "settings.gradle",
113
+ "settings.gradle.kts",
114
+ // C# / .NET
115
+ "Directory.Build.props",
116
+ "global.json",
117
+ "nuget.config",
118
+ // Ruby
119
+ "Gemfile",
120
+ "Rakefile",
121
+ // PHP
122
+ "composer.json",
123
+ // Swift / Obj-C / Apple
124
+ "Package.swift",
125
+ "Podfile",
126
+ // C / C++
127
+ "CMakeLists.txt",
128
+ "Makefile",
129
+ "configure.ac",
130
+ "meson.build",
131
+ "conanfile.txt",
132
+ "conanfile.py",
133
+ "vcpkg.json",
134
+ // Dart / Flutter
135
+ "pubspec.yaml",
136
+ // Elixir
137
+ "mix.exs",
138
+ // Scala
139
+ "build.sbt",
140
+ "build.sc",
141
+ // Haskell
142
+ "stack.yaml",
143
+ "cabal.project",
144
+ // Clojure
145
+ "project.clj",
146
+ "deps.edn",
147
+ "shadow-cljs.edn",
148
+ // Zig
149
+ "build.zig",
150
+ "build.zig.zon",
151
+ // Julia
152
+ "Project.toml",
153
+ // Terraform / IaC
154
+ "main.tf",
155
+ "terraform.tf",
156
+ "pulumi.yaml",
157
+ "serverless.yml",
158
+ "cdk.json",
159
+ "sam.yaml",
160
+ // Containers
161
+ "Dockerfile",
162
+ "docker-compose.yml",
163
+ "docker-compose.yaml",
164
+ // Monorepo
165
+ "lerna.json",
166
+ "nx.json",
167
+ "turbo.json",
168
+ "pnpm-workspace.yaml",
169
+ "rush.json",
170
+ "pants.toml",
171
+ // Bazel
172
+ "BUILD.bazel",
173
+ "WORKSPACE",
174
+ "WORKSPACE.bazel",
175
+ // General build / task
176
+ "Justfile",
177
+ "Taskfile.yml",
178
+ // Nix
179
+ "flake.nix",
180
+ "shell.nix",
181
+ "default.nix",
182
+ // Android
183
+ "AndroidManifest.xml",
184
+ ];
185
+ /**
186
+ * TIER 2: Strong signals — VCS, IDE, CI/CD, lock files, editor configs.
187
+ * Not definitive alone (a stray .gitignore doesn't make a project) but
188
+ * contribute significant score.
189
+ */
190
+ const STRONG_SIGNAL_FILES = [
191
+ // Lock files (imply a package manager was run here)
192
+ "package-lock.json",
193
+ "yarn.lock",
194
+ "pnpm-lock.yaml",
195
+ "Pipfile.lock",
196
+ "poetry.lock",
197
+ "Gemfile.lock",
198
+ "composer.lock",
199
+ "Cargo.lock",
200
+ "flake.lock",
201
+ "pubspec.lock",
202
+ "mix.lock",
203
+ "go.sum",
204
+ "uv.lock",
205
+ "pdm.lock",
206
+ // CI/CD (a CI config strongly implies project root)
207
+ ".gitlab-ci.yml",
208
+ "Jenkinsfile",
209
+ ".travis.yml",
210
+ "azure-pipelines.yml",
211
+ "bitbucket-pipelines.yml",
212
+ // Editor / LSP configs (placed at project root)
213
+ ".editorconfig",
214
+ ".prettierrc",
215
+ ".prettierrc.json",
216
+ ".eslintrc",
217
+ ".eslintrc.json",
218
+ ".eslintrc.js",
219
+ "biome.json",
220
+ "biome.jsonc",
221
+ "pyrightconfig.json",
222
+ "rust-toolchain.toml",
223
+ ".clang-format",
224
+ ".clangd",
225
+ "compile_commands.json",
226
+ ".luarc.json",
227
+ "stylua.toml",
228
+ ".rubocop.yml",
229
+ ".php-cs-fixer.php",
230
+ // Environment
231
+ ".env",
232
+ ".envrc",
233
+ // Git-specific (at root level these are strong signals)
234
+ ".gitignore",
235
+ ".gitattributes",
236
+ ];
237
+ /** TIER 2: Directories that are strong signals when present at root. */
238
+ const STRONG_SIGNAL_DIRS = [
239
+ ".git",
240
+ ".svn",
241
+ ".hg",
242
+ ".fossil",
243
+ ".bzr",
244
+ "_darcs", // VCS
245
+ ".github",
246
+ ".circleci",
247
+ ".buildkite", // CI/CD
248
+ ".idea",
249
+ ".vscode",
250
+ ".vs",
251
+ ".fleet",
252
+ ".zed", // IDE
253
+ ];
254
+ /** Glob patterns for file-extension markers (e.g., *.sln, *.csproj). */
255
+ const EXTENSION_MARKERS = [
256
+ ".sln",
257
+ ".csproj",
258
+ ".fsproj",
259
+ ".vbproj", // .NET
260
+ ".xcodeproj",
261
+ ".xcworkspace", // Xcode (dirs)
262
+ ".cabal", // Haskell
263
+ ".nimble", // Nim
264
+ ".gemspec", // Ruby
265
+ ".rockspec", // Lua
266
+ ];
267
+ /**
268
+ * TIER 3: Code file extensions — comprehensive across all mainstream
269
+ * and emerging languages. Used to scan root + source dirs.
270
+ */
271
+ const CODE_EXTENSIONS = new Set([
272
+ // Web / JS ecosystem
273
+ ".ts",
274
+ ".tsx",
275
+ ".js",
276
+ ".jsx",
277
+ ".mjs",
278
+ ".cjs",
279
+ ".vue",
280
+ ".svelte",
281
+ ".astro",
282
+ // Systems
283
+ ".rs",
284
+ ".go",
285
+ ".c",
286
+ ".h",
287
+ ".cpp",
288
+ ".cc",
289
+ ".cxx",
290
+ ".hpp",
291
+ ".hxx",
292
+ ".zig",
293
+ // JVM
294
+ ".java",
295
+ ".kt",
296
+ ".kts",
297
+ ".scala",
298
+ ".sc",
299
+ ".clj",
300
+ ".cljs",
301
+ ".cljc",
302
+ // .NET
303
+ ".cs",
304
+ ".fs",
305
+ ".fsx",
306
+ ".vb",
307
+ // Scripting
308
+ ".py",
309
+ ".pyi",
310
+ ".rb",
311
+ ".php",
312
+ ".lua",
313
+ ".pl",
314
+ ".pm",
315
+ ".raku",
316
+ // Apple / Mobile
317
+ ".swift",
318
+ ".m",
319
+ ".mm",
320
+ ".dart",
321
+ // Functional
322
+ ".hs",
323
+ ".lhs",
324
+ ".ml",
325
+ ".mli",
326
+ ".re",
327
+ ".rei",
328
+ ".elm",
329
+ ".ex",
330
+ ".exs",
331
+ ".purs",
332
+ ".idr",
333
+ ".agda",
334
+ ".lean",
335
+ // Data / Science
336
+ ".r",
337
+ ".R",
338
+ ".jl",
339
+ // Infrastructure
340
+ ".tf",
341
+ ".hcl",
342
+ // Emerging / Niche
343
+ ".nim",
344
+ ".cr",
345
+ ".d",
346
+ ".v",
347
+ ".sol",
348
+ ".move",
349
+ ".cairo",
350
+ ".nr",
351
+ // Shell / Config as code
352
+ ".sh",
353
+ ".bash",
354
+ ".zsh",
355
+ ".fish",
356
+ ".ps1",
357
+ ]);
358
+ /**
359
+ * TIER 4: Anti-signals — files/dirs that indicate this is a home dir,
360
+ * system path, or otherwise NOT a project root. Each match subtracts score.
361
+ */
362
+ const ANTI_SIGNAL_FILES = [
363
+ ".bashrc",
364
+ ".zshrc",
365
+ ".bash_profile",
366
+ ".profile",
367
+ ".zprofile",
368
+ ".zshenv",
369
+ ".bash_history",
370
+ ".zsh_history",
371
+ ];
372
+ const ANTI_SIGNAL_DIRS = [
373
+ ".config",
374
+ ".local",
375
+ ".cache",
376
+ ".ssh",
377
+ ".gnupg",
378
+ ".npm",
379
+ ".cargo",
380
+ "Desktop",
381
+ "Downloads",
382
+ "Documents",
383
+ "Pictures",
384
+ "Music",
385
+ "Movies",
386
+ "Library",
387
+ "Applications",
388
+ ];
389
+ const ANTI_SIGNAL_PATHS = [
390
+ "/",
391
+ "/usr",
392
+ "/tmp",
393
+ "/var",
394
+ "/etc",
395
+ "/opt",
396
+ "/home",
397
+ "/Users",
398
+ "/root",
399
+ ];
400
+ /**
401
+ * TIER 5: Well-known source directories — if these exist at root AND
402
+ * contain code files, that's a strong project signal.
403
+ */
404
+ const SOURCE_DIRS = new Set([
405
+ "src",
406
+ "lib",
407
+ "app",
408
+ "apps",
409
+ "cmd",
410
+ "pkg",
411
+ "packages",
412
+ "internal",
413
+ "modules",
414
+ "components",
415
+ "pages",
416
+ "routes",
417
+ "api",
418
+ "server",
419
+ "client",
420
+ "web",
421
+ "core",
422
+ "common",
423
+ "shared",
424
+ "utils",
425
+ "helpers",
426
+ "services",
427
+ "models",
428
+ "views",
429
+ "controllers",
430
+ "handlers",
431
+ "middleware",
432
+ "plugins",
433
+ "test",
434
+ "tests",
435
+ "spec",
436
+ "__tests__",
437
+ "e2e",
438
+ "integration",
439
+ "scripts",
440
+ "tools",
441
+ "bin",
442
+ "examples",
443
+ "samples",
444
+ "proto",
445
+ "schemas",
446
+ "migrations",
447
+ "seeds",
448
+ ]);
449
+ /**
450
+ * Scored project-root detection. Accumulates evidence across 5 tiers
451
+ * and subtracts anti-signals. A score >= THRESHOLD means "this is a project".
452
+ *
453
+ * Scoring weights:
454
+ * Definitive marker file: +10 (instant pass)
455
+ * VCS directory (.git, .hg): +8
456
+ * Strong signal file/dir: +4
457
+ * Extension marker (*.sln): +10
458
+ * Code files in root: +5
459
+ * Code files in source dir: +6
460
+ * Anti-signal file: -3
461
+ * Anti-signal directory: -2
462
+ * Anti-signal path: -15 (instant fail for /, /usr, etc.)
463
+ *
464
+ * Threshold: 5 (a single definitive marker or VCS dir passes)
465
+ */
466
+ const DETECTION_THRESHOLD = 5;
467
+ async function detectProjectRoot(cwd) {
468
+ const { readdirSync } = await import("node:fs");
469
+ let score = 0;
470
+ const signals = [];
471
+ let hasGit = false;
472
+ // ── TIER 4 first: Anti-signal paths (early reject) ──────────
473
+ const normalizedCwd = cwd.replace(/\\/g, "/");
474
+ for (const ap of ANTI_SIGNAL_PATHS) {
475
+ if (normalizedCwd === ap || normalizedCwd === `${ap}/`) {
476
+ return {
477
+ isProject: false,
478
+ hasGit: false,
479
+ reason: `System/root path: ${cwd}`,
480
+ score: -15,
481
+ signals: [`anti-path: ${ap}`],
482
+ };
483
+ }
484
+ }
485
+ // Read root directory entries once
486
+ let rootEntries = [];
487
+ try {
488
+ rootEntries = readdirSync(cwd, { withFileTypes: true }).map((e) => ({
489
+ name: e.name,
490
+ isFile: e.isFile(),
491
+ isDir: e.isDirectory(),
492
+ }));
493
+ }
494
+ catch {
495
+ return {
496
+ isProject: false,
497
+ hasGit: false,
498
+ reason: "Cannot read directory",
499
+ score: -1,
500
+ signals: ["unreadable"],
501
+ };
502
+ }
503
+ const rootFileNames = new Set(rootEntries.filter((e) => e.isFile).map((e) => e.name));
504
+ const rootDirNames = new Set(rootEntries.filter((e) => e.isDir).map((e) => e.name));
505
+ // ── TIER 4: Anti-signal files & dirs at root ────────────────
506
+ for (const af of ANTI_SIGNAL_FILES) {
507
+ if (rootFileNames.has(af)) {
508
+ score -= 3;
509
+ signals.push(`anti-file: ${af}`);
510
+ }
511
+ }
512
+ for (const ad of ANTI_SIGNAL_DIRS) {
513
+ if (rootDirNames.has(ad)) {
514
+ score -= 2;
515
+ signals.push(`anti-dir: ${ad}/`);
516
+ }
517
+ }
518
+ // ── TIER 1: Definitive marker files ─────────────────────────
519
+ for (const marker of DEFINITIVE_MARKERS) {
520
+ if (rootFileNames.has(marker)) {
521
+ score += 10;
522
+ signals.push(`marker: ${marker}`);
523
+ break; // one is enough
524
+ }
525
+ }
526
+ // ── TIER 1: Extension-based markers (*.sln, *.csproj, etc.) ─
527
+ if (score < DETECTION_THRESHOLD) {
528
+ for (const entry of rootEntries) {
529
+ if (!entry.isFile && !entry.isDir)
530
+ continue;
531
+ const name = entry.name.toLowerCase();
532
+ for (const ext of EXTENSION_MARKERS) {
533
+ if (name.endsWith(ext)) {
534
+ score += 10;
535
+ signals.push(`ext-marker: ${entry.name}`);
536
+ break;
537
+ }
538
+ }
539
+ if (score >= DETECTION_THRESHOLD)
540
+ break;
541
+ }
542
+ }
543
+ // ── TIER 2: VCS directories ─────────────────────────────────
544
+ for (const vcs of STRONG_SIGNAL_DIRS.slice(0, 6)) {
545
+ if (rootDirNames.has(vcs)) {
546
+ if (vcs === ".git")
547
+ hasGit = true;
548
+ score += 8;
549
+ signals.push(`vcs: ${vcs}/`);
550
+ break;
551
+ }
552
+ }
553
+ // ── TIER 2: Strong signal files ─────────────────────────────
554
+ for (const sf of STRONG_SIGNAL_FILES) {
555
+ if (rootFileNames.has(sf)) {
556
+ score += 4;
557
+ signals.push(`strong: ${sf}`);
558
+ if (score >= DETECTION_THRESHOLD)
559
+ break;
560
+ }
561
+ }
562
+ // ── TIER 2: Strong signal dirs (IDE, CI) ────────────────────
563
+ for (const sd of STRONG_SIGNAL_DIRS.slice(6)) {
564
+ if (rootDirNames.has(sd)) {
565
+ score += 4;
566
+ signals.push(`strong: ${sd}/`);
567
+ if (score >= DETECTION_THRESHOLD)
568
+ break;
569
+ }
570
+ }
571
+ // ── TIER 2: Git repo check (may be in a parent .git) ───────
572
+ if (!hasGit) {
573
+ try {
574
+ hasGit = await isInsideGitRepo();
575
+ if (hasGit) {
576
+ score += 6;
577
+ signals.push("git: inside work tree");
578
+ }
579
+ }
580
+ catch {
581
+ // ignore
582
+ }
583
+ }
584
+ // Already passing? Skip expensive file scan.
585
+ if (score >= DETECTION_THRESHOLD) {
586
+ const topSignal = signals.find((s) => !s.startsWith("anti-")) ?? signals[0] ?? "unknown";
587
+ return { isProject: true, hasGit, reason: topSignal, score, signals };
588
+ }
589
+ // ── TIER 3 + 5: Code files in root, then source dirs ───────
590
+ function dirHasCodeFile(dir) {
591
+ try {
592
+ const entries = readdirSync(dir, { withFileTypes: true });
593
+ for (const entry of entries) {
594
+ if (!entry.isFile())
595
+ continue;
596
+ const dot = entry.name.lastIndexOf(".");
597
+ if (dot >= 0 &&
598
+ CODE_EXTENSIONS.has(entry.name.slice(dot).toLowerCase())) {
599
+ return entry.name;
600
+ }
601
+ }
602
+ }
603
+ catch {
604
+ // skip
605
+ }
606
+ return null;
607
+ }
608
+ // Code files directly in cwd
609
+ const rootCodeFile = dirHasCodeFile(cwd);
610
+ if (rootCodeFile) {
611
+ score += 5;
612
+ signals.push(`code-root: ${rootCodeFile}`);
613
+ }
614
+ if (score >= DETECTION_THRESHOLD) {
615
+ const topSignal = signals.find((s) => !s.startsWith("anti-")) ?? signals[0] ?? "unknown";
616
+ return { isProject: true, hasGit, reason: topSignal, score, signals };
617
+ }
618
+ // Code files inside well-known source dirs (+ one level deeper)
619
+ for (const dirEntry of rootEntries) {
620
+ if (!dirEntry.isDir || dirEntry.name.startsWith("."))
621
+ continue;
622
+ if (!SOURCE_DIRS.has(dirEntry.name.toLowerCase()))
623
+ continue;
624
+ const sourceDir = join(cwd, dirEntry.name);
625
+ const srcCodeFile = dirHasCodeFile(sourceDir);
626
+ if (srcCodeFile) {
627
+ score += 6;
628
+ signals.push(`code-src: ${dirEntry.name}/${srcCodeFile}`);
629
+ break;
630
+ }
631
+ // One level deeper (src/components/, lib/utils/)
632
+ try {
633
+ const subEntries = readdirSync(sourceDir, { withFileTypes: true });
634
+ let found = false;
635
+ for (const sub of subEntries) {
636
+ if (!sub.isDirectory() || sub.name.startsWith("."))
637
+ continue;
638
+ const deepCode = dirHasCodeFile(join(sourceDir, sub.name));
639
+ if (deepCode) {
640
+ score += 6;
641
+ signals.push(`code-src: ${dirEntry.name}/${sub.name}/${deepCode}`);
642
+ found = true;
643
+ break;
644
+ }
645
+ }
646
+ if (found)
647
+ break;
648
+ }
649
+ catch {
650
+ // skip
651
+ }
652
+ }
653
+ const isProject = score >= DETECTION_THRESHOLD;
654
+ const topSignal = signals.find((s) => !s.startsWith("anti-")) ?? signals[0] ?? "No signals";
655
+ return {
656
+ isProject,
657
+ hasGit,
658
+ reason: isProject ? topSignal : "No code files or project markers found",
659
+ score,
660
+ signals,
661
+ };
662
+ }
663
+ /**
664
+ * Read .unerr/config.json if it exists.
665
+ */
666
+ function readLocalConfig(cwd) {
667
+ const configPath = join(cwd, ".unerr", "config.json");
668
+ if (!existsSync(configPath))
669
+ return null;
670
+ try {
671
+ return JSON.parse(readFileSync(configPath, "utf-8"));
672
+ }
673
+ catch {
674
+ return null;
675
+ }
676
+ }
677
+ // ── Boot State Machine ─────────────────────────────────────
678
+ /**
679
+ * Resume path: config exists, skip all interactive prompts.
680
+ */
681
+ async function resumeBoot(config) {
682
+ initFileLog(process.cwd());
683
+ // Verify this is still a valid project directory (config may be stale)
684
+ const detection = await detectProjectRoot(process.cwd());
685
+ if (!detection.isProject) {
686
+ const antiSignals = detection.signals.filter((s) => s.startsWith("anti-"));
687
+ process.stderr.write(`\x1b[38;2;248;113;113m\u2717\x1b[0m No code project detected in this directory.\n Found .unerr/config.json but the directory doesn't look like a project root.\n Detection score: ${detection.score} (need ${DETECTION_THRESHOLD})\n${antiSignals.length > 0
688
+ ? ` Negative signals: ${antiSignals.map((s) => s.replace("anti-", "")).join(", ")}\n`
689
+ : ""}\n unerr checks for: project files (package.json, Cargo.toml, go.mod, ...),\n VCS directories (.git, .hg), IDE configs, CI/CD files, lock files,\n and source code across 50+ languages.\n\n \u25b8 Run \x1b[1munerr\x1b[0m from a project root directory.\n`);
690
+ process.exit(1);
691
+ }
692
+ const { initSessionLogger, createSessionModuleLogger } = await import("../utils/session-logger.js");
693
+ initSessionLogger();
694
+ const log = createSessionModuleLogger("boot");
695
+ log.info({ msg: "Resume boot", mode: "local", repoId: config.repoId });
696
+ // Show update notice (non-blocking, from cache only)
697
+ try {
698
+ const { getCachedUpdateInfo } = await import("../daemon/version-checker.js");
699
+ const info = getCachedUpdateInfo();
700
+ if (info.available && !info.dismissed) {
701
+ process.stderr.write(`\x1b[38;2;34;211;238m▸\x1b[0m Update available: ${info.current} → ${info.latest} — run \x1b[38;2;139;92;246munerr daemon update\x1b[0m\n`);
702
+ }
703
+ }
704
+ catch {
705
+ // Non-blocking
706
+ }
707
+ process.stderr.write("[unerr] Starting proxy...\n");
708
+ await autoVerifyIdeConfigs();
709
+ await startProxy(config.repoId);
710
+ }
711
+ /**
712
+ * First-run path: no config exists. Auto-detect environment, prompt if needed.
713
+ */
714
+ async function firstRunBoot() {
715
+ initFileLog(process.cwd());
716
+ const { initSessionLogger, createSessionModuleLogger } = await import("../utils/session-logger.js");
717
+ initSessionLogger();
718
+ const log = createSessionModuleLogger("boot");
719
+ // Must be in a project directory
720
+ const detection = await detectProjectRoot(process.cwd());
721
+ if (!detection.isProject) {
722
+ const antiSignals = detection.signals.filter((s) => s.startsWith("anti-"));
723
+ process.stderr.write(`\x1b[38;2;248;113;113m\u2717\x1b[0m No code project detected in this directory.\n unerr needs a folder containing source code to index.\n Detection score: ${detection.score} (need ${DETECTION_THRESHOLD})\n${antiSignals.length > 0
724
+ ? ` Negative signals: ${antiSignals.map((s) => s.replace("anti-", "")).join(", ")}\n`
725
+ : ""}\n Checked for: project files (package.json, Cargo.toml, go.mod, pyproject.toml, ...),\n VCS directories (.git, .hg, .svn), IDE configs (.vscode, .idea),\n CI/CD files (.github, Jenkinsfile), lock files, and source code\n across 50+ languages in root + standard source directories.\n\n \u25b8 Run \x1b[1munerr\x1b[0m from a project root directory.\n`);
726
+ process.exit(1);
727
+ }
728
+ if (!detection.hasGit) {
729
+ process.stderr.write(`\x1b[38;2;251;191;36m\u26a0\x1b[0m Project detected (${detection.reason}) but no git repository found.\n unerr works best with git. Consider running \x1b[1mgit init\x1b[0m first.\n Continuing anyway...\n\n`);
730
+ }
731
+ log.info({
732
+ msg: "First-run boot, entering local setup",
733
+ detection: detection.reason,
734
+ score: detection.score,
735
+ hasGit: detection.hasGit,
736
+ });
737
+ const { runSetup } = await import("../commands/setup-wizard.js");
738
+ const result = await runSetup();
739
+ if (result.action === "setup") {
740
+ await autoVerifyIdeConfigs();
741
+ await startProxy(result.repoId);
742
+ return;
743
+ }
744
+ process.exit(0);
745
+ }
746
+ /**
747
+ * Daemon-child mode: spawned and managed by unerrd.
748
+ *
749
+ * Differences from standalone `unerr`:
750
+ * - No interactive prompts (process.stdin.isTTY is false)
751
+ * - IPC channel to parent: sends { type: "ready", sock }, { type: "activity" }
752
+ * - SIGTERM triggers snapshot + clean exit (no delay)
753
+ * - Orphan detection: checks ppid every 60s, self-exits if parent died
754
+ * - Activity reports: stats sent every 60s while running
755
+ */
756
+ async function daemonChildBoot(cwd) {
757
+ installFileLogger({
758
+ filePath: join(cwd, ".unerr", "logs", `child-${process.pid}.log`),
759
+ maxBytes: 5_000_000,
760
+ keep: 5,
761
+ });
762
+ initFileLog(cwd);
763
+ const config = readLocalConfig(cwd);
764
+ if (!config) {
765
+ process.stderr.write("[unerr:child] No .unerr/config.json — run `unerr` interactively first.\n");
766
+ process.exit(1);
767
+ }
768
+ const originalPpid = process.ppid;
769
+ // Orphan detection: if parent (unerrd) dies, self-exit
770
+ const orphanTimer = setInterval(() => {
771
+ if (process.ppid !== originalPpid) {
772
+ process.stderr.write("[unerr:child] Parent died — orphan exit.\n");
773
+ clearInterval(orphanTimer);
774
+ clearInterval(statsTimer);
775
+ shutdownProxy("orphan");
776
+ }
777
+ }, 60_000);
778
+ orphanTimer.unref();
779
+ // SIGTERM from parent: graceful shutdown
780
+ process.on("SIGTERM", () => {
781
+ clearInterval(orphanTimer);
782
+ clearInterval(statsTimer);
783
+ shutdownProxy("sigterm");
784
+ });
785
+ // Start the proxy (bypass local wrapper to get shutdown handle + stats)
786
+ const { startProxy: bootProxy } = await import("../proxy/proxy.js");
787
+ const proxyResult = await bootProxy({
788
+ repoId: config.repoId,
789
+ daemonChild: true,
790
+ });
791
+ // Notify parent: ready
792
+ const stateDir = join(cwd, ".unerr", "state");
793
+ const sockPath = join(stateDir, "proxy.sock");
794
+ if (process.send) {
795
+ process.send({ type: "ready", sock: sockPath });
796
+ }
797
+ // Inject update notification into MCP _meta if behind >2 minor versions
798
+ try {
799
+ const { getCachedUpdateInfo } = await import("../daemon/version-checker.js");
800
+ const { setUpdateNotification } = await import("../proxy/response-envelope.js");
801
+ const info = getCachedUpdateInfo();
802
+ if (info.available && !info.dismissed && info.behindMinor > 2) {
803
+ setUpdateNotification(info.latest, info.current);
804
+ }
805
+ }
806
+ catch {
807
+ // Non-critical
808
+ }
809
+ function collectStats() {
810
+ const mem = process.memoryUsage();
811
+ return {
812
+ entities: proxyResult.stats.toolCallsLocal,
813
+ edges: 0,
814
+ memory: Math.round(mem.rss / 1024 / 1024),
815
+ };
816
+ }
817
+ // Periodic stats report to parent
818
+ const statsTimer = setInterval(() => {
819
+ if (!process.send)
820
+ return;
821
+ process.send({ type: "stats", ...collectStats() });
822
+ }, 60_000);
823
+ statsTimer.unref();
824
+ // IPC messages from parent
825
+ process.on("message", (msg) => {
826
+ if (msg.type === "shutdown") {
827
+ clearInterval(orphanTimer);
828
+ clearInterval(statsTimer);
829
+ shutdownProxy("parent-shutdown");
830
+ }
831
+ if (msg.type === "get-stats") {
832
+ if (!process.send)
833
+ return;
834
+ process.send({ type: "stats", ...collectStats() });
835
+ }
836
+ });
837
+ async function shutdownProxy(reason) {
838
+ process.stderr.write(`[unerr:child] Shutting down: ${reason}\n`);
839
+ try {
840
+ await proxyResult.shutdown();
841
+ }
842
+ catch (err) {
843
+ process.stderr.write(`[unerr:child] Shutdown error: ${err.message}\n`);
844
+ }
845
+ process.exit(0);
846
+ }
847
+ }
848
+ /**
849
+ * MCP mode: headless boot for IDE integration.
850
+ *
851
+ * Socket discovery order:
852
+ * 1. Per-repo proxy sock (`<cwd>/.unerr/state/proxy.sock`) — direct bridge
853
+ * 2. unerrd daemon sock (`~/.unerr/unerrd.sock`) — bridge if repo is registered
854
+ *
855
+ * The bridge NEVER spawns unerrd or registers repos. It only connects to
856
+ * what's already running. If nothing is available, it exits with an error.
857
+ */
858
+ async function mcpBoot(cwd) {
859
+ installFileLogger({
860
+ filePath: join(cwd, ".unerr", "logs", `mcp-${process.pid}.log`),
861
+ maxBytes: 5_000_000,
862
+ keep: 5,
863
+ });
864
+ initFileLog(cwd);
865
+ const detection = await detectProjectRoot(cwd);
866
+ if (!detection.isProject) {
867
+ const antiSignals = detection.signals.filter((s) => s.startsWith("anti-"));
868
+ process.stderr.write(`\x1b[38;2;248;113;113m\u2717\x1b[0m No code project detected in this directory.\n unerr needs a folder containing source code to index.\n Detection score: ${detection.score} (need ${DETECTION_THRESHOLD})\n${antiSignals.length > 0
869
+ ? ` Negative signals: ${antiSignals.map((s) => s.replace("anti-", "")).join(", ")}\n`
870
+ : ""}\n \u25b8 Run \x1b[1munerr --mcp\x1b[0m from a project root directory.\n`);
871
+ process.exit(1);
872
+ }
873
+ const { startUdsBridge } = await import("../proxy/bridge.js");
874
+ // ── Step 1: Try per-repo proxy sock (standalone `unerr` running) ──
875
+ const repoSock = join(cwd, ".unerr", "state", "proxy.sock");
876
+ if (existsSync(repoSock)) {
877
+ const { PidLock } = await import("../proxy/pid-lock.js");
878
+ const pidLock = new PidLock(join(cwd, ".unerr", "state"));
879
+ const probeResult = await pidLock.probe();
880
+ if (probeResult.alive) {
881
+ process.stderr.write(`[unerr:mcp] Bridging to running proxy (PID ${probeResult.pid})\n`);
882
+ return bridgeAndExit(startUdsBridge, repoSock);
883
+ }
884
+ }
885
+ // ── Step 2: Try unerrd (must already be running, repo must be registered) ──
886
+ const { daemonSockPath, probeDaemon, ensureRepo, connectRepo, disconnectRepo, sendActivity, } = await import("../daemon/client.js");
887
+ const { findRepo } = await import("../daemon/registry.js");
888
+ const daemonSock = daemonSockPath();
889
+ const daemonRunning = await probeDaemon(daemonSock);
890
+ if (!daemonRunning) {
891
+ process.stderr.write("\x1b[38;2;248;113;113m\u2717\x1b[0m No unerr process found for this project.\n\n" +
892
+ " To use standalone mode:\n" +
893
+ " unerr # start per-repo process in this directory\n\n" +
894
+ " To use daemon mode:\n" +
895
+ " unerr daemon initialize # one-time setup\n" +
896
+ " unerr install <agent> # register this repo\n");
897
+ process.exit(1);
898
+ }
899
+ // Daemon is running — check if this repo is registered
900
+ const repoEntry = findRepo(cwd);
901
+ if (!repoEntry) {
902
+ process.stderr.write("\x1b[38;2;248;113;113m\u2717\x1b[0m Repo not registered with unerrd.\n\n" +
903
+ " Run: unerr install <agent> # registers this repo with the daemon\n" +
904
+ " Or: unerr daemon add . # register without installing agent config\n");
905
+ process.exit(1);
906
+ }
907
+ // Daemon running + repo registered → ensure the per-repo process is up
908
+ let repoSockViaEnsure;
909
+ try {
910
+ repoSockViaEnsure = await ensureRepo(daemonSock, cwd);
911
+ }
912
+ catch (err) {
913
+ process.stderr.write(`\x1b[38;2;248;113;113m\u2717\x1b[0m Failed to ensure repo process: ${err.message}\n`);
914
+ process.exit(1);
915
+ }
916
+ // Register this bridge connection
917
+ try {
918
+ await connectRepo(daemonSock, cwd);
919
+ }
920
+ catch {
921
+ // Non-fatal — idle sweep may stop the repo eventually
922
+ }
923
+ process.stderr.write(`[unerr:mcp] Bridging to repo process via unerrd (sock: ${repoSockViaEnsure})\n`);
924
+ // Throttled activity reporting (1/min)
925
+ const ACTIVITY_THROTTLE_MS = 60_000;
926
+ let lastActivitySent = 0;
927
+ const activityInterval = setInterval(() => {
928
+ const now = Date.now();
929
+ if (now - lastActivitySent >= ACTIVITY_THROTTLE_MS) {
930
+ sendActivity(daemonSock, cwd);
931
+ lastActivitySent = now;
932
+ }
933
+ }, ACTIVITY_THROTTLE_MS);
934
+ activityInterval.unref();
935
+ // Bridge to the per-repo process
936
+ const bridgeResult = await startUdsBridge(repoSockViaEnsure);
937
+ // Cleanup: disconnect from daemon, stop activity reporting
938
+ clearInterval(activityInterval);
939
+ try {
940
+ await disconnectRepo(daemonSock, cwd);
941
+ }
942
+ catch {
943
+ // Best-effort — daemon may already be gone
944
+ }
945
+ if (bridgeResult.reason === "daemon_dead") {
946
+ process.stderr.write("\x1b[38;2;248;113;113m\u2717\x1b[0m unerr proxy disconnected mid-session.\n The repo process may have been idle-stopped or crashed.\n");
947
+ process.exit(1);
948
+ }
949
+ }
950
+ /** Bridge to a UDS sock and handle disconnect/error. */
951
+ async function bridgeAndExit(startBridge, sockPath) {
952
+ const result = await startBridge(sockPath);
953
+ if (result.reason === "daemon_dead") {
954
+ process.stderr.write("\x1b[38;2;248;113;113m\u2717\x1b[0m unerr proxy disconnected mid-session.\n");
955
+ process.exit(1);
956
+ }
957
+ }
958
+ // ── Commander Setup ─────────────────────────────────────────
959
+ const program = new Command();
960
+ program
961
+ .name("unerr")
962
+ .description("Code intelligence for AI agents")
963
+ .version("0.1.0")
964
+ .option("--ide <type>", "IDE type: cursor, vscode, claude-code, windsurf")
965
+ .option("--mcp", "Start in MCP server mode (stdio, no interactive prompts)")
966
+ .option("--daemon-child", "Run as a daemon-managed child process (internal, set by unerrd)")
967
+ .showHelpAfterError("(use --help for available commands)")
968
+ .action(async (opts) => {
969
+ const cwd = process.cwd();
970
+ // --daemon-child: managed child mode (spawned by unerrd)
971
+ if (opts.daemonChild) {
972
+ await daemonChildBoot(cwd);
973
+ return;
974
+ }
975
+ // --mcp: headless MCP server mode for IDE integration
976
+ if (opts.mcp) {
977
+ await mcpBoot(cwd);
978
+ return;
979
+ }
980
+ const config = readLocalConfig(cwd);
981
+ if (config) {
982
+ await resumeBoot(config);
983
+ }
984
+ else {
985
+ await firstRunBoot();
986
+ }
987
+ });
988
+ // ── Visible Commands (shown in --help) ──────────────────────
989
+ program
990
+ .command("chat")
991
+ .description("Interactive AI assistant (coming soon)")
992
+ .option("--model <model>", "Claude model to use")
993
+ .option("--no-graph", "Skip loading the code intelligence graph")
994
+ .action(async () => {
995
+ process.stderr.write("\n unerr chat is temporarily disabled.\n Use unerr as an MCP proxy with your preferred AI agent instead.\n\n");
996
+ process.exit(0);
997
+ });
998
+ registerStatusCommand(program);
999
+ registerStatsCommand(program);
1000
+ registerInstallCommand(program);
1001
+ registerDashboardCommand(program);
1002
+ registerDebugCommand(program);
1003
+ registerGainCommand(program);
1004
+ registerDiscoverCommand(program);
1005
+ registerDaemonCommand(program);
1006
+ // ── Hidden Commands (callable but not shown in --help) ──────
1007
+ const hiddenCommands = [
1008
+ registerBranchesCommand,
1009
+ registerCheckCommitCommand,
1010
+ registerCompressOutputCommand,
1011
+ registerConfigVerifyCommand,
1012
+ registerEnrichCommand,
1013
+ registerExecCommand,
1014
+ registerHookCommand,
1015
+ registerIndexCommand,
1016
+ registerInitCommand,
1017
+ registerLearnCommand,
1018
+ registerManifestCommand,
1019
+ registerRewindCommand,
1020
+ registerSkillsCommand,
1021
+ registerTimelineCommand,
1022
+ registerUninstallCommand,
1023
+ ];
1024
+ for (const register of hiddenCommands) {
1025
+ register(program);
1026
+ }
1027
+ // Hide all commands except chat, status, debug from --help output
1028
+ const visibleCommands = new Set([
1029
+ "status",
1030
+ "stats",
1031
+ "install",
1032
+ "dashboard",
1033
+ "debug",
1034
+ "init",
1035
+ "daemon",
1036
+ ]);
1037
+ for (const cmd of program.commands) {
1038
+ if (!visibleCommands.has(cmd.name())) {
1039
+ // Commander internal property — commands with _hidden=true are omitted from help
1040
+ cmd._hidden = true;
1041
+ }
1042
+ }
1043
+ program.parse();