codetrellis 0.0.0-stage → 0.3.0

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 (448) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +27 -2
  3. package/bin/codetrellis.mjs +4 -0
  4. package/package.json +41 -4
  5. package/reader/material-reader.mjs +130346 -0
  6. package/resources/tree-sitter/README.md +150 -0
  7. package/resources/tree-sitter/tree-sitter-c-sharp.wasm +0 -0
  8. package/resources/tree-sitter/tree-sitter-go.wasm +0 -0
  9. package/resources/tree-sitter/tree-sitter-java.wasm +0 -0
  10. package/resources/tree-sitter/tree-sitter-javascript.wasm +0 -0
  11. package/resources/tree-sitter/tree-sitter-kotlin.wasm +0 -0
  12. package/resources/tree-sitter/tree-sitter-php.wasm +0 -0
  13. package/resources/tree-sitter/tree-sitter-python.wasm +0 -0
  14. package/resources/tree-sitter/tree-sitter-ruby.wasm +0 -0
  15. package/resources/tree-sitter/tree-sitter-rust.wasm +0 -0
  16. package/resources/tree-sitter/tree-sitter-swift.wasm +0 -0
  17. package/resources/tree-sitter/tree-sitter-tsx.wasm +0 -0
  18. package/resources/tree-sitter/tree-sitter-typescript.wasm +0 -0
  19. package/resources/tree-sitter/tree-sitter.wasm +0 -0
  20. package/src/backend/agent/claude-code-watcher.js +270 -0
  21. package/src/backend/index.js +8 -0
  22. package/src/backend/lib/sha256-file.js +39 -0
  23. package/src/backend/lib/zip-entries.js +98 -0
  24. package/src/backend/lifecycle.js +102 -0
  25. package/src/backend/mcp/binding-headers.js +54 -0
  26. package/src/backend/mcp/client-identity.js +44 -0
  27. package/src/backend/mcp/connector/command.js +110 -0
  28. package/src/backend/mcp/connector/core.js +278 -0
  29. package/src/backend/mcp/connector/files.js +121 -0
  30. package/src/backend/mcp/connector/hook.js +284 -0
  31. package/src/backend/mcp/connector/main.js +126 -0
  32. package/src/backend/mcp/connector/sse-upstream.js +152 -0
  33. package/src/backend/mcp/helpers.js +43 -0
  34. package/src/backend/mcp/prompt-builders.js +104 -0
  35. package/src/backend/mcp/resources.js +197 -0
  36. package/src/backend/mcp/server.js +813 -0
  37. package/src/backend/mcp/skill-guide.js +1528 -0
  38. package/src/backend/mcp/tools/architecture-tools.js +273 -0
  39. package/src/backend/mcp/tools/audio-tools.js +117 -0
  40. package/src/backend/mcp/tools/awareness-tools.js +623 -0
  41. package/src/backend/mcp/tools/budget-tools.js +185 -0
  42. package/src/backend/mcp/tools/channel-tools.js +205 -0
  43. package/src/backend/mcp/tools/contribution-tools.js +181 -0
  44. package/src/backend/mcp/tools/drift-tools.js +252 -0
  45. package/src/backend/mcp/tools/git-tools.js +316 -0
  46. package/src/backend/mcp/tools/governance-tools.js +175 -0
  47. package/src/backend/mcp/tools/graph-tools.js +181 -0
  48. package/src/backend/mcp/tools/intake-tools.js +244 -0
  49. package/src/backend/mcp/tools/mobile-tools.js +118 -0
  50. package/src/backend/mcp/tools/peer-tools.js +330 -0
  51. package/src/backend/mcp/tools/plan-item-tools.js +1601 -0
  52. package/src/backend/mcp/tools/plan-tools.js +680 -0
  53. package/src/backend/mcp/tools/presence-tools.js +185 -0
  54. package/src/backend/mcp/tools/project-config-tools.js +150 -0
  55. package/src/backend/mcp/tools/review-tools.js +172 -0
  56. package/src/backend/mcp/tools/session-tools.js +554 -0
  57. package/src/backend/mcp/tools/system-docs-tools.js +168 -0
  58. package/src/backend/mcp/tools/terminal-tools.js +186 -0
  59. package/src/backend/mcp/tools/test-tools.js +117 -0
  60. package/src/backend/mcp/tools/ui-tools.js +356 -0
  61. package/src/backend/mcp/types.js +15 -0
  62. package/src/backend/middleware/local-auth.js +116 -0
  63. package/src/backend/server.js +5951 -0
  64. package/src/backend/services/agent-event-log.js +350 -0
  65. package/src/backend/services/architecture-rule.js +584 -0
  66. package/src/backend/services/architecture-rules.js +275 -0
  67. package/src/backend/services/artefact-content-service.js +181 -0
  68. package/src/backend/services/artefact-service.js +305 -0
  69. package/src/backend/services/artefact-watcher.js +167 -0
  70. package/src/backend/services/ast-parser.js +327 -0
  71. package/src/backend/services/audio-buffer-service.js +152 -0
  72. package/src/backend/services/awareness-notices.js +139 -0
  73. package/src/backend/services/awareness-replies.js +194 -0
  74. package/src/backend/services/awareness-service.js +344 -0
  75. package/src/backend/services/awareness-signals.js +267 -0
  76. package/src/backend/services/baseline-store.js +83 -0
  77. package/src/backend/services/branch-workstreams.js +341 -0
  78. package/src/backend/services/breakpoint-service.js +584 -0
  79. package/src/backend/services/brief-service.js +299 -0
  80. package/src/backend/services/budget-service.js +528 -0
  81. package/src/backend/services/callsites/base.js +15 -0
  82. package/src/backend/services/callsites/csharp.js +148 -0
  83. package/src/backend/services/callsites/go.js +163 -0
  84. package/src/backend/services/callsites/index.js +53 -0
  85. package/src/backend/services/callsites/kotlin.js +123 -0
  86. package/src/backend/services/callsites/process-env.js +125 -0
  87. package/src/backend/services/callsites/python.js +91 -0
  88. package/src/backend/services/callsites/ruby.js +164 -0
  89. package/src/backend/services/callsites/shared.js +198 -0
  90. package/src/backend/services/callsites/swift.js +115 -0
  91. package/src/backend/services/callsites/typescript.js +87 -0
  92. package/src/backend/services/capability-token.js +108 -0
  93. package/src/backend/services/change-check.js +156 -0
  94. package/src/backend/services/channel-dispatcher-service.js +235 -0
  95. package/src/backend/services/channel-event-file-service.js +125 -0
  96. package/src/backend/services/channel-event-service.js +297 -0
  97. package/src/backend/services/check-runs.js +177 -0
  98. package/src/backend/services/checkout-identity.js +73 -0
  99. package/src/backend/services/claude-code-parallel.js +221 -0
  100. package/src/backend/services/claude-desktop-config.js +186 -0
  101. package/src/backend/services/cli-install.js +249 -0
  102. package/src/backend/services/clock.js +57 -0
  103. package/src/backend/services/cloud-files.js +191 -0
  104. package/src/backend/services/coalesce.js +50 -0
  105. package/src/backend/services/code-breakpoints.js +291 -0
  106. package/src/backend/services/comment-service.js +168 -0
  107. package/src/backend/services/commit-attribution.js +134 -0
  108. package/src/backend/services/commit-edges.js +99 -0
  109. package/src/backend/services/confined-fs.js +241 -0
  110. package/src/backend/services/conformity-gate.js +132 -0
  111. package/src/backend/services/contribution-service.js +409 -0
  112. package/src/backend/services/coverage-service.js +173 -0
  113. package/src/backend/services/criteria-service.js +721 -0
  114. package/src/backend/services/criterion-checks.js +387 -0
  115. package/src/backend/services/criterion-loop-service.js +411 -0
  116. package/src/backend/services/cross-system-service.js +231 -0
  117. package/src/backend/services/database.js +916 -0
  118. package/src/backend/services/db-schema.js +1358 -0
  119. package/src/backend/services/deviation-service.js +344 -0
  120. package/src/backend/services/diff-engine.js +168 -0
  121. package/src/backend/services/evidence.js +363 -0
  122. package/src/backend/services/external-intake-service.js +269 -0
  123. package/src/backend/services/external-pointer-service.js +195 -0
  124. package/src/backend/services/external-refs-service.js +214 -0
  125. package/src/backend/services/file-history.js +158 -0
  126. package/src/backend/services/file-watcher.js +193 -0
  127. package/src/backend/services/folder-requests.js +118 -0
  128. package/src/backend/services/freeze-service.js +189 -0
  129. package/src/backend/services/gemini-cli-hook.js +172 -0
  130. package/src/backend/services/git-activity-service.js +325 -0
  131. package/src/backend/services/git-blobs.js +70 -0
  132. package/src/backend/services/git-branches.js +357 -0
  133. package/src/backend/services/git-checkout.js +153 -0
  134. package/src/backend/services/git-commit-service.js +91 -0
  135. package/src/backend/services/git-env.js +121 -0
  136. package/src/backend/services/git-identity.js +84 -0
  137. package/src/backend/services/git-refs.js +386 -0
  138. package/src/backend/services/git-safety.js +58 -0
  139. package/src/backend/services/grant-guard.js +67 -0
  140. package/src/backend/services/html-view-policy.js +135 -0
  141. package/src/backend/services/human-decision.js +55 -0
  142. package/src/backend/services/importers.js +159 -0
  143. package/src/backend/services/intent-service.js +105 -0
  144. package/src/backend/services/ipc-dispatcher.js +164 -0
  145. package/src/backend/services/item-git-state.js +208 -0
  146. package/src/backend/services/line-changes.js +232 -0
  147. package/src/backend/services/line-history.js +174 -0
  148. package/src/backend/services/local-api-changes.js +40 -0
  149. package/src/backend/services/logger.js +217 -0
  150. package/src/backend/services/material-footprints.js +203 -0
  151. package/src/backend/services/material-place.js +82 -0
  152. package/src/backend/services/material-reader/docx-markdown.js +198 -0
  153. package/src/backend/services/material-reader/fixtures.test-helper.js +169 -0
  154. package/src/backend/services/material-reader/quote.js +44 -0
  155. package/src/backend/services/material-reader/reader-host.js +202 -0
  156. package/src/backend/services/material-signals.js +141 -0
  157. package/src/backend/services/mcp-capabilities.js +390 -0
  158. package/src/backend/services/mdns-service.js +304 -0
  159. package/src/backend/services/mobile-api-server.js +281 -0
  160. package/src/backend/services/mobile-approvals.js +306 -0
  161. package/src/backend/services/mobile-awareness.js +180 -0
  162. package/src/backend/services/mobile-breakpoints.js +115 -0
  163. package/src/backend/services/mobile-budget.js +98 -0
  164. package/src/backend/services/mobile-freeze.js +106 -0
  165. package/src/backend/services/mobile-proposals.js +100 -0
  166. package/src/backend/services/mobile-rpc-service.js +1289 -0
  167. package/src/backend/services/mobile-workstreams.js +160 -0
  168. package/src/backend/services/monorepo-detector.js +131 -0
  169. package/src/backend/services/other-work.js +45 -0
  170. package/src/backend/services/pack-seal.js +129 -0
  171. package/src/backend/services/paired-device-service.js +192 -0
  172. package/src/backend/services/pairing-server.js +323 -0
  173. package/src/backend/services/pairing-service.js +200 -0
  174. package/src/backend/services/pantry-resolution-service.js +166 -0
  175. package/src/backend/services/parsers/base.js +124 -0
  176. package/src/backend/services/parsers/csharp.js +224 -0
  177. package/src/backend/services/parsers/go.js +180 -0
  178. package/src/backend/services/parsers/index.js +101 -0
  179. package/src/backend/services/parsers/java.js +103 -0
  180. package/src/backend/services/parsers/kotlin.js +252 -0
  181. package/src/backend/services/parsers/php.js +113 -0
  182. package/src/backend/services/parsers/python.js +189 -0
  183. package/src/backend/services/parsers/ruby.js +212 -0
  184. package/src/backend/services/parsers/rust.js +97 -0
  185. package/src/backend/services/parsers/swift.js +221 -0
  186. package/src/backend/services/parsers/typescript.js +235 -0
  187. package/src/backend/services/pattern-scan.js +65 -0
  188. package/src/backend/services/patterns.js +281 -0
  189. package/src/backend/services/peer-audit-service.js +123 -0
  190. package/src/backend/services/peer-auth.js +153 -0
  191. package/src/backend/services/peer-capabilities.js +209 -0
  192. package/src/backend/services/peer-connection-service.js +450 -0
  193. package/src/backend/services/peer-grants.js +33 -0
  194. package/src/backend/services/persistence.js +116 -0
  195. package/src/backend/services/personal-sync-service.js +232 -0
  196. package/src/backend/services/pipeline-approvals.js +72 -0
  197. package/src/backend/services/pipeline.js +232 -0
  198. package/src/backend/services/plan-arrivals.js +68 -0
  199. package/src/backend/services/plan-changes-service.js +273 -0
  200. package/src/backend/services/plan-conflict-service.js +288 -0
  201. package/src/backend/services/plan-dependencies.js +91 -0
  202. package/src/backend/services/plan-doc-guard.js +90 -0
  203. package/src/backend/services/plan-documents-service.js +275 -0
  204. package/src/backend/services/plan-event-service.js +154 -0
  205. package/src/backend/services/plan-file-refs.js +106 -0
  206. package/src/backend/services/plan-file-service.js +1564 -0
  207. package/src/backend/services/plan-history-service.js +156 -0
  208. package/src/backend/services/plan-import-service.js +261 -0
  209. package/src/backend/services/plan-item-service.js +1223 -0
  210. package/src/backend/services/plan-migrate-service.js +395 -0
  211. package/src/backend/services/plan-overlay-service.js +173 -0
  212. package/src/backend/services/plan-phases-service.js +182 -0
  213. package/src/backend/services/plan-progress-service.js +134 -0
  214. package/src/backend/services/plan-review-service.js +262 -0
  215. package/src/backend/services/plan-service.js +682 -0
  216. package/src/backend/services/plan-status.js +113 -0
  217. package/src/backend/services/plan-template-publish-service.js +217 -0
  218. package/src/backend/services/plan-templates-service.js +242 -0
  219. package/src/backend/services/plan-templates.js +1164 -0
  220. package/src/backend/services/planned-overlap-actions.js +200 -0
  221. package/src/backend/services/plans-home.js +224 -0
  222. package/src/backend/services/play-forward.js +256 -0
  223. package/src/backend/services/playback-service.js +117 -0
  224. package/src/backend/services/power-service.js +167 -0
  225. package/src/backend/services/power-signals.js +81 -0
  226. package/src/backend/services/pr-draft-service.js +142 -0
  227. package/src/backend/services/presence-service.js +122 -0
  228. package/src/backend/services/pricing.js +60 -0
  229. package/src/backend/services/project-config-service.js +474 -0
  230. package/src/backend/services/project-scanner.js +184 -0
  231. package/src/backend/services/projection-service.js +69 -0
  232. package/src/backend/services/push-notification-service.js +288 -0
  233. package/src/backend/services/recent-projects-service.js +204 -0
  234. package/src/backend/services/record-chain.js +162 -0
  235. package/src/backend/services/recurrence-rule.js +63 -0
  236. package/src/backend/services/recurring-agent.js +89 -0
  237. package/src/backend/services/recurring-scheduler.js +77 -0
  238. package/src/backend/services/recurring-service.js +276 -0
  239. package/src/backend/services/reference-service.js +169 -0
  240. package/src/backend/services/release-public-key.js +30 -0
  241. package/src/backend/services/release-signature.js +64 -0
  242. package/src/backend/services/remote-audio-service.js +224 -0
  243. package/src/backend/services/remote-interaction-service.js +275 -0
  244. package/src/backend/services/remote-terminal-service.js +324 -0
  245. package/src/backend/services/rendition/child/main.js +76 -0
  246. package/src/backend/services/rendition/engine-host.js +249 -0
  247. package/src/backend/services/rendition/engine-lock.js +39 -0
  248. package/src/backend/services/rendition/engine-lock.json +14 -0
  249. package/src/backend/services/rendition/engine-manifest.js +97 -0
  250. package/src/backend/services/rendition/network-proof.js +73 -0
  251. package/src/backend/services/rendition/rendition-service.js +175 -0
  252. package/src/backend/services/replay-frames.js +387 -0
  253. package/src/backend/services/replay-state.js +201 -0
  254. package/src/backend/services/resolvers/base.js +108 -0
  255. package/src/backend/services/resolvers/csharp.js +109 -0
  256. package/src/backend/services/resolvers/go.js +105 -0
  257. package/src/backend/services/resolvers/index.js +60 -0
  258. package/src/backend/services/resolvers/java.js +63 -0
  259. package/src/backend/services/resolvers/kotlin.js +109 -0
  260. package/src/backend/services/resolvers/php.js +89 -0
  261. package/src/backend/services/resolvers/python.js +154 -0
  262. package/src/backend/services/resolvers/ruby.js +103 -0
  263. package/src/backend/services/resolvers/rust.js +77 -0
  264. package/src/backend/services/resolvers/swift.js +98 -0
  265. package/src/backend/services/resolvers/typescript.js +71 -0
  266. package/src/backend/services/retention.js +54 -0
  267. package/src/backend/services/review-architecture.js +236 -0
  268. package/src/backend/services/review-attest.js +68 -0
  269. package/src/backend/services/review-bundle.js +226 -0
  270. package/src/backend/services/review-graduation.js +93 -0
  271. package/src/backend/services/review-host/bitbucket.js +79 -0
  272. package/src/backend/services/review-host/detect.js +80 -0
  273. package/src/backend/services/review-host/github.js +97 -0
  274. package/src/backend/services/review-host/gitlab.js +77 -0
  275. package/src/backend/services/review-host/host-state.js +103 -0
  276. package/src/backend/services/review-host/http.js +58 -0
  277. package/src/backend/services/review-host/switch.js +120 -0
  278. package/src/backend/services/review-marks.js +72 -0
  279. package/src/backend/services/review-notes.js +169 -0
  280. package/src/backend/services/review-other-work.js +90 -0
  281. package/src/backend/services/review-queue-service.js +147 -0
  282. package/src/backend/services/review-risk.js +127 -0
  283. package/src/backend/services/review-task.js +121 -0
  284. package/src/backend/services/rule-approvals.js +275 -0
  285. package/src/backend/services/rule-baseline.js +134 -0
  286. package/src/backend/services/rule-changes.js +162 -0
  287. package/src/backend/services/rule-preview.js +47 -0
  288. package/src/backend/services/rule-proposals.js +104 -0
  289. package/src/backend/services/rule-scope.js +76 -0
  290. package/src/backend/services/rulebook.js +286 -0
  291. package/src/backend/services/rules-at.js +56 -0
  292. package/src/backend/services/rules-overview.js +88 -0
  293. package/src/backend/services/schema-reconciler.js +250 -0
  294. package/src/backend/services/secret-store.js +119 -0
  295. package/src/backend/services/section-workstreams.js +95 -0
  296. package/src/backend/services/self-write-tracker.js +75 -0
  297. package/src/backend/services/sensor-bridge-service.js +285 -0
  298. package/src/backend/services/session-service.js +192 -0
  299. package/src/backend/services/settings-service.js +324 -0
  300. package/src/backend/services/signal-breakpoints.js +172 -0
  301. package/src/backend/services/signed-approval-record.js +86 -0
  302. package/src/backend/services/signed-approvals.js +244 -0
  303. package/src/backend/services/signoff-pack.js +328 -0
  304. package/src/backend/services/signoff-rows.js +114 -0
  305. package/src/backend/services/skill-arrival-service.js +138 -0
  306. package/src/backend/services/skill-model.js +193 -0
  307. package/src/backend/services/skill-use-service.js +140 -0
  308. package/src/backend/services/skills-service.js +150 -0
  309. package/src/backend/services/snapshot-compare-service.js +397 -0
  310. package/src/backend/services/source-control.js +189 -0
  311. package/src/backend/services/spec-links-service.js +123 -0
  312. package/src/backend/services/spec-proposal-withdraw.js +50 -0
  313. package/src/backend/services/spec-proposals-service.js +470 -0
  314. package/src/backend/services/sql/embedded.js +95 -0
  315. package/src/backend/services/sql/index.js +63 -0
  316. package/src/backend/services/sql/refs.js +357 -0
  317. package/src/backend/services/sql/schema.js +312 -0
  318. package/src/backend/services/sql/tokenizer.js +195 -0
  319. package/src/backend/services/stack-overlaps.js +117 -0
  320. package/src/backend/services/stack-service.js +225 -0
  321. package/src/backend/services/state-sync-service.js +384 -0
  322. package/src/backend/services/stuck-sensor-service.js +200 -0
  323. package/src/backend/services/system-discovery.js +481 -0
  324. package/src/backend/services/system-docs-service.js +701 -0
  325. package/src/backend/services/task-attachments-service.js +340 -0
  326. package/src/backend/services/task-grounding.js +60 -0
  327. package/src/backend/services/task-records/check-run-record.js +146 -0
  328. package/src/backend/services/task-records/check-runs.js +115 -0
  329. package/src/backend/services/task-records/heads.js +88 -0
  330. package/src/backend/services/task-records/material-reads.js +225 -0
  331. package/src/backend/services/task-records/read-record.js +100 -0
  332. package/src/backend/services/task-records/record.js +173 -0
  333. package/src/backend/services/task-records/run-record.js +136 -0
  334. package/src/backend/services/task-records/shared-state.js +548 -0
  335. package/src/backend/services/task-records/signing.js +140 -0
  336. package/src/backend/services/task-records/split-signals.js +52 -0
  337. package/src/backend/services/task-records/test-runs.js +164 -0
  338. package/src/backend/services/task-records/trust.js +243 -0
  339. package/src/backend/services/task-rules.js +81 -0
  340. package/src/backend/services/task-workstreams.js +90 -0
  341. package/src/backend/services/terminal-history-service.js +266 -0
  342. package/src/backend/services/terminal-service.js +267 -0
  343. package/src/backend/services/test-clock.js +53 -0
  344. package/src/backend/services/tests/grounding.js +266 -0
  345. package/src/backend/services/tests/junit.js +104 -0
  346. package/src/backend/services/tests/teammate-runs.js +134 -0
  347. package/src/backend/services/tests/test-results.js +234 -0
  348. package/src/backend/services/tree-watcher.js +204 -0
  349. package/src/backend/services/trellis-service.js +204 -0
  350. package/src/backend/services/trusted-roots.js +186 -0
  351. package/src/backend/services/update-download-service.js +342 -0
  352. package/src/backend/services/update-service.js +266 -0
  353. package/src/backend/services/watch-ignore.js +76 -0
  354. package/src/backend/services/webhook-egress.js +206 -0
  355. package/src/backend/services/webrtc-service.js +413 -0
  356. package/src/backend/services/work-changes.js +59 -0
  357. package/src/backend/services/workstream-binding.js +82 -0
  358. package/src/backend/services/workstream-commits.js +116 -0
  359. package/src/backend/services/workstream-imports.js +177 -0
  360. package/src/backend/services/workstream-service.js +335 -0
  361. package/src/backend/services/workstream-symbols.js +223 -0
  362. package/src/backend/services/workstream-watch-service.js +391 -0
  363. package/src/backend/services/worktree-service.js +235 -0
  364. package/src/cli/agent.js +100 -0
  365. package/src/cli/args.js +209 -0
  366. package/src/cli/conformity.js +106 -0
  367. package/src/cli/desktop.js +91 -0
  368. package/src/cli/main.js +411 -0
  369. package/src/cli/pipeline.js +109 -0
  370. package/src/cli/plan-verbs.js +259 -0
  371. package/src/cli/review-adapters.js +220 -0
  372. package/src/cli/review-output.js +93 -0
  373. package/src/cli/review-post.js +89 -0
  374. package/src/cli/review-sink.js +183 -0
  375. package/src/cli/review-skill.js +44 -0
  376. package/src/cli/review-verify.js +104 -0
  377. package/src/cli/review.js +386 -0
  378. package/src/cli/sarif.js +148 -0
  379. package/src/cli/verbs.js +360 -0
  380. package/src/shared/build-info.js +39 -0
  381. package/src/shared/lib/agent-review.js +199 -0
  382. package/src/shared/lib/agent-turns.js +140 -0
  383. package/src/shared/lib/awareness-digest.js +120 -0
  384. package/src/shared/lib/branch-name.js +45 -0
  385. package/src/shared/lib/breakpoint-words.js +118 -0
  386. package/src/shared/lib/budget-words.js +56 -0
  387. package/src/shared/lib/burst.js +69 -0
  388. package/src/shared/lib/call-entry.js +105 -0
  389. package/src/shared/lib/check-compare.js +42 -0
  390. package/src/shared/lib/check-words.js +216 -0
  391. package/src/shared/lib/csv.js +62 -0
  392. package/src/shared/lib/folder-entry.js +87 -0
  393. package/src/shared/lib/freeze-words.js +60 -0
  394. package/src/shared/lib/fuzzy.js +84 -0
  395. package/src/shared/lib/git-state-words.js +80 -0
  396. package/src/shared/lib/grep-entry.js +86 -0
  397. package/src/shared/lib/grounding-line.js +61 -0
  398. package/src/shared/lib/import-line.js +71 -0
  399. package/src/shared/lib/item-status.js +249 -0
  400. package/src/shared/lib/line-changes.js +53 -0
  401. package/src/shared/lib/locator.js +71 -0
  402. package/src/shared/lib/matcher.js +120 -0
  403. package/src/shared/lib/merge-order.js +65 -0
  404. package/src/shared/lib/open-findings.js +68 -0
  405. package/src/shared/lib/other-work.js +108 -0
  406. package/src/shared/lib/package-entry.js +142 -0
  407. package/src/shared/lib/plan-vocab.js +40 -0
  408. package/src/shared/lib/pptx-xml.js +86 -0
  409. package/src/shared/lib/proposal-words.js +61 -0
  410. package/src/shared/lib/recurrence.js +183 -0
  411. package/src/shared/lib/references.js +72 -0
  412. package/src/shared/lib/rule-pattern.js +56 -0
  413. package/src/shared/lib/sdp-fingerprint.js +115 -0
  414. package/src/shared/lib/sdp-minimal.js +123 -0
  415. package/src/shared/lib/secret-paths.js +34 -0
  416. package/src/shared/lib/signal-words.js +172 -0
  417. package/src/shared/lib/signoff.js +56 -0
  418. package/src/shared/lib/skills-note.js +60 -0
  419. package/src/shared/lib/spec-sections.js +78 -0
  420. package/src/shared/lib/symbol-entry.js +60 -0
  421. package/src/shared/lib/tool-phrasing.js +338 -0
  422. package/src/shared/lib/turn-gap.js +27 -0
  423. package/src/shared/lib/workstream-words.js +38 -0
  424. package/src/shared/lib/xlsx-xml.js +144 -0
  425. package/src/shared/lib/zip-reader.js +99 -0
  426. package/src/shared/types/agent.js +27 -0
  427. package/src/shared/types/architecture-rules.js +30 -0
  428. package/src/shared/types/ast.js +15 -0
  429. package/src/shared/types/breakpoint.js +33 -0
  430. package/src/shared/types/channel.js +41 -0
  431. package/src/shared/types/criteria.js +15 -0
  432. package/src/shared/types/graph.js +15 -0
  433. package/src/shared/types/index.js +53 -0
  434. package/src/shared/types/peer.js +36 -0
  435. package/src/shared/types/pipeline.js +15 -0
  436. package/src/shared/types/plan.js +15 -0
  437. package/src/shared/types/play-forward.js +15 -0
  438. package/src/shared/types/power.js +15 -0
  439. package/src/shared/types/presence.js +15 -0
  440. package/src/shared/types/project-config.js +35 -0
  441. package/src/shared/types/project.js +15 -0
  442. package/src/shared/types/record.js +15 -0
  443. package/src/shared/types/recurring.js +15 -0
  444. package/src/shared/types/review.js +15 -0
  445. package/src/shared/types/settings.js +114 -0
  446. package/src/shared/types/stack.js +15 -0
  447. package/src/shared/types/system-doc.js +15 -0
  448. package/src/shared/types/system.js +15 -0
@@ -0,0 +1,390 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var mcp_capabilities_exports = {};
19
+ __export(mcp_capabilities_exports, {
20
+ McpAuthorizationError: () => McpAuthorizationError,
21
+ TOOL_CAPABILITIES: () => TOOL_CAPABILITIES,
22
+ assertMcpMayCall: () => assertMcpMayCall,
23
+ assertMcpProjectInScope: () => assertMcpProjectInScope,
24
+ listAuthorisedTools: () => listAuthorisedTools
25
+ });
26
+ module.exports = __toCommonJS(mcp_capabilities_exports);
27
+ var import_peer_capabilities = require("./peer-capabilities");
28
+ var import_trusted_roots = require("./trusted-roots");
29
+ const TOOL_CAPABILITIES = Object.freeze({
30
+ // ── architecture-tools ──────────────────────────────────────────────
31
+ search_symbols: "read",
32
+ get_dependencies: "read",
33
+ check_architecture: "read",
34
+ list_cross_system_edges: "read",
35
+ check_conformity: "read",
36
+ // ── budget-tools ────────────────────────────────────────────────────
37
+ get_budget: "read",
38
+ set_budget: "write",
39
+ check_budget: "read",
40
+ // ── channel-tools ───────────────────────────────────────────────────
41
+ post_channel_event: "write",
42
+ list_channel_events: "read",
43
+ get_channel_thread: "read",
44
+ resolve_channel_event: "write",
45
+ dismiss_channel_event: "write",
46
+ // ── drift-tools ─────────────────────────────────────────────────────
47
+ get_deviations: "read",
48
+ reconcile: "write",
49
+ detect_deviations: "read",
50
+ list_proposed_changes: "read",
51
+ get_changes_summary: "read",
52
+ get_change_status: "read",
53
+ get_drift_report: "read",
54
+ capture_checkpoint: "write",
55
+ // ── git-tools ───────────────────────────────────────────────────────
56
+ // `commit_manifest_changes` and `resolve_conflict` mutate the repository,
57
+ // but only under `.codetrellis/` — the manifest this product owns. That is
58
+ // persisting plan state, which is what `write` means here.
59
+ commit_manifest_changes: "write",
60
+ get_team_activity: "read",
61
+ get_plan_history: "read",
62
+ get_plan_at_commit: "read",
63
+ diff_plan_between_commits: "read",
64
+ search_plan_history: "read",
65
+ detect_conflicts: "read",
66
+ resolve_conflict: "write",
67
+ // ── test-tools (Phase 32 B8.1) ──────────────────────────────────────
68
+ // Handing over a report keeps results in this machine's database: a write.
69
+ // Reading what the runs said is a read. Neither runs anything.
70
+ report_tests: "write",
71
+ get_test_results: "read",
72
+ // ── governance-tools ────────────────────────────────────────────────
73
+ get_freeze_status: "read",
74
+ verify_record: "read",
75
+ export_evidence: "read",
76
+ line_history: "read",
77
+ set_freeze: "write",
78
+ check_freeze: "read",
79
+ exempt_plan_from_freeze: "write",
80
+ // ── graph-tools ─────────────────────────────────────────────────────
81
+ // Driving the graph changes what is on the user's screen. That is not
82
+ // `read`, even though no data is written: an agent granted only `read`
83
+ // should not be able to move the view the user is looking at. `graph_export`
84
+ // and `graph_snapshot` return the graph's own contents and are `read`.
85
+ graph_focus: "write",
86
+ graph_set_mode: "write",
87
+ graph_set_scope: "write",
88
+ graph_select: "write",
89
+ graph_set_layout: "write",
90
+ graph_set_depth: "write",
91
+ graph_toggle_projection: "write",
92
+ graph_export: "read",
93
+ graph_snapshot: "read",
94
+ // Not `capture`: this returns whether the window is usable, never what
95
+ // is on it. Any agent about to drive the UI should be able to ask
96
+ // first — gating it behind a capability most installs withhold would
97
+ // leave exactly the agents that need it unable to check.
98
+ ui_ready: "read",
99
+ // ── intake-tools ────────────────────────────────────────────────────
100
+ create_plan_from_external: "write",
101
+ set_plan_external_ref: "write",
102
+ get_external_sync_state: "read",
103
+ mark_external_synced: "write",
104
+ list_plan_external_refs: "read",
105
+ // ── mobile-tools ────────────────────────────────────────────────────
106
+ // These drive a PAIRED DEVICE. `mobile_screenshot` returns a picture of
107
+ // someone's phone screen, which is `capture` for the same reason the
108
+ // desktop screenshot is.
109
+ mobile_navigate: "write",
110
+ mobile_screenshot: "capture",
111
+ mobile_present: "write",
112
+ // ── plan-item-tools ─────────────────────────────────────────────────
113
+ add_item: "write",
114
+ bulk_add_items: "write",
115
+ get_item: "read",
116
+ read_item_full: "read",
117
+ update_item: "write",
118
+ move_item: "write",
119
+ delete_item: "write",
120
+ claim_item: "write",
121
+ // A project skill's text; records the read as proof of use on the caller's own tasks (A8.4).
122
+ get_skill: "read",
123
+ // Phase 32 C5.1 — which worktree a section is worked in: a plan edit.
124
+ assign_workstream: "write",
125
+ get_next_item: "read",
126
+ // Retired in Phase 31.1 — it refuses. Kept one release so an agent that
127
+ // learned it gets a direction rather than a missing tool.
128
+ approve_gate: "read",
129
+ list_criteria: "read",
130
+ record_artefact: "write",
131
+ add_criterion: "write",
132
+ submit_criterion: "write",
133
+ // Phase 31 §8 — the loops. Reads: they report, and a check run is a
134
+ // record of what was found, never a decision.
135
+ check_criterion: "read",
136
+ get_worklist: "read",
137
+ run_checks: "read",
138
+ // Phase 31 §5 — the Brief. Reading a material hands over a file's
139
+ // contents, so it is `files`, as reading any project file is.
140
+ get_brief: "read",
141
+ list_materials: "read",
142
+ read_material: "files",
143
+ list_items: "read",
144
+ search_items: "read",
145
+ get_plan_timeline: "read",
146
+ restore_item_version: "write",
147
+ list_item_versions: "read",
148
+ list_item_comments: "read",
149
+ resolve_reference: "read",
150
+ add_item_comment: "write",
151
+ update_item_progress: "write",
152
+ set_item_blocked: "write",
153
+ add_item_attachment: "write",
154
+ delete_item_comment: "write",
155
+ delete_item_attachment: "write",
156
+ list_external_refs: "read",
157
+ add_external_ref: "write",
158
+ remove_external_ref: "write",
159
+ suggest_specs: "read",
160
+ get_plan_summary: "read",
161
+ // ── plan-tools ──────────────────────────────────────────────────────
162
+ // The four file-mapping tools are `files`: they read and write plan
163
+ // documents on disk rather than rows in the database.
164
+ create_plan: "write",
165
+ get_plan: "read",
166
+ update_plan: "write",
167
+ list_plans: "read",
168
+ get_stack: "read",
169
+ get_play_forward: "read",
170
+ list_recurring: "read",
171
+ list_rules: "read",
172
+ // Phase 33 R3: proposes only; a person decides in the app. No tool writes a rule.
173
+ propose_rule: "write",
174
+ // Phase 33 V1: what a change does to the architecture, between two commits. Read only.
175
+ review_change: "read",
176
+ get_spec_links: "read",
177
+ list_spec_proposals: "read",
178
+ reply_to_spec_proposal: "write",
179
+ propose_spec_change: "write",
180
+ // Asks the person; deletes nothing (plan deletion left MCP in Phase 32 §0.4c-3).
181
+ request_plan_deletion: "write",
182
+ export_plan_to_files: "files",
183
+ import_plan_from_files: "files",
184
+ discover_plan_files: "files",
185
+ unlink_plan_from_files: "write",
186
+ publish_plan_as_template: "write",
187
+ list_plan_templates: "read",
188
+ create_plan_from_template: "write",
189
+ import_external: "write",
190
+ copy_plan_as_prompt: "read",
191
+ set_plan_home_repo: "write",
192
+ add_plan_scope: "write",
193
+ remove_plan_scope: "write",
194
+ list_plan_pointers: "read",
195
+ list_plans_by_repo: "read",
196
+ // ── presence-tools ──────────────────────────────────────────────────
197
+ // These interrupt the user with a modal and wait for them. Intrusive,
198
+ // and squarely a change to desktop state.
199
+ present: "write",
200
+ await_ack: "write",
201
+ dismiss_presence: "write",
202
+ await_user_input: "write",
203
+ // Waiting on a person's answer changes nothing; the answer is spent by the next call.
204
+ await_decision: "read",
205
+ // Asks whether a file is held by a breakpoint; records the hit so the person can answer it (B4.2).
206
+ check_breakpoint: "read",
207
+ check_changes: "read",
208
+ list_check_runs: "read",
209
+ // Phase 33 C4b: a review bundle, and a review reported and kept as a check run, as check_changes keeps one.
210
+ get_review_bundle: "read",
211
+ report_review: "read",
212
+ // Another workstream's changed lines, from git (B3.1): the repository, not an agent's words.
213
+ get_line_changes: "read",
214
+ // ── project-config-tools ────────────────────────────────────────────
215
+ get_project_config: "read",
216
+ update_project_config: "write",
217
+ // ── review-tools ────────────────────────────────────────────────────
218
+ // Read-only by construction: review and pr-draft never touch the
219
+ // repository, and comparands / compare only read snapshots. Same call
220
+ // the peer matrix makes for the identical four methods.
221
+ list_comparands: "read",
222
+ compare_snapshots: "read",
223
+ review_plan: "read",
224
+ get_pr_draft: "read",
225
+ get_review_queue: "read",
226
+ // ── session-tools ───────────────────────────────────────────────────
227
+ // `register_session` is the handshake and is deliberately the cheapest
228
+ // grant: an agent that cannot register cannot report itself at all, and
229
+ // refusing it would make the Timeline lie about who is connected.
230
+ //
231
+ // `setup_agent_permissions` WRITES `.claude/settings.local.json` to
232
+ // auto-approve every CodeTrellis MCP tool. That is a tool which widens the
233
+ // caller's own approval posture, so it sits with `settings` and out of the
234
+ // defaults — the same reasoning that keeps `settings.update` off a paired
235
+ // phone.
236
+ register_session: "read",
237
+ set_active_plan: "write",
238
+ navigate_to: "write",
239
+ open_plan: "write",
240
+ toggle_panel: "write",
241
+ refresh_ui: "write",
242
+ rescan_project: "project",
243
+ set_baseline: "write",
244
+ list_recent_projects: "read",
245
+ pin_project: "project",
246
+ unpin_project: "project",
247
+ remove_recent_project: "project",
248
+ close_project: "project",
249
+ get_repo_identity: "read",
250
+ set_repo_alias: "project",
251
+ refresh_repo_origin: "project",
252
+ navigate_item_back: "write",
253
+ navigate_item_forward: "write",
254
+ toggle_activity_drawer: "write",
255
+ open_history_drawer: "write",
256
+ open_settings: "write",
257
+ close_settings: "write",
258
+ open_mcp_guide: "write",
259
+ setup_agent_permissions: "settings",
260
+ // ── system-docs-tools ───────────────────────────────────────────────
261
+ list_system_docs: "read",
262
+ read_system_doc: "read",
263
+ write_system_doc: "write",
264
+ delete_system_doc: "write",
265
+ verify_system_doc: "write",
266
+ check_doc_freshness: "read",
267
+ // ── terminal-tools — COMMAND EXECUTION ──────────────────────────────
268
+ // Every one of them, including the read-shaped ones. A terminal's
269
+ // scrollback is the output of commands and frequently holds secrets; the
270
+ // peer matrix makes the same call for `terminal.read` and `terminal.list`.
271
+ terminal_create: "terminal",
272
+ terminal_write: "terminal",
273
+ terminal_read: "terminal",
274
+ terminal_list: "terminal",
275
+ terminal_kill: "terminal",
276
+ terminal_resize: "terminal",
277
+ terminal_focus: "terminal",
278
+ // ── ui-tools ────────────────────────────────────────────────────────
279
+ // `screenshot` captures the CodeTrellis window and `clipboard_read` returns
280
+ // whatever the user last copied — which is routinely a password or a token.
281
+ // Neither is a file, so `files` does not describe them, and putting them in
282
+ // `read` would have handed both to every client by default.
283
+ screenshot: "capture",
284
+ select_item: "write",
285
+ open_project: "project",
286
+ clipboard_write: "write",
287
+ clipboard_read: "capture",
288
+ get_settings: "read",
289
+ update_settings: "settings",
290
+ get_logs: "read",
291
+ get_log_path: "read",
292
+ get_app_guide: "read",
293
+ // ── contribution-tools ──────────────────────────────────────────────
294
+ resolve_pantry_references: "read",
295
+ promote_to_contribution: "write",
296
+ list_contributions: "read",
297
+ accept_contributions: "write",
298
+ prepare_contributor_branch: "write",
299
+ // ── audio-tools — THE USER'S MICROPHONE ─────────────────────────────
300
+ start_audio_capture: "capture",
301
+ stop_audio_capture: "capture",
302
+ push_audio_chunk: "capture",
303
+ get_audio_context: "capture",
304
+ get_audio_status: "capture",
305
+ // ── peer-tools ──────────────────────────────────────────────────────
306
+ // `write_remote_terminal` drives a terminal on a PAIRED DEVICE. It is
307
+ // command execution wearing a different name, and it is the single tool
308
+ // this whole phase exists for: it was registered through the deprecated
309
+ // `server.tool()` API, so it was not even visible in the Agent Timeline.
310
+ get_peer_status: "read",
311
+ list_discovered_peers: "read",
312
+ list_paired_devices: "read",
313
+ list_peer_connections: "read",
314
+ unpair_device: "settings",
315
+ get_remote_state: "read",
316
+ list_remote_terminals: "terminal",
317
+ write_remote_terminal: "terminal",
318
+ get_remote_audio: "capture",
319
+ list_remote_input_requests: "read",
320
+ respond_remote_input: "write",
321
+ // ── awareness-tools ─────────────────────────────────────────────────
322
+ // Phase 32 A1.3. Reads only: who else is working, and where.
323
+ list_workstreams: "read",
324
+ get_awareness: "read",
325
+ check_footprint: "read",
326
+ // A2.4: an agent says what it is about to change. It writes only its own
327
+ // session's intent, which ends with the session.
328
+ declare_intent: "write",
329
+ // A2.6: the agent's own note beside a signal; it never sets the person's answer.
330
+ acknowledge_signal: "write",
331
+ // B5.4: the project as it was at a moment. Reads only, like replay.
332
+ get_state_at: "read"
333
+ });
334
+ class McpAuthorizationError extends Error {
335
+ code = "EMCP_FORBIDDEN";
336
+ /** The capability the caller was missing, for the settings hint. */
337
+ required;
338
+ constructor(message, required) {
339
+ super(message);
340
+ this.name = "McpAuthorizationError";
341
+ this.required = required;
342
+ }
343
+ }
344
+ function assertMcpMayCall(tool, grants) {
345
+ const required = TOOL_CAPABILITIES[tool];
346
+ if (!required) {
347
+ throw new McpAuthorizationError(
348
+ `Tool "${tool}" is not authorised for MCP clients. Every tool must be listed in TOOL_CAPABILITIES; unlisted tools are refused.`,
349
+ null
350
+ );
351
+ }
352
+ const held = grants ?? import_peer_capabilities.DEFAULT_GRANTS;
353
+ if (!held.includes(required)) {
354
+ throw new McpAuthorizationError(
355
+ `"${tool}" needs the "${required}" capability, which this installation does not grant to MCP clients. Turn it on in Settings \u2192 MCP Server, then try again.`,
356
+ required
357
+ );
358
+ }
359
+ return required;
360
+ }
361
+ function listAuthorisedTools() {
362
+ return Object.keys(TOOL_CAPABILITIES).sort();
363
+ }
364
+ function assertMcpProjectInScope(tool, args, scope) {
365
+ if (scope === "anywhere") return;
366
+ const planDir = args?.plan_dir;
367
+ if (typeof planDir === "string" && planDir.trim().length > 0 && !(0, import_trusted_roots.isTrustedPlanDir)(planDir)) {
368
+ throw new McpAuthorizationError(
369
+ `"${tool}" named a plan directory outside the projects this app has opened: "${planDir}". Plan directories are read from <opened project>/.codetrellis/plans/<slug>. Open the project first, or set MCP project scope to "anywhere" in Settings \u2192 MCP Server.`,
370
+ null
371
+ );
372
+ }
373
+ const candidate = args?.project_path;
374
+ if (typeof candidate !== "string" || candidate.trim().length === 0) return;
375
+ if (!(0, import_trusted_roots.isTrustedProjectRoot)(candidate)) {
376
+ const evicted = (0, import_trusted_roots.evictedHint)(candidate);
377
+ throw new McpAuthorizationError(
378
+ `"${tool}" named a project that is not open: "${candidate}". ` + (evicted ? evicted : 'Project roots come from the projects this app has opened, not from the request. Open it first, or set MCP project scope to "anywhere" in Settings \u2192 MCP Server.'),
379
+ null
380
+ );
381
+ }
382
+ }
383
+ // Annotate the CommonJS export names for ESM import in node:
384
+ 0 && (module.exports = {
385
+ McpAuthorizationError,
386
+ TOOL_CAPABILITIES,
387
+ assertMcpMayCall,
388
+ assertMcpProjectInScope,
389
+ listAuthorisedTools
390
+ });
@@ -0,0 +1,304 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var mdns_service_exports = {};
29
+ __export(mdns_service_exports, {
30
+ getDiscoveredPeer: () => getDiscoveredPeer,
31
+ getDiscoveredPeers: () => getDiscoveredPeers,
32
+ getInstanceId: () => getInstanceId,
33
+ isMdnsRunning: () => isMdnsRunning,
34
+ onPeerDiscovered: () => onPeerDiscovered,
35
+ onPeerLost: () => onPeerLost,
36
+ startMdns: () => startMdns,
37
+ stopMdns: () => stopMdns,
38
+ updateAdvertisedName: () => updateAdvertisedName
39
+ });
40
+ module.exports = __toCommonJS(mdns_service_exports);
41
+ var import_node_os = __toESM(require("node:os"));
42
+ var import_node_fs = __toESM(require("node:fs"));
43
+ var import_node_path = __toESM(require("node:path"));
44
+ var import_node_crypto = require("node:crypto");
45
+ var import_build_info = require("../../shared/build-info");
46
+ var import_persistence = require("./persistence");
47
+ let Bonjour = null;
48
+ const SERVICE_TYPE = "codetrellis";
49
+ const STALE_PEER_MS = 12e4;
50
+ const BASE_ID_FILE = "mdns-instance-id";
51
+ const INSTANCES_FILE = "mdns-instances.json";
52
+ function isPidAlive(pid) {
53
+ if (!pid || pid === process.pid) return false;
54
+ try {
55
+ process.kill(pid, 0);
56
+ return true;
57
+ } catch (err) {
58
+ return err.code === "EPERM";
59
+ }
60
+ }
61
+ function readLiveInstances(dir) {
62
+ try {
63
+ const arr = JSON.parse(import_node_fs.default.readFileSync(import_node_path.default.join(dir, INSTANCES_FILE), "utf-8"));
64
+ return Array.isArray(arr) ? arr.filter((e) => e && typeof e.id === "string" && typeof e.pid === "number") : [];
65
+ } catch {
66
+ return [];
67
+ }
68
+ }
69
+ function writeLiveInstances(dir, list) {
70
+ try {
71
+ import_node_fs.default.mkdirSync(dir, { recursive: true });
72
+ const tmp = import_node_path.default.join(dir, `${INSTANCES_FILE}.tmp`);
73
+ import_node_fs.default.writeFileSync(tmp, JSON.stringify(list), "utf-8");
74
+ import_node_fs.default.renameSync(tmp, import_node_path.default.join(dir, INSTANCES_FILE));
75
+ } catch {
76
+ }
77
+ }
78
+ function loadStableBaseId(dir) {
79
+ try {
80
+ const file = import_node_path.default.join(dir, BASE_ID_FILE);
81
+ if (import_node_fs.default.existsSync(file)) {
82
+ const existing = import_node_fs.default.readFileSync(file, "utf-8").trim();
83
+ if (/^[0-9a-f]{8}$/i.test(existing)) return existing;
84
+ }
85
+ const id = (0, import_node_crypto.randomUUID)().slice(0, 8);
86
+ import_node_fs.default.mkdirSync(dir, { recursive: true });
87
+ import_node_fs.default.writeFileSync(file, id, "utf-8");
88
+ return id;
89
+ } catch {
90
+ return (0, import_node_crypto.randomUUID)().slice(0, 8);
91
+ }
92
+ }
93
+ function acquireInstanceId() {
94
+ let dir;
95
+ try {
96
+ dir = (0, import_persistence.getSettingsDir)();
97
+ } catch {
98
+ return (0, import_node_crypto.randomUUID)().slice(0, 8);
99
+ }
100
+ const baseId = loadStableBaseId(dir);
101
+ const live = readLiveInstances(dir).filter((e) => isPidAlive(e.pid));
102
+ const taken = new Set(live.map((e) => e.id));
103
+ let chosen = baseId;
104
+ if (taken.has(chosen)) {
105
+ for (let i = 0; i < 50 && taken.has(chosen); i++) {
106
+ chosen = `${baseId}${(0, import_node_crypto.randomUUID)().slice(0, 2)}`.slice(0, 12);
107
+ }
108
+ if (taken.has(chosen)) chosen = (0, import_node_crypto.randomUUID)().slice(0, 8);
109
+ console.log(`[mDNS] Base id ${baseId} held by a live instance \u2014 using ${chosen} to avoid an A-record collision.`);
110
+ }
111
+ writeLiveInstances(dir, [...live, { id: chosen, pid: process.pid, startedAt: (/* @__PURE__ */ new Date()).toISOString() }]);
112
+ return chosen;
113
+ }
114
+ function releaseInstanceId() {
115
+ try {
116
+ const dir = (0, import_persistence.getSettingsDir)();
117
+ writeLiveInstances(dir, readLiveInstances(dir).filter((e) => e.pid !== process.pid && isPidAlive(e.pid)));
118
+ } catch {
119
+ }
120
+ }
121
+ const instanceId = acquireInstanceId();
122
+ process.once("exit", () => releaseInstanceId());
123
+ let bonjourInstance = null;
124
+ let publishedService = null;
125
+ let browser = null;
126
+ let sweepInterval = null;
127
+ const peers = /* @__PURE__ */ new Map();
128
+ const listeners = {
129
+ discovered: /* @__PURE__ */ new Set(),
130
+ lost: /* @__PURE__ */ new Set()
131
+ };
132
+ function getInstanceId() {
133
+ return instanceId;
134
+ }
135
+ function startMdns(deviceName, fingerprint, mobileApiPort) {
136
+ stopMdns();
137
+ try {
138
+ if (!Bonjour) {
139
+ const mod = require("bonjour-service");
140
+ Bonjour = mod.default ?? mod.Bonjour ?? mod;
141
+ }
142
+ bonjourInstance = new Bonjour();
143
+ } catch (err) {
144
+ console.warn("[mDNS] Failed to initialise bonjour-service \u2014 discovery disabled:", err);
145
+ return;
146
+ }
147
+ const name = deviceName || import_node_os.default.hostname();
148
+ const version = import_build_info.BUILD_INFO?.version ?? "0.0.0";
149
+ const fp = fingerprint || "pending";
150
+ const advertisePort = mobileApiPort && mobileApiPort > 0 ? mobileApiPort : 1;
151
+ try {
152
+ publishedService = bonjourInstance.publish({
153
+ name: `${name} (${instanceId})`,
154
+ type: SERVICE_TYPE,
155
+ // Advertise under a unique, CodeTrellis-owned hostname rather than the
156
+ // machine's real `.local` name. bonjour-service runs its own mDNS
157
+ // responder and announces A-records for `host`; if that's the system
158
+ // hostname (the default), it collides with macOS's built-in Bonjour
159
+ // responder, which resolves the conflict by renaming the Mac to
160
+ // "…-2.local", "…-3.local" on every (especially unclean) restart.
161
+ // A dedicated host keeps discovery working (peers read the IP from the
162
+ // record's addresses) without ever touching the OS hostname.
163
+ host: `codetrellis-${instanceId}.local`,
164
+ port: advertisePort,
165
+ txt: {
166
+ instanceId,
167
+ version,
168
+ fingerprint: fp,
169
+ deviceName: name,
170
+ mobileApiPort: String(advertisePort)
171
+ }
172
+ });
173
+ console.log(`[mDNS] Advertising as "${name}" (${instanceId}) mobileApiPort=${advertisePort}`);
174
+ } catch (err) {
175
+ console.warn("[mDNS] Failed to publish service:", err);
176
+ }
177
+ try {
178
+ browser = bonjourInstance.find({ type: SERVICE_TYPE });
179
+ browser.on("up", (service) => {
180
+ const txt = service.txt ?? {};
181
+ const peerInstanceId = txt.instanceId;
182
+ if (!peerInstanceId || peerInstanceId === instanceId) return;
183
+ const address = service.addresses?.[0] ?? service.host ?? "";
184
+ const peer = {
185
+ instanceId: peerInstanceId,
186
+ name: txt.deviceName || "Unknown",
187
+ version: txt.version || "?",
188
+ fingerprint: txt.fingerprint || "",
189
+ address,
190
+ lastSeen: (/* @__PURE__ */ new Date()).toISOString()
191
+ };
192
+ const isNew = !peers.has(peerInstanceId);
193
+ peers.set(peerInstanceId, peer);
194
+ if (isNew) {
195
+ console.log(`[mDNS] Discovered peer: "${peer.name}" at ${peer.address}`);
196
+ for (const cb of listeners.discovered) {
197
+ try {
198
+ cb(peer);
199
+ } catch {
200
+ }
201
+ }
202
+ }
203
+ });
204
+ browser.on("down", (service) => {
205
+ const txt = service.txt ?? {};
206
+ const peerInstanceId = txt.instanceId;
207
+ if (!peerInstanceId) return;
208
+ const peer = peers.get(peerInstanceId);
209
+ if (peer) {
210
+ peers.delete(peerInstanceId);
211
+ console.log(`[mDNS] Lost peer: "${peer.name}"`);
212
+ for (const cb of listeners.lost) {
213
+ try {
214
+ cb(peer);
215
+ } catch {
216
+ }
217
+ }
218
+ }
219
+ });
220
+ console.log(`[mDNS] Browsing for _${SERVICE_TYPE}._tcp services`);
221
+ } catch (err) {
222
+ console.warn("[mDNS] Failed to start browser:", err);
223
+ }
224
+ sweepInterval = setInterval(() => {
225
+ const cutoff = Date.now() - STALE_PEER_MS;
226
+ for (const [id, peer] of peers) {
227
+ if (new Date(peer.lastSeen).getTime() < cutoff) {
228
+ peers.delete(id);
229
+ console.log(`[mDNS] Stale peer removed: "${peer.name}"`);
230
+ for (const cb of listeners.lost) {
231
+ try {
232
+ cb(peer);
233
+ } catch {
234
+ }
235
+ }
236
+ }
237
+ }
238
+ }, 3e4);
239
+ }
240
+ function stopMdns() {
241
+ if (sweepInterval) {
242
+ clearInterval(sweepInterval);
243
+ sweepInterval = null;
244
+ }
245
+ if (publishedService) {
246
+ try {
247
+ publishedService.stop?.();
248
+ } catch {
249
+ }
250
+ publishedService = null;
251
+ }
252
+ if (browser) {
253
+ try {
254
+ browser.stop();
255
+ } catch {
256
+ }
257
+ browser = null;
258
+ }
259
+ if (bonjourInstance) {
260
+ try {
261
+ bonjourInstance.destroy();
262
+ } catch {
263
+ }
264
+ bonjourInstance = null;
265
+ }
266
+ peers.clear();
267
+ }
268
+ function updateAdvertisedName(name, fingerprint, mobileApiPort) {
269
+ if (!bonjourInstance) return;
270
+ startMdns(name, fingerprint, mobileApiPort);
271
+ }
272
+ function getDiscoveredPeers() {
273
+ return Array.from(peers.values());
274
+ }
275
+ function getDiscoveredPeer(peerInstanceId) {
276
+ return peers.get(peerInstanceId);
277
+ }
278
+ function onPeerDiscovered(cb) {
279
+ listeners.discovered.add(cb);
280
+ return () => {
281
+ listeners.discovered.delete(cb);
282
+ };
283
+ }
284
+ function onPeerLost(cb) {
285
+ listeners.lost.add(cb);
286
+ return () => {
287
+ listeners.lost.delete(cb);
288
+ };
289
+ }
290
+ function isMdnsRunning() {
291
+ return bonjourInstance !== null;
292
+ }
293
+ // Annotate the CommonJS export names for ESM import in node:
294
+ 0 && (module.exports = {
295
+ getDiscoveredPeer,
296
+ getDiscoveredPeers,
297
+ getInstanceId,
298
+ isMdnsRunning,
299
+ onPeerDiscovered,
300
+ onPeerLost,
301
+ startMdns,
302
+ stopMdns,
303
+ updateAdvertisedName
304
+ });