@quolu/lattice 0.70.0 → 0.71.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 (603) hide show
  1. package/bin/lattice.mjs +21 -0
  2. package/package.json +1 -1
  3. package/sensor/dist/bin/lattice-sensor.js +746 -323
  4. package/sensor/dist/bin/viewer-gate.d.ts +17 -0
  5. package/sensor/dist/bin/viewer-gate.d.ts.map +1 -0
  6. package/sensor/dist/bin/viewer-gate.js +31 -0
  7. package/sensor/dist/bin/viewer-gate.js.map +1 -0
  8. package/sensor/dist/context/formatter.d.ts +7 -1
  9. package/sensor/dist/context/formatter.d.ts.map +1 -1
  10. package/sensor/dist/context/formatter.js +12 -6
  11. package/sensor/dist/context/formatter.js.map +1 -1
  12. package/sensor/dist/context/index.d.ts +12 -0
  13. package/sensor/dist/context/index.d.ts.map +1 -1
  14. package/sensor/dist/context/index.js +103 -16
  15. package/sensor/dist/context/index.js.map +1 -1
  16. package/sensor/dist/db/index.d.ts +23 -2
  17. package/sensor/dist/db/index.d.ts.map +1 -1
  18. package/sensor/dist/db/index.js +109 -31
  19. package/sensor/dist/db/index.js.map +1 -1
  20. package/sensor/dist/db/migrations.d.ts +1 -1
  21. package/sensor/dist/db/migrations.d.ts.map +1 -1
  22. package/sensor/dist/db/migrations.js +68 -1
  23. package/sensor/dist/db/migrations.js.map +1 -1
  24. package/sensor/dist/db/queries.d.ts +583 -6
  25. package/sensor/dist/db/queries.d.ts.map +1 -1
  26. package/sensor/dist/db/queries.js +1425 -57
  27. package/sensor/dist/db/queries.js.map +1 -1
  28. package/sensor/dist/db/schema.sql +27 -4
  29. package/sensor/dist/db/sqlite-adapter.d.ts +2 -0
  30. package/sensor/dist/db/sqlite-adapter.d.ts.map +1 -1
  31. package/sensor/dist/db/sqlite-adapter.js +56 -7
  32. package/sensor/dist/db/sqlite-adapter.js.map +1 -1
  33. package/sensor/dist/db/synthesis-stage.d.ts +12 -0
  34. package/sensor/dist/db/synthesis-stage.d.ts.map +1 -0
  35. package/sensor/dist/db/synthesis-stage.js +93 -0
  36. package/sensor/dist/db/synthesis-stage.js.map +1 -0
  37. package/sensor/dist/db/wal-valve.d.ts +32 -12
  38. package/sensor/dist/db/wal-valve.d.ts.map +1 -1
  39. package/sensor/dist/db/wal-valve.js +65 -22
  40. package/sensor/dist/db/wal-valve.js.map +1 -1
  41. package/sensor/dist/db/wsl-shared-index.d.ts +53 -0
  42. package/sensor/dist/db/wsl-shared-index.d.ts.map +1 -0
  43. package/sensor/dist/db/wsl-shared-index.js +121 -0
  44. package/sensor/dist/db/wsl-shared-index.js.map +1 -0
  45. package/sensor/dist/directory.d.ts +126 -2
  46. package/sensor/dist/directory.d.ts.map +1 -1
  47. package/sensor/dist/directory.js +285 -16
  48. package/sensor/dist/directory.js.map +1 -1
  49. package/sensor/dist/errors.d.ts +14 -0
  50. package/sensor/dist/errors.d.ts.map +1 -1
  51. package/sensor/dist/errors.js +16 -1
  52. package/sensor/dist/errors.js.map +1 -1
  53. package/sensor/dist/extraction/cfml-extractor.d.ts +1 -0
  54. package/sensor/dist/extraction/cfml-extractor.d.ts.map +1 -1
  55. package/sensor/dist/extraction/cfml-extractor.js +15 -3
  56. package/sensor/dist/extraction/cfml-extractor.js.map +1 -1
  57. package/sensor/dist/extraction/dfm-extractor.d.ts.map +1 -1
  58. package/sensor/dist/extraction/dfm-extractor.js +14 -10
  59. package/sensor/dist/extraction/dfm-extractor.js.map +1 -1
  60. package/sensor/dist/extraction/extraction-version.d.ts +1 -1
  61. package/sensor/dist/extraction/extraction-version.d.ts.map +1 -1
  62. package/sensor/dist/extraction/extraction-version.js +3 -1
  63. package/sensor/dist/extraction/extraction-version.js.map +1 -1
  64. package/sensor/dist/extraction/function-ref.d.ts +6 -4
  65. package/sensor/dist/extraction/function-ref.d.ts.map +1 -1
  66. package/sensor/dist/extraction/function-ref.js +35 -14
  67. package/sensor/dist/extraction/function-ref.js.map +1 -1
  68. package/sensor/dist/extraction/generated-detection.d.ts +48 -12
  69. package/sensor/dist/extraction/generated-detection.d.ts.map +1 -1
  70. package/sensor/dist/extraction/generated-detection.js +176 -11
  71. package/sensor/dist/extraction/generated-detection.js.map +1 -1
  72. package/sensor/dist/extraction/grammars.d.ts +38 -0
  73. package/sensor/dist/extraction/grammars.d.ts.map +1 -1
  74. package/sensor/dist/extraction/grammars.js +115 -3
  75. package/sensor/dist/extraction/grammars.js.map +1 -1
  76. package/sensor/dist/extraction/index.d.ts +218 -14
  77. package/sensor/dist/extraction/index.d.ts.map +1 -1
  78. package/sensor/dist/extraction/index.js +887 -175
  79. package/sensor/dist/extraction/index.js.map +1 -1
  80. package/sensor/dist/extraction/languages/c-cpp.d.ts +58 -0
  81. package/sensor/dist/extraction/languages/c-cpp.d.ts.map +1 -1
  82. package/sensor/dist/extraction/languages/c-cpp.js +310 -19
  83. package/sensor/dist/extraction/languages/c-cpp.js.map +1 -1
  84. package/sensor/dist/extraction/languages/dart.d.ts.map +1 -1
  85. package/sensor/dist/extraction/languages/dart.js +8 -3
  86. package/sensor/dist/extraction/languages/dart.js.map +1 -1
  87. package/sensor/dist/extraction/languages/erlang.d.ts.map +1 -1
  88. package/sensor/dist/extraction/languages/erlang.js +58 -22
  89. package/sensor/dist/extraction/languages/erlang.js.map +1 -1
  90. package/sensor/dist/extraction/languages/javascript.js +1 -1
  91. package/sensor/dist/extraction/languages/javascript.js.map +1 -1
  92. package/sensor/dist/extraction/languages/kotlin.d.ts.map +1 -1
  93. package/sensor/dist/extraction/languages/kotlin.js +169 -36
  94. package/sensor/dist/extraction/languages/kotlin.js.map +1 -1
  95. package/sensor/dist/extraction/languages/lua.d.ts.map +1 -1
  96. package/sensor/dist/extraction/languages/lua.js +4 -1
  97. package/sensor/dist/extraction/languages/lua.js.map +1 -1
  98. package/sensor/dist/extraction/languages/objc.d.ts.map +1 -1
  99. package/sensor/dist/extraction/languages/objc.js +4 -0
  100. package/sensor/dist/extraction/languages/objc.js.map +1 -1
  101. package/sensor/dist/extraction/languages/python.d.ts.map +1 -1
  102. package/sensor/dist/extraction/languages/python.js +71 -0
  103. package/sensor/dist/extraction/languages/python.js.map +1 -1
  104. package/sensor/dist/extraction/languages/rust.d.ts +20 -0
  105. package/sensor/dist/extraction/languages/rust.d.ts.map +1 -1
  106. package/sensor/dist/extraction/languages/rust.js +50 -20
  107. package/sensor/dist/extraction/languages/rust.js.map +1 -1
  108. package/sensor/dist/extraction/languages/scala.d.ts.map +1 -1
  109. package/sensor/dist/extraction/languages/scala.js +18 -3
  110. package/sensor/dist/extraction/languages/scala.js.map +1 -1
  111. package/sensor/dist/extraction/languages/swift.d.ts +15 -0
  112. package/sensor/dist/extraction/languages/swift.d.ts.map +1 -1
  113. package/sensor/dist/extraction/languages/swift.js +50 -0
  114. package/sensor/dist/extraction/languages/swift.js.map +1 -1
  115. package/sensor/dist/extraction/languages/typescript.d.ts.map +1 -1
  116. package/sensor/dist/extraction/languages/typescript.js +9 -2
  117. package/sensor/dist/extraction/languages/typescript.js.map +1 -1
  118. package/sensor/dist/extraction/liquid-extractor.d.ts +18 -0
  119. package/sensor/dist/extraction/liquid-extractor.d.ts.map +1 -1
  120. package/sensor/dist/extraction/liquid-extractor.js +98 -22
  121. package/sensor/dist/extraction/liquid-extractor.js.map +1 -1
  122. package/sensor/dist/extraction/mybatis-extractor.d.ts.map +1 -1
  123. package/sensor/dist/extraction/mybatis-extractor.js +6 -4
  124. package/sensor/dist/extraction/mybatis-extractor.js.map +1 -1
  125. package/sensor/dist/extraction/parse-pool.d.ts +7 -0
  126. package/sensor/dist/extraction/parse-pool.d.ts.map +1 -1
  127. package/sensor/dist/extraction/parse-pool.js +20 -1
  128. package/sensor/dist/extraction/parse-pool.js.map +1 -1
  129. package/sensor/dist/extraction/syntax-tokens.d.ts +103 -0
  130. package/sensor/dist/extraction/syntax-tokens.d.ts.map +1 -0
  131. package/sensor/dist/extraction/syntax-tokens.js +381 -0
  132. package/sensor/dist/extraction/syntax-tokens.js.map +1 -0
  133. package/sensor/dist/extraction/tree-sitter-helpers.d.ts +5 -0
  134. package/sensor/dist/extraction/tree-sitter-helpers.d.ts.map +1 -1
  135. package/sensor/dist/extraction/tree-sitter-helpers.js +17 -0
  136. package/sensor/dist/extraction/tree-sitter-helpers.js.map +1 -1
  137. package/sensor/dist/extraction/tree-sitter-types.d.ts +31 -3
  138. package/sensor/dist/extraction/tree-sitter-types.d.ts.map +1 -1
  139. package/sensor/dist/extraction/tree-sitter.d.ts +101 -18
  140. package/sensor/dist/extraction/tree-sitter.d.ts.map +1 -1
  141. package/sensor/dist/extraction/tree-sitter.js +928 -134
  142. package/sensor/dist/extraction/tree-sitter.js.map +1 -1
  143. package/sensor/dist/extraction/wasm/tree-sitter-scala.wasm +0 -0
  144. package/sensor/dist/file-limits.d.ts +40 -0
  145. package/sensor/dist/file-limits.d.ts.map +1 -0
  146. package/sensor/dist/file-limits.js +147 -0
  147. package/sensor/dist/file-limits.js.map +1 -0
  148. package/sensor/dist/graph/branch-guards.d.ts +265 -0
  149. package/sensor/dist/graph/branch-guards.d.ts.map +1 -0
  150. package/sensor/dist/graph/branch-guards.js +2325 -0
  151. package/sensor/dist/graph/branch-guards.js.map +1 -0
  152. package/sensor/dist/graph/dead-code.d.ts +251 -0
  153. package/sensor/dist/graph/dead-code.d.ts.map +1 -0
  154. package/sensor/dist/graph/dead-code.js +776 -0
  155. package/sensor/dist/graph/dead-code.js.map +1 -0
  156. package/sensor/dist/graph/dynamic-boundary-report.d.ts +121 -0
  157. package/sensor/dist/graph/dynamic-boundary-report.d.ts.map +1 -0
  158. package/sensor/dist/graph/dynamic-boundary-report.js +283 -0
  159. package/sensor/dist/graph/dynamic-boundary-report.js.map +1 -0
  160. package/sensor/dist/graph/index.d.ts +4 -0
  161. package/sensor/dist/graph/index.d.ts.map +1 -1
  162. package/sensor/dist/graph/index.js +16 -1
  163. package/sensor/dist/graph/index.js.map +1 -1
  164. package/sensor/dist/graph/named-symbol-flow.d.ts +125 -0
  165. package/sensor/dist/graph/named-symbol-flow.d.ts.map +1 -0
  166. package/sensor/dist/graph/named-symbol-flow.js +552 -0
  167. package/sensor/dist/graph/named-symbol-flow.js.map +1 -0
  168. package/sensor/dist/graph/queries.d.ts.map +1 -1
  169. package/sensor/dist/graph/queries.js +2 -0
  170. package/sensor/dist/graph/queries.js.map +1 -1
  171. package/sensor/dist/graph/symbol-lookup.d.ts +83 -0
  172. package/sensor/dist/graph/symbol-lookup.d.ts.map +1 -0
  173. package/sensor/dist/graph/symbol-lookup.js +181 -0
  174. package/sensor/dist/graph/symbol-lookup.js.map +1 -0
  175. package/sensor/dist/graph/traversal.d.ts +9 -0
  176. package/sensor/dist/graph/traversal.d.ts.map +1 -1
  177. package/sensor/dist/graph/traversal.js +62 -36
  178. package/sensor/dist/graph/traversal.js.map +1 -1
  179. package/sensor/dist/graph/type-hierarchy.d.ts +155 -0
  180. package/sensor/dist/graph/type-hierarchy.d.ts.map +1 -0
  181. package/sensor/dist/graph/type-hierarchy.js +382 -0
  182. package/sensor/dist/graph/type-hierarchy.js.map +1 -0
  183. package/sensor/dist/index.d.ts +272 -10
  184. package/sensor/dist/index.d.ts.map +1 -1
  185. package/sensor/dist/index.js +510 -34
  186. package/sensor/dist/index.js.map +1 -1
  187. package/sensor/dist/mcp/answer-freshness.d.ts +10 -0
  188. package/sensor/dist/mcp/answer-freshness.d.ts.map +1 -0
  189. package/sensor/dist/mcp/answer-freshness.js +68 -0
  190. package/sensor/dist/mcp/answer-freshness.js.map +1 -0
  191. package/sensor/dist/mcp/daemon-manager.d.ts +1 -1
  192. package/sensor/dist/mcp/daemon-manager.d.ts.map +1 -1
  193. package/sensor/dist/mcp/daemon-manager.js +17 -1
  194. package/sensor/dist/mcp/daemon-manager.js.map +1 -1
  195. package/sensor/dist/mcp/daemon-paths.d.ts +8 -0
  196. package/sensor/dist/mcp/daemon-paths.d.ts.map +1 -1
  197. package/sensor/dist/mcp/daemon-paths.js +65 -2
  198. package/sensor/dist/mcp/daemon-paths.js.map +1 -1
  199. package/sensor/dist/mcp/daemon-registry.d.ts +17 -4
  200. package/sensor/dist/mcp/daemon-registry.d.ts.map +1 -1
  201. package/sensor/dist/mcp/daemon-registry.js +133 -23
  202. package/sensor/dist/mcp/daemon-registry.js.map +1 -1
  203. package/sensor/dist/mcp/daemon.d.ts +26 -13
  204. package/sensor/dist/mcp/daemon.d.ts.map +1 -1
  205. package/sensor/dist/mcp/daemon.js +126 -32
  206. package/sensor/dist/mcp/daemon.js.map +1 -1
  207. package/sensor/dist/mcp/dynamic-boundaries.d.ts +1 -10
  208. package/sensor/dist/mcp/dynamic-boundaries.d.ts.map +1 -1
  209. package/sensor/dist/mcp/dynamic-boundaries.js +46 -42
  210. package/sensor/dist/mcp/dynamic-boundaries.js.map +1 -1
  211. package/sensor/dist/mcp/engine.d.ts +31 -9
  212. package/sensor/dist/mcp/engine.d.ts.map +1 -1
  213. package/sensor/dist/mcp/engine.js +190 -79
  214. package/sensor/dist/mcp/engine.js.map +1 -1
  215. package/sensor/dist/mcp/explore-dedup.d.ts +140 -0
  216. package/sensor/dist/mcp/explore-dedup.d.ts.map +1 -0
  217. package/sensor/dist/mcp/explore-dedup.js +239 -0
  218. package/sensor/dist/mcp/explore-dedup.js.map +1 -0
  219. package/sensor/dist/mcp/explore-diagnostics.d.ts +289 -0
  220. package/sensor/dist/mcp/explore-diagnostics.d.ts.map +1 -0
  221. package/sensor/dist/mcp/explore-diagnostics.js +558 -0
  222. package/sensor/dist/mcp/explore-diagnostics.js.map +1 -0
  223. package/sensor/dist/mcp/explore-session-state.d.ts +217 -0
  224. package/sensor/dist/mcp/explore-session-state.d.ts.map +1 -0
  225. package/sensor/dist/mcp/explore-session-state.js +322 -0
  226. package/sensor/dist/mcp/explore-session-state.js.map +1 -0
  227. package/sensor/dist/mcp/index-freshness-worker.d.ts +2 -0
  228. package/sensor/dist/mcp/index-freshness-worker.d.ts.map +1 -0
  229. package/sensor/dist/mcp/index-freshness-worker.js +30 -0
  230. package/sensor/dist/mcp/index-freshness-worker.js.map +1 -0
  231. package/sensor/dist/mcp/index-freshness.d.ts +7 -0
  232. package/sensor/dist/mcp/index-freshness.d.ts.map +1 -0
  233. package/sensor/dist/mcp/index-freshness.js +94 -0
  234. package/sensor/dist/mcp/index-freshness.js.map +1 -0
  235. package/sensor/dist/mcp/index.d.ts +3 -1
  236. package/sensor/dist/mcp/index.d.ts.map +1 -1
  237. package/sensor/dist/mcp/index.js +109 -12
  238. package/sensor/dist/mcp/index.js.map +1 -1
  239. package/sensor/dist/mcp/liveness-watchdog.d.ts +4 -1
  240. package/sensor/dist/mcp/liveness-watchdog.d.ts.map +1 -1
  241. package/sensor/dist/mcp/liveness-watchdog.js +11 -2
  242. package/sensor/dist/mcp/liveness-watchdog.js.map +1 -1
  243. package/sensor/dist/mcp/project-lifecycle.d.ts +9 -0
  244. package/sensor/dist/mcp/project-lifecycle.d.ts.map +1 -0
  245. package/sensor/dist/mcp/project-lifecycle.js +182 -0
  246. package/sensor/dist/mcp/project-lifecycle.js.map +1 -0
  247. package/sensor/dist/mcp/proxy.d.ts.map +1 -1
  248. package/sensor/dist/mcp/proxy.js +15 -1
  249. package/sensor/dist/mcp/proxy.js.map +1 -1
  250. package/sensor/dist/mcp/query-pool.d.ts +2 -2
  251. package/sensor/dist/mcp/query-pool.d.ts.map +1 -1
  252. package/sensor/dist/mcp/query-pool.js +9 -7
  253. package/sensor/dist/mcp/query-pool.js.map +1 -1
  254. package/sensor/dist/mcp/query-worker.js +2 -2
  255. package/sensor/dist/mcp/query-worker.js.map +1 -1
  256. package/sensor/dist/mcp/server-instructions.d.ts +2 -2
  257. package/sensor/dist/mcp/server-instructions.d.ts.map +1 -1
  258. package/sensor/dist/mcp/server-instructions.js +13 -6
  259. package/sensor/dist/mcp/server-instructions.js.map +1 -1
  260. package/sensor/dist/mcp/session.d.ts +16 -0
  261. package/sensor/dist/mcp/session.d.ts.map +1 -1
  262. package/sensor/dist/mcp/session.js +36 -13
  263. package/sensor/dist/mcp/session.js.map +1 -1
  264. package/sensor/dist/mcp/startup-handshake.d.ts +3 -1
  265. package/sensor/dist/mcp/startup-handshake.d.ts.map +1 -1
  266. package/sensor/dist/mcp/startup-handshake.js +10 -2
  267. package/sensor/dist/mcp/startup-handshake.js.map +1 -1
  268. package/sensor/dist/mcp/tools.d.ts +496 -38
  269. package/sensor/dist/mcp/tools.d.ts.map +1 -1
  270. package/sensor/dist/mcp/tools.js +4021 -772
  271. package/sensor/dist/mcp/tools.js.map +1 -1
  272. package/sensor/dist/mcp/writer-lock.d.ts +61 -0
  273. package/sensor/dist/mcp/writer-lock.d.ts.map +1 -0
  274. package/sensor/dist/mcp/writer-lock.js +260 -0
  275. package/sensor/dist/mcp/writer-lock.js.map +1 -0
  276. package/sensor/dist/project-config.d.ts +23 -0
  277. package/sensor/dist/project-config.d.ts.map +1 -1
  278. package/sensor/dist/project-config.js +39 -2
  279. package/sensor/dist/project-config.js.map +1 -1
  280. package/sensor/dist/resolution/alias-binding.d.ts +56 -0
  281. package/sensor/dist/resolution/alias-binding.d.ts.map +1 -0
  282. package/sensor/dist/resolution/alias-binding.js +127 -0
  283. package/sensor/dist/resolution/alias-binding.js.map +1 -0
  284. package/sensor/dist/resolution/c-fnptr-synthesizer.d.ts.map +1 -1
  285. package/sensor/dist/resolution/c-fnptr-synthesizer.js +21 -19
  286. package/sensor/dist/resolution/c-fnptr-synthesizer.js.map +1 -1
  287. package/sensor/dist/resolution/callback-synthesizer.d.ts +23 -1
  288. package/sensor/dist/resolution/callback-synthesizer.d.ts.map +1 -1
  289. package/sensor/dist/resolution/callback-synthesizer.js +356 -155
  290. package/sensor/dist/resolution/callback-synthesizer.js.map +1 -1
  291. package/sensor/dist/resolution/cpp-constructor.d.ts +4 -0
  292. package/sensor/dist/resolution/cpp-constructor.d.ts.map +1 -0
  293. package/sensor/dist/resolution/cpp-constructor.js +123 -0
  294. package/sensor/dist/resolution/cpp-constructor.js.map +1 -0
  295. package/sensor/dist/resolution/cpp-macro-visibility.d.ts +12 -0
  296. package/sensor/dist/resolution/cpp-macro-visibility.d.ts.map +1 -0
  297. package/sensor/dist/resolution/cpp-macro-visibility.js +342 -0
  298. package/sensor/dist/resolution/cpp-macro-visibility.js.map +1 -0
  299. package/sensor/dist/resolution/expo-router-synthesizer.d.ts +32 -0
  300. package/sensor/dist/resolution/expo-router-synthesizer.d.ts.map +1 -0
  301. package/sensor/dist/resolution/expo-router-synthesizer.js +189 -0
  302. package/sensor/dist/resolution/expo-router-synthesizer.js.map +1 -0
  303. package/sensor/dist/resolution/frameworks/csharp.d.ts.map +1 -1
  304. package/sensor/dist/resolution/frameworks/csharp.js +96 -2
  305. package/sensor/dist/resolution/frameworks/csharp.js.map +1 -1
  306. package/sensor/dist/resolution/frameworks/expo-router.d.ts +189 -0
  307. package/sensor/dist/resolution/frameworks/expo-router.d.ts.map +1 -0
  308. package/sensor/dist/resolution/frameworks/expo-router.js +785 -0
  309. package/sensor/dist/resolution/frameworks/expo-router.js.map +1 -0
  310. package/sensor/dist/resolution/frameworks/express.d.ts.map +1 -1
  311. package/sensor/dist/resolution/frameworks/express.js +251 -16
  312. package/sensor/dist/resolution/frameworks/express.js.map +1 -1
  313. package/sensor/dist/resolution/frameworks/index.d.ts +5 -0
  314. package/sensor/dist/resolution/frameworks/index.d.ts.map +1 -1
  315. package/sensor/dist/resolution/frameworks/index.js +29 -1
  316. package/sensor/dist/resolution/frameworks/index.js.map +1 -1
  317. package/sensor/dist/resolution/frameworks/java.d.ts.map +1 -1
  318. package/sensor/dist/resolution/frameworks/java.js +79 -47
  319. package/sensor/dist/resolution/frameworks/java.js.map +1 -1
  320. package/sensor/dist/resolution/frameworks/laravel.d.ts.map +1 -1
  321. package/sensor/dist/resolution/frameworks/laravel.js +294 -4
  322. package/sensor/dist/resolution/frameworks/laravel.js.map +1 -1
  323. package/sensor/dist/resolution/frameworks/nestjs.d.ts.map +1 -1
  324. package/sensor/dist/resolution/frameworks/nestjs.js +6 -14
  325. package/sensor/dist/resolution/frameworks/nestjs.js.map +1 -1
  326. package/sensor/dist/resolution/frameworks/nextjs.d.ts +76 -0
  327. package/sensor/dist/resolution/frameworks/nextjs.d.ts.map +1 -0
  328. package/sensor/dist/resolution/frameworks/nextjs.js +328 -0
  329. package/sensor/dist/resolution/frameworks/nextjs.js.map +1 -0
  330. package/sensor/dist/resolution/frameworks/object-literal.d.ts +32 -0
  331. package/sensor/dist/resolution/frameworks/object-literal.d.ts.map +1 -0
  332. package/sensor/dist/resolution/frameworks/object-literal.js +139 -0
  333. package/sensor/dist/resolution/frameworks/object-literal.js.map +1 -0
  334. package/sensor/dist/resolution/frameworks/package-deps.d.ts +14 -0
  335. package/sensor/dist/resolution/frameworks/package-deps.d.ts.map +1 -0
  336. package/sensor/dist/resolution/frameworks/package-deps.js +78 -0
  337. package/sensor/dist/resolution/frameworks/package-deps.js.map +1 -0
  338. package/sensor/dist/resolution/frameworks/python.d.ts.map +1 -1
  339. package/sensor/dist/resolution/frameworks/python.js +166 -0
  340. package/sensor/dist/resolution/frameworks/python.js.map +1 -1
  341. package/sensor/dist/resolution/frameworks/react-native.d.ts +26 -0
  342. package/sensor/dist/resolution/frameworks/react-native.d.ts.map +1 -1
  343. package/sensor/dist/resolution/frameworks/react-native.js +153 -14
  344. package/sensor/dist/resolution/frameworks/react-native.js.map +1 -1
  345. package/sensor/dist/resolution/frameworks/react-router.d.ts +46 -0
  346. package/sensor/dist/resolution/frameworks/react-router.d.ts.map +1 -0
  347. package/sensor/dist/resolution/frameworks/react-router.js +187 -0
  348. package/sensor/dist/resolution/frameworks/react-router.js.map +1 -0
  349. package/sensor/dist/resolution/frameworks/react.d.ts +2 -1
  350. package/sensor/dist/resolution/frameworks/react.d.ts.map +1 -1
  351. package/sensor/dist/resolution/frameworks/react.js +188 -139
  352. package/sensor/dist/resolution/frameworks/react.js.map +1 -1
  353. package/sensor/dist/resolution/frameworks/svelte.d.ts.map +1 -1
  354. package/sensor/dist/resolution/frameworks/svelte.js +6 -1
  355. package/sensor/dist/resolution/frameworks/svelte.js.map +1 -1
  356. package/sensor/dist/resolution/frameworks/sveltekit-router.d.ts +36 -0
  357. package/sensor/dist/resolution/frameworks/sveltekit-router.d.ts.map +1 -0
  358. package/sensor/dist/resolution/frameworks/sveltekit-router.js +156 -0
  359. package/sensor/dist/resolution/frameworks/sveltekit-router.js.map +1 -0
  360. package/sensor/dist/resolution/frameworks/swift.d.ts.map +1 -1
  361. package/sensor/dist/resolution/frameworks/swift.js +140 -99
  362. package/sensor/dist/resolution/frameworks/swift.js.map +1 -1
  363. package/sensor/dist/resolution/frameworks/tanstack-router.d.ts +84 -0
  364. package/sensor/dist/resolution/frameworks/tanstack-router.d.ts.map +1 -0
  365. package/sensor/dist/resolution/frameworks/tanstack-router.js +437 -0
  366. package/sensor/dist/resolution/frameworks/tanstack-router.js.map +1 -0
  367. package/sensor/dist/resolution/frameworks/vue-router.d.ts +82 -0
  368. package/sensor/dist/resolution/frameworks/vue-router.d.ts.map +1 -0
  369. package/sensor/dist/resolution/frameworks/vue-router.js +377 -0
  370. package/sensor/dist/resolution/frameworks/vue-router.js.map +1 -0
  371. package/sensor/dist/resolution/import-resolver.d.ts +38 -0
  372. package/sensor/dist/resolution/import-resolver.d.ts.map +1 -1
  373. package/sensor/dist/resolution/import-resolver.js +394 -28
  374. package/sensor/dist/resolution/import-resolver.js.map +1 -1
  375. package/sensor/dist/resolution/index.d.ts +89 -25
  376. package/sensor/dist/resolution/index.d.ts.map +1 -1
  377. package/sensor/dist/resolution/index.js +573 -148
  378. package/sensor/dist/resolution/index.js.map +1 -1
  379. package/sensor/dist/resolution/js-builtins.d.ts +13 -0
  380. package/sensor/dist/resolution/js-builtins.d.ts.map +1 -0
  381. package/sensor/dist/resolution/js-builtins.js +46 -0
  382. package/sensor/dist/resolution/js-builtins.js.map +1 -0
  383. package/sensor/dist/resolution/name-matcher.d.ts +99 -22
  384. package/sensor/dist/resolution/name-matcher.d.ts.map +1 -1
  385. package/sensor/dist/resolution/name-matcher.js +2220 -86
  386. package/sensor/dist/resolution/name-matcher.js.map +1 -1
  387. package/sensor/dist/resolution/next-router-synthesizer.d.ts +27 -0
  388. package/sensor/dist/resolution/next-router-synthesizer.d.ts.map +1 -0
  389. package/sensor/dist/resolution/next-router-synthesizer.js +113 -0
  390. package/sensor/dist/resolution/next-router-synthesizer.js.map +1 -0
  391. package/sensor/dist/resolution/path-aliases.d.ts +6 -4
  392. package/sensor/dist/resolution/path-aliases.d.ts.map +1 -1
  393. package/sensor/dist/resolution/path-aliases.js +125 -17
  394. package/sensor/dist/resolution/path-aliases.js.map +1 -1
  395. package/sensor/dist/resolution/react-router-synthesizer.d.ts +33 -0
  396. package/sensor/dist/resolution/react-router-synthesizer.d.ts.map +1 -0
  397. package/sensor/dist/resolution/react-router-synthesizer.js +126 -0
  398. package/sensor/dist/resolution/react-router-synthesizer.js.map +1 -0
  399. package/sensor/dist/resolution/resolver-pool.d.ts +2 -0
  400. package/sensor/dist/resolution/resolver-pool.d.ts.map +1 -1
  401. package/sensor/dist/resolution/resolver-pool.js +4 -0
  402. package/sensor/dist/resolution/resolver-pool.js.map +1 -1
  403. package/sensor/dist/resolution/strip-comments.d.ts +6 -0
  404. package/sensor/dist/resolution/strip-comments.d.ts.map +1 -1
  405. package/sensor/dist/resolution/strip-comments.js +58 -0
  406. package/sensor/dist/resolution/strip-comments.js.map +1 -1
  407. package/sensor/dist/resolution/sveltekit-synthesizer.d.ts +58 -0
  408. package/sensor/dist/resolution/sveltekit-synthesizer.d.ts.map +1 -0
  409. package/sensor/dist/resolution/sveltekit-synthesizer.js +173 -0
  410. package/sensor/dist/resolution/sveltekit-synthesizer.js.map +1 -0
  411. package/sensor/dist/resolution/swift-type-visibility.d.ts +52 -0
  412. package/sensor/dist/resolution/swift-type-visibility.d.ts.map +1 -0
  413. package/sensor/dist/resolution/swift-type-visibility.js +328 -0
  414. package/sensor/dist/resolution/swift-type-visibility.js.map +1 -0
  415. package/sensor/dist/resolution/synth-utils.d.ts +26 -0
  416. package/sensor/dist/resolution/synth-utils.d.ts.map +1 -0
  417. package/sensor/dist/resolution/synth-utils.js +75 -0
  418. package/sensor/dist/resolution/synth-utils.js.map +1 -0
  419. package/sensor/dist/resolution/tanstack-router-synthesizer.d.ts +31 -0
  420. package/sensor/dist/resolution/tanstack-router-synthesizer.d.ts.map +1 -0
  421. package/sensor/dist/resolution/tanstack-router-synthesizer.js +114 -0
  422. package/sensor/dist/resolution/tanstack-router-synthesizer.js.map +1 -0
  423. package/sensor/dist/resolution/tier-synthesizer.d.ts +54 -0
  424. package/sensor/dist/resolution/tier-synthesizer.d.ts.map +1 -0
  425. package/sensor/dist/resolution/tier-synthesizer.js +1294 -0
  426. package/sensor/dist/resolution/tier-synthesizer.js.map +1 -0
  427. package/sensor/dist/resolution/types.d.ts +78 -2
  428. package/sensor/dist/resolution/types.d.ts.map +1 -1
  429. package/sensor/dist/resolution/types.js +64 -0
  430. package/sensor/dist/resolution/types.js.map +1 -1
  431. package/sensor/dist/resolution/vue-router-synthesizer.d.ts +30 -0
  432. package/sensor/dist/resolution/vue-router-synthesizer.d.ts.map +1 -0
  433. package/sensor/dist/resolution/vue-router-synthesizer.js +115 -0
  434. package/sensor/dist/resolution/vue-router-synthesizer.js.map +1 -0
  435. package/sensor/dist/search/identifier-segments.d.ts +10 -0
  436. package/sensor/dist/search/identifier-segments.d.ts.map +1 -1
  437. package/sensor/dist/search/identifier-segments.js +29 -0
  438. package/sensor/dist/search/identifier-segments.js.map +1 -1
  439. package/sensor/dist/search/query-paths.d.ts +106 -0
  440. package/sensor/dist/search/query-paths.d.ts.map +1 -0
  441. package/sensor/dist/search/query-paths.js +513 -0
  442. package/sensor/dist/search/query-paths.js.map +1 -0
  443. package/sensor/dist/search/query-utils.d.ts +22 -2
  444. package/sensor/dist/search/query-utils.d.ts.map +1 -1
  445. package/sensor/dist/search/query-utils.js +56 -16
  446. package/sensor/dist/search/query-utils.js.map +1 -1
  447. package/sensor/dist/sync/watch-policy.d.ts +14 -0
  448. package/sensor/dist/sync/watch-policy.d.ts.map +1 -1
  449. package/sensor/dist/sync/watch-policy.js +19 -0
  450. package/sensor/dist/sync/watch-policy.js.map +1 -1
  451. package/sensor/dist/sync/watcher.d.ts +74 -35
  452. package/sensor/dist/sync/watcher.d.ts.map +1 -1
  453. package/sensor/dist/sync/watcher.js +281 -99
  454. package/sensor/dist/sync/watcher.js.map +1 -1
  455. package/sensor/dist/telemetry/index.d.ts +4 -2
  456. package/sensor/dist/telemetry/index.d.ts.map +1 -1
  457. package/sensor/dist/telemetry/index.js +92 -41
  458. package/sensor/dist/telemetry/index.js.map +1 -1
  459. package/sensor/dist/types.d.ts +18 -2
  460. package/sensor/dist/types.d.ts.map +1 -1
  461. package/sensor/dist/types.js +2 -0
  462. package/sensor/dist/types.js.map +1 -1
  463. package/sensor/dist/ui-server/api/deadcode.d.ts +84 -0
  464. package/sensor/dist/ui-server/api/deadcode.d.ts.map +1 -0
  465. package/sensor/dist/ui-server/api/deadcode.js +136 -0
  466. package/sensor/dist/ui-server/api/deadcode.js.map +1 -0
  467. package/sensor/dist/ui-server/api/effects.d.ts +94 -0
  468. package/sensor/dist/ui-server/api/effects.d.ts.map +1 -0
  469. package/sensor/dist/ui-server/api/effects.js +527 -0
  470. package/sensor/dist/ui-server/api/effects.js.map +1 -0
  471. package/sensor/dist/ui-server/api/entrypoints.d.ts +92 -0
  472. package/sensor/dist/ui-server/api/entrypoints.d.ts.map +1 -0
  473. package/sensor/dist/ui-server/api/entrypoints.js +361 -0
  474. package/sensor/dist/ui-server/api/entrypoints.js.map +1 -0
  475. package/sensor/dist/ui-server/api/events.d.ts +183 -0
  476. package/sensor/dist/ui-server/api/events.d.ts.map +1 -0
  477. package/sensor/dist/ui-server/api/events.js +430 -0
  478. package/sensor/dist/ui-server/api/events.js.map +1 -0
  479. package/sensor/dist/ui-server/api/file.d.ts +66 -0
  480. package/sensor/dist/ui-server/api/file.d.ts.map +1 -0
  481. package/sensor/dist/ui-server/api/file.js +235 -0
  482. package/sensor/dist/ui-server/api/file.js.map +1 -0
  483. package/sensor/dist/ui-server/api/filecode.d.ts +126 -0
  484. package/sensor/dist/ui-server/api/filecode.d.ts.map +1 -0
  485. package/sensor/dist/ui-server/api/filecode.js +205 -0
  486. package/sensor/dist/ui-server/api/filecode.js.map +1 -0
  487. package/sensor/dist/ui-server/api/flow.d.ts +226 -0
  488. package/sensor/dist/ui-server/api/flow.d.ts.map +1 -0
  489. package/sensor/dist/ui-server/api/flow.js +612 -0
  490. package/sensor/dist/ui-server/api/flow.js.map +1 -0
  491. package/sensor/dist/ui-server/api/hierarchy.d.ts +81 -0
  492. package/sensor/dist/ui-server/api/hierarchy.d.ts.map +1 -0
  493. package/sensor/dist/ui-server/api/hierarchy.js +92 -0
  494. package/sensor/dist/ui-server/api/hierarchy.js.map +1 -0
  495. package/sensor/dist/ui-server/api/index.d.ts +90 -0
  496. package/sensor/dist/ui-server/api/index.d.ts.map +1 -0
  497. package/sensor/dist/ui-server/api/index.js +332 -0
  498. package/sensor/dist/ui-server/api/index.js.map +1 -0
  499. package/sensor/dist/ui-server/api/map.d.ts +256 -0
  500. package/sensor/dist/ui-server/api/map.d.ts.map +1 -0
  501. package/sensor/dist/ui-server/api/map.js +760 -0
  502. package/sensor/dist/ui-server/api/map.js.map +1 -0
  503. package/sensor/dist/ui-server/api/node.d.ts +81 -0
  504. package/sensor/dist/ui-server/api/node.d.ts.map +1 -0
  505. package/sensor/dist/ui-server/api/node.js +388 -0
  506. package/sensor/dist/ui-server/api/node.js.map +1 -0
  507. package/sensor/dist/ui-server/api/nodes.d.ts +25 -0
  508. package/sensor/dist/ui-server/api/nodes.d.ts.map +1 -0
  509. package/sensor/dist/ui-server/api/nodes.js +45 -0
  510. package/sensor/dist/ui-server/api/nodes.js.map +1 -0
  511. package/sensor/dist/ui-server/api/program.d.ts +139 -0
  512. package/sensor/dist/ui-server/api/program.d.ts.map +1 -0
  513. package/sensor/dist/ui-server/api/program.js +315 -0
  514. package/sensor/dist/ui-server/api/program.js.map +1 -0
  515. package/sensor/dist/ui-server/api/respond.d.ts +76 -0
  516. package/sensor/dist/ui-server/api/respond.d.ts.map +1 -0
  517. package/sensor/dist/ui-server/api/respond.js +186 -0
  518. package/sensor/dist/ui-server/api/respond.js.map +1 -0
  519. package/sensor/dist/ui-server/api/route-roots.d.ts +39 -0
  520. package/sensor/dist/ui-server/api/route-roots.d.ts.map +1 -0
  521. package/sensor/dist/ui-server/api/route-roots.js +96 -0
  522. package/sensor/dist/ui-server/api/route-roots.js.map +1 -0
  523. package/sensor/dist/ui-server/api/routes.d.ts +59 -0
  524. package/sensor/dist/ui-server/api/routes.d.ts.map +1 -0
  525. package/sensor/dist/ui-server/api/routes.js +108 -0
  526. package/sensor/dist/ui-server/api/routes.js.map +1 -0
  527. package/sensor/dist/ui-server/api/screens.d.ts +117 -0
  528. package/sensor/dist/ui-server/api/screens.d.ts.map +1 -0
  529. package/sensor/dist/ui-server/api/screens.js +611 -0
  530. package/sensor/dist/ui-server/api/screens.js.map +1 -0
  531. package/sensor/dist/ui-server/api/search.d.ts +29 -0
  532. package/sensor/dist/ui-server/api/search.d.ts.map +1 -0
  533. package/sensor/dist/ui-server/api/search.js +232 -0
  534. package/sensor/dist/ui-server/api/search.js.map +1 -0
  535. package/sensor/dist/ui-server/api/session.d.ts +52 -0
  536. package/sensor/dist/ui-server/api/session.d.ts.map +1 -0
  537. package/sensor/dist/ui-server/api/session.js +196 -0
  538. package/sensor/dist/ui-server/api/session.js.map +1 -0
  539. package/sensor/dist/ui-server/api/source.d.ts +200 -0
  540. package/sensor/dist/ui-server/api/source.d.ts.map +1 -0
  541. package/sensor/dist/ui-server/api/source.js +422 -0
  542. package/sensor/dist/ui-server/api/source.js.map +1 -0
  543. package/sensor/dist/ui-server/api/stats.d.ts +27 -0
  544. package/sensor/dist/ui-server/api/stats.d.ts.map +1 -0
  545. package/sensor/dist/ui-server/api/stats.js +164 -0
  546. package/sensor/dist/ui-server/api/stats.js.map +1 -0
  547. package/sensor/dist/ui-server/api/steps.d.ts +274 -0
  548. package/sensor/dist/ui-server/api/steps.d.ts.map +1 -0
  549. package/sensor/dist/ui-server/api/steps.js +1544 -0
  550. package/sensor/dist/ui-server/api/steps.js.map +1 -0
  551. package/sensor/dist/ui-server/api/trail-store.d.ts +142 -0
  552. package/sensor/dist/ui-server/api/trail-store.d.ts.map +1 -0
  553. package/sensor/dist/ui-server/api/trail-store.js +325 -0
  554. package/sensor/dist/ui-server/api/trail-store.js.map +1 -0
  555. package/sensor/dist/ui-server/api/trails.d.ts +163 -0
  556. package/sensor/dist/ui-server/api/trails.d.ts.map +1 -0
  557. package/sensor/dist/ui-server/api/trails.js +369 -0
  558. package/sensor/dist/ui-server/api/trails.js.map +1 -0
  559. package/sensor/dist/ui-server/api/when.d.ts +133 -0
  560. package/sensor/dist/ui-server/api/when.d.ts.map +1 -0
  561. package/sensor/dist/ui-server/api/when.js +275 -0
  562. package/sensor/dist/ui-server/api/when.js.map +1 -0
  563. package/sensor/dist/ui-server/api/wire.d.ts +179 -0
  564. package/sensor/dist/ui-server/api/wire.d.ts.map +1 -0
  565. package/sensor/dist/ui-server/api/wire.js +231 -0
  566. package/sensor/dist/ui-server/api/wire.js.map +1 -0
  567. package/sensor/dist/ui-server/assets.d.ts +40 -0
  568. package/sensor/dist/ui-server/assets.d.ts.map +1 -0
  569. package/sensor/dist/ui-server/assets.js +110 -0
  570. package/sensor/dist/ui-server/assets.js.map +1 -0
  571. package/sensor/dist/ui-server/constants.d.ts +32 -0
  572. package/sensor/dist/ui-server/constants.d.ts.map +1 -0
  573. package/sensor/dist/ui-server/constants.js +35 -0
  574. package/sensor/dist/ui-server/constants.js.map +1 -0
  575. package/sensor/dist/ui-server/highlight/index.d.ts +113 -0
  576. package/sensor/dist/ui-server/highlight/index.d.ts.map +1 -0
  577. package/sensor/dist/ui-server/highlight/index.js +307 -0
  578. package/sensor/dist/ui-server/highlight/index.js.map +1 -0
  579. package/sensor/dist/ui-server/highlight/languages.d.ts +36 -0
  580. package/sensor/dist/ui-server/highlight/languages.d.ts.map +1 -0
  581. package/sensor/dist/ui-server/highlight/languages.js +50 -0
  582. package/sensor/dist/ui-server/highlight/languages.js.map +1 -0
  583. package/sensor/dist/ui-server/index.d.ts +92 -0
  584. package/sensor/dist/ui-server/index.d.ts.map +1 -0
  585. package/sensor/dist/ui-server/index.js +399 -0
  586. package/sensor/dist/ui-server/index.js.map +1 -0
  587. package/sensor/dist/ui-server/open-browser.d.ts +31 -0
  588. package/sensor/dist/ui-server/open-browser.d.ts.map +1 -0
  589. package/sensor/dist/ui-server/open-browser.js +79 -0
  590. package/sensor/dist/ui-server/open-browser.js.map +1 -0
  591. package/sensor/dist/ui-server/security.d.ts +127 -0
  592. package/sensor/dist/ui-server/security.d.ts.map +1 -0
  593. package/sensor/dist/ui-server/security.js +332 -0
  594. package/sensor/dist/ui-server/security.js.map +1 -0
  595. package/sensor/dist/ui-server/static.d.ts +45 -0
  596. package/sensor/dist/ui-server/static.d.ts.map +1 -0
  597. package/sensor/dist/ui-server/static.js +165 -0
  598. package/sensor/dist/ui-server/static.js.map +1 -0
  599. package/sensor/dist/utils.d.ts +14 -2
  600. package/sensor/dist/utils.d.ts.map +1 -1
  601. package/sensor/dist/utils.js +25 -10
  602. package/sensor/dist/utils.js.map +1 -1
  603. package/src/sensor-adapter.mjs +5 -1
@@ -38,6 +38,8 @@ exports.isProcessAlive = isProcessAlive;
38
38
  exports.registerDaemon = registerDaemon;
39
39
  exports.deregisterDaemon = deregisterDaemon;
40
40
  exports.listDaemons = listDaemons;
41
+ exports.listVerifiedDaemons = listVerifiedDaemons;
42
+ exports.clearStaleDaemonArtifacts = clearStaleDaemonArtifacts;
41
43
  exports.stopDaemonAt = stopDaemonAt;
42
44
  exports.stopAllDaemons = stopAllDaemons;
43
45
  /**
@@ -66,6 +68,7 @@ const os = __importStar(require("os"));
66
68
  const path = __importStar(require("path"));
67
69
  const crypto = __importStar(require("crypto"));
68
70
  const daemon_paths_1 = require("./daemon-paths");
71
+ const writer_lock_1 = require("./writer-lock");
69
72
  /**
70
73
  * `~/.lattice/sensor/daemons` — GLOBAL, keyed off the home dir. (The per-project
71
74
  * index dir is fixed at `.lattice/sensor` and has no env override — see
@@ -174,24 +177,97 @@ function listDaemons(opts = {}) {
174
177
  }
175
178
  return live.sort((a, b) => b.startedAt - a.startedAt);
176
179
  }
177
- /** Remove a stopped daemon's leftover lockfile + socket + registry record. */
178
- function cleanupDaemonArtifacts(root) {
179
- try {
180
- fs.unlinkSync((0, daemon_paths_1.getDaemonPidPath)(root));
180
+ /**
181
+ * Registry entries whose socket hello proves the recorded process is the
182
+ * daemon. Used by every user-facing list/stop-all path so a reused PID cannot
183
+ * appear as a phantom running daemon (#1553).
184
+ */
185
+ async function listVerifiedDaemons(opts = {}) {
186
+ const prune = opts.prune ?? true;
187
+ const candidates = listDaemons({ prune });
188
+ const checks = await Promise.all(candidates.map(async (rec) => ({
189
+ rec,
190
+ verified: await (0, daemon_paths_1.probeDaemonIdentity)(rec),
191
+ })));
192
+ const verified = [];
193
+ for (const check of checks) {
194
+ if (check.verified)
195
+ verified.push(check.rec);
196
+ else if (prune)
197
+ deregisterDaemon(check.rec.root);
181
198
  }
182
- catch { /* gone */ }
183
- // POSIX sockets are real files; Windows named pipes vanish with the process.
184
- // Sweep every candidate — a daemon that relocated past an unusable in-project
185
- // FS (ExFAT/FAT; #997) left its socket at the tmpdir fallback, not candidate 0.
186
- if (process.platform !== 'win32') {
187
- for (const candidate of (0, daemon_paths_1.getDaemonSocketCandidates)(root)) {
199
+ return verified;
200
+ }
201
+ /** Remove stale artifacts while holding the project writer slot exclusively. */
202
+ function cleanupDaemonArtifacts(root, expectedLockContents) {
203
+ const pidPath = (0, daemon_paths_1.getDaemonPidPath)(root);
204
+ // A daemon owns writer.pid before binding or relocating its socket. Claiming
205
+ // the writer slot therefore freezes every legitimate daemon artifact writer
206
+ // while we compare the inspected lock snapshot and clean it up.
207
+ if ((0, writer_lock_1.readWriterLock)(root)?.pid === process.pid)
208
+ return false;
209
+ const claim = (0, writer_lock_1.tryAcquireWriterLock)(root, 'cleanup');
210
+ if (claim.kind === 'taken')
211
+ return false;
212
+ try {
213
+ if (expectedLockContents === null) {
214
+ if (fs.existsSync(pidPath))
215
+ return false;
216
+ }
217
+ else {
188
218
  try {
189
- fs.unlinkSync(candidate);
219
+ if (fs.readFileSync(pidPath, 'utf8') !== expectedLockContents)
220
+ return false;
221
+ }
222
+ catch {
223
+ return false;
224
+ }
225
+ }
226
+ // POSIX sockets are real files; Windows named pipes vanish with the process.
227
+ // Sweep every candidate before releasing daemon.pid, so no successor can
228
+ // acquire the lock and bind a socket that this cleanup then removes.
229
+ if (process.platform !== 'win32') {
230
+ for (const candidate of (0, daemon_paths_1.getDaemonSocketCandidates)(root)) {
231
+ try {
232
+ fs.unlinkSync(candidate);
233
+ }
234
+ catch { /* gone */ }
190
235
  }
191
- catch { /* gone */ }
192
236
  }
237
+ deregisterDaemon(root);
238
+ try {
239
+ fs.unlinkSync(pidPath);
240
+ }
241
+ catch (err) {
242
+ if (err.code !== 'ENOENT')
243
+ return false;
244
+ }
245
+ return true;
193
246
  }
194
- deregisterDaemon(root);
247
+ finally {
248
+ (0, writer_lock_1.releaseWriterLock)(root);
249
+ }
250
+ }
251
+ /** Remove daemon artifacts only when no matching daemon answers the socket hello. */
252
+ async function clearStaleDaemonArtifacts(root) {
253
+ const pidPath = (0, daemon_paths_1.getDaemonPidPath)(root);
254
+ const hadArtifacts = fs.existsSync(pidPath) || (process.platform !== 'win32' && (0, daemon_paths_1.getDaemonSocketCandidates)(root).some((p) => fs.existsSync(p)));
255
+ if (!hadArtifacts)
256
+ return false;
257
+ let info = null;
258
+ let lockContents = null;
259
+ try {
260
+ lockContents = fs.readFileSync(pidPath, 'utf8');
261
+ info = (0, daemon_paths_1.decodeLockInfo)(lockContents);
262
+ }
263
+ catch { /* missing/corrupt */ }
264
+ if (info && isProcessAlive(info.pid)) {
265
+ // A live legacy holder has no socket path to probe. That is inconclusive,
266
+ // not proof of PID reuse, so preserve its lock rather than risk two writers.
267
+ if (!(0, daemon_paths_1.canProbeDaemonIdentity)(info) || await (0, daemon_paths_1.probeDaemonIdentity)(info))
268
+ return false;
269
+ }
270
+ return cleanupDaemonArtifacts(root, lockContents);
195
271
  }
196
272
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
197
273
  async function waitForDeath(pid, timeoutMs) {
@@ -207,13 +283,17 @@ async function waitForDeath(pid, timeoutMs) {
207
283
  * Stop the daemon serving `root`: SIGTERM, wait, then SIGKILL if it won't go,
208
284
  * then sweep its artifacts. `root` must be realpath'd (match how the daemon
209
285
  * keys its socket/lockfile). Resolves the pid from the authoritative lockfile,
210
- * falling back to the registry.
286
+ * falling back to the registry. Rebuild callers preserve unverified live locks
287
+ * instead of interpreting a failed probe as permission to discard the database.
211
288
  */
212
- async function stopDaemonAt(root) {
289
+ async function stopDaemonAt(root, options = {}) {
213
290
  let pid = null;
291
+ let identity = null;
292
+ let lockContents = null;
214
293
  try {
215
- const info = (0, daemon_paths_1.decodeLockInfo)(fs.readFileSync((0, daemon_paths_1.getDaemonPidPath)(root), 'utf8'));
216
- pid = info?.pid ?? null;
294
+ lockContents = fs.readFileSync((0, daemon_paths_1.getDaemonPidPath)(root), 'utf8');
295
+ identity = (0, daemon_paths_1.decodeLockInfo)(lockContents);
296
+ pid = identity?.pid ?? null;
217
297
  }
218
298
  catch {
219
299
  /* no lockfile */
@@ -221,15 +301,39 @@ async function stopDaemonAt(root) {
221
301
  if (pid == null) {
222
302
  const rec = listDaemons({ prune: false }).find((r) => path.resolve(r.root) === path.resolve(root));
223
303
  pid = rec?.pid ?? null;
304
+ if (rec)
305
+ identity = rec;
224
306
  }
225
307
  if (pid == null) {
226
- cleanupDaemonArtifacts(root);
308
+ cleanupDaemonArtifacts(root, lockContents);
227
309
  return { root, pid: null, outcome: 'no-daemon' };
228
310
  }
229
311
  if (!isProcessAlive(pid)) {
230
- cleanupDaemonArtifacts(root);
231
- return { root, pid, outcome: 'not-running' };
312
+ const removed = cleanupDaemonArtifacts(root, lockContents);
313
+ return { root, pid, outcome: removed ? 'not-running' : 'unverified' };
314
+ }
315
+ // Never signal a process merely because it reused a stale daemon PID. The
316
+ // daemon's immediate hello is the process-identity proof (#1553).
317
+ if (!identity || !(0, daemon_paths_1.canProbeDaemonIdentity)(identity)) {
318
+ return { root, pid, outcome: 'unverified' };
319
+ }
320
+ if (!await (0, daemon_paths_1.probeDaemonIdentity)(identity)) {
321
+ if (options.preserveUnverified)
322
+ return { root, pid, outcome: 'unverified' };
323
+ const removed = cleanupDaemonArtifacts(root, lockContents);
324
+ return { root, pid, outcome: removed ? 'not-running' : 'unverified' };
232
325
  }
326
+ // Identity probing awaits I/O: never act on a superseded ownership record.
327
+ const sameLock = () => {
328
+ try {
329
+ return fs.readFileSync((0, daemon_paths_1.getDaemonPidPath)(root), 'utf8') === lockContents;
330
+ }
331
+ catch {
332
+ return lockContents === null;
333
+ }
334
+ };
335
+ if (!sameLock())
336
+ return { root, pid, outcome: 'unverified' };
233
337
  // POSIX: SIGTERM runs the daemon's graceful shutdown. Windows: TerminateProcess
234
338
  // (no graceful path), so we always sweep artifacts ourselves below.
235
339
  try {
@@ -238,20 +342,26 @@ async function stopDaemonAt(root) {
238
342
  catch { /* raced to exit */ }
239
343
  let outcome = 'term';
240
344
  if (!(await waitForDeath(pid, 3000))) {
345
+ // Re-prove identity before escalating; the old PID may have been reused.
346
+ if (!sameLock() || !await (0, daemon_paths_1.probeDaemonIdentity)(identity) || !sameLock()) {
347
+ return { root, pid, outcome: 'still-running' };
348
+ }
241
349
  try {
242
350
  process.kill(pid, 'SIGKILL');
243
351
  }
244
352
  catch { /* raced to exit */ }
245
- await waitForDeath(pid, 2000);
353
+ if (!(await waitForDeath(pid, 2000))) {
354
+ return { root, pid, outcome: 'still-running' };
355
+ }
246
356
  outcome = 'kill';
247
357
  }
248
- cleanupDaemonArtifacts(root);
358
+ cleanupDaemonArtifacts(root, lockContents);
249
359
  return { root, pid, outcome };
250
360
  }
251
361
  /** Stop every registered, live daemon. */
252
362
  async function stopAllDaemons() {
253
363
  const results = [];
254
- for (const rec of listDaemons()) {
364
+ for (const rec of await listVerifiedDaemons()) {
255
365
  results.push(await stopDaemonAt(rec.root));
256
366
  }
257
367
  return results;
@@ -1 +1 @@
1
- {"version":3,"file":"daemon-registry.js","sourceRoot":"","sources":["../../src/mcp/daemon-registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"daemon-registry.js","sourceRoot":"","sources":["../../src/mcp/daemon-registry.ts"],"names":[],"mappings":"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"}
@@ -92,13 +92,13 @@ export interface DaemonStartResult {
92
92
  *
93
93
  * Race-safe: callers must first call `tryAcquireDaemonLock(projectRoot)` and
94
94
  * only construct a Daemon if they got the lock (`kind: 'acquired'`). The atomic
95
- * `O_EXCL` create inside the acquire helper — which now also writes the full
96
- * record before returning — is the only synchronization between competing
97
- * daemons.
95
+ * create/link inside the acquire helper elects one candidate. The project
96
+ * writer lock then fences bind/ownership refresh against stale-artifact cleanup.
98
97
  */
99
98
  export declare class Daemon {
100
99
  private projectRoot;
101
100
  private server;
101
+ private acceptedSockets;
102
102
  private clients;
103
103
  /** Per-client peer pids from the optional client-hello, for the liveness sweep. */
104
104
  private clientPeers;
@@ -117,10 +117,9 @@ export declare class Daemon {
117
117
  maxIdleMs?: number;
118
118
  });
119
119
  /**
120
- * Bind the socket, kick off engine init, and register signal handlers. The
121
- * lockfile body was already written atomically by `tryAcquireDaemonLock`, so
122
- * there is nothing to write here. The promise resolves once the server is
123
- * listening — the daemon then sticks around until idle/shutdown.
120
+ * Bind the socket, refresh the ownership record, kick off engine init, and
121
+ * register signal handlers. The promise resolves once the server is listening
122
+ * — the daemon then sticks around until idle/shutdown.
124
123
  */
125
124
  start(): Promise<DaemonStartResult>;
126
125
  /** Currently-connected client count. Exposed for tests / status output. */
@@ -177,6 +176,14 @@ export declare class Daemon {
177
176
  reapDeadClients(isAlive: (pid: number) => boolean): number;
178
177
  private cleanupLockfile;
179
178
  }
179
+ /**
180
+ * Publish the bound socket without abandoning a live daemon on a transient
181
+ * Windows sharing violation. Keep this startup step synchronous: accepting a
182
+ * client before ownership is refreshed could initialize an engine too early.
183
+ * Retries wait per {@link LOCK_REFRESH_RETRY_DELAYS_MS}; permanent failures
184
+ * still abort startup.
185
+ */
186
+ export declare function refreshDaemonLock(pidPath: string, initialContents: string, lock: DaemonLockInfo, platform?: NodeJS.Platform): void;
180
187
  /**
181
188
  * Result of `tryAcquireDaemonLock`. Either we got the lockfile (caller becomes
182
189
  * the daemon), or it already existed (caller should connect to the existing
@@ -189,6 +196,8 @@ export type AcquireResult = {
189
196
  } | {
190
197
  kind: 'taken';
191
198
  existing: DaemonLockInfo | null;
199
+ /** Exact record read after losing acquisition; null when it was unreadable. */
200
+ lockContents: string | null;
192
201
  pidPath: string;
193
202
  };
194
203
  /**
@@ -234,17 +243,21 @@ export declare function tryAcquireDaemonLock(projectRoot: string): AcquireResult
234
243
  */
235
244
  export declare function acquireLockViaExclusiveOpen(pidPath: string, info: DaemonLockInfo): boolean;
236
245
  /**
237
- * Remove a stale pidfile, but only if it still names a dead process. Re-reads
238
- * the file immediately before unlinking so we never delete a lock that a live
239
- * daemon (re)acquired in the meantime.
246
+ * Remove a stale pidfile. Re-reads the file immediately before unlinking so a
247
+ * different daemon that acquired the lock in the meantime is never disturbed.
240
248
  *
241
249
  * must-fix 1 (issue #411 review): the original unconditionally `unlink`'d,
242
250
  * which let a racing candidate delete a healthy daemon's lock. Passing
243
251
  * `expectedDeadPid` (the pid the caller believed was dead) makes the clear a
244
- * compare-and-delete: bail if the file now holds a different pid, or any live
245
- * pid. Returns true when the stale lock is gone (or was already gone).
252
+ * compare-and-delete: bail if the file now holds a different pid. By default a
253
+ * live pid is also preserved; `allowLivePid` is reserved for callers that have
254
+ * already disproved daemon identity with the socket hello (#1553). Returns true
255
+ * when the stale lock is gone (or was already gone).
246
256
  */
247
- export declare function clearStaleDaemonLock(pidPath: string, expectedDeadPid?: number): boolean;
257
+ export declare function clearStaleDaemonLock(pidPath: string, expectedDeadPid?: number, opts?: {
258
+ allowLivePid?: boolean;
259
+ expectedLockContents?: string;
260
+ }): boolean;
248
261
  /**
249
262
  * Probe whether `pid` is currently alive (signal-0). Treats EPERM as alive on
250
263
  * every platform (the process exists, it's just not ours to signal) so we never
@@ -1 +1 @@
1
- {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/mcp/daemon.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/mcp/daemon.ts"],"names":[],"mappings":"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"}
@@ -76,6 +76,7 @@ var __importStar = (this && this.__importStar) || (function () {
76
76
  Object.defineProperty(exports, "__esModule", { value: true });
77
77
  exports.MAX_HELLO_LINE_BYTES = exports.Daemon = void 0;
78
78
  exports.finalizeDaemonExit = finalizeDaemonExit;
79
+ exports.refreshDaemonLock = refreshDaemonLock;
79
80
  exports.tryAcquireDaemonLock = tryAcquireDaemonLock;
80
81
  exports.acquireLockViaExclusiveOpen = acquireLockViaExclusiveOpen;
81
82
  exports.clearStaleDaemonLock = clearStaleDaemonLock;
@@ -91,6 +92,7 @@ const session_1 = require("./session");
91
92
  const transport_1 = require("./transport");
92
93
  const daemon_paths_1 = require("./daemon-paths");
93
94
  const version_1 = require("./version");
95
+ const writer_lock_1 = require("./writer-lock");
94
96
  const daemon_registry_1 = require("./daemon-registry");
95
97
  /** Default idle linger after the last client disconnects. */
96
98
  const DEFAULT_IDLE_TIMEOUT_MS = 300_000;
@@ -151,13 +153,15 @@ exports.MAX_HELLO_LINE_BYTES = MAX_HELLO_LINE_BYTES;
151
153
  *
152
154
  * Race-safe: callers must first call `tryAcquireDaemonLock(projectRoot)` and
153
155
  * only construct a Daemon if they got the lock (`kind: 'acquired'`). The atomic
154
- * `O_EXCL` create inside the acquire helper — which now also writes the full
155
- * record before returning — is the only synchronization between competing
156
- * daemons.
156
+ * create/link inside the acquire helper elects one candidate. The project
157
+ * writer lock then fences bind/ownership refresh against stale-artifact cleanup.
157
158
  */
158
159
  class Daemon {
159
160
  projectRoot;
160
161
  server = null;
162
+ // Includes sockets waiting for the optional client hello, before a session
163
+ // exists. server.close() waits for these too, so stop must destroy them.
164
+ acceptedSockets = new Set();
161
165
  clients = new Set();
162
166
  /** Per-client peer pids from the optional client-hello, for the liveness sweep. */
163
167
  clientPeers = new Map();
@@ -191,16 +195,32 @@ class Daemon {
191
195
  this.engine.setExecutionMode('daemon', 'daemon');
192
196
  }
193
197
  /**
194
- * Bind the socket, kick off engine init, and register signal handlers. The
195
- * lockfile body was already written atomically by `tryAcquireDaemonLock`, so
196
- * there is nothing to write here. The promise resolves once the server is
197
- * listening — the daemon then sticks around until idle/shutdown.
198
+ * Bind the socket, refresh the ownership record, kick off engine init, and
199
+ * register signal handlers. The promise resolves once the server is listening
200
+ * — the daemon then sticks around until idle/shutdown.
198
201
  */
199
202
  async start() {
200
- // Engine init is deliberately backgrounded — see #172. The first session
201
- // to land waits on `ensureInitialized` either way, and unloaded sessions
202
- // (cross-project tool calls only) shouldn't pay any open cost.
203
- void this.engine.ensureInitialized(this.projectRoot);
203
+ // #1740: claim the project writer lock before opening/watching so a
204
+ // concurrent direct-mode serve --mcp cannot start a second watcher.
205
+ (0, writer_lock_1.assertNoRebuild)(this.projectRoot);
206
+ const writer = (0, writer_lock_1.tryAcquireWriterLock)(this.projectRoot, 'daemon');
207
+ if (writer.kind === 'taken') {
208
+ const msg = (0, writer_lock_1.writerLockHeldMessage)(writer.existing, writer.pidPath);
209
+ process.stderr.write(`[LatticeSensor daemon] ${msg}\n`);
210
+ this.cleanupLockfile();
211
+ throw new Error(msg);
212
+ }
213
+ let initialLockContents;
214
+ try {
215
+ initialLockContents = fs.readFileSync(this.pidPath, 'utf8');
216
+ if ((0, daemon_paths_1.decodeLockInfo)(initialLockContents)?.pid !== process.pid) {
217
+ throw new Error('daemon lock belongs to another process');
218
+ }
219
+ }
220
+ catch {
221
+ (0, writer_lock_1.releaseWriterLock)(this.projectRoot);
222
+ throw new Error('Lost daemon lock ownership before startup.');
223
+ }
204
224
  // Walk the ordered socket candidates and bind the first that works. The
205
225
  // in-project path comes first; the deterministic tmpdir path is the fallback
206
226
  // for a filesystem that can't host an AF_UNIX node at all (ExFAT/FAT external
@@ -265,19 +285,24 @@ class Daemon {
265
285
  socketPath: this.socketPath,
266
286
  startedAt: Date.now(),
267
287
  };
268
- // `tryAcquireDaemonLock` wrote the pidfile with the PREFERRED path (candidate
269
- // 0) before we knew which one would bind. If we relocated, rewrite it so the
270
- // per-project record is honest. Atomic temp+rename; safe because we hold the
271
- // lock and we're alive — `clearStaleDaemonLock` pid-verifies, so no racing
272
- // candidate clears or clobbers a live daemon's lock.
273
- if (this.socketPath !== candidates[0]) {
288
+ // Refresh the lock on every successful bind, not only relocation. The
289
+ // writer lock prevents stale-artifact cleanup from racing this ownership
290
+ // check, and the exact snapshot prevents overwriting a replacement record.
291
+ try {
292
+ refreshDaemonLock(this.pidPath, initialLockContents, lock);
293
+ }
294
+ catch (err) {
274
295
  try {
275
- const tmpPid = `${this.pidPath}.${process.pid}.relocate`;
276
- fs.writeFileSync(tmpPid, (0, daemon_paths_1.encodeLockInfo)(lock), { mode: 0o600 });
277
- fs.renameSync(tmpPid, this.pidPath);
296
+ bound.server.close();
278
297
  }
279
- catch { /* best-effort; the registry record below carries the real path */ }
298
+ catch { /* best-effort */ }
299
+ this.cleanupLockfile();
300
+ throw err;
280
301
  }
302
+ // Engine init is deliberately backgrounded — see #172. It starts only
303
+ // after bind and ownership refresh, so a delayed daemon that lost election
304
+ // can never open a second watcher or writer.
305
+ void this.engine.ensureInitialized(this.projectRoot);
281
306
  // Drop a discovery record so `lattice sensor list` / `stop --all` can find us.
282
307
  // Best-effort; a missing record only means list's liveness prune covers it.
283
308
  (0, daemon_registry_1.registerDaemon)({ root: this.projectRoot, ...lock });
@@ -324,11 +349,14 @@ class Daemon {
324
349
  catch { /* best-effort */ }
325
350
  }
326
351
  this.clients.clear();
352
+ for (const socket of this.acceptedSockets)
353
+ socket.destroy();
354
+ this.acceptedSockets.clear();
327
355
  if (this.server) {
328
356
  await new Promise((resolve) => this.server.close(() => resolve()));
329
357
  this.server = null;
330
358
  }
331
- this.engine.stop();
359
+ await this.engine.stop();
332
360
  this.cleanupLockfile();
333
361
  (0, daemon_registry_1.deregisterDaemon)(this.projectRoot);
334
362
  if (process.platform !== 'win32') {
@@ -343,6 +371,12 @@ class Daemon {
343
371
  finalizeDaemonExit(process.platform, (code) => process.exit(code));
344
372
  }
345
373
  handleConnection(socket) {
374
+ if (this.stopping) {
375
+ socket.destroy();
376
+ return;
377
+ }
378
+ this.acceptedSockets.add(socket);
379
+ socket.once('close', () => this.acceptedSockets.delete(socket));
346
380
  // Hello first so the proxy can verify versions before piping any
347
381
  // application bytes. The proxy reads exactly one line, then forwards.
348
382
  const hello = {
@@ -357,6 +391,10 @@ class Daemon {
357
391
  // timeout, a non-hello first line, an early close — yields null pids and we
358
392
  // fall back to the socket-close lifecycle exactly as before (#692).
359
393
  void readClientHello(socket).then((peers) => {
394
+ if (this.stopping || socket.destroyed) {
395
+ socket.destroy();
396
+ return;
397
+ }
360
398
  const transport = new transport_1.SocketTransport(socket);
361
399
  const session = new session_1.MCPSession(transport, this.engine, {
362
400
  explicitProjectPath: this.projectRoot,
@@ -493,6 +531,7 @@ class Daemon {
493
531
  return reaped;
494
532
  }
495
533
  cleanupLockfile() {
534
+ (0, writer_lock_1.releaseWriterLock)(this.projectRoot);
496
535
  try {
497
536
  if (fs.existsSync(this.pidPath)) {
498
537
  // Only remove if it still belongs to us — another daemon may have
@@ -508,6 +547,52 @@ class Daemon {
508
547
  }
509
548
  }
510
549
  exports.Daemon = Daemon;
550
+ /**
551
+ * Waits between retries of the pid-file replace on Windows, doubling to a cap:
552
+ * eight attempts wait about 1.6s in all. Windows refuses to replace a file
553
+ * while any handle to it is open, so an antivirus scan, an indexer, or another
554
+ * session reading the lock can each hold it for a moment, and for longer on a
555
+ * loaded machine (#1773). The total stays well inside a launcher's ~6s connect
556
+ * window.
557
+ */
558
+ const LOCK_REFRESH_RETRY_DELAYS_MS = [25, 50, 100, 200, 400, 400, 400];
559
+ /**
560
+ * Publish the bound socket without abandoning a live daemon on a transient
561
+ * Windows sharing violation. Keep this startup step synchronous: accepting a
562
+ * client before ownership is refreshed could initialize an engine too early.
563
+ * Retries wait per {@link LOCK_REFRESH_RETRY_DELAYS_MS}; permanent failures
564
+ * still abort startup.
565
+ */
566
+ function refreshDaemonLock(pidPath, initialContents, lock, platform = process.platform) {
567
+ const tmpPid = `${pidPath}.${process.pid}.bound`;
568
+ try {
569
+ fs.writeFileSync(tmpPid, (0, daemon_paths_1.encodeLockInfo)(lock), { mode: 0o600 });
570
+ for (let attempt = 0;; attempt++) {
571
+ // A retry must never replace a record whose owner changed while waiting.
572
+ if (fs.readFileSync(pidPath, 'utf8') !== initialContents) {
573
+ throw new Error('Lost daemon lock ownership after binding.');
574
+ }
575
+ try {
576
+ fs.renameSync(tmpPid, pidPath);
577
+ return;
578
+ }
579
+ catch (error) {
580
+ const code = error.code;
581
+ const delay = LOCK_REFRESH_RETRY_DELAYS_MS[attempt];
582
+ if (platform !== 'win32' || !['EPERM', 'EACCES', 'EBUSY'].includes(code ?? '') || delay === undefined) {
583
+ throw error;
584
+ }
585
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, delay);
586
+ }
587
+ }
588
+ }
589
+ finally {
590
+ try {
591
+ fs.unlinkSync(tmpPid);
592
+ }
593
+ catch { /* renamed, or best-effort cleanup */ }
594
+ }
595
+ }
511
596
  /**
512
597
  * Atomically create the daemon pidfile with its full record already in place.
513
598
  * Returns either an `acquired` result (the caller is the daemon-elect and may
@@ -587,11 +672,13 @@ function tryAcquireDaemonLock(projectRoot) {
587
672
  // record — `existing` is null only for a genuinely corrupt leftover, never a
588
673
  // mid-write race.
589
674
  let existing = null;
675
+ let lockContents = null;
590
676
  try {
591
- existing = (0, daemon_paths_1.decodeLockInfo)(fs.readFileSync(pidPath, 'utf8'));
677
+ lockContents = fs.readFileSync(pidPath, 'utf8');
678
+ existing = (0, daemon_paths_1.decodeLockInfo)(lockContents);
592
679
  }
593
680
  catch { /* unreadable lockfile — treat as malformed */ }
594
- return { kind: 'taken', existing, pidPath };
681
+ return { kind: 'taken', existing, lockContents, pidPath };
595
682
  }
596
683
  /**
597
684
  * Exclusive-create the pidfile (O_CREAT|O_EXCL via the `wx` flag) and write the
@@ -621,26 +708,33 @@ function acquireLockViaExclusiveOpen(pidPath, info) {
621
708
  return true;
622
709
  }
623
710
  /**
624
- * Remove a stale pidfile, but only if it still names a dead process. Re-reads
625
- * the file immediately before unlinking so we never delete a lock that a live
626
- * daemon (re)acquired in the meantime.
711
+ * Remove a stale pidfile. Re-reads the file immediately before unlinking so a
712
+ * different daemon that acquired the lock in the meantime is never disturbed.
627
713
  *
628
714
  * must-fix 1 (issue #411 review): the original unconditionally `unlink`'d,
629
715
  * which let a racing candidate delete a healthy daemon's lock. Passing
630
716
  * `expectedDeadPid` (the pid the caller believed was dead) makes the clear a
631
- * compare-and-delete: bail if the file now holds a different pid, or any live
632
- * pid. Returns true when the stale lock is gone (or was already gone).
717
+ * compare-and-delete: bail if the file now holds a different pid. By default a
718
+ * live pid is also preserved; `allowLivePid` is reserved for callers that have
719
+ * already disproved daemon identity with the socket hello (#1553). Returns true
720
+ * when the stale lock is gone (or was already gone).
633
721
  */
634
- function clearStaleDaemonLock(pidPath, expectedDeadPid) {
722
+ function clearStaleDaemonLock(pidPath, expectedDeadPid, opts = {}) {
635
723
  try {
636
724
  const raw = fs.readFileSync(pidPath, 'utf8');
725
+ // The identity record changed after the caller inspected it. Even the same
726
+ // PID may now advertise a newly-bound socket, so this snapshot was never
727
+ // disproved and must not be deleted.
728
+ if (opts.expectedLockContents !== undefined && raw !== opts.expectedLockContents)
729
+ return false;
637
730
  const info = (0, daemon_paths_1.decodeLockInfo)(raw);
638
731
  if (info) {
639
732
  // A different pid took over since we read it — not ours to clear.
640
733
  if (expectedDeadPid !== undefined && info.pid !== expectedDeadPid)
641
734
  return false;
642
- // Holder is actually alive — never clear a live daemon's lock.
643
- if (info.pid > 0 && isProcessAlive(info.pid))
735
+ // PID liveness is normally sufficient. The takeover caller may override
736
+ // it only after a failed identity handshake proves PID reuse.
737
+ if (!opts.allowLivePid && info.pid > 0 && isProcessAlive(info.pid))
644
738
  return false;
645
739
  }
646
740
  fs.unlinkSync(pidPath);