@mesh-tech/mesh-cli 0.20.2 → 0.20.4

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 (436) hide show
  1. package/dist/bin/mesh.d.ts +0 -12
  2. package/dist/bin/mesh.js +15 -13
  3. package/dist/bin/mesh.js.map +1 -2
  4. package/dist/build-info.json +2 -2
  5. package/dist/src/commands/agent-api-client.d.ts +0 -70
  6. package/dist/src/commands/agent-api-client.js +0 -80
  7. package/dist/src/commands/app-check.d.ts +0 -56
  8. package/dist/src/commands/app-check.js +0 -72
  9. package/dist/src/commands/artifacts.d.ts +0 -11
  10. package/dist/src/commands/artifacts.js +0 -33
  11. package/dist/src/commands/cluster.d.ts +0 -39
  12. package/dist/src/commands/cluster.js +0 -73
  13. package/dist/src/commands/conversations.d.ts +0 -36
  14. package/dist/src/commands/conversations.js +0 -59
  15. package/dist/src/commands/create-app.d.ts +0 -98
  16. package/dist/src/commands/create-app.js +1 -163
  17. package/dist/src/commands/db/connect.d.ts +0 -7
  18. package/dist/src/commands/db/connect.js +0 -9
  19. package/dist/src/commands/db/credentials.d.ts +0 -7
  20. package/dist/src/commands/db/credentials.js +0 -10
  21. package/dist/src/commands/db/env.d.ts +0 -6
  22. package/dist/src/commands/db/env.js +0 -14
  23. package/dist/src/commands/db/exec.d.ts +0 -43
  24. package/dist/src/commands/db/exec.js +0 -69
  25. package/dist/src/commands/db/index.d.ts +0 -10
  26. package/dist/src/commands/db/index.js +0 -10
  27. package/dist/src/commands/db/psql.d.ts +0 -7
  28. package/dist/src/commands/db/psql.js +0 -18
  29. package/dist/src/commands/deploy.d.ts +0 -38
  30. package/dist/src/commands/deploy.js +1 -76
  31. package/dist/src/commands/dev-doctor.d.ts +0 -82
  32. package/dist/src/commands/dev-doctor.js +3 -132
  33. package/dist/src/commands/dev-launch.d.ts +0 -52
  34. package/dist/src/commands/dev-launch.js +0 -56
  35. package/dist/src/commands/dev-token-server.d.ts +0 -18
  36. package/dist/src/commands/dev-token-server.js +1 -24
  37. package/dist/src/commands/dev.d.ts +0 -246
  38. package/dist/src/commands/dev.js +5 -963
  39. package/dist/src/commands/docs.d.ts +0 -1
  40. package/dist/src/commands/docs.js +0 -12
  41. package/dist/src/commands/hub/index.d.ts +0 -60
  42. package/dist/src/commands/hub/index.js +2 -139
  43. package/dist/src/commands/init/wizard.d.ts +0 -128
  44. package/dist/src/commands/init/wizard.js +0 -109
  45. package/dist/src/commands/init.d.ts +0 -55
  46. package/dist/src/commands/init.js +0 -70
  47. package/dist/src/commands/install-shim.d.ts +0 -23
  48. package/dist/src/commands/install-shim.js +2 -29
  49. package/dist/src/commands/local/auth-provision.d.ts +0 -80
  50. package/dist/src/commands/local/auth-provision.js +0 -109
  51. package/dist/src/commands/local/dev-local.d.ts +0 -91
  52. package/dist/src/commands/local/dev-local.js +0 -147
  53. package/dist/src/commands/local/docker-runner.d.ts +0 -22
  54. package/dist/src/commands/local/docker-runner.js +2 -35
  55. package/dist/src/commands/local/helpers.d.ts +0 -14
  56. package/dist/src/commands/local/helpers.js +0 -13
  57. package/dist/src/commands/local/hub-local.d.ts +0 -96
  58. package/dist/src/commands/local/hub-local.js +0 -111
  59. package/dist/src/commands/local/index.d.ts +0 -14
  60. package/dist/src/commands/local/index.js +0 -86
  61. package/dist/src/commands/local/mocks.d.ts +0 -269
  62. package/dist/src/commands/local/mocks.js +1 -274
  63. package/dist/src/commands/local/seed-hub-catalog.d.ts +0 -25
  64. package/dist/src/commands/local/seed-hub-catalog.js +0 -41
  65. package/dist/src/commands/local/seed-zitadel.d.ts +0 -82
  66. package/dist/src/commands/local/seed-zitadel.js +0 -158
  67. package/dist/src/commands/local/seed.d.ts +0 -64
  68. package/dist/src/commands/local/seed.js +0 -78
  69. package/dist/src/commands/local/stack.d.ts +0 -141
  70. package/dist/src/commands/local/stack.js +0 -153
  71. package/dist/src/commands/login.d.ts +0 -265
  72. package/dist/src/commands/login.js +4 -418
  73. package/dist/src/commands/peer-addressing.d.ts +0 -39
  74. package/dist/src/commands/peer-addressing.js +0 -37
  75. package/dist/src/commands/port-ownership.d.ts +0 -44
  76. package/dist/src/commands/port-ownership.js +0 -47
  77. package/dist/src/commands/registry-publish.d.ts +0 -1
  78. package/dist/src/commands/registry-publish.js +0 -46
  79. package/dist/src/commands/registry.d.ts +4 -237
  80. package/dist/src/commands/registry.js +2 -316
  81. package/dist/src/commands/secrets/exec.d.ts +0 -16
  82. package/dist/src/commands/secrets/exec.js +0 -24
  83. package/dist/src/commands/secrets/index.d.ts +0 -9
  84. package/dist/src/commands/secrets/index.js +0 -10
  85. package/dist/src/commands/secrets/migrate-config.d.ts +0 -17
  86. package/dist/src/commands/secrets/migrate-config.js +0 -40
  87. package/dist/src/commands/secrets/reindex.d.ts +0 -38
  88. package/dist/src/commands/secrets/reindex.js +0 -39
  89. package/dist/src/commands/secrets/set.d.ts +0 -47
  90. package/dist/src/commands/secrets/set.js +0 -107
  91. package/dist/src/commands/site.d.ts +0 -1
  92. package/dist/src/commands/site.js +0 -61
  93. package/dist/src/commands/skills.d.ts +0 -61
  94. package/dist/src/commands/skills.js +0 -83
  95. package/dist/src/commands/stack.d.ts +0 -15
  96. package/dist/src/commands/stack.js +1 -128
  97. package/dist/src/commands/temporal.d.ts +0 -30
  98. package/dist/src/commands/temporal.js +3 -1
  99. package/dist/src/commands/temporal.js.map +1 -2
  100. package/dist/src/commands/tenant.d.ts +0 -31
  101. package/dist/src/commands/tenant.js +0 -55
  102. package/dist/src/commands/tunnel/index.d.ts +0 -40
  103. package/dist/src/commands/tunnel/index.js +0 -141
  104. package/dist/src/commands/vcs/clone.d.ts +0 -1
  105. package/dist/src/commands/vcs/clone.js +0 -4
  106. package/dist/src/commands/vcs/common.d.ts +0 -32
  107. package/dist/src/commands/vcs/common.js +0 -41
  108. package/dist/src/commands/vcs/drafts.d.ts +0 -1
  109. package/dist/src/commands/vcs/drafts.js +0 -1
  110. package/dist/src/commands/vcs/get.d.ts +0 -1
  111. package/dist/src/commands/vcs/get.js +0 -11
  112. package/dist/src/commands/vcs/index.d.ts +0 -1
  113. package/dist/src/commands/vcs/index.js +0 -1
  114. package/dist/src/commands/vcs/propose.d.ts +0 -26
  115. package/dist/src/commands/vcs/propose.js +3 -34
  116. package/dist/src/commands/vcs/review.d.ts +0 -1
  117. package/dist/src/commands/vcs/review.js +0 -1
  118. package/dist/src/commands/vcs/rm.d.ts +0 -11
  119. package/dist/src/commands/vcs/rm.js +0 -14
  120. package/dist/src/commands/vcs-enrich.d.ts +0 -12
  121. package/dist/src/commands/vcs-enrich.js +0 -12
  122. package/dist/src/commands/vpn/index.d.ts +0 -17
  123. package/dist/src/commands/vpn/index.js +0 -102
  124. package/dist/src/commands/vpn/tunnel.d.ts +0 -9
  125. package/dist/src/commands/vpn/tunnel.js +0 -37
  126. package/dist/src/commands/workflow.d.ts +0 -22
  127. package/dist/src/commands/workflow.js +0 -80
  128. package/dist/src/docs/assemble.d.ts +0 -117
  129. package/dist/src/docs/assemble.js +0 -142
  130. package/dist/src/docs/cli-reference.d.ts +0 -58
  131. package/dist/src/docs/cli-reference.js +0 -77
  132. package/dist/src/docs/discover.d.ts +0 -40
  133. package/dist/src/docs/discover.js +2 -60
  134. package/dist/src/docs/portal.d.ts +0 -44
  135. package/dist/src/docs/portal.js +0 -49
  136. package/dist/src/docs/registry-docs.d.ts +0 -29
  137. package/dist/src/docs/registry-docs.js +0 -40
  138. package/dist/src/docs/schema.d.ts +0 -36
  139. package/dist/src/docs/schema.js +0 -52
  140. package/dist/src/docs/serve.d.ts +0 -18
  141. package/dist/src/docs/serve.js +2 -30
  142. package/dist/src/docs/start.d.ts +0 -42
  143. package/dist/src/docs/start.js +0 -70
  144. package/dist/src/eval/agent-eval.d.mts +0 -12
  145. package/dist/src/eval/agent-eval.mjs +0 -22
  146. package/dist/src/index.d.ts +0 -6
  147. package/dist/src/index.js.map +0 -1
  148. package/dist/src/program.d.ts +0 -20
  149. package/dist/src/program.js +0 -24
  150. package/dist/src/utils/auth-preflight.d.ts +0 -137
  151. package/dist/src/utils/auth-preflight.js +0 -149
  152. package/dist/src/utils/aws-auth.d.ts +0 -163
  153. package/dist/src/utils/aws-auth.js +3 -232
  154. package/dist/src/utils/bastion.d.ts +0 -27
  155. package/dist/src/utils/bastion.js +0 -28
  156. package/dist/src/utils/build-info.d.ts +0 -22
  157. package/dist/src/utils/build-info.js +0 -27
  158. package/dist/src/utils/cache-home.d.ts +0 -23
  159. package/dist/src/utils/cache-home.js +0 -25
  160. package/dist/src/utils/capture-history.d.ts +0 -54
  161. package/dist/src/utils/capture-history.js +1 -55
  162. package/dist/src/utils/context.d.ts +0 -23
  163. package/dist/src/utils/context.js +0 -43
  164. package/dist/src/utils/credentials.d.ts +0 -38
  165. package/dist/src/utils/credentials.js +0 -39
  166. package/dist/src/utils/deploy-preflight.d.ts +0 -38
  167. package/dist/src/utils/deploy-preflight.js +1 -71
  168. package/dist/src/utils/errors.d.ts +0 -53
  169. package/dist/src/utils/errors.js +0 -49
  170. package/dist/src/utils/first-party-contexts.d.ts +0 -38
  171. package/dist/src/utils/first-party-contexts.js +0 -44
  172. package/dist/src/utils/index.d.ts +0 -4
  173. package/dist/src/utils/index.js +0 -4
  174. package/dist/src/utils/kubeconfig.d.ts +0 -40
  175. package/dist/src/utils/kubeconfig.js +0 -44
  176. package/dist/src/utils/log.d.ts +0 -20
  177. package/dist/src/utils/log.js +0 -20
  178. package/dist/src/utils/mesh-json.d.ts +0 -46
  179. package/dist/src/utils/mesh-json.js +0 -39
  180. package/dist/src/utils/pid.d.ts +0 -42
  181. package/dist/src/utils/pid.js +0 -48
  182. package/dist/src/utils/pulumi-run.d.ts +0 -14
  183. package/dist/src/utils/pulumi-run.js +0 -42
  184. package/dist/src/utils/pulumi.d.ts +0 -34
  185. package/dist/src/utils/pulumi.js +0 -38
  186. package/dist/src/utils/reachability.d.ts +0 -27
  187. package/dist/src/utils/reachability.js +0 -40
  188. package/dist/src/utils/recover-conversation.d.ts +0 -110
  189. package/dist/src/utils/recover-conversation.js +0 -108
  190. package/dist/src/utils/registry-broker.d.ts +5 -84
  191. package/dist/src/utils/registry-broker.js +0 -62
  192. package/dist/src/utils/registry-identity.d.ts +0 -149
  193. package/dist/src/utils/registry-identity.js +0 -143
  194. package/dist/src/utils/scaffold-versions.d.ts +0 -41
  195. package/dist/src/utils/scaffold-versions.js +0 -42
  196. package/dist/src/utils/socks-forward.d.ts +0 -24
  197. package/dist/src/utils/socks-forward.js +2 -25
  198. package/dist/src/utils/stack-flag.d.ts +0 -13
  199. package/dist/src/utils/stack-flag.js +0 -21
  200. package/dist/src/utils/tailscale-targets.d.ts +0 -37
  201. package/dist/src/utils/tailscale-targets.js +0 -33
  202. package/dist/src/utils/tailscale.d.ts +0 -177
  203. package/dist/src/utils/tailscale.js +6 -337
  204. package/dist/src/utils/temporal-auth.d.ts +0 -41
  205. package/dist/src/utils/temporal-auth.js +0 -52
  206. package/dist/src/utils/temporal-codec.d.ts +0 -89
  207. package/dist/src/utils/temporal-codec.js.map +0 -1
  208. package/dist/src/utils/tunnel-ownership.d.ts +0 -79
  209. package/dist/src/utils/tunnel-ownership.js +0 -74
  210. package/dist/src/utils/vpn-join.d.ts +0 -16
  211. package/dist/src/utils/vpn-join.js +0 -17
  212. package/dist/src/utils/vpn.d.ts +0 -42
  213. package/dist/src/utils/vpn.js +0 -52
  214. package/dist/src/utils/workflow-fingerprint.d.ts +0 -39
  215. package/dist/src/utils/workflow-fingerprint.js +1 -63
  216. package/dist/src/utils/worktree-identity.d.ts +0 -62
  217. package/dist/src/utils/worktree-identity.js +0 -88
  218. package/package.json +2 -2
  219. package/skills/core/SKILL.md +9 -10
  220. package/templates/api-auth/api/src/index.ts.hbs +1 -1
  221. package/templates/api-auth/api/src/spicedb-http-provider.ts.hbs +2 -2
  222. package/templates/api-role-gating/api/src/authn.ts.hbs +2 -2
  223. package/templates/api-role-gating/index.ts.hbs +1 -1
  224. package/templates/api-role-gating/skills/develop/SKILL.md.hbs +1 -1
  225. package/templates/platform-repo/core/Pulumi.{{tenant}}-{{env}}.yaml.hbs +2 -2
  226. package/templates/platform-repo/platform/index.ts +1 -1
  227. package/dist/bin/mesh.d.ts.map +0 -1
  228. package/dist/src/commands/agent-api-client.d.ts.map +0 -1
  229. package/dist/src/commands/agent-api-client.js.map +0 -1
  230. package/dist/src/commands/app-check.d.ts.map +0 -1
  231. package/dist/src/commands/app-check.js.map +0 -1
  232. package/dist/src/commands/artifacts.d.ts.map +0 -1
  233. package/dist/src/commands/artifacts.js.map +0 -1
  234. package/dist/src/commands/cluster.d.ts.map +0 -1
  235. package/dist/src/commands/cluster.js.map +0 -1
  236. package/dist/src/commands/conversations.d.ts.map +0 -1
  237. package/dist/src/commands/conversations.js.map +0 -1
  238. package/dist/src/commands/create-app.d.ts.map +0 -1
  239. package/dist/src/commands/create-app.js.map +0 -1
  240. package/dist/src/commands/db/connect.d.ts.map +0 -1
  241. package/dist/src/commands/db/connect.js.map +0 -1
  242. package/dist/src/commands/db/credentials.d.ts.map +0 -1
  243. package/dist/src/commands/db/credentials.js.map +0 -1
  244. package/dist/src/commands/db/env.d.ts.map +0 -1
  245. package/dist/src/commands/db/env.js.map +0 -1
  246. package/dist/src/commands/db/exec.d.ts.map +0 -1
  247. package/dist/src/commands/db/exec.js.map +0 -1
  248. package/dist/src/commands/db/index.d.ts.map +0 -1
  249. package/dist/src/commands/db/index.js.map +0 -1
  250. package/dist/src/commands/db/psql.d.ts.map +0 -1
  251. package/dist/src/commands/db/psql.js.map +0 -1
  252. package/dist/src/commands/deploy.d.ts.map +0 -1
  253. package/dist/src/commands/deploy.js.map +0 -1
  254. package/dist/src/commands/dev-doctor.d.ts.map +0 -1
  255. package/dist/src/commands/dev-doctor.js.map +0 -1
  256. package/dist/src/commands/dev-launch.d.ts.map +0 -1
  257. package/dist/src/commands/dev-launch.js.map +0 -1
  258. package/dist/src/commands/dev-token-server.d.ts.map +0 -1
  259. package/dist/src/commands/dev-token-server.js.map +0 -1
  260. package/dist/src/commands/dev.d.ts.map +0 -1
  261. package/dist/src/commands/dev.js.map +0 -1
  262. package/dist/src/commands/docs.d.ts.map +0 -1
  263. package/dist/src/commands/docs.js.map +0 -1
  264. package/dist/src/commands/hub/index.d.ts.map +0 -1
  265. package/dist/src/commands/hub/index.js.map +0 -1
  266. package/dist/src/commands/init/wizard.d.ts.map +0 -1
  267. package/dist/src/commands/init/wizard.js.map +0 -1
  268. package/dist/src/commands/init.d.ts.map +0 -1
  269. package/dist/src/commands/init.js.map +0 -1
  270. package/dist/src/commands/install-shim.d.ts.map +0 -1
  271. package/dist/src/commands/install-shim.js.map +0 -1
  272. package/dist/src/commands/local/auth-provision.d.ts.map +0 -1
  273. package/dist/src/commands/local/auth-provision.js.map +0 -1
  274. package/dist/src/commands/local/dev-local.d.ts.map +0 -1
  275. package/dist/src/commands/local/dev-local.js.map +0 -1
  276. package/dist/src/commands/local/docker-runner.d.ts.map +0 -1
  277. package/dist/src/commands/local/docker-runner.js.map +0 -1
  278. package/dist/src/commands/local/helpers.d.ts.map +0 -1
  279. package/dist/src/commands/local/helpers.js.map +0 -1
  280. package/dist/src/commands/local/hub-local.d.ts.map +0 -1
  281. package/dist/src/commands/local/hub-local.js.map +0 -1
  282. package/dist/src/commands/local/index.d.ts.map +0 -1
  283. package/dist/src/commands/local/index.js.map +0 -1
  284. package/dist/src/commands/local/mocks.d.ts.map +0 -1
  285. package/dist/src/commands/local/mocks.js.map +0 -1
  286. package/dist/src/commands/local/seed-hub-catalog.d.ts.map +0 -1
  287. package/dist/src/commands/local/seed-hub-catalog.js.map +0 -1
  288. package/dist/src/commands/local/seed-zitadel.d.ts.map +0 -1
  289. package/dist/src/commands/local/seed-zitadel.js.map +0 -1
  290. package/dist/src/commands/local/seed.d.ts.map +0 -1
  291. package/dist/src/commands/local/seed.js.map +0 -1
  292. package/dist/src/commands/local/stack.d.ts.map +0 -1
  293. package/dist/src/commands/local/stack.js.map +0 -1
  294. package/dist/src/commands/login.d.ts.map +0 -1
  295. package/dist/src/commands/login.js.map +0 -1
  296. package/dist/src/commands/peer-addressing.d.ts.map +0 -1
  297. package/dist/src/commands/peer-addressing.js.map +0 -1
  298. package/dist/src/commands/port-ownership.d.ts.map +0 -1
  299. package/dist/src/commands/port-ownership.js.map +0 -1
  300. package/dist/src/commands/registry-publish.d.ts.map +0 -1
  301. package/dist/src/commands/registry-publish.js.map +0 -1
  302. package/dist/src/commands/registry.d.ts.map +0 -1
  303. package/dist/src/commands/registry.js.map +0 -1
  304. package/dist/src/commands/secrets/exec.d.ts.map +0 -1
  305. package/dist/src/commands/secrets/exec.js.map +0 -1
  306. package/dist/src/commands/secrets/index.d.ts.map +0 -1
  307. package/dist/src/commands/secrets/index.js.map +0 -1
  308. package/dist/src/commands/secrets/migrate-config.d.ts.map +0 -1
  309. package/dist/src/commands/secrets/migrate-config.js.map +0 -1
  310. package/dist/src/commands/secrets/reindex.d.ts.map +0 -1
  311. package/dist/src/commands/secrets/reindex.js.map +0 -1
  312. package/dist/src/commands/secrets/set.d.ts.map +0 -1
  313. package/dist/src/commands/secrets/set.js.map +0 -1
  314. package/dist/src/commands/site.d.ts.map +0 -1
  315. package/dist/src/commands/site.js.map +0 -1
  316. package/dist/src/commands/skills.d.ts.map +0 -1
  317. package/dist/src/commands/skills.js.map +0 -1
  318. package/dist/src/commands/stack.d.ts.map +0 -1
  319. package/dist/src/commands/stack.js.map +0 -1
  320. package/dist/src/commands/temporal.d.ts.map +0 -1
  321. package/dist/src/commands/tenant.d.ts.map +0 -1
  322. package/dist/src/commands/tenant.js.map +0 -1
  323. package/dist/src/commands/tunnel/index.d.ts.map +0 -1
  324. package/dist/src/commands/tunnel/index.js.map +0 -1
  325. package/dist/src/commands/vcs/clone.d.ts.map +0 -1
  326. package/dist/src/commands/vcs/clone.js.map +0 -1
  327. package/dist/src/commands/vcs/common.d.ts.map +0 -1
  328. package/dist/src/commands/vcs/common.js.map +0 -1
  329. package/dist/src/commands/vcs/drafts.d.ts.map +0 -1
  330. package/dist/src/commands/vcs/drafts.js.map +0 -1
  331. package/dist/src/commands/vcs/get.d.ts.map +0 -1
  332. package/dist/src/commands/vcs/get.js.map +0 -1
  333. package/dist/src/commands/vcs/index.d.ts.map +0 -1
  334. package/dist/src/commands/vcs/index.js.map +0 -1
  335. package/dist/src/commands/vcs/propose.d.ts.map +0 -1
  336. package/dist/src/commands/vcs/propose.js.map +0 -1
  337. package/dist/src/commands/vcs/review.d.ts.map +0 -1
  338. package/dist/src/commands/vcs/review.js.map +0 -1
  339. package/dist/src/commands/vcs/rm.d.ts.map +0 -1
  340. package/dist/src/commands/vcs/rm.js.map +0 -1
  341. package/dist/src/commands/vcs-enrich.d.ts.map +0 -1
  342. package/dist/src/commands/vcs-enrich.js.map +0 -1
  343. package/dist/src/commands/vpn/index.d.ts.map +0 -1
  344. package/dist/src/commands/vpn/index.js.map +0 -1
  345. package/dist/src/commands/vpn/tunnel.d.ts.map +0 -1
  346. package/dist/src/commands/vpn/tunnel.js.map +0 -1
  347. package/dist/src/commands/workflow.d.ts.map +0 -1
  348. package/dist/src/commands/workflow.js.map +0 -1
  349. package/dist/src/docs/assemble.d.ts.map +0 -1
  350. package/dist/src/docs/assemble.js.map +0 -1
  351. package/dist/src/docs/cli-reference.d.ts.map +0 -1
  352. package/dist/src/docs/cli-reference.js.map +0 -1
  353. package/dist/src/docs/discover.d.ts.map +0 -1
  354. package/dist/src/docs/discover.js.map +0 -1
  355. package/dist/src/docs/portal.d.ts.map +0 -1
  356. package/dist/src/docs/portal.js.map +0 -1
  357. package/dist/src/docs/registry-docs.d.ts.map +0 -1
  358. package/dist/src/docs/registry-docs.js.map +0 -1
  359. package/dist/src/docs/schema.d.ts.map +0 -1
  360. package/dist/src/docs/schema.js.map +0 -1
  361. package/dist/src/docs/serve.d.ts.map +0 -1
  362. package/dist/src/docs/serve.js.map +0 -1
  363. package/dist/src/docs/start.d.ts.map +0 -1
  364. package/dist/src/docs/start.js.map +0 -1
  365. package/dist/src/eval/agent-eval.d.mts.map +0 -1
  366. package/dist/src/eval/agent-eval.mjs.map +0 -1
  367. package/dist/src/index.d.ts.map +0 -1
  368. package/dist/src/program.d.ts.map +0 -1
  369. package/dist/src/program.js.map +0 -1
  370. package/dist/src/utils/auth-preflight.d.ts.map +0 -1
  371. package/dist/src/utils/auth-preflight.js.map +0 -1
  372. package/dist/src/utils/aws-auth.d.ts.map +0 -1
  373. package/dist/src/utils/aws-auth.js.map +0 -1
  374. package/dist/src/utils/bastion.d.ts.map +0 -1
  375. package/dist/src/utils/bastion.js.map +0 -1
  376. package/dist/src/utils/build-info.d.ts.map +0 -1
  377. package/dist/src/utils/build-info.js.map +0 -1
  378. package/dist/src/utils/cache-home.d.ts.map +0 -1
  379. package/dist/src/utils/cache-home.js.map +0 -1
  380. package/dist/src/utils/capture-history.d.ts.map +0 -1
  381. package/dist/src/utils/capture-history.js.map +0 -1
  382. package/dist/src/utils/context.d.ts.map +0 -1
  383. package/dist/src/utils/context.js.map +0 -1
  384. package/dist/src/utils/credentials.d.ts.map +0 -1
  385. package/dist/src/utils/credentials.js.map +0 -1
  386. package/dist/src/utils/deploy-preflight.d.ts.map +0 -1
  387. package/dist/src/utils/deploy-preflight.js.map +0 -1
  388. package/dist/src/utils/errors.d.ts.map +0 -1
  389. package/dist/src/utils/errors.js.map +0 -1
  390. package/dist/src/utils/first-party-contexts.d.ts.map +0 -1
  391. package/dist/src/utils/first-party-contexts.js.map +0 -1
  392. package/dist/src/utils/index.d.ts.map +0 -1
  393. package/dist/src/utils/index.js.map +0 -1
  394. package/dist/src/utils/kubeconfig.d.ts.map +0 -1
  395. package/dist/src/utils/kubeconfig.js.map +0 -1
  396. package/dist/src/utils/log.d.ts.map +0 -1
  397. package/dist/src/utils/log.js.map +0 -1
  398. package/dist/src/utils/mesh-json.d.ts.map +0 -1
  399. package/dist/src/utils/mesh-json.js.map +0 -1
  400. package/dist/src/utils/pid.d.ts.map +0 -1
  401. package/dist/src/utils/pid.js.map +0 -1
  402. package/dist/src/utils/pulumi-run.d.ts.map +0 -1
  403. package/dist/src/utils/pulumi-run.js.map +0 -1
  404. package/dist/src/utils/pulumi.d.ts.map +0 -1
  405. package/dist/src/utils/pulumi.js.map +0 -1
  406. package/dist/src/utils/reachability.d.ts.map +0 -1
  407. package/dist/src/utils/reachability.js.map +0 -1
  408. package/dist/src/utils/recover-conversation.d.ts.map +0 -1
  409. package/dist/src/utils/recover-conversation.js.map +0 -1
  410. package/dist/src/utils/registry-broker.d.ts.map +0 -1
  411. package/dist/src/utils/registry-broker.js.map +0 -1
  412. package/dist/src/utils/registry-identity.d.ts.map +0 -1
  413. package/dist/src/utils/registry-identity.js.map +0 -1
  414. package/dist/src/utils/scaffold-versions.d.ts.map +0 -1
  415. package/dist/src/utils/scaffold-versions.js.map +0 -1
  416. package/dist/src/utils/socks-forward.d.ts.map +0 -1
  417. package/dist/src/utils/socks-forward.js.map +0 -1
  418. package/dist/src/utils/stack-flag.d.ts.map +0 -1
  419. package/dist/src/utils/stack-flag.js.map +0 -1
  420. package/dist/src/utils/tailscale-targets.d.ts.map +0 -1
  421. package/dist/src/utils/tailscale-targets.js.map +0 -1
  422. package/dist/src/utils/tailscale.d.ts.map +0 -1
  423. package/dist/src/utils/tailscale.js.map +0 -1
  424. package/dist/src/utils/temporal-auth.d.ts.map +0 -1
  425. package/dist/src/utils/temporal-auth.js.map +0 -1
  426. package/dist/src/utils/temporal-codec.d.ts.map +0 -1
  427. package/dist/src/utils/tunnel-ownership.d.ts.map +0 -1
  428. package/dist/src/utils/tunnel-ownership.js.map +0 -1
  429. package/dist/src/utils/vpn-join.d.ts.map +0 -1
  430. package/dist/src/utils/vpn-join.js.map +0 -1
  431. package/dist/src/utils/vpn.d.ts.map +0 -1
  432. package/dist/src/utils/vpn.js.map +0 -1
  433. package/dist/src/utils/workflow-fingerprint.d.ts.map +0 -1
  434. package/dist/src/utils/workflow-fingerprint.js.map +0 -1
  435. package/dist/src/utils/worktree-identity.d.ts.map +0 -1
  436. package/dist/src/utils/worktree-identity.js.map +0 -1
@@ -1,12 +1,3 @@
1
- /**
2
- * Userspace-Tailscale daemon management + tunnel-session state for
3
- * `mesh vpn tunnel` (MESH-2040 / Slice 1 of MESH-2014).
4
- *
5
- * A per-tenant `tailscaled` runs in userspace-networking mode (brew formula,
6
- * NOT the GUI app) exposing a SOCKS5 proxy; forwarders bridge `localhost:PORT`
7
- * to VPC services through it. State lives under `~/.config/mesh/tailscale/<tenant>/`
8
- * (r+w-granted under safehouse — see the MESH-2036 spike).
9
- */
10
1
  import * as fs from "node:fs";
11
2
  import * as net from "node:net";
12
3
  import * as os from "node:os";
@@ -22,9 +13,6 @@ import { resolveTunnelTargets, resolveElbIp, tenantPortIndex, PORT_BLOCK } from
22
13
  import { createForwarder } from "./socks-forward.js";
23
14
  import { mintRunnerToken, readRunnerManifest, writeRunnerManifest, clearRunnerManifest, getProcessGroupId, discoverRunnerPids, startControlServer, verifyRunnerOwnership, pollOwnership, findSquattedPorts, buildSquatterError, } from "./tunnel-ownership.js";
24
15
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
25
- // ============================================================================
26
- // Paths
27
- // ============================================================================
28
16
  export function tenantStateDir(tenant) {
29
17
  return path.join(CONFIG_DIR, "tailscale", tenant);
30
18
  }
@@ -37,22 +25,9 @@ export function logPath(tenant) {
37
25
  export function statePath(tenant) {
38
26
  return path.join(tenantStateDir(tenant), "tunnel-state.json");
39
27
  }
40
- /**
41
- * Daemon-scoped metadata, written by `ensureDaemon` when it actually spawns the
42
- * daemon. Unlike `tunnel-state.json` (which `down` clears), this survives `down`
43
- * so a later `up` reuses the RUNNING daemon's SOCKS port instead of minting a
44
- * fresh one the daemon isn't listening on (which would leave every forwarder
45
- * dialing a dead port). Also records the daemon pid so `stopDaemon` can kill it.
46
- */
47
28
  export function daemonMetaPath(tenant) {
48
29
  return path.join(tenantStateDir(tenant), "daemon.json");
49
30
  }
50
- /**
51
- * Ownership manifest written by the RUNNER (the process that binds the
52
- * forwarder ports) — pid, process-group id, per-run token, control port. The
53
- * ownership handshake (MESH-2407) verifies against it; teardown signals the
54
- * recorded process group.
55
- */
56
31
  export function runnerManifestPath(tenant) {
57
32
  return path.join(tenantStateDir(tenant), "runner.json");
58
33
  }
@@ -76,7 +51,6 @@ export function clearTunnelState(tenant) {
76
51
  fs.unlinkSync(statePath(tenant));
77
52
  }
78
53
  catch {
79
- /* already gone */
80
54
  }
81
55
  }
82
56
  export function readDaemonMeta(tenant) {
@@ -99,13 +73,8 @@ export function clearDaemonMeta(tenant) {
99
73
  fs.unlinkSync(daemonMetaPath(tenant));
100
74
  }
101
75
  catch {
102
- /* already gone */
103
76
  }
104
77
  }
105
- // ============================================================================
106
- // Daemon status parsing
107
- // ============================================================================
108
- /** Parse `tailscale status --json` → the fields we care about. */
109
78
  export function parseDaemonState(statusJson) {
110
79
  try {
111
80
  const j = JSON.parse(statusJson);
@@ -115,14 +84,9 @@ export function parseDaemonState(statusJson) {
115
84
  return { backendState: "Unknown" };
116
85
  }
117
86
  }
118
- // ============================================================================
119
- // Binary resolution (macOS / brew — Slice 1)
120
- // ============================================================================
121
- /** The brew `tailscaled` (NOT the GUI app, which ships no standalone daemon). */
122
87
  export function tailscaledBinPath() {
123
88
  return resolveBrewBin("tailscaled");
124
89
  }
125
- /** The brew `tailscale` CLI (prefer it over the GUI shim, which aborts under sandbox). */
126
90
  export function tailscaleBinPath() {
127
91
  return resolveBrewBin("tailscale");
128
92
  }
@@ -136,14 +100,9 @@ function resolveBrewBin(name) {
136
100
  return p;
137
101
  }
138
102
  catch {
139
- /* fall through */
140
103
  }
141
104
  throw new Error(`${name} not found — install the standalone binary: brew install tailscale`);
142
105
  }
143
- // ============================================================================
144
- // Daemon lifecycle
145
- // ============================================================================
146
- /** Backend state via the tenant's control socket; "Down" when no daemon answers. */
147
106
  export function daemonState(tenant) {
148
107
  if (!fs.existsSync(socketPath(tenant)))
149
108
  return { backendState: "Down" };
@@ -155,12 +114,6 @@ export function daemonState(tenant) {
155
114
  return { backendState: "Down" };
156
115
  }
157
116
  }
158
- /**
159
- * Extract the `--socks5-server` port from a `tailscaled` command line. Pure so
160
- * it's unit-testable. Accepts both `--socks5-server=127.0.0.1:PORT` and the
161
- * space-separated form, and a `localhost` host literal. Returns null if absent
162
- * or malformed.
163
- */
164
117
  export function parseSocksPortFromArgv(argv) {
165
118
  const m = argv.match(/--socks5-server[=\s]+(?:127\.0\.0\.1|localhost):(\d+)/);
166
119
  if (!m)
@@ -168,13 +121,6 @@ export function parseSocksPortFromArgv(argv) {
168
121
  const port = Number(m[1]);
169
122
  return Number.isInteger(port) && port > 0 && port <= 65535 ? port : null;
170
123
  }
171
- /**
172
- * Find the running userspace `tailscaled` for a tenant by its unique
173
- * `--socket=<path>` argument, returning its pid and the SOCKS port it ACTUALLY
174
- * bound (parsed from argv). Authoritative when `daemon.json` is missing or stale
175
- * (e.g. a daemon left by an older build that predates the meta file). Returns
176
- * null when no matching process is found or `ps` is unavailable.
177
- */
178
124
  export function findRunningDaemon(tenant) {
179
125
  const sock = socketPath(tenant);
180
126
  let out;
@@ -188,8 +134,6 @@ export function findRunningDaemon(tenant) {
188
134
  return null;
189
135
  }
190
136
  for (const line of out.split("\n")) {
191
- // Match this tenant's daemon by its unique --socket path (skips the ps line,
192
- // other tenants' daemons, and the GUI app).
193
137
  if (!line.includes("tailscaled") || !line.includes(`--socket=${sock}`))
194
138
  continue;
195
139
  const m = line.trim().match(/^(\d+)\s+(.*)$/);
@@ -199,7 +143,6 @@ export function findRunningDaemon(tenant) {
199
143
  }
200
144
  return null;
201
145
  }
202
- /** True if something accepts TCP on 127.0.0.1:port within `timeoutMs`. */
203
146
  export function portAccepts(port, timeoutMs = 400) {
204
147
  return new Promise((resolve) => {
205
148
  const s = new net.Socket();
@@ -218,18 +161,8 @@ export function portAccepts(port, timeoutMs = 400) {
218
161
  s.connect(port, "127.0.0.1");
219
162
  });
220
163
  }
221
- /**
222
- * Ensure a userspace `tailscaled` is running for the tenant and return the SOCKS
223
- * port the forwarders should dial. Idempotent — reuses a live daemon, but
224
- * RECONCILES the port: a daemon that's up on a different port than requested
225
- * (older build with no `daemon.json`, or stale meta) would otherwise leave every
226
- * forwarder dialing a dead port (MESH-2169). Trust `opts.socksPort` only if it
227
- * truly accepts; else adopt the running daemon's real port; else restart fresh.
228
- */
229
164
  export async function ensureDaemon(tenant, opts) {
230
165
  if (daemonState(tenant).backendState !== "Down") {
231
- // The daemon's SOCKS proxy is only useful on the exact port the forwarders
232
- // will dial. If the requested port already accepts, record it and use it.
233
166
  if (await portAccepts(opts.socksPort)) {
234
167
  writeDaemonMeta(tenant, {
235
168
  socksPort: opts.socksPort,
@@ -237,17 +170,11 @@ export async function ensureDaemon(tenant, opts) {
237
170
  });
238
171
  return opts.socksPort;
239
172
  }
240
- // Requested port is dead — the daemon is on a different one. Discover its
241
- // real SOCKS port from argv and adopt it (no restart → no severing other
242
- // sessions), rewriting daemon.json so future runs read the right port.
243
173
  const running = findRunningDaemon(tenant);
244
174
  if (running?.socksPort && (await portAccepts(running.socksPort))) {
245
175
  writeDaemonMeta(tenant, { socksPort: running.socksPort, pid: running.pid });
246
176
  return running.socksPort;
247
177
  }
248
- // Can't discover/verify a working SOCKS port — the daemon is unusable to us.
249
- // Tear it down (state dir keeps the node identity → no re-login) and fall
250
- // through to a fresh start on opts.socksPort.
251
178
  stopDaemon(tenant);
252
179
  for (let i = 0; i < 12 && daemonState(tenant).backendState !== "Down"; i++) {
253
180
  await sleep(250);
@@ -269,8 +196,6 @@ export async function ensureDaemon(tenant, opts) {
269
196
  env: { ...process.env, AWS_REGION: opts.region },
270
197
  });
271
198
  child.unref();
272
- // Persist the socks port + pid so `down` → `up` reuses this daemon's real
273
- // port (not a fresh one it isn't listening on) and `stopDaemon` can kill it.
274
199
  if (child.pid)
275
200
  writeDaemonMeta(tenant, { socksPort: opts.socksPort, pid: child.pid });
276
201
  }
@@ -284,31 +209,11 @@ export async function ensureDaemon(tenant, opts) {
284
209
  }
285
210
  throw new Error(`tailscaled did not start for tenant '${tenant}' — see ${logPath(tenant)}`);
286
211
  }
287
- /**
288
- * Stop the detached `tailscaled` for a tenant (SIGTERM its pid) and remove the
289
- * socket + daemon metadata. Leaves the Headscale node identity in `tailscaled.state`
290
- * so a later `up` re-spawns and rejoins without an interactive re-login — unless
291
- * the caller logged out first.
292
- *
293
- * Best-effort, and that includes a corrupt `daemon.json`: an unsignalable
294
- * recorded pid is REFUSED (never handed to `kill`) but only warns — the socket
295
- * and meta are still cleared. `ensureDaemon` calls this on the UP path to
296
- * recycle a daemon it can't verify, so throwing here would dead-end
297
- * `mesh vpn tunnel up` / `mesh dev` on the very file this function deletes.
298
- * Safe to call when nothing is running.
299
- */
300
212
  export function stopDaemon(tenant) {
301
- // Prefer the recorded pid; fall back to discovering it from argv so a daemon
302
- // left without a daemon.json (older build / cleared meta) can still be killed.
303
213
  const meta = readDaemonMeta(tenant) ?? (() => {
304
214
  const running = findRunningDaemon(tenant);
305
215
  return running ? { socksPort: running.socksPort ?? 0, pid: running.pid } : null;
306
216
  })();
307
- // `ensureDaemon` records `pid: 0` when it adopts a running daemon whose pid it
308
- // could not attribute, so absent-or-0 is this file's "no pid known" sentinel —
309
- // skip it, don't signal and don't fail. EVERY other unsignalable value (1, a
310
- // negative, a fraction, a string from a truncated/hand-edited daemon.json) is
311
- // corruption and must be refused rather than handed to kill. See utils/pid.ts.
312
217
  if (meta?.pid) {
313
218
  try {
314
219
  assertSignalablePid(meta.pid, {
@@ -318,13 +223,8 @@ export function stopDaemon(tenant) {
318
223
  process.kill(meta.pid, "SIGTERM");
319
224
  }
320
225
  catch (err) {
321
- // Refusing to SIGNAL is the whole point; refusing to CLEAN UP is not.
322
- // The unlink + clearDaemonMeta below are what make the corrupt file
323
- // self-healing, and `ensureDaemon` (the UP path) depends on them. Warn
324
- // with the `rm` remediation intact and fall through.
325
226
  if (err instanceof MeshCliError)
326
227
  logWarn(renderErrorBody(err));
327
- /* else: ESRCH/EPERM from process.kill — already gone, as before */
328
228
  }
329
229
  }
330
230
  for (const p of [socketPath(tenant)]) {
@@ -332,16 +232,10 @@ export function stopDaemon(tenant) {
332
232
  fs.unlinkSync(p);
333
233
  }
334
234
  catch {
335
- /* already gone */
336
235
  }
337
236
  }
338
237
  clearDaemonMeta(tenant);
339
238
  }
340
- /**
341
- * Build the `tailscale up` argument vector. Pure so it can be unit-tested and so
342
- * the interactive (browser-register) and zero-touch (pre-auth key) forms differ
343
- * only by the trailing `--authkey`.
344
- */
345
239
  export function buildTailscaleUpArgs(opts) {
346
240
  const args = [
347
241
  "--socket", opts.socket, "up",
@@ -353,12 +247,6 @@ export function buildTailscaleUpArgs(opts) {
353
247
  args.push("--authkey", opts.preAuthKey);
354
248
  return args;
355
249
  }
356
- /**
357
- * Join the tenant's Headscale tailnet via Zitadel OIDC if not already Running.
358
- * Prints the device-flow registration URL and polls until registered. When a
359
- * pre-auth key is supplied the join is non-interactive: no `/register/` URL is
360
- * emitted, so the scrape/relay is skipped and we just wait for Running.
361
- */
362
250
  export async function joinHeadscale(tenant, loginServer, opts = {}) {
363
251
  if (daemonState(tenant).backendState === "Running")
364
252
  return;
@@ -374,8 +262,6 @@ export async function joinHeadscale(tenant, loginServer, opts = {}) {
374
262
  const m = buf.match(/https?:\/\/\S+\/register\/\S+/);
375
263
  if (m) {
376
264
  urlShown = true;
377
- // Relay the registration URL for headless/SSH machines (there's no local
378
- // browser to pop). One-time per machine — the node registration persists.
379
265
  logInfo(`\n This machine isn't registered with the platform VPN yet.\n` +
380
266
  ` Open this URL in a browser to authorize it (one-time, sign in with Zitadel):\n\n` +
381
267
  ` ${m[0]}\n\n` +
@@ -385,7 +271,6 @@ export async function joinHeadscale(tenant, loginServer, opts = {}) {
385
271
  child.stdout.on("data", capture);
386
272
  child.stderr.on("data", capture);
387
273
  }
388
- // Poll up to ~5 min — the join is an interactive browser approval.
389
274
  for (let i = 0; i < 600; i++) {
390
275
  await sleep(500);
391
276
  if (daemonState(tenant).backendState === "Running") {
@@ -396,29 +281,17 @@ export async function joinHeadscale(tenant, loginServer, opts = {}) {
396
281
  child.kill();
397
282
  throw new Error(`VPN join not completed for tenant '${tenant}' within 5 min. Re-run \`mesh vpn tunnel up\` to resume — the daemon is still up.`);
398
283
  }
399
- /** Log the tenant daemon out of Headscale (disconnect). Daemon process persists. */
400
284
  export function logout(tenant) {
401
285
  try {
402
286
  execFileSync(tailscaleBinPath(), ["--socket", socketPath(tenant), "logout"], { stdio: "ignore" });
403
287
  }
404
288
  catch {
405
- /* best-effort */
406
- }
407
- }
408
- // ============================================================================
409
- // Forwarder supervisor (shared per tenant) + devOutput rewrite
410
- // ============================================================================
411
- /**
412
- * True iff two target sets are identical down to targetIp + remotePort. A live
413
- * runner pins each forwarder's target at startup, so if the ELB IP rotated (or a
414
- * port changed) the running forwarders point at a dead address and must be
415
- * respawned, not reused. Pid-agnostic (a launchd runner records no supervisor pid).
416
- */
289
+ }
290
+ }
417
291
  export function tunnelTargetsEqual(a, b) {
418
292
  const key = (ts) => ts.map((t) => `${t.name}:${t.localPort}:${t.targetIp}:${t.remotePort}`).sort().join(",");
419
293
  return key(a) === key(b);
420
294
  }
421
- /** True iff `state` has a supervisor pid and its target set equals `targets`. */
422
295
  export function supervisorTargetsMatch(state, targets) {
423
296
  if (!state || !state.supervisorPid)
424
297
  return false;
@@ -435,60 +308,19 @@ function pidAlive(pid) {
435
308
  return false;
436
309
  }
437
310
  }
438
- /**
439
- * SIGTERM the supervisor's whole process GROUP, not the bare pid.
440
- *
441
- * `state.supervisorPid` is the pid of the detached spawn — which, under the
442
- * canonical source launcher, is `bin/mesh.mjs`. That launcher blocks in
443
- * `execFileSync` around the *real* runner (a `node --import tsx … mesh.ts`
444
- * grandchild that actually binds the forwarder ports), and `execFileSync` does
445
- * not forward signals. So signalling the bare pid kills only the launcher and
446
- * ORPHANS the runner, which keeps its ports bound — the orphan then answers
447
- * `allForwardersListening`'s ownership-less liveness dial and silently pins
448
- * every tunnel to a stale target (the MESH-2169 / MESH-2014 failure class).
449
- *
450
- * The launcher is spawned `detached: true`, so it is a process-group leader
451
- * (`pgid === pid`); `process.kill(-pid, …)` reaps the launcher and the runner
452
- * together. Falls back to the bare pid for a legacy state file whose pid was
453
- * not a group leader, and tolerates ESRCH (already gone).
454
- *
455
- * `pid` is always recovered — from `tunnel-state.json`, `runner.json`, or a
456
- * `ps` scan — never constructed here, so it is guarded first. The guard rejects
457
- * anything below 2, which is what makes the NEGATED form safe: `pid >= 2` ⇒
458
- * `-pid <= -2`, a real process group, never `kill(0)` (this shell's own group)
459
- * or `kill(-1)` (broadcast to everything the user can signal). See utils/pid.ts.
460
- *
461
- * @throws {MeshCliError} when `pid` is unsignalable. Callers reaping SEVERAL
462
- * independently-recovered pids must catch per-pid (see `stopTunnelRunners`) —
463
- * letting one refusal propagate would skip the other pids and leave a live
464
- * runner holding ports.
465
- */
466
311
  export function killSupervisor(pid, source) {
467
- // MUST be outside the try — both signals below are wrapped in catch-alls, so a
468
- // guard placed inside would have its refusal swallowed and fall through to the
469
- // bare-pid kill it was meant to prevent.
470
312
  assertSignalablePid(pid, source ?? { what: "tunnel supervisor pid" });
471
313
  try {
472
- process.kill(-pid, "SIGTERM"); // detached spawn ⇒ pid is the group leader
314
+ process.kill(-pid, "SIGTERM");
473
315
  }
474
316
  catch {
475
317
  try {
476
- process.kill(pid, "SIGTERM"); // not a group leader (old state file) — best effort
318
+ process.kill(pid, "SIGTERM");
477
319
  }
478
320
  catch {
479
- /* already gone (ESRCH) */
480
321
  }
481
322
  }
482
323
  }
483
- /**
484
- * The ownership handshake for a tenant's tunnel runner (MESH-2407): manifest →
485
- * live pid → control endpoint → token + SOCKS port + port coverage. This is
486
- * the ONLY readiness/reuse signal — a bare TCP dial proves a listener exists,
487
- * not that it is ours, and adopting a foreign listener is exactly the
488
- * silent-dead-tunnel class (MESH-2169 / MESH-2014 / #2991). As a bonus the
489
- * handshake reads listening state from the runner's in-process servers, so it
490
- * opens no SOCKS→VPC data connection the way port dials do.
491
- */
492
324
  export async function verifyTunnelOwnership(tenant, expected) {
493
325
  return verifyRunnerOwnership({
494
326
  manifest: readRunnerManifest(runnerManifestPath(tenant)),
@@ -496,37 +328,12 @@ export async function verifyTunnelOwnership(tenant, expected) {
496
328
  expectedPorts: expected.ports,
497
329
  });
498
330
  }
499
- /**
500
- * Poll the ownership handshake until it passes or `deadlineMs` of WALL CLOCK
501
- * elapses (each check can cost up to the control-query timeout, so the bound
502
- * must be time, not rounds); returns the last check.
503
- */
504
331
  function awaitOwnership(tenant, expected, deadlineMs) {
505
332
  return pollOwnership(() => verifyTunnelOwnership(tenant, expected), deadlineMs);
506
333
  }
507
- /**
508
- * Tear down EVERY runner we can attribute to the tenant: the recorded
509
- * supervisor pid (as a process group — see `killSupervisor`), the launchd
510
- * agent, the manifest's process group, and any `__run`/`__supervise` process
511
- * discovered from argv (a runner from an older build, or one whose state file
512
- * was lost). This is the single teardown path — the #2991 lesson generalized:
513
- * no kill path may leave a grandchild with ports still bound.
514
- */
515
334
  export function stopTunnelRunners(tenant, prior) {
516
335
  if (prior?.managed === "launchd")
517
336
  uninstallLaunchAgent(tenant);
518
- // Each pid below is RECOVERED (two state files and a ps scan), so each names
519
- // its own provenance — the refusal has to point at the exact file to delete,
520
- // or a corrupt state dir bricks the very command that would have cleared it.
521
- //
522
- // The three sources are INDEPENDENT, so a refusal on one must not skip the
523
- // others or `clearRunnerManifest`. Aborting would let one corrupt integer in
524
- // `tunnel-state.json` strand a live, uncorrupted runner from `runner.json`
525
- // with its forwarder ports still bound — the silent-squatter class this
526
- // teardown exists to prevent ("no kill path may leave a grandchild with ports
527
- // still bound", MESH-2407). Refuse the bad pid, reap the rest;
528
- // `assertTunnelPortsFree` is the backstop that still fails loudly if an
529
- // un-reaped runner really is holding ports.
530
337
  const killOrWarn = (pid, source) => {
531
338
  try {
532
339
  killSupervisor(pid, source);
@@ -552,12 +359,6 @@ export function stopTunnelRunners(tenant, prior) {
552
359
  killOrWarn(pid, { what: `a tunnel runner pid discovered from 'ps' for tenant '${tenant}'` });
553
360
  clearRunnerManifest(runnerManifestPath(tenant));
554
361
  }
555
- /**
556
- * After teardown, wait for the tenant's forwarder ports to actually free. Any
557
- * port still accepting is held by a process we could not kill — a foreign
558
- * squatter — and spawning a runner over it would produce forwarders that
559
- * silently fail to bind (the false-green readiness gate). Fail LOUDLY instead.
560
- */
561
362
  async function assertTunnelPortsFree(tenant, ports) {
562
363
  let held = ports;
563
364
  for (let i = 0; i < 8; i++) {
@@ -574,40 +375,15 @@ async function assertTunnelPortsFree(tenant, ports) {
574
375
  const squatted = await findSquattedPorts(held, (p) => portAccepts(p, 250));
575
376
  throw new Error(buildSquatterError(tenant, squatted, "still bound after teardown"));
576
377
  }
577
- /**
578
- * Ensure the per-tenant forwarder supervisor is running for `state.tunnels`.
579
- * Idempotent: reuses a live runner ONLY when it passes the ownership handshake
580
- * (our manifest token, our SOCKS port, every target port listening in-process);
581
- * otherwise tears down every attributable runner, verifies the ports actually
582
- * freed (a still-held port is a foreign squatter → loud failure, never spawn
583
- * over it), and (re)spawns a fresh runner — whose readiness is again the
584
- * handshake, not a bare port dial. Persists the state and returns the pid.
585
- */
586
378
  export async function ensureForwarders(state) {
587
379
  const prior = readTunnelState(state.tenant);
588
380
  const expected = { socksPort: state.socksPort, ports: state.tunnels.map((t) => t.localPort) };
589
- // Reuse-if-healthy must be mode-aware. A launchd runner records no supervisorPid
590
- // (KeepAlive owns liveness), so gating reuse on pidAlive would tear down + rebind
591
- // the shared tunnels on EVERY `up`/`mesh dev` — severing other concurrent sessions,
592
- // the exact failure MESH-2014 exists to kill. Treat the launchd agent as "alive"
593
- // when its plist is installed; keep the pid check for the detached path.
594
381
  const runnerAlive = prior?.managed === "launchd"
595
382
  ? fs.existsSync(launchAgentPath(state.tenant))
596
383
  : pidAlive(prior?.supervisorPid);
597
384
  if (prior &&
598
385
  runnerAlive &&
599
386
  tunnelTargetsEqual(prior.tunnels, state.tunnels) &&
600
- // A prior supervisor spawned for a DIFFERENT SOCKS port still binds the same
601
- // local ports but dials a dead upstream — reusing it silently strands every
602
- // tunnel (MESH-2169). The port must match, and the runner must PROVE it is
603
- // ours via the ownership handshake (liveness ≠ ownership — a port answering
604
- // a dial can be another session's SSM tunnel or an orphaned runner, #2991).
605
- // Poll briefly rather than sample once: `ports-not-listening` during the
606
- // runner's own rebind window and `no-control-answer` under load are
607
- // transient, and a single miss here would tear down a healthy runner SHARED
608
- // by every concurrent session on the tenant (MESH-2014). This branch is
609
- // only reached when the runner is alive with matching targets, so the
610
- // retry costs nothing on cold-start or genuinely-dead paths.
611
387
  prior.socksPort === state.socksPort &&
612
388
  (await awaitOwnership(state.tenant, expected, 1000)).ok) {
613
389
  state.supervisorPid = prior.supervisorPid;
@@ -615,38 +391,17 @@ export async function ensureForwarders(state) {
615
391
  writeTunnelState(state.tenant, state);
616
392
  return prior.supervisorPid ?? 0;
617
393
  }
618
- // Tear down every attributable runner (state pid group, launchd agent,
619
- // manifest process group, argv-discovered strays), then require the ports to
620
- // actually free — a still-held port is foreign and must fail loudly here,
621
- // not surface later as a forwarder that silently failed to bind.
622
394
  stopTunnelRunners(state.tenant, prior);
623
395
  await assertTunnelPortsFree(state.tenant, expected.ports);
624
- // Write state first so the runner reads the correct targets on start.
625
396
  state.supervisorPid = null;
626
- // Prefer a launchd-supervised runner (survives reboot/crash); fall back to a
627
- // detached runner where launchd isn't usable (e.g. sandboxed shells). Both run
628
- // the same self-healing `__run`.
629
- // argv[1] under the canonical source launcher is bin/mesh.ts, which plain
630
- // node cannot execute (same failure class as the credential_process fix in
631
- // aws-auth.ts) — resolve to the stable launcher, or the bare `mesh` fallback.
632
397
  const meshBin = resolveStableMeshBin(process.argv[1]);
633
398
  if (launchdAvailable()) {
634
399
  state.managed = "launchd";
635
400
  writeTunnelState(state.tenant, state);
636
- // launchd does no PATH lookup, so the bare `mesh` fallback can't back a
637
- // LaunchAgent (it would become `node mesh …`, crash-looping under KeepAlive).
638
- // Require an absolute path; otherwise fall through to the detached runner,
639
- // where spawn *does* resolve `mesh` on PATH.
640
401
  if (path.isAbsolute(meshBin) && installLaunchAgent(state.tenant, meshBin)) {
641
- // Installing the agent proves nothing about the forwarders — wait for the
642
- // runner's ownership handshake (this path used to return success blind).
643
402
  if ((await awaitOwnership(state.tenant, expected, 8000)).ok)
644
403
  return 0;
645
404
  uninstallLaunchAgent(state.tenant);
646
- // `launchctl bootout` signals the job but doesn't wait for it — spawning
647
- // the detached runner immediately would race the dying launchd runner for
648
- // the ports (EADDRINUSE → a transient turned into a hard failure). Every
649
- // teardown path must be followed by the ports-actually-freed check.
650
405
  await assertTunnelPortsFree(state.tenant, expected.ports);
651
406
  logInfo("launchd runner did not take ownership of the tunnel ports — using a detached runner.");
652
407
  }
@@ -656,29 +411,17 @@ export async function ensureForwarders(state) {
656
411
  }
657
412
  state.managed = "detached";
658
413
  writeTunnelState(state.tenant, state);
659
- // meshBin is the stable launcher, or the bare `mesh` fallback which spawn
660
- // resolves on PATH here (no PATH-lookup ternary needed — that was a no-op).
661
414
  const child = spawn(meshBin, ["vpn", "tunnel", "__run", state.tenant], {
662
415
  detached: true,
663
416
  stdio: "ignore",
664
417
  });
665
- // ENOENT from the bare `mesh` fallback (mesh-cli not installed globally)
666
- // arrives asynchronously — without this handler an unhandled 'error' throws
667
- // an uncaught exception and takes down `mesh dev` instead of degrading.
668
418
  child.on("error", (err) => logWarn(`tunnel supervisor failed to start (${err.message}) — falling back to SSM.`));
669
419
  child.unref();
670
420
  state.supervisorPid = child.pid ?? null;
671
421
  writeTunnelState(state.tenant, state);
672
- // Readiness = the ownership handshake, not a port dial: the fresh runner must
673
- // present its manifest token and report every forwarder listening from its
674
- // own in-process servers. A dial would also pass for another session's SSM
675
- // tunnel on the same 2XXXX port — the false-green this contract kills.
676
- // Throwing here lands in startServices' catch → clean SSM fallback.
677
422
  const last = await awaitOwnership(state.tenant, expected, 5000);
678
423
  if (last.ok)
679
424
  return child.pid ?? -1;
680
- // Diagnose before failing: a port that accepts TCP while ownership failed is
681
- // held by someone else — name it and say exactly what to do.
682
425
  const squatted = await findSquattedPorts(expected.ports, (p) => portAccepts(p, 250));
683
426
  if (squatted.length > 0) {
684
427
  throw new Error(buildSquatterError(state.tenant, squatted, `ownership check: ${last.reason}`));
@@ -689,11 +432,6 @@ export async function ensureForwarders(state) {
689
432
  throw new Error(`Tailscale forwarders did not take ownership for tenant '${state.tenant}' ` +
690
433
  `(${last.reason}${bindErrors ? `; ${bindErrors}` : ""}) — see ${logPath(state.tenant)}.`);
691
434
  }
692
- /**
693
- * Rewrite `devOutput.tunnels` so each resolved target points at its local
694
- * forwarder (`localhost:localPort`) — the same shape `startSsmTunnels`
695
- * produces. Unmatched tunnels are left untouched. Pure (no mutation of input).
696
- */
697
435
  export function rewriteTunnelsForTargets(devOutput, targets) {
698
436
  const tunnels = { ...devOutput.tunnels };
699
437
  for (const t of targets) {
@@ -701,7 +439,6 @@ export function rewriteTunnelsForTargets(devOutput, targets) {
701
439
  }
702
440
  return { ...devOutput, tunnels };
703
441
  }
704
- /** True when the brew `tailscaled` binary is resolvable (Tailscale transport is usable). */
705
442
  export function tailscaleAvailable() {
706
443
  try {
707
444
  tailscaledBinPath();
@@ -711,23 +448,9 @@ export function tailscaleAvailable() {
711
448
  return false;
712
449
  }
713
450
  }
714
- // ============================================================================
715
- // Shared engine: ensure/start Tailscale tunnels (used by the command + mesh dev)
716
- // ============================================================================
717
- /**
718
- * Ensure the tenant's Tailscale tunnels are fully up: the shared per-tenant
719
- * daemon (started + OIDC-joined if needed), the resolved VPC targets, and the
720
- * forwarder supervisor. Idempotent (shared across worktrees/invocations of the
721
- * same tenant). Returns the resolved targets. Used by both `mesh vpn tunnel up`
722
- * and `mesh dev --transport=tailscale`.
723
- */
724
451
  export async function ensureTailscaleTunnels(tenant, env, opts) {
725
- // Reconcile the daemon's SOCKS port — an already-running daemon may be on a
726
- // different port than requested; the forwarders MUST dial the real one (MESH-2169).
727
452
  const socksPort = await ensureDaemon(tenant, { region: opts.region, socksPort: opts.socksPort });
728
453
  await joinHeadscale(tenant, opts.loginServer, { preAuthKey: opts.preAuthKey });
729
- // Pass the region explicitly rather than clobbering process.env.AWS_REGION —
730
- // this runs mid `mesh dev` launch and must not mutate the global env.
731
454
  const bastion = await getPlatformBastionInfo(tenant, env, opts.region);
732
455
  if (!bastion) {
733
456
  throw new Error(`Could not read the platform bastion for ${tenant}/${env} (check AWS credentials).`);
@@ -749,10 +472,6 @@ export async function ensureTailscaleTunnels(tenant, env, opts) {
749
472
  await ensureForwarders(state);
750
473
  return targets;
751
474
  }
752
- /**
753
- * `startSsmTunnels` drop-in for `mesh dev`: ensure the tenant's Tailscale
754
- * tunnels, then rewrite `devOutput.tunnels` to the local forwarder ports.
755
- */
756
475
  export async function startTailscaleTunnels(devOutput, ctx) {
757
476
  const targets = await ensureTailscaleTunnels(ctx.tenant, ctx.env, {
758
477
  region: ctx.region,
@@ -762,20 +481,15 @@ export async function startTailscaleTunnels(devOutput, ctx) {
762
481
  });
763
482
  return rewriteTunnelsForTargets(devOutput, targets);
764
483
  }
765
- // ============================================================================
766
- // launchd supervision + self-heal (Slice 2a)
767
- // ============================================================================
768
484
  export function launchAgentLabel(tenant) {
769
485
  return `tech.mesh.tunnel.${tenant}`;
770
486
  }
771
- /** Minimal XML-escape for plist string values (controlled inputs, but paths can vary). */
772
487
  function xmlEscape(s) {
773
488
  return s
774
489
  .replace(/&/g, "&amp;")
775
490
  .replace(/</g, "&lt;")
776
491
  .replace(/>/g, "&gt;");
777
492
  }
778
- /** Render the per-tenant LaunchAgent plist (pure). */
779
493
  export function renderLaunchAgentPlist(args) {
780
494
  const pathEnv = args.pathEnv ?? "/usr/bin:/bin:/usr/sbin:/sbin";
781
495
  return `<?xml version="1.0" encoding="UTF-8"?>
@@ -813,7 +527,6 @@ export function renderLaunchAgentPlist(args) {
813
527
  </plist>
814
528
  `;
815
529
  }
816
- /** Targets whose local forwarder port isn't currently accepting connections. */
817
530
  export function forwardersNeedingRebind(targets, listening) {
818
531
  return targets.filter((t) => !listening.has(t.localPort));
819
532
  }
@@ -824,7 +537,6 @@ function guiDomain() {
824
537
  return `gui/${process.getuid?.() ?? 0}`;
825
538
  }
826
539
  let _launchdAvailable;
827
- /** True when launchctl works for this user (blocked under the seatbelt sandbox → false). */
828
540
  export function launchdAvailable() {
829
541
  if (_launchdAvailable !== undefined)
830
542
  return _launchdAvailable;
@@ -838,32 +550,20 @@ export function launchdAvailable() {
838
550
  }
839
551
  return _launchdAvailable;
840
552
  }
841
- /**
842
- * Write + (re)load the per-tenant LaunchAgent. Returns true iff it fully
843
- * succeeded — any failure (plist write blocked by the sandbox, `launchctl`
844
- * bootstrap denied, …) returns false so the caller falls back to a detached
845
- * runner. Never throws.
846
- */
847
553
  export function installLaunchAgent(tenant, meshBin) {
848
554
  const plistPath = launchAgentPath(tenant);
849
555
  try {
850
- // Resolve symlinks so the plist embeds a stable path (a since-deleted
851
- // worktree symlink would leave a KeepAlive agent respawning a dead binary).
852
556
  let realMeshBin = meshBin;
853
557
  try {
854
558
  realMeshBin = fs.realpathSync(meshBin);
855
559
  }
856
560
  catch {
857
- /* keep the raw path */
858
561
  }
859
- // Bake a PATH that includes the tailscaled dir so the runner's daemon reheal
860
- // works under launchd's minimal PATH (Intel installs live in /usr/local/bin).
861
562
  let pathEnv = "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin";
862
563
  try {
863
564
  pathEnv = `${path.dirname(tailscaledBinPath())}:${pathEnv}`;
864
565
  }
865
566
  catch {
866
- /* fall back to the default PATH */
867
567
  }
868
568
  fs.mkdirSync(path.dirname(plistPath), { recursive: true });
869
569
  fs.writeFileSync(plistPath, renderLaunchAgentPlist({
@@ -877,7 +577,6 @@ export function installLaunchAgent(tenant, meshBin) {
877
577
  execFileSync("launchctl", ["bootout", guiDomain(), plistPath], { stdio: "ignore" });
878
578
  }
879
579
  catch {
880
- /* not loaded — fine */
881
580
  }
882
581
  execFileSync("launchctl", ["bootstrap", guiDomain(), plistPath], { stdio: "ignore" });
883
582
  return true;
@@ -886,50 +585,28 @@ export function installLaunchAgent(tenant, meshBin) {
886
585
  return false;
887
586
  }
888
587
  }
889
- /** Unload + remove the per-tenant LaunchAgent (best-effort). */
890
588
  export function uninstallLaunchAgent(tenant) {
891
589
  const plistPath = launchAgentPath(tenant);
892
590
  try {
893
591
  execFileSync("launchctl", ["bootout", guiDomain(), plistPath], { stdio: "ignore" });
894
592
  }
895
593
  catch {
896
- /* not loaded */
897
594
  }
898
595
  try {
899
596
  fs.unlinkSync(plistPath);
900
597
  }
901
598
  catch {
902
- /* already gone */
903
- }
904
- }
905
- // ============================================================================
906
- // The runner (__run): forwarders + continuous self-heal
907
- // ============================================================================
908
- /**
909
- * Long-lived runner for a tenant's tunnels — used both under launchd and as the
910
- * detached fallback. Runs a forwarder per target and, every ~5s, self-heals:
911
- * respawns the daemon if its process died, and rebinds any forwarder whose port
912
- * stopped listening. As the process that actually binds the ports, it is the
913
- * sole author of the ownership manifest + control endpoint (MESH-2407) that
914
- * callers verify against. Needs no AWS (targets come from tunnel-state). Never
915
- * returns.
916
- */
599
+ }
600
+ }
917
601
  export async function runTunnels(tenant) {
918
602
  const st = readTunnelState(tenant);
919
603
  if (!st) {
920
- // State is gone (torn down). Under launchd's KeepAlive a non-zero exit would
921
- // respawn every ~10s forever (surviving reboots) — so self-uninstall the
922
- // agent (no-op when detached), drop any manifest a previous incarnation
923
- // left (it describes a runner that no longer exists), and exit cleanly.
924
604
  uninstallLaunchAgent(tenant);
925
605
  clearRunnerManifest(runnerManifestPath(tenant));
926
606
  process.exit(0);
927
607
  }
928
608
  const token = mintRunnerToken();
929
609
  const servers = new Map();
930
- // port → last bind error code. Surfaced through the control endpoint so a
931
- // failed bind (EADDRINUSE from a squatted port) is a visible, attributable
932
- // failure at the caller — never a silently-dead forwarder.
933
610
  const bindErrors = new Map();
934
611
  const spawnFor = (t) => {
935
612
  servers.get(t.localPort)?.close();
@@ -971,8 +648,6 @@ export async function runTunnels(tenant) {
971
648
  control.server.close();
972
649
  for (const s of servers.values())
973
650
  s.close();
974
- // Token-guarded: never clobber the manifest of a newer runner that already
975
- // replaced us (teardown kills groups, and signal delivery order is loose).
976
651
  clearRunnerManifest(runnerManifestPath(tenant), token);
977
652
  process.exit(0);
978
653
  };
@@ -987,10 +662,6 @@ export async function runTunnels(tenant) {
987
662
  socksPort: st.socksPort,
988
663
  });
989
664
  }
990
- // Check the in-process net.Server directly — do NOT dial the forwarder.
991
- // A dial makes the forwarder open a real SOCKS→VPC-target connection, and
992
- // the probe's clean FIN doesn't tear the upstream leg down, leaking a
993
- // connection to Temporal/RDS/etc. every 5s per target.
994
665
  const listening = new Set();
995
666
  for (const t of st.tunnels) {
996
667
  if (servers.get(t.localPort)?.listening)
@@ -1000,8 +671,6 @@ export async function runTunnels(tenant) {
1000
671
  spawnFor(t);
1001
672
  }
1002
673
  catch {
1003
- /* keep the loop alive across transient errors */
1004
674
  }
1005
675
  }
1006
676
  }
1007
- //# sourceMappingURL=tailscale.js.map