@mesh-tech/mesh-cli 0.1.1 → 0.12.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 (504) hide show
  1. package/assets/intent/agents-fence.md +10 -0
  2. package/assets/intent/intent-claude-gate.mjs +255 -0
  3. package/assets/log-shipper.mjs +94 -0
  4. package/bin/mesh.mjs +80 -0
  5. package/dist/bin/mesh.d.ts +7 -9
  6. package/dist/bin/mesh.d.ts.map +1 -1
  7. package/dist/bin/mesh.js +20826 -37
  8. package/dist/bin/mesh.js.map +7 -1
  9. package/dist/build-info.json +4 -0
  10. package/dist/src/commands/agent-api-client.d.ts +79 -0
  11. package/dist/src/commands/agent-api-client.d.ts.map +1 -0
  12. package/dist/src/commands/agent-api-client.js +170 -0
  13. package/dist/src/commands/agent-api-client.js.map +1 -0
  14. package/dist/src/commands/artifacts.d.ts +13 -0
  15. package/dist/src/commands/artifacts.d.ts.map +1 -0
  16. package/dist/src/commands/artifacts.js +140 -0
  17. package/dist/src/commands/artifacts.js.map +1 -0
  18. package/dist/src/commands/cluster.d.ts +45 -0
  19. package/dist/src/commands/cluster.d.ts.map +1 -0
  20. package/dist/src/commands/cluster.js +259 -0
  21. package/dist/src/commands/cluster.js.map +1 -0
  22. package/dist/src/commands/conversations.d.ts +61 -0
  23. package/dist/src/commands/conversations.d.ts.map +1 -0
  24. package/dist/src/commands/conversations.js +239 -0
  25. package/dist/src/commands/conversations.js.map +1 -0
  26. package/dist/src/commands/create-app.d.ts +26 -3
  27. package/dist/src/commands/create-app.d.ts.map +1 -1
  28. package/dist/src/commands/create-app.js +465 -107
  29. package/dist/src/commands/create-app.js.map +1 -1
  30. package/dist/src/commands/deploy.d.ts +19 -0
  31. package/dist/src/commands/deploy.d.ts.map +1 -1
  32. package/dist/src/commands/deploy.js +83 -142
  33. package/dist/src/commands/deploy.js.map +1 -1
  34. package/dist/src/commands/dev-doctor.d.ts +137 -0
  35. package/dist/src/commands/dev-doctor.d.ts.map +1 -0
  36. package/dist/src/commands/dev-doctor.js +671 -0
  37. package/dist/src/commands/dev-doctor.js.map +1 -0
  38. package/dist/src/commands/dev-launch.d.ts +59 -0
  39. package/dist/src/commands/dev-launch.d.ts.map +1 -0
  40. package/dist/src/commands/dev-launch.js +118 -0
  41. package/dist/src/commands/dev-launch.js.map +1 -0
  42. package/dist/src/commands/dev-token-server.d.ts +32 -0
  43. package/dist/src/commands/dev-token-server.d.ts.map +1 -0
  44. package/dist/src/commands/dev-token-server.js +68 -0
  45. package/dist/src/commands/dev-token-server.js.map +1 -0
  46. package/dist/src/commands/dev.d.ts +289 -2
  47. package/dist/src/commands/dev.d.ts.map +1 -1
  48. package/dist/src/commands/dev.js +2501 -574
  49. package/dist/src/commands/dev.js.map +1 -1
  50. package/dist/src/commands/docs.d.ts +3 -0
  51. package/dist/src/commands/docs.d.ts.map +1 -0
  52. package/dist/src/commands/docs.js +262 -0
  53. package/dist/src/commands/docs.js.map +1 -0
  54. package/dist/src/commands/hub/index.d.ts +99 -0
  55. package/dist/src/commands/hub/index.d.ts.map +1 -0
  56. package/dist/src/commands/hub/index.js +452 -0
  57. package/dist/src/commands/hub/index.js.map +1 -0
  58. package/dist/src/commands/init.d.ts +65 -0
  59. package/dist/src/commands/init.d.ts.map +1 -0
  60. package/dist/src/commands/init.js +370 -0
  61. package/dist/src/commands/init.js.map +1 -0
  62. package/dist/src/commands/install-shim.d.ts +21 -0
  63. package/dist/src/commands/install-shim.d.ts.map +1 -0
  64. package/dist/src/commands/install-shim.js +132 -0
  65. package/dist/src/commands/install-shim.js.map +1 -0
  66. package/dist/src/commands/local/auth-provision.d.ts +71 -0
  67. package/dist/src/commands/local/auth-provision.d.ts.map +1 -0
  68. package/dist/src/commands/local/auth-provision.js +286 -0
  69. package/dist/src/commands/local/auth-provision.js.map +1 -0
  70. package/dist/src/commands/local/dev-local.d.ts +97 -0
  71. package/dist/src/commands/local/dev-local.d.ts.map +1 -0
  72. package/dist/src/commands/local/dev-local.js +306 -0
  73. package/dist/src/commands/local/dev-local.js.map +1 -0
  74. package/dist/src/commands/local/docker-runner.d.ts +37 -0
  75. package/dist/src/commands/local/docker-runner.d.ts.map +1 -0
  76. package/dist/src/commands/local/docker-runner.js +104 -0
  77. package/dist/src/commands/local/docker-runner.js.map +1 -0
  78. package/dist/src/commands/local/helpers.d.ts +22 -0
  79. package/dist/src/commands/local/helpers.d.ts.map +1 -0
  80. package/dist/src/commands/local/helpers.js +46 -0
  81. package/dist/src/commands/local/helpers.js.map +1 -0
  82. package/dist/src/commands/local/hub-local.d.ts +51 -0
  83. package/dist/src/commands/local/hub-local.d.ts.map +1 -0
  84. package/dist/src/commands/local/hub-local.js +197 -0
  85. package/dist/src/commands/local/hub-local.js.map +1 -0
  86. package/dist/src/commands/local/index.d.ts +23 -0
  87. package/dist/src/commands/local/index.d.ts.map +1 -0
  88. package/dist/src/commands/local/index.js +386 -0
  89. package/dist/src/commands/local/index.js.map +1 -0
  90. package/dist/src/commands/local/mocks.d.ts +361 -0
  91. package/dist/src/commands/local/mocks.d.ts.map +1 -0
  92. package/dist/src/commands/local/mocks.js +756 -0
  93. package/dist/src/commands/local/mocks.js.map +1 -0
  94. package/dist/src/commands/local/seed-zitadel.d.ts +151 -0
  95. package/dist/src/commands/local/seed-zitadel.d.ts.map +1 -0
  96. package/dist/src/commands/local/seed-zitadel.js +408 -0
  97. package/dist/src/commands/local/seed-zitadel.js.map +1 -0
  98. package/dist/src/commands/local/seed.d.ts +106 -0
  99. package/dist/src/commands/local/seed.d.ts.map +1 -0
  100. package/dist/src/commands/local/seed.js +252 -0
  101. package/dist/src/commands/local/seed.js.map +1 -0
  102. package/dist/src/commands/local/stack.d.ts +173 -0
  103. package/dist/src/commands/local/stack.d.ts.map +1 -0
  104. package/dist/src/commands/local/stack.js +499 -0
  105. package/dist/src/commands/local/stack.js.map +1 -0
  106. package/dist/src/commands/login.d.ts +256 -12
  107. package/dist/src/commands/login.d.ts.map +1 -1
  108. package/dist/src/commands/login.js +978 -50
  109. package/dist/src/commands/login.js.map +1 -1
  110. package/dist/src/commands/peer-addressing.d.ts +51 -0
  111. package/dist/src/commands/peer-addressing.d.ts.map +1 -0
  112. package/dist/src/commands/peer-addressing.js +64 -0
  113. package/dist/src/commands/peer-addressing.js.map +1 -0
  114. package/dist/src/commands/port-ownership.d.ts +69 -0
  115. package/dist/src/commands/port-ownership.d.ts.map +1 -0
  116. package/dist/src/commands/port-ownership.js +161 -0
  117. package/dist/src/commands/port-ownership.js.map +1 -0
  118. package/dist/src/commands/registry-publish.d.ts +3 -0
  119. package/dist/src/commands/registry-publish.d.ts.map +1 -0
  120. package/dist/src/commands/registry-publish.js +161 -0
  121. package/dist/src/commands/registry-publish.js.map +1 -0
  122. package/dist/src/commands/registry.d.ts +146 -2
  123. package/dist/src/commands/registry.d.ts.map +1 -1
  124. package/dist/src/commands/registry.js +541 -85
  125. package/dist/src/commands/registry.js.map +1 -1
  126. package/dist/src/commands/secrets/index.d.ts.map +1 -1
  127. package/dist/src/commands/secrets/index.js +15 -1
  128. package/dist/src/commands/secrets/index.js.map +1 -1
  129. package/dist/src/commands/secrets/migrate-config.d.ts +24 -0
  130. package/dist/src/commands/secrets/migrate-config.d.ts.map +1 -0
  131. package/dist/src/commands/secrets/migrate-config.js +277 -0
  132. package/dist/src/commands/secrets/migrate-config.js.map +1 -0
  133. package/dist/src/commands/secrets/set.d.ts +1 -0
  134. package/dist/src/commands/secrets/set.d.ts.map +1 -1
  135. package/dist/src/commands/secrets/set.js +96 -2
  136. package/dist/src/commands/secrets/set.js.map +1 -1
  137. package/dist/src/commands/skills.d.ts +34 -0
  138. package/dist/src/commands/skills.d.ts.map +1 -0
  139. package/dist/src/commands/skills.js +207 -0
  140. package/dist/src/commands/skills.js.map +1 -0
  141. package/dist/src/commands/stack.d.ts.map +1 -1
  142. package/dist/src/commands/stack.js +361 -23
  143. package/dist/src/commands/stack.js.map +1 -1
  144. package/dist/src/commands/temporal.d.ts +15 -0
  145. package/dist/src/commands/temporal.d.ts.map +1 -0
  146. package/dist/src/commands/temporal.js +781 -0
  147. package/dist/src/commands/temporal.js.map +1 -0
  148. package/dist/src/commands/tenant.d.ts +56 -0
  149. package/dist/src/commands/tenant.d.ts.map +1 -0
  150. package/dist/src/commands/tenant.js +233 -0
  151. package/dist/src/commands/tenant.js.map +1 -0
  152. package/dist/src/commands/tunnel/index.d.ts +49 -3
  153. package/dist/src/commands/tunnel/index.d.ts.map +1 -1
  154. package/dist/src/commands/tunnel/index.js +331 -8
  155. package/dist/src/commands/tunnel/index.js.map +1 -1
  156. package/dist/src/commands/vcs/clone.d.ts +3 -0
  157. package/dist/src/commands/vcs/clone.d.ts.map +1 -0
  158. package/dist/src/commands/vcs/clone.js +20 -0
  159. package/dist/src/commands/vcs/clone.js.map +1 -0
  160. package/dist/src/commands/vcs/common.d.ts +21 -0
  161. package/dist/src/commands/vcs/common.d.ts.map +1 -0
  162. package/dist/src/commands/vcs/common.js +62 -0
  163. package/dist/src/commands/vcs/common.js.map +1 -0
  164. package/dist/src/commands/vcs/drafts.d.ts +13 -0
  165. package/dist/src/commands/vcs/drafts.d.ts.map +1 -0
  166. package/dist/src/commands/vcs/drafts.js +45 -0
  167. package/dist/src/commands/vcs/drafts.js.map +1 -0
  168. package/dist/src/commands/vcs/get.d.ts +8 -0
  169. package/dist/src/commands/vcs/get.d.ts.map +1 -0
  170. package/dist/src/commands/vcs/get.js +61 -0
  171. package/dist/src/commands/vcs/get.js.map +1 -0
  172. package/dist/src/commands/vcs/index.d.ts +3 -0
  173. package/dist/src/commands/vcs/index.d.ts.map +1 -0
  174. package/dist/src/commands/vcs/index.js +58 -0
  175. package/dist/src/commands/vcs/index.js.map +1 -0
  176. package/dist/src/commands/vcs/propose.d.ts +23 -0
  177. package/dist/src/commands/vcs/propose.d.ts.map +1 -0
  178. package/dist/src/commands/vcs/propose.js +94 -0
  179. package/dist/src/commands/vcs/propose.js.map +1 -0
  180. package/dist/src/commands/vcs/review.d.ts +15 -0
  181. package/dist/src/commands/vcs/review.d.ts.map +1 -0
  182. package/dist/src/commands/vcs/review.js +35 -0
  183. package/dist/src/commands/vcs/review.js.map +1 -0
  184. package/dist/src/commands/vcs-enrich.d.ts +15 -0
  185. package/dist/src/commands/vcs-enrich.d.ts.map +1 -0
  186. package/dist/src/commands/vcs-enrich.js +28 -0
  187. package/dist/src/commands/vcs-enrich.js.map +1 -0
  188. package/dist/src/commands/vpn/index.d.ts +24 -0
  189. package/dist/src/commands/vpn/index.d.ts.map +1 -0
  190. package/dist/src/commands/vpn/index.js +543 -0
  191. package/dist/src/commands/vpn/index.js.map +1 -0
  192. package/dist/src/commands/vpn/tunnel.d.ts +11 -0
  193. package/dist/src/commands/vpn/tunnel.d.ts.map +1 -0
  194. package/dist/src/commands/vpn/tunnel.js +188 -0
  195. package/dist/src/commands/vpn/tunnel.js.map +1 -0
  196. package/dist/src/commands/workflow.d.ts +24 -0
  197. package/dist/src/commands/workflow.d.ts.map +1 -0
  198. package/dist/src/commands/workflow.js +577 -0
  199. package/dist/src/commands/workflow.js.map +1 -0
  200. package/dist/src/docs/assemble.d.ts +217 -0
  201. package/dist/src/docs/assemble.d.ts.map +1 -0
  202. package/dist/src/docs/assemble.js +739 -0
  203. package/dist/src/docs/assemble.js.map +1 -0
  204. package/dist/src/docs/cli-reference.d.ts +93 -0
  205. package/dist/src/docs/cli-reference.d.ts.map +1 -0
  206. package/dist/src/docs/cli-reference.js +256 -0
  207. package/dist/src/docs/cli-reference.js.map +1 -0
  208. package/dist/src/docs/discover.d.ts +60 -0
  209. package/dist/src/docs/discover.d.ts.map +1 -0
  210. package/dist/src/docs/discover.js +233 -0
  211. package/dist/src/docs/discover.js.map +1 -0
  212. package/dist/src/docs/portal.d.ts +79 -0
  213. package/dist/src/docs/portal.d.ts.map +1 -0
  214. package/dist/src/docs/portal.js +242 -0
  215. package/dist/src/docs/portal.js.map +1 -0
  216. package/dist/src/docs/registry-docs.d.ts +43 -0
  217. package/dist/src/docs/registry-docs.d.ts.map +1 -0
  218. package/dist/src/docs/registry-docs.js +138 -0
  219. package/dist/src/docs/registry-docs.js.map +1 -0
  220. package/dist/src/docs/schema.d.ts +48 -0
  221. package/dist/src/docs/schema.d.ts.map +1 -0
  222. package/dist/src/docs/schema.js +96 -0
  223. package/dist/src/docs/schema.js.map +1 -0
  224. package/dist/src/docs/serve.d.ts +27 -0
  225. package/dist/src/docs/serve.d.ts.map +1 -0
  226. package/dist/src/docs/serve.js +102 -0
  227. package/dist/src/docs/serve.js.map +1 -0
  228. package/dist/src/docs/start.d.ts +80 -0
  229. package/dist/src/docs/start.d.ts.map +1 -0
  230. package/dist/src/docs/start.js +313 -0
  231. package/dist/src/docs/start.js.map +1 -0
  232. package/dist/src/eval/agent-eval.d.mts +14 -0
  233. package/dist/src/eval/agent-eval.d.mts.map +1 -0
  234. package/dist/src/eval/agent-eval.mjs +273 -0
  235. package/dist/src/eval/agent-eval.mjs.map +1 -0
  236. package/dist/src/index.js +624 -7
  237. package/dist/src/index.js.map +7 -1
  238. package/dist/src/program.d.ts +26 -0
  239. package/dist/src/program.d.ts.map +1 -0
  240. package/dist/src/program.js +76 -0
  241. package/dist/src/program.js.map +1 -0
  242. package/dist/src/utils/auth-preflight.d.ts +159 -0
  243. package/dist/src/utils/auth-preflight.d.ts.map +1 -0
  244. package/dist/src/utils/auth-preflight.js +298 -0
  245. package/dist/src/utils/auth-preflight.js.map +1 -0
  246. package/dist/src/utils/aws-auth.d.ts +181 -0
  247. package/dist/src/utils/aws-auth.d.ts.map +1 -0
  248. package/dist/src/utils/aws-auth.js +527 -0
  249. package/dist/src/utils/aws-auth.js.map +1 -0
  250. package/dist/src/utils/bastion.d.ts +1 -1
  251. package/dist/src/utils/bastion.d.ts.map +1 -1
  252. package/dist/src/utils/bastion.js +29 -8
  253. package/dist/src/utils/bastion.js.map +1 -1
  254. package/dist/src/utils/build-info.d.ts +33 -0
  255. package/dist/src/utils/build-info.d.ts.map +1 -0
  256. package/dist/src/utils/build-info.js +102 -0
  257. package/dist/src/utils/build-info.js.map +1 -0
  258. package/dist/src/utils/capture-history.d.ts +62 -0
  259. package/dist/src/utils/capture-history.d.ts.map +1 -0
  260. package/dist/src/utils/capture-history.js +94 -0
  261. package/dist/src/utils/capture-history.js.map +1 -0
  262. package/dist/src/utils/deploy-preflight.d.ts +52 -0
  263. package/dist/src/utils/deploy-preflight.d.ts.map +1 -0
  264. package/dist/src/utils/deploy-preflight.js +183 -0
  265. package/dist/src/utils/deploy-preflight.js.map +1 -0
  266. package/dist/src/utils/errors.d.ts +75 -0
  267. package/dist/src/utils/errors.d.ts.map +1 -0
  268. package/dist/src/utils/errors.js +106 -0
  269. package/dist/src/utils/errors.js.map +1 -0
  270. package/dist/src/utils/first-party-contexts.d.ts +40 -0
  271. package/dist/src/utils/first-party-contexts.d.ts.map +1 -0
  272. package/dist/src/utils/first-party-contexts.js +53 -0
  273. package/dist/src/utils/first-party-contexts.js.map +1 -0
  274. package/dist/src/utils/index.d.ts +2 -0
  275. package/dist/src/utils/index.d.ts.map +1 -1
  276. package/dist/src/utils/index.js +2 -0
  277. package/dist/src/utils/index.js.map +1 -1
  278. package/dist/src/utils/kubeconfig.d.ts +62 -0
  279. package/dist/src/utils/kubeconfig.d.ts.map +1 -0
  280. package/dist/src/utils/kubeconfig.js +118 -0
  281. package/dist/src/utils/kubeconfig.js.map +1 -0
  282. package/dist/src/utils/log.d.ts +27 -1
  283. package/dist/src/utils/log.d.ts.map +1 -1
  284. package/dist/src/utils/log.js +59 -5
  285. package/dist/src/utils/log.js.map +1 -1
  286. package/dist/src/utils/pid.d.ts +47 -0
  287. package/dist/src/utils/pid.d.ts.map +1 -0
  288. package/dist/src/utils/pid.js +83 -0
  289. package/dist/src/utils/pid.js.map +1 -0
  290. package/dist/src/utils/pulumi-run.d.ts +23 -0
  291. package/dist/src/utils/pulumi-run.d.ts.map +1 -0
  292. package/dist/src/utils/pulumi-run.js +112 -0
  293. package/dist/src/utils/pulumi-run.js.map +1 -0
  294. package/dist/src/utils/pulumi.d.ts +15 -0
  295. package/dist/src/utils/pulumi.d.ts.map +1 -1
  296. package/dist/src/utils/pulumi.js +35 -0
  297. package/dist/src/utils/pulumi.js.map +1 -1
  298. package/dist/src/utils/reachability.d.ts +29 -0
  299. package/dist/src/utils/reachability.d.ts.map +1 -0
  300. package/dist/src/utils/reachability.js +81 -0
  301. package/dist/src/utils/reachability.js.map +1 -0
  302. package/dist/src/utils/recover-conversation.d.ts +154 -0
  303. package/dist/src/utils/recover-conversation.d.ts.map +1 -0
  304. package/dist/src/utils/recover-conversation.js +314 -0
  305. package/dist/src/utils/recover-conversation.js.map +1 -0
  306. package/dist/src/utils/registry-broker.d.ts +148 -0
  307. package/dist/src/utils/registry-broker.d.ts.map +1 -0
  308. package/dist/src/utils/registry-broker.js +180 -0
  309. package/dist/src/utils/registry-broker.js.map +1 -0
  310. package/dist/src/utils/socks-forward.d.ts +40 -0
  311. package/dist/src/utils/socks-forward.d.ts.map +1 -0
  312. package/dist/src/utils/socks-forward.js +97 -0
  313. package/dist/src/utils/socks-forward.js.map +1 -0
  314. package/dist/src/utils/stack-flag.d.ts +23 -0
  315. package/dist/src/utils/stack-flag.d.ts.map +1 -0
  316. package/dist/src/utils/stack-flag.js +41 -0
  317. package/dist/src/utils/stack-flag.js.map +1 -0
  318. package/dist/src/utils/tailscale-targets.d.ts +52 -0
  319. package/dist/src/utils/tailscale-targets.d.ts.map +1 -0
  320. package/dist/src/utils/tailscale-targets.js +93 -0
  321. package/dist/src/utils/tailscale-targets.js.map +1 -0
  322. package/dist/src/utils/tailscale.d.ts +277 -0
  323. package/dist/src/utils/tailscale.d.ts.map +1 -0
  324. package/dist/src/utils/tailscale.js +1007 -0
  325. package/dist/src/utils/tailscale.js.map +1 -0
  326. package/dist/src/utils/temporal-auth.d.ts +43 -0
  327. package/dist/src/utils/temporal-auth.d.ts.map +1 -0
  328. package/dist/src/utils/temporal-auth.js +176 -0
  329. package/dist/src/utils/temporal-auth.js.map +1 -0
  330. package/dist/src/utils/temporal-codec.d.ts +101 -0
  331. package/dist/src/utils/temporal-codec.d.ts.map +1 -0
  332. package/dist/src/utils/temporal-codec.js +319 -0
  333. package/dist/src/utils/temporal-codec.js.map +1 -0
  334. package/dist/src/utils/tunnel-ownership.d.ts +130 -0
  335. package/dist/src/utils/tunnel-ownership.d.ts.map +1 -0
  336. package/dist/src/utils/tunnel-ownership.js +274 -0
  337. package/dist/src/utils/tunnel-ownership.js.map +1 -0
  338. package/dist/src/utils/vpn-join.d.ts +32 -0
  339. package/dist/src/utils/vpn-join.d.ts.map +1 -0
  340. package/dist/src/utils/vpn-join.js +62 -0
  341. package/dist/src/utils/vpn-join.js.map +1 -0
  342. package/dist/src/utils/vpn.d.ts +62 -0
  343. package/dist/src/utils/vpn.d.ts.map +1 -0
  344. package/dist/src/utils/vpn.js +183 -0
  345. package/dist/src/utils/vpn.js.map +1 -0
  346. package/dist/src/utils/workflow-fingerprint.d.ts +49 -0
  347. package/dist/src/utils/workflow-fingerprint.d.ts.map +1 -0
  348. package/dist/src/utils/workflow-fingerprint.js +135 -0
  349. package/dist/src/utils/workflow-fingerprint.js.map +1 -0
  350. package/dist/src/utils/worktree-identity.d.ts +86 -0
  351. package/dist/src/utils/worktree-identity.d.ts.map +1 -0
  352. package/dist/src/utils/worktree-identity.js +164 -0
  353. package/dist/src/utils/worktree-identity.js.map +1 -0
  354. package/fragments/agents/AGENTS.md.hbs +92 -0
  355. package/fragments/agents/CLAUDE.md.hbs +8 -0
  356. package/fragments/base/Pulumi.dev.yaml.hbs +10 -0
  357. package/fragments/base/Pulumi.yaml.hbs +9 -0
  358. package/fragments/base/index.ts.hbs +107 -0
  359. package/fragments/base/package.json.hbs +22 -0
  360. package/{templates/api-web-db/api → fragments/base}/tsconfig.json +3 -4
  361. package/fragments/bucket/api/src/storage.ts.hbs +81 -0
  362. package/fragments/database/api/src/db.ts.hbs +23 -0
  363. package/fragments/database/prisma/schema.prisma.hbs +18 -0
  364. package/{templates/api-web-db → fragments/service}/api/.dockerignore +2 -0
  365. package/fragments/service/api/package.json.hbs +40 -0
  366. package/fragments/service/api/src/index.ts.hbs +58 -0
  367. package/{templates/api-web-db → fragments/service/api}/tsconfig.json +5 -3
  368. package/fragments/temporal/worker/.dockerignore +4 -0
  369. package/fragments/temporal/worker/Dockerfile +15 -0
  370. package/{templates/temporal-api-worker → fragments/temporal}/worker/package.json.hbs +3 -2
  371. package/fragments/temporal/worker/src/activities.ts.hbs +14 -0
  372. package/fragments/temporal/worker/src/worker.ts.hbs +27 -0
  373. package/fragments/temporal/worker/src/workflows.ts.hbs +24 -0
  374. package/fragments/temporal/worker/tsconfig.json +13 -0
  375. package/package.json +36 -22
  376. package/skills/core/SKILL.md +365 -0
  377. package/skills/pull-remote-agent-context/SKILL.md +194 -0
  378. package/stack/docker-compose.hub.yml +134 -0
  379. package/stack/docker-compose.yml +447 -0
  380. package/stack/hub/Dockerfile.api +18 -0
  381. package/stack/hub/Dockerfile.auth +10 -0
  382. package/stack/hub/Dockerfile.ui +10 -0
  383. package/stack/init/01-databases.sql +12 -0
  384. package/stack/observability/blackbox.yml +20 -0
  385. package/stack/observability/otel-collector.yaml +73 -0
  386. package/stack/observability/prometheus.yml +36 -0
  387. package/stack/observability/tempo.yaml +25 -0
  388. package/stack/temporal/local.yaml +44 -0
  389. package/templates/api-auth/AGENTS.md.hbs +16 -0
  390. package/templates/api-auth/Pulumi.dev.yaml.hbs +8 -0
  391. package/templates/api-auth/Pulumi.yaml.hbs +8 -0
  392. package/templates/api-auth/README.md.hbs +67 -0
  393. package/templates/api-auth/api/package.json.hbs +28 -0
  394. package/templates/api-auth/api/src/index.ts.hbs +96 -0
  395. package/templates/api-auth/api/src/schema.ts.hbs +35 -0
  396. package/templates/api-auth/api/src/seed-authz.ts.hbs +48 -0
  397. package/templates/api-auth/api/src/spicedb-http-provider.ts.hbs +89 -0
  398. package/templates/api-auth/index.ts.hbs +65 -0
  399. package/templates/api-auth/package.json.hbs +20 -0
  400. package/templates/api-auth/skills/develop/SKILL.md.hbs +32 -0
  401. package/templates/api-role-gating/AGENTS.md.hbs +20 -0
  402. package/templates/api-role-gating/Pulumi.dev.yaml.hbs +8 -0
  403. package/templates/api-role-gating/Pulumi.yaml.hbs +8 -0
  404. package/templates/api-role-gating/README.md.hbs +64 -0
  405. package/templates/api-role-gating/api/Dockerfile +17 -0
  406. package/templates/api-role-gating/api/package.json.hbs +28 -0
  407. package/templates/api-role-gating/api/src/authn.ts.hbs +29 -0
  408. package/templates/api-role-gating/api/src/authz.ts.hbs +12 -0
  409. package/templates/api-role-gating/api/src/main.ts.hbs +58 -0
  410. package/templates/api-role-gating/api/src/schema.ts.hbs +22 -0
  411. package/templates/api-role-gating/api/tsconfig.json +13 -0
  412. package/templates/api-role-gating/index.ts.hbs +107 -0
  413. package/templates/api-role-gating/package.json.hbs +21 -0
  414. package/templates/api-role-gating/skills/develop/SKILL.md.hbs +60 -0
  415. package/templates/api-role-gating/tsconfig.json +10 -0
  416. package/templates/apps-repo/README.md.hbs +24 -0
  417. package/templates/apps-repo/gitignore +41 -0
  418. package/templates/apps-repo/npmrc.hbs +7 -0
  419. package/templates/apps-repo/package.json.hbs +15 -0
  420. package/templates/apps-repo/pnpm-workspace.yaml +3 -0
  421. package/templates/apps-repo/tsconfig.json +18 -0
  422. package/templates/external-service/AGENTS.md.hbs +20 -0
  423. package/templates/external-service/Pulumi.dev.yaml.hbs +8 -0
  424. package/templates/external-service/Pulumi.yaml.hbs +8 -0
  425. package/templates/external-service/README.md.hbs +56 -0
  426. package/templates/external-service/api/Dockerfile +15 -0
  427. package/templates/external-service/api/package.json.hbs +25 -0
  428. package/templates/external-service/api/src/index.ts.hbs +81 -0
  429. package/templates/external-service/index.ts.hbs +82 -0
  430. package/templates/external-service/mocks/vendorpay/package.json.hbs +9 -0
  431. package/templates/external-service/mocks/vendorpay/server.mjs.hbs +61 -0
  432. package/templates/external-service/package.json.hbs +34 -0
  433. package/templates/external-service/skills/develop/SKILL.md.hbs +55 -0
  434. package/templates/external-service/tsconfig.json +10 -0
  435. package/templates/platform-repo/AGENTS.md.hbs +18 -0
  436. package/templates/platform-repo/README.md.hbs +38 -0
  437. package/templates/platform-repo/core/Pulumi.yaml.hbs +12 -0
  438. package/templates/platform-repo/core/Pulumi.{{tenant}}-{{env}}.yaml.hbs +57 -0
  439. package/templates/platform-repo/core/index.ts +62 -0
  440. package/templates/platform-repo/core/package.json.hbs +22 -0
  441. package/templates/platform-repo/core/tsconfig.json +8 -0
  442. package/templates/platform-repo/package.json.hbs +15 -0
  443. package/templates/platform-repo/platform/Pulumi.yaml.hbs +12 -0
  444. package/templates/platform-repo/platform/Pulumi.{{tenant}}-{{env}}.yaml.hbs +59 -0
  445. package/templates/platform-repo/platform/index.ts +95 -0
  446. package/templates/platform-repo/platform/package.json.hbs +26 -0
  447. package/templates/platform-repo/platform/tsconfig.json +8 -0
  448. package/templates/platform-repo/pnpm-workspace.yaml +3 -0
  449. package/templates/workflow/AGENTS.md.hbs +15 -0
  450. package/templates/workflow/Pulumi.dev.yaml.hbs +8 -0
  451. package/templates/workflow/Pulumi.yaml.hbs +8 -0
  452. package/templates/workflow/README.md.hbs +45 -0
  453. package/templates/workflow/api/.dockerignore +4 -0
  454. package/templates/workflow/api/Dockerfile +15 -0
  455. package/templates/{temporal-api-worker → workflow}/api/package.json.hbs +8 -6
  456. package/templates/workflow/api/src/index.ts.hbs +130 -0
  457. package/templates/workflow/api/tsconfig.json +14 -0
  458. package/templates/workflow/index.ts.hbs +67 -0
  459. package/templates/workflow/package.json.hbs +20 -0
  460. package/templates/workflow/skills/develop/SKILL.md.hbs +32 -0
  461. package/templates/workflow/tsconfig.json +10 -0
  462. package/templates/workflow/worker/.dockerignore +4 -0
  463. package/templates/workflow/worker/Dockerfile +13 -0
  464. package/templates/workflow/worker/package.json.hbs +25 -0
  465. package/templates/workflow/worker/src/worker.ts.hbs +24 -0
  466. package/templates/workflow/worker/tsconfig.json +14 -0
  467. package/dist/src/commands/devbox.d.ts +0 -22
  468. package/dist/src/commands/devbox.d.ts.map +0 -1
  469. package/dist/src/commands/devbox.js +0 -463
  470. package/dist/src/commands/devbox.js.map +0 -1
  471. package/templates/api-web-db/api/Dockerfile +0 -16
  472. package/templates/api-web-db/api/package.json.hbs +0 -21
  473. package/templates/api-web-db/api/src/index.ts.hbs +0 -123
  474. package/templates/api-web-db/package.json.hbs +0 -27
  475. package/templates/api-web-db/sst.config.ts.hbs +0 -151
  476. package/templates/api-web-db/web/.dockerignore +0 -3
  477. package/templates/api-web-db/web/Dockerfile +0 -17
  478. package/templates/api-web-db/web/app/lib/db.server.ts +0 -36
  479. package/templates/api-web-db/web/app/root.tsx +0 -29
  480. package/templates/api-web-db/web/app/routes/home.tsx.hbs +0 -114
  481. package/templates/api-web-db/web/app/routes.ts +0 -3
  482. package/templates/api-web-db/web/package.json.hbs +0 -30
  483. package/templates/api-web-db/web/prisma/schema.prisma +0 -25
  484. package/templates/api-web-db/web/prisma.config.ts +0 -18
  485. package/templates/api-web-db/web/react-router.config.ts +0 -5
  486. package/templates/api-web-db/web/tsconfig.json +0 -19
  487. package/templates/api-web-db/web/vite.config.ts +0 -9
  488. package/templates/temporal-api-worker/README.md.hbs +0 -133
  489. package/templates/temporal-api-worker/api/src/index.ts.hbs +0 -145
  490. package/templates/temporal-api-worker/package.json.hbs +0 -29
  491. package/templates/temporal-api-worker/sst.config.ts.hbs +0 -161
  492. package/templates/temporal-api-worker/worker/Dockerfile +0 -11
  493. package/templates/temporal-api-worker/worker/src/bundle-workflows.ts +0 -38
  494. package/templates/temporal-api-worker/worker/src/worker.ts.hbs +0 -93
  495. /package/templates/{temporal-api-worker → api-auth}/api/.dockerignore +0 -0
  496. /package/templates/{temporal-api-worker → api-auth}/api/Dockerfile +0 -0
  497. /package/templates/{temporal-api-worker → api-auth}/api/tsconfig.json +0 -0
  498. /package/templates/{temporal-api-worker → api-auth}/tsconfig.json +0 -0
  499. /package/templates/{temporal-api-worker/worker → api-role-gating/api}/.dockerignore +0 -0
  500. /package/templates/{temporal-api-worker/worker → external-service/api}/tsconfig.json +0 -0
  501. /package/templates/{temporal-api-worker → workflow}/api/src/encryption-codec.ts +0 -0
  502. /package/templates/{temporal-api-worker → workflow}/worker/src/activities.ts.hbs +0 -0
  503. /package/templates/{temporal-api-worker → workflow}/worker/src/encryption-codec.ts +0 -0
  504. /package/templates/{temporal-api-worker → workflow}/worker/src/workflows.ts.hbs +0 -0
@@ -0,0 +1,274 @@
1
+ /**
2
+ * Ownership contract for the tunnel runner (MESH-2407).
3
+ *
4
+ * Three silent-dead-tunnel incidents in ten days (MESH-2169, MESH-2014, the
5
+ * #2991 re-review) shared one enabler: readiness was inferred from "something
6
+ * accepts TCP on the port". That conflates LIVENESS (a listener exists) with
7
+ * OWNERSHIP (the listener is OUR runner, wired to OUR SOCKS upstream). This
8
+ * module is the ownership half of the contract:
9
+ *
10
+ * - The runner that actually binds the forwarder ports writes a MANIFEST
11
+ * (pid, process-group id, a per-run random token, a loopback control port)
12
+ * and answers a one-shot control handshake with that token plus the ports
13
+ * it is listening on — read from its in-process `net.Server`s, so the
14
+ * answer can't be faked by a foreign listener and probing it opens no
15
+ * SOCKS→VPC data connection.
16
+ * - Callers verify ownership (manifest → live pid → control handshake →
17
+ * token/socks-port/port-coverage match) instead of dialing ports. A port
18
+ * that accepts TCP without passing the handshake is a SQUATTER and must be
19
+ * a loud failure, never adopt-and-continue.
20
+ * - Teardown signals process GROUPS recorded here (plus argv-discovered
21
+ * runners), so no kill path can orphan a grandchild with ports still bound.
22
+ */
23
+ import * as crypto from 'node:crypto';
24
+ import * as fs from 'node:fs';
25
+ import * as net from 'node:net';
26
+ import * as path from 'node:path';
27
+ import { execFileSync } from 'node:child_process';
28
+ export function mintRunnerToken() {
29
+ return crypto.randomBytes(16).toString('hex');
30
+ }
31
+ export function readRunnerManifest(file) {
32
+ if (!fs.existsSync(file))
33
+ return null;
34
+ try {
35
+ return JSON.parse(fs.readFileSync(file, 'utf8'));
36
+ }
37
+ catch {
38
+ return null;
39
+ }
40
+ }
41
+ export function writeRunnerManifest(file, manifest) {
42
+ fs.mkdirSync(path.dirname(file), { recursive: true });
43
+ fs.writeFileSync(file, JSON.stringify(manifest, null, 2), { mode: 0o600 });
44
+ }
45
+ /**
46
+ * Remove the manifest — but only if it is still OURS (`token` matches). A dying
47
+ * runner must not clobber the manifest of a newer runner that already replaced it.
48
+ * Omit `token` for teardown paths that own the whole tenant state.
49
+ */
50
+ export function clearRunnerManifest(file, token) {
51
+ if (token !== undefined && readRunnerManifest(file)?.token !== token)
52
+ return;
53
+ try {
54
+ fs.unlinkSync(file);
55
+ }
56
+ catch {
57
+ /* already gone */
58
+ }
59
+ }
60
+ /** Process-group id of a pid via `ps` (macOS/BSD); null when undiscoverable. */
61
+ export function getProcessGroupId(pid) {
62
+ try {
63
+ const out = execFileSync('ps', ['-o', 'pgid=', '-p', String(pid)], {
64
+ encoding: 'utf8',
65
+ stdio: ['ignore', 'pipe', 'ignore'],
66
+ }).trim();
67
+ const pgid = Number(out);
68
+ return Number.isInteger(pgid) && pgid > 0 ? pgid : null;
69
+ }
70
+ catch {
71
+ return null;
72
+ }
73
+ }
74
+ /**
75
+ * Pids of tunnel-runner processes for a tenant, parsed from `ps` output
76
+ * (`pid command` lines). Matches both `__run` and the legacy `__supervise`
77
+ * argv, and skips `exclude` (the calling process, when it IS the runner).
78
+ * Pure for unit tests; `discoverRunnerPids` feeds it live `ps` output.
79
+ */
80
+ export function parseRunnerPidsFromPs(psOutput, tenant, exclude) {
81
+ const pids = [];
82
+ for (const line of psOutput.split('\n')) {
83
+ if (!/vpn\s+tunnel\s+(?:__run|__supervise)\s+/.test(line))
84
+ continue;
85
+ const m = line.trim().match(/^(\d+)\s+(.*)$/);
86
+ if (!m)
87
+ continue;
88
+ const argv = m[2].split(/\s+/);
89
+ // The tenant is the argument right after __run/__supervise — an exact
90
+ // match, so tenant "enc" never matches a runner for tenant "encore".
91
+ const i = argv.findIndex((a) => a === '__run' || a === '__supervise');
92
+ if (i === -1 || argv[i + 1] !== tenant)
93
+ continue;
94
+ const pid = Number(m[1]);
95
+ if (pid !== exclude)
96
+ pids.push(pid);
97
+ }
98
+ return pids;
99
+ }
100
+ /** Live argv discovery of runner pids for a tenant (empty when `ps` fails). */
101
+ export function discoverRunnerPids(tenant, exclude) {
102
+ try {
103
+ const out = execFileSync('ps', ['ax', '-o', 'pid=,command='], {
104
+ encoding: 'utf8',
105
+ stdio: ['ignore', 'pipe', 'ignore'],
106
+ });
107
+ return parseRunnerPidsFromPs(out, tenant, exclude);
108
+ }
109
+ catch {
110
+ return [];
111
+ }
112
+ }
113
+ /**
114
+ * Start the runner's one-shot control endpoint on a loopback ephemeral port.
115
+ * Each connection gets one JSON line (the live payload) and is closed — no
116
+ * protocol state, nothing routable, and probing it touches no data plane.
117
+ */
118
+ export function startControlServer(payload) {
119
+ return new Promise((resolve, reject) => {
120
+ const server = net.createServer((socket) => {
121
+ socket.on('error', () => { });
122
+ try {
123
+ socket.end(`${JSON.stringify(payload())}\n`);
124
+ }
125
+ catch {
126
+ socket.destroy();
127
+ }
128
+ });
129
+ server.on('error', reject);
130
+ server.listen(0, '127.0.0.1', () => {
131
+ resolve({ server, port: server.address().port });
132
+ });
133
+ });
134
+ }
135
+ /** Dial the control endpoint and parse its one-line JSON answer; null on any failure. */
136
+ export function queryControl(port, timeoutMs = 700) {
137
+ return new Promise((resolve) => {
138
+ const s = new net.Socket();
139
+ let buf = '';
140
+ let done = false;
141
+ const fin = (v) => {
142
+ if (done)
143
+ return;
144
+ done = true;
145
+ s.destroy();
146
+ resolve(v);
147
+ };
148
+ s.setTimeout(timeoutMs);
149
+ s.once('timeout', () => fin(null));
150
+ s.once('error', () => fin(null));
151
+ s.on('data', (d) => {
152
+ buf += d.toString();
153
+ });
154
+ s.once('close', () => {
155
+ try {
156
+ fin(JSON.parse(buf));
157
+ }
158
+ catch {
159
+ fin(null);
160
+ }
161
+ });
162
+ s.connect(port, '127.0.0.1');
163
+ });
164
+ }
165
+ function defaultPidAlive(pid) {
166
+ try {
167
+ process.kill(pid, 0);
168
+ return true;
169
+ }
170
+ catch {
171
+ return false;
172
+ }
173
+ }
174
+ /**
175
+ * The ownership handshake: manifest → live pid → control endpoint → token,
176
+ * SOCKS port, and port coverage all match. Anything less is NOT ours — the
177
+ * caller must treat an accepting-but-unowned port as a squatter, never reuse it.
178
+ */
179
+ export async function verifyRunnerOwnership(args) {
180
+ const { manifest } = args;
181
+ if (!manifest)
182
+ return { ok: false, reason: 'no-manifest' };
183
+ const alive = args.isPidAlive ?? defaultPidAlive;
184
+ if (!alive(manifest.pid))
185
+ return { ok: false, reason: 'runner-dead' };
186
+ const resp = await (args.query ?? queryControl)(manifest.controlPort);
187
+ if (!resp)
188
+ return { ok: false, reason: 'no-control-answer' };
189
+ if (resp.token !== manifest.token)
190
+ return { ok: false, reason: 'token-mismatch', resp };
191
+ if (resp.socksPort !== args.expectedSocksPort) {
192
+ return { ok: false, reason: 'socks-port-mismatch', resp };
193
+ }
194
+ const listening = new Set(resp.listening);
195
+ const missing = args.expectedPorts.filter((p) => !listening.has(p));
196
+ if (missing.length > 0) {
197
+ return { ok: false, reason: `ports-not-listening:${missing.join(',')}`, resp };
198
+ }
199
+ return { ok: true, reason: '', resp };
200
+ }
201
+ /**
202
+ * Poll an ownership check until it passes or `deadlineMs` of wall-clock elapses;
203
+ * returns the last (failing) check otherwise. The deadline bounds TIME, not
204
+ * rounds — each check can itself cost up to the control-query timeout, so a
205
+ * round-counting loop would multiply the promised deadline several-fold.
206
+ * Retrying also matters for correctness, not just latency: two failure reasons
207
+ * are transient by design (`ports-not-listening:` while the runner's self-heal
208
+ * loop rebinds a forwarder, `no-control-answer` under accept-backlog pressure),
209
+ * and a single-shot sample of a healthy shared runner in one of those windows
210
+ * would tear it down for every concurrent session on the tenant (MESH-2014).
211
+ */
212
+ export async function pollOwnership(check, deadlineMs) {
213
+ let last = { ok: false, reason: 'not-checked' };
214
+ const end = Date.now() + deadlineMs;
215
+ do {
216
+ last = await check();
217
+ if (last.ok)
218
+ return last;
219
+ await new Promise((r) => setTimeout(r, 250));
220
+ } while (Date.now() < end);
221
+ return last;
222
+ }
223
+ /** Best-effort `lsof` description of what holds a port ("cmd (pid N)"); null if unknown. */
224
+ export function describePortOwner(port) {
225
+ try {
226
+ const out = execFileSync('lsof', ['-nP', `-iTCP:${port}`, '-sTCP:LISTEN', '-Fcp'], {
227
+ encoding: 'utf8',
228
+ stdio: ['ignore', 'pipe', 'ignore'],
229
+ });
230
+ // -F output: "p<pid>\nc<command>\n…" per process.
231
+ const pid = out.match(/^p(\d+)$/m)?.[1];
232
+ const cmd = out.match(/^c(.+)$/m)?.[1];
233
+ if (!pid && !cmd)
234
+ return null;
235
+ return `${cmd ?? '?'} (pid ${pid ?? '?'})`;
236
+ }
237
+ catch {
238
+ return null;
239
+ }
240
+ }
241
+ /**
242
+ * Of `ports`, the ones something is accepting TCP on. Called AFTER ownership
243
+ * failed / teardown ran, so every hit is a foreign or stale listener.
244
+ */
245
+ export async function findSquattedPorts(ports, accepts) {
246
+ const squatted = [];
247
+ for (const port of ports) {
248
+ if (await accepts(port))
249
+ squatted.push({ port, owner: describePortOwner(port) });
250
+ }
251
+ return squatted;
252
+ }
253
+ /**
254
+ * The loud-failure text for a squatted tunnel port (`mesh dev doctor` style:
255
+ * what is wrong, why we refuse, exactly what to run). Never adopt-and-continue.
256
+ */
257
+ export function buildSquatterError(tenant, squatted, detail) {
258
+ const lines = squatted.map((s) => ` 127.0.0.1:${s.port} held by ${s.owner ?? 'an unidentified process'}`);
259
+ const first = squatted[0]?.port ?? '<port>';
260
+ return [
261
+ `Tunnel port(s) for tenant '${tenant}' are bound by a process mesh does not own${detail ? ` (${detail})` : ''}:`,
262
+ ...lines,
263
+ ` Refusing to reuse a foreign listener — traffic would silently flow to the wrong upstream.`,
264
+ ` To fix:`,
265
+ ` mesh vpn -t ${tenant} tunnel down --stop # tear down mesh-owned runners + daemon`,
266
+ ` lsof -nP -iTCP:${first} -sTCP:LISTEN # identify what still holds the port`,
267
+ ` then stop that process and re-run.`,
268
+ // Port blocks are a 63-bucket hash (MESH-2375), so a DIFFERENT tenant's
269
+ // runner can collide onto this block — in which case the `down` above is a
270
+ // no-op and only lsof identifies the real owner.
271
+ ` (If lsof names another mesh runner, it belongs to a different tenant — tear that one down instead.)`,
272
+ ].join('\n');
273
+ }
274
+ //# sourceMappingURL=tunnel-ownership.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tunnel-ownership.js","sourceRoot":"","sources":["../../../src/utils/tunnel-ownership.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ type CtxConfig = {
2
+ issuer?: string;
3
+ vpnJoinBroker?: string;
4
+ } | null;
5
+ /**
6
+ * Resolve the broker URL, preferring the platform-published value from
7
+ * discovery (ContextConfig.vpnJoinBroker) and falling back to DNS-convention
8
+ * derivation for platforms not yet redeployed with the payload field.
9
+ */
10
+ export declare function resolveVpnJoinBroker(context: string, getCfg?: (c: string) => CtxConfig): string | null;
11
+ /**
12
+ * FALLBACK ONLY. Derive by convention — issuer host `identity.<env>.<domain>`
13
+ * → `vpn-join.<env>.<domain>` — mirroring deriveLoginServer (dev.ts:1479).
14
+ * Prefer resolveVpnJoinBroker, which reads the platform-published URL first.
15
+ */
16
+ export declare function deriveVpnJoinBroker(context: string, getCfg?: (c: string) => CtxConfig): string | null;
17
+ export interface MintDeps {
18
+ getValidToken: (context: string) => Promise<string | null>;
19
+ fetchFn?: typeof fetch;
20
+ }
21
+ /**
22
+ * Fetch a single-use pre-auth key from the broker. Returns null on ANY failure
23
+ * (no token, non-2xx, network error) so the caller falls back to the browser
24
+ * relay join — the broker path is strictly additive.
25
+ */
26
+ export declare function mintPreAuthKey(context: string, brokerUrl: string, deps: MintDeps): Promise<{
27
+ authKey: string;
28
+ loginServer: string;
29
+ } | null>;
30
+ export declare function realMintDeps(): MintDeps;
31
+ export {};
32
+ //# sourceMappingURL=vpn-join.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vpn-join.d.ts","sourceRoot":"","sources":["../../../src/utils/vpn-join.ts"],"names":[],"mappings":"AAEA,KAAK,SAAS,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC;AAEpE;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,CAAC,CAAC,EAAE,MAAM,KAAK,SAA4B,GAClD,MAAM,GAAG,IAAI,CAIf;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,CAAC,CAAC,EAAE,MAAM,KAAK,SAA4B,GAClD,MAAM,GAAG,IAAI,CAWf;AAED,MAAM,WAAW,QAAQ;IACvB,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC3D,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,QAAQ,GACb,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAgB1D;AAGD,wBAAgB,YAAY,IAAI,QAAQ,CAEvC"}
@@ -0,0 +1,62 @@
1
+ import { getContextConfig, getValidToken } from "../commands/login.js";
2
+ /**
3
+ * Resolve the broker URL, preferring the platform-published value from
4
+ * discovery (ContextConfig.vpnJoinBroker) and falling back to DNS-convention
5
+ * derivation for platforms not yet redeployed with the payload field.
6
+ */
7
+ export function resolveVpnJoinBroker(context, getCfg = getContextConfig) {
8
+ const cfg = getCfg(context);
9
+ if (cfg?.vpnJoinBroker)
10
+ return cfg.vpnJoinBroker;
11
+ return deriveVpnJoinBroker(context, getCfg);
12
+ }
13
+ /**
14
+ * FALLBACK ONLY. Derive by convention — issuer host `identity.<env>.<domain>`
15
+ * → `vpn-join.<env>.<domain>` — mirroring deriveLoginServer (dev.ts:1479).
16
+ * Prefer resolveVpnJoinBroker, which reads the platform-published URL first.
17
+ */
18
+ export function deriveVpnJoinBroker(context, getCfg = getContextConfig) {
19
+ const cfg = getCfg(context);
20
+ if (!cfg?.issuer)
21
+ return null;
22
+ try {
23
+ const u = new URL(cfg.issuer);
24
+ const parts = u.hostname.split(".");
25
+ parts[0] = "vpn-join";
26
+ return `https://${parts.join(".")}`;
27
+ }
28
+ catch {
29
+ return null;
30
+ }
31
+ }
32
+ /**
33
+ * Fetch a single-use pre-auth key from the broker. Returns null on ANY failure
34
+ * (no token, non-2xx, network error) so the caller falls back to the browser
35
+ * relay join — the broker path is strictly additive.
36
+ */
37
+ export async function mintPreAuthKey(context, brokerUrl, deps) {
38
+ const token = await deps.getValidToken(context);
39
+ if (!token)
40
+ return null;
41
+ const doFetch = deps.fetchFn ?? fetch;
42
+ try {
43
+ const res = await doFetch(`${brokerUrl}/preauth`, {
44
+ method: "POST",
45
+ headers: { authorization: `Bearer ${token}` },
46
+ });
47
+ if (!res.ok)
48
+ return null;
49
+ const body = (await res.json());
50
+ if (!body.authKey)
51
+ return null;
52
+ return { authKey: body.authKey, loginServer: body.loginServer ?? "" };
53
+ }
54
+ catch {
55
+ return null;
56
+ }
57
+ }
58
+ // Convenience for production callers that use the real login.ts token source.
59
+ export function realMintDeps() {
60
+ return { getValidToken: (c) => getValidToken(c) };
61
+ }
62
+ //# sourceMappingURL=vpn-join.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vpn-join.js","sourceRoot":"","sources":["../../../src/utils/vpn-join.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIvE;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAe,EACf,SAAmC,gBAAgB;IAEnD,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5B,IAAI,GAAG,EAAE,aAAa;QAAE,OAAO,GAAG,CAAC,aAAa,CAAC;IACjD,OAAO,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAC9C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAAe,EACf,SAAmC,gBAAgB;IAEnD,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5B,IAAI,CAAC,GAAG,EAAE,MAAM;QAAE,OAAO,IAAI,CAAC;IAC9B,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC9B,MAAM,KAAK,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACpC,KAAK,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC;QACtB,OAAO,WAAW,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAOD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAe,EACf,SAAiB,EACjB,IAAc;IAEd,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAChD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC;IACtC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,SAAS,UAAU,EAAE;YAChD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;SAC9C,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QACzB,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA+C,CAAC;QAC9E,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC/B,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,EAAE,EAAE,CAAC;IACxE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,YAAY;IAC1B,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;AACpD,CAAC"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * VPN detection utilities
3
+ */
4
+ /**
5
+ * Detect whether a Tailscale VPN connection is active.
6
+ *
7
+ * Uses socket-aware `execTailscaleCmd` so it works in both kernel tun mode
8
+ * (standard socket) and legacy userspace networking (/tmp/tailscale.sock).
9
+ * Returns `true` only when BackendState is "Running" and Self.Online is true.
10
+ * Returns `false` silently on any failure (binary missing, daemon stopped,
11
+ * parse error, missing fields).
12
+ */
13
+ export declare function isVpnConnected(): Promise<boolean>;
14
+ /** Connection details for the Headscale DNS writer sidecar. */
15
+ export interface HeadscaleDnsConfig {
16
+ namespace: string;
17
+ pod: string;
18
+ container: string;
19
+ filePath: string;
20
+ }
21
+ /**
22
+ * Build a HeadscaleDnsConfig from tenant/env, following the same naming
23
+ * convention as `mesh vpn` (⁠{tenant}-{env}-headscale).
24
+ *
25
+ * Pod name, container, and file path are infrastructure conventions that
26
+ * rarely change — override via the optional parameter if they do.
27
+ */
28
+ export declare function headscaleDnsConfig(tenant?: string, env?: string, overrides?: Partial<HeadscaleDnsConfig>): HeadscaleDnsConfig;
29
+ export interface DnsRecord {
30
+ name: string;
31
+ type: "A";
32
+ value: string;
33
+ }
34
+ /**
35
+ * Retrieve the current Tailscale hostname and IP address.
36
+ *
37
+ * Returns `null` when Tailscale is not installed, not running, or not online.
38
+ */
39
+ export declare function getTailscaleInfo(): Promise<{
40
+ hostname: string;
41
+ ip: string;
42
+ } | null>;
43
+ /**
44
+ * Read DNS records from the dns-writer sidecar in the Headscale pod.
45
+ *
46
+ * Throws with an actionable message if kubectl can't reach the pod.
47
+ * Returns an empty array when the file is missing or contains invalid JSON.
48
+ */
49
+ export declare function readDnsRecords(cfg: HeadscaleDnsConfig): DnsRecord[];
50
+ /**
51
+ * Write DNS A records to the dns-writer sidecar in the Headscale pod.
52
+ *
53
+ * Pipes JSON via stdin to avoid shell-escaping issues.
54
+ * Throws with an actionable message if kubectl can't reach the pod.
55
+ */
56
+ export declare function registerDnsRecords(cfg: HeadscaleDnsConfig, records: DnsRecord[]): void;
57
+ /**
58
+ * Remove DNS records whose `name` ends with `suffix` from the Headscale pod.
59
+ * Best-effort: logs a warning on failure instead of throwing.
60
+ */
61
+ export declare function unregisterDnsRecords(cfg: HeadscaleDnsConfig, suffix: string): void;
62
+ //# sourceMappingURL=vpn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vpn.d.ts","sourceRoot":"","sources":["../../../src/utils/vpn.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH;;;;;;;;GAQG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAQvD;AASD,+DAA+D;AAC/D,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,SAAS,EACf,GAAG,SAAQ,EACX,SAAS,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,GACtC,kBAAkB,CAQpB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,GAAG,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;CACf;AAsDD;;;;GAIG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAqBzF;AAUD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EAAE,CA6BnE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,kBAAkB,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,IAAI,CAgBtF;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAQlF"}
@@ -0,0 +1,183 @@
1
+ /**
2
+ * VPN detection utilities
3
+ */
4
+ import { execFile, execFileSync } from "node:child_process";
5
+ import { existsSync } from "node:fs";
6
+ const TAILSCALE_PATHS = [
7
+ "tailscale",
8
+ "/Applications/Tailscale.app/Contents/MacOS/Tailscale",
9
+ ];
10
+ /**
11
+ * Detect whether a Tailscale VPN connection is active.
12
+ *
13
+ * Uses socket-aware `execTailscaleCmd` so it works in both kernel tun mode
14
+ * (standard socket) and legacy userspace networking (/tmp/tailscale.sock).
15
+ * Returns `true` only when BackendState is "Running" and Self.Online is true.
16
+ * Returns `false` silently on any failure (binary missing, daemon stopped,
17
+ * parse error, missing fields).
18
+ */
19
+ export async function isVpnConnected() {
20
+ try {
21
+ const stdout = await execTailscaleCmd(["status", "--json"]);
22
+ const status = JSON.parse(stdout);
23
+ return status.BackendState === "Running" && status.Self?.Online === true;
24
+ }
25
+ catch {
26
+ return false;
27
+ }
28
+ }
29
+ // ---------------------------------------------------------------------------
30
+ // DNS record management & Tailscale info
31
+ // ---------------------------------------------------------------------------
32
+ /** Standard socket (kernel tun mode), then legacy (userspace mode). */
33
+ const TAILSCALE_SOCKET_PATHS = ["/var/run/tailscale/tailscaled.sock", "/tmp/tailscale.sock"];
34
+ /**
35
+ * Build a HeadscaleDnsConfig from tenant/env, following the same naming
36
+ * convention as `mesh vpn` (⁠{tenant}-{env}-headscale).
37
+ *
38
+ * Pod name, container, and file path are infrastructure conventions that
39
+ * rarely change — override via the optional parameter if they do.
40
+ */
41
+ export function headscaleDnsConfig(tenant = "mesh", env = "dev", overrides) {
42
+ return {
43
+ namespace: `${tenant}-${env}-headscale`,
44
+ pod: "headscale-0",
45
+ container: "dns-writer",
46
+ filePath: "/var/lib/headscale/dns/extra-records.json",
47
+ ...overrides,
48
+ };
49
+ }
50
+ /**
51
+ * Execute a tailscale CLI command, trying each known binary path.
52
+ * Automatically appends `--socket <path>` when a tailscale socket is found.
53
+ */
54
+ function execTailscaleCmd(args) {
55
+ const socketPath = TAILSCALE_SOCKET_PATHS.find(existsSync);
56
+ const attempts = [];
57
+ for (const binary of TAILSCALE_PATHS) {
58
+ if (socketPath) {
59
+ attempts.push({ binary, args: ["--socket", socketPath, ...args] });
60
+ }
61
+ attempts.push({ binary, args });
62
+ }
63
+ return new Promise((resolve, reject) => {
64
+ let index = 0;
65
+ function tryNext() {
66
+ if (index >= attempts.length) {
67
+ reject(new Error("All tailscale binary attempts failed"));
68
+ return;
69
+ }
70
+ const attempt = attempts[index++];
71
+ execFile(attempt.binary, attempt.args, (error, stdout) => {
72
+ if (error) {
73
+ tryNext();
74
+ }
75
+ else {
76
+ resolve(stdout);
77
+ }
78
+ });
79
+ }
80
+ tryNext();
81
+ });
82
+ }
83
+ /**
84
+ * Retrieve the current Tailscale hostname and IP address.
85
+ *
86
+ * Returns `null` when Tailscale is not installed, not running, or not online.
87
+ */
88
+ export async function getTailscaleInfo() {
89
+ try {
90
+ const stdout = await execTailscaleCmd(["status", "--json"]);
91
+ const status = JSON.parse(stdout);
92
+ if (status.BackendState === "Running" &&
93
+ status.Self?.Online === true &&
94
+ status.Self.HostName &&
95
+ status.Self.TailscaleIPs?.length) {
96
+ return {
97
+ hostname: status.Self.HostName,
98
+ ip: status.Self.TailscaleIPs[0],
99
+ };
100
+ }
101
+ return null;
102
+ }
103
+ catch {
104
+ return null;
105
+ }
106
+ }
107
+ /** Helper: build kubectl exec args for the dns-writer sidecar. */
108
+ function dnsWriterExec(cfg, cmd, interactive = false) {
109
+ return [
110
+ "exec", ...(interactive ? ["-i"] : []),
111
+ "-n", cfg.namespace, cfg.pod, "-c", cfg.container, "--", ...cmd,
112
+ ];
113
+ }
114
+ /**
115
+ * Read DNS records from the dns-writer sidecar in the Headscale pod.
116
+ *
117
+ * Throws with an actionable message if kubectl can't reach the pod.
118
+ * Returns an empty array when the file is missing or contains invalid JSON.
119
+ */
120
+ export function readDnsRecords(cfg) {
121
+ try {
122
+ const raw = execFileSync("kubectl", dnsWriterExec(cfg, ["cat", cfg.filePath]), {
123
+ encoding: "utf-8",
124
+ stdio: ["ignore", "pipe", "pipe"],
125
+ });
126
+ const trimmed = raw.trim();
127
+ if (!trimmed || trimmed === "[]")
128
+ return [];
129
+ try {
130
+ return JSON.parse(trimmed);
131
+ }
132
+ catch {
133
+ console.warn(`[vpn] DNS records file contains invalid JSON, treating as empty`);
134
+ return [];
135
+ }
136
+ }
137
+ catch (err) {
138
+ const msg = err.message ?? String(err);
139
+ if (msg.includes("not found") || msg.includes("Unable to connect")) {
140
+ throw new Error(`Cannot reach Headscale DNS writer (namespace=${cfg.namespace}, pod=${cfg.pod}).\n` +
141
+ `Verify kubectl context and that the Headscale pod is running:\n` +
142
+ ` kubectl get pods -n ${cfg.namespace}`);
143
+ }
144
+ if (msg.includes("No such file")) {
145
+ return [];
146
+ }
147
+ // Unexpected error — rethrow
148
+ throw err;
149
+ }
150
+ }
151
+ /**
152
+ * Write DNS A records to the dns-writer sidecar in the Headscale pod.
153
+ *
154
+ * Pipes JSON via stdin to avoid shell-escaping issues.
155
+ * Throws with an actionable message if kubectl can't reach the pod.
156
+ */
157
+ export function registerDnsRecords(cfg, records) {
158
+ const json = JSON.stringify(records);
159
+ try {
160
+ execFileSync("kubectl", dnsWriterExec(cfg, ["sh", "-c", `cat > '${cfg.filePath}'`], true), { input: json, stdio: ["pipe", "pipe", "pipe"] });
161
+ }
162
+ catch (err) {
163
+ const msg = err.message ?? String(err);
164
+ throw new Error(`Failed to write DNS records to Headscale (namespace=${cfg.namespace}, pod=${cfg.pod}).\n` +
165
+ `${msg.includes("not found") ? "Pod not found. " : ""}` +
166
+ `Verify kubectl context: kubectl get pods -n ${cfg.namespace}`);
167
+ }
168
+ }
169
+ /**
170
+ * Remove DNS records whose `name` ends with `suffix` from the Headscale pod.
171
+ * Best-effort: logs a warning on failure instead of throwing.
172
+ */
173
+ export function unregisterDnsRecords(cfg, suffix) {
174
+ try {
175
+ const records = readDnsRecords(cfg);
176
+ const filtered = records.filter((r) => !r.name.endsWith(suffix));
177
+ registerDnsRecords(cfg, filtered);
178
+ }
179
+ catch {
180
+ // Best-effort cleanup — silent on failure
181
+ }
182
+ }
183
+ //# sourceMappingURL=vpn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vpn.js","sourceRoot":"","sources":["../../../src/utils/vpn.ts"],"names":[],"mappings":"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"}